diff --git a/src/main/java/com/l2jserver/datapack/custom/service/base/model/entity/CustomServiceProduct.java b/src/main/java/com/l2jserver/datapack/custom/service/base/model/entity/CustomServiceProduct.java
index ff2aacf97afa21c4ffcbc6343b306479bd66a639..b09f476206028d4dcc4aebe6ede6403974ae35b0 100644
--- a/src/main/java/com/l2jserver/datapack/custom/service/base/model/entity/CustomServiceProduct.java
+++ b/src/main/java/com/l2jserver/datapack/custom/service/base/model/entity/CustomServiceProduct.java
@@ -40,6 +40,7 @@ public abstract class CustomServiceProduct extends Refable {
 		if (!items.isEmpty()) {
 			HTMLTemplatePlaceholder itemsPlaceholder = getPlaceholder().addChild("items", null).getChild("items");
 			for (ItemRequirement item : items) {
+				item.afterDeserialize();
 				itemsPlaceholder.addAliasChild(String.valueOf(itemsPlaceholder.getChildrenSize()), item.getPlaceholder());
 			}
 		}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterService.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterService.java
new file mode 100644
index 0000000000000000000000000000000000000000..221eea3ef09061102e249676c15715a1d118eac5
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterService.java
@@ -0,0 +1,557 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.l2jserver.datapack.custom.service.base.CustomServiceScript;
+import com.l2jserver.datapack.custom.service.base.util.CommandProcessor;
+import com.l2jserver.datapack.custom.service.base.util.htmltmpls.HTMLTemplatePlaceholder;
+import com.l2jserver.datapack.custom.service.teleporter.model.TeleporterConfig;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.AbstractTeleporter;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.GroupTeleport;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.GroupTeleportCategory;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.SoloTeleport;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.SoloTeleportCategory;
+import com.l2jserver.gameserver.config.Configuration;
+import com.l2jserver.gameserver.handler.BypassHandler;
+import com.l2jserver.gameserver.handler.ItemHandler;
+import com.l2jserver.gameserver.handler.VoicedCommandHandler;
+import com.l2jserver.gameserver.instancemanager.InstanceManager;
+import com.l2jserver.gameserver.model.AbstractPlayerGroup;
+import com.l2jserver.gameserver.model.L2CommandChannel;
+import com.l2jserver.gameserver.model.L2Party;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.entity.TvTEvent;
+import com.l2jserver.gameserver.model.instancezone.InstanceWorld;
+import com.l2jserver.gameserver.network.SystemMessageId;
+import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
+import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager;
+
+/**
+ * Teleporter service.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public final class TeleporterService extends CustomServiceScript {
+	private static final Logger LOG = LoggerFactory.getLogger(TeleporterService.class.getName());
+	
+	public static final String SCRIPT_NAME = "teleporter";
+	public static final Path SCRIPT_PATH = Paths.get(SCRIPT_COLLECTION, SCRIPT_NAME);
+	
+	private static TeleporterConfig config;
+	private static TeleporterService script;
+	
+	public static TeleporterConfig getConfig() {
+		return config;
+	}
+	
+	public static TeleporterService getService() {
+		return script;
+	}
+	
+	public static void main(String[] args) {
+		if (!Configuration.teleporterService().enable()) {
+			LOG.info("Disabled.");
+			return;
+		}
+		
+		LOG.info("Loading...");
+		try {
+			config = new TeleporterConfig();
+			script = new TeleporterService();
+		} catch (Exception e) {
+			LOG.error("Failed to load!", e);
+			return;
+		}
+		
+		getConfig().registerNpcs(script);
+	}
+	
+	public TeleporterService() {
+		super(SCRIPT_NAME);
+		
+		BypassHandler.getInstance().registerHandler(TeleporterServiceBypassHandler.getInstance());
+		
+		if (Configuration.teleporterService().getVoicedEnable()) {
+			VoicedCommandHandler.getInstance().registerHandler(TeleporterServiceVoicedCommandHandler.getInstance());
+			ItemHandler.getInstance().registerHandler(TeleporterServiceItemHandler.getInstance());
+		}
+	}
+	
+	@Override
+	public boolean unload() {
+		BypassHandler.getInstance().removeHandler(TeleporterServiceBypassHandler.getInstance());
+		if (Configuration.teleporterService().getVoicedEnable()) {
+			VoicedCommandHandler.getInstance().removeHandler(TeleporterServiceVoicedCommandHandler.getInstance());
+			ItemHandler.getInstance().removeHandler(TeleporterServiceItemHandler.getInstance());
+		}
+		return super.unload();
+	}
+	
+	// ////////////////////////////////////
+	// UTILITY METHODS
+	// ////////////////////////////////////
+	private void _showAdvancedHtml(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc, String htmlPath, Map<String, HTMLTemplatePlaceholder> placeholders) {
+		showAdvancedHtml(player, teleporter, npc, htmlPath, placeholders);
+	}
+	
+	private void _showTeleportHtml(L2PcInstance player, AbstractTeleporter teleporter, SoloTeleport teleport, L2Npc npc, String htmlPath) {
+		Map<String, HTMLTemplatePlaceholder> placeholders = new HashMap<>();
+		placeholders.put("teleport", teleport.getPlaceholder());
+		
+		_showAdvancedHtml(player, teleporter, npc, htmlPath, placeholders);
+	}
+	
+	private boolean _takeTeleportItems(SoloTeleport teleport, L2PcInstance initiator) {
+		if (!teleport.getItems().isEmpty()) {
+			HashMap<Integer, Long> items = new HashMap<>();
+			fillItemAmountMap(items, teleport);
+			
+			for (Entry<Integer, Long> item : items.entrySet()) {
+				if (initiator.getInventory().getInventoryItemCount(item.getKey(), 0, true) < item.getValue()) {
+					initiator.sendMessage("Not enough items!");
+					return false;
+				}
+			}
+			
+			for (Entry<Integer, Long> item : items.entrySet()) {
+				initiator.destroyItemByItemId("TeleporterService", item.getKey(), item.getValue(), initiator, true);
+			}
+		}
+		
+		return true;
+	}
+	
+	private InstanceWorld _createInstance(String instanceDefinition) {
+		int instanceId = InstanceManager.getInstance().createDynamicInstance(instanceDefinition);
+		InstanceWorld world = new InstanceWorld();
+		world.setInstanceId(instanceId);
+		// TODO: world.setTemplateId(???);
+		InstanceManager.getInstance().addWorld(world);
+		return world;
+	}
+	
+	// ////////////////////////////////////
+	// HTML COMMANDS
+	// ////////////////////////////////////
+	private boolean _showMainHtml(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc) {
+		_showAdvancedHtml(player, teleporter, npc, "main.html", new HashMap<String, HTMLTemplatePlaceholder>());
+		return true;
+	}
+	
+	private boolean _showSoloCategoryList(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc) {
+		_showAdvancedHtml(player, teleporter, npc, "solo_category_list.html", new HashMap<String, HTMLTemplatePlaceholder>());
+		return true;
+	}
+	
+	private boolean _showPartyCategoryList(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc) {
+		_showAdvancedHtml(player, teleporter, npc, "p_category_list.html", new HashMap<String, HTMLTemplatePlaceholder>());
+		return true;
+	}
+	
+	private boolean _showCommandChannelCategoryList(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc) {
+		_showAdvancedHtml(player, teleporter, npc, "cc_category_list.html", new HashMap<String, HTMLTemplatePlaceholder>());
+		return true;
+	}
+	
+	private boolean _showSoloListHtml(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc, String soloListIdent) {
+		Map<String, HTMLTemplatePlaceholder> placeholders = new HashMap<>();
+		
+		if (soloListIdent != null && !soloListIdent.isEmpty()) {
+			SoloTeleportCategory category = teleporter.getSoloTeleportCategories().get(soloListIdent);
+			placeholders.put("category", category.getPlaceholder());
+		}
+		
+		_showAdvancedHtml(player, teleporter, npc, "solo_teleport_list.html", placeholders);
+		return true;
+	}
+	
+	private boolean _showPartyListHtml(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc, String partyListIdent) {
+		Map<String, HTMLTemplatePlaceholder> placeholders = new HashMap<>();
+		
+		if (partyListIdent != null && !partyListIdent.isEmpty()) {
+			GroupTeleportCategory category = teleporter.getPartyTeleportCategories().get(partyListIdent);
+			placeholders.put("category", category.getPlaceholder());
+		}
+		
+		_showAdvancedHtml(player, teleporter, npc, "p_teleport_list.html", placeholders);
+		return true;
+	}
+	
+	private boolean _showCommandChannelListHtml(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc, String commandChannelListIdent) {
+		Map<String, HTMLTemplatePlaceholder> placeholders = new HashMap<>();
+		
+		if (commandChannelListIdent != null && !commandChannelListIdent.isEmpty()) {
+			GroupTeleportCategory category = teleporter.getCommandChannelTeleportCategories().get(commandChannelListIdent);
+			placeholders.put("category", category.getPlaceholder());
+		}
+		
+		_showAdvancedHtml(player, teleporter, npc, "cc_teleport_list.html", placeholders);
+		return true;
+	}
+	
+	private boolean _showSoloTeleportHtml(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc, String teleIdent, String catIdent) {
+		SoloTeleport teleport = null;
+		if (catIdent != null && !catIdent.isEmpty()) {
+			SoloTeleportCategory category = teleporter.getSoloTeleportCategories().get(catIdent);
+			if (category == null) {
+				debug(player, "Invalid category ident: " + catIdent);
+				return false;
+			}
+			
+			teleport = category.getSoloTeleports().get(teleIdent);
+		} else {
+			teleport = teleporter.getSoloTeleports().get(teleIdent);
+		}
+		
+		if (teleport == null) {
+			debug(player, "Invalid teleport ident: " + teleIdent);
+			return false;
+		}
+		
+		_showTeleportHtml(player, teleporter, teleport, npc, "solo_teleport.html");
+		return true;
+	}
+	
+	private boolean _showPartyTeleportHtml(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc, String teleIdent, String catIdent) {
+		GroupTeleport teleport = null;
+		if (catIdent != null && !catIdent.isEmpty()) {
+			GroupTeleportCategory category = teleporter.getPartyTeleportCategories().get(catIdent);
+			if (category == null) {
+				debug(player, "Invalid category ident: " + catIdent);
+				return false;
+			}
+			
+			teleport = category.getGroupTeleports().get(teleIdent);
+		} else {
+			teleport = teleporter.getPartyTeleports().get(teleIdent);
+		}
+		
+		if (teleport == null) {
+			debug(player, "Invalid teleport ident: " + teleIdent);
+			return false;
+		}
+		
+		_showTeleportHtml(player, teleporter, teleport, npc, "p_teleport.html");
+		return true;
+	}
+	
+	private boolean _showCommandChannelTeleportHtml(L2PcInstance player, AbstractTeleporter teleporter, L2Npc npc, String teleIdent, String catIdent) {
+		GroupTeleport teleport = null;
+		if (catIdent != null && !catIdent.isEmpty()) {
+			GroupTeleportCategory category = teleporter.getCommandChannelTeleportCategories().get(catIdent);
+			if (category == null) {
+				debug(player, "Invalid category ident: " + catIdent);
+				return false;
+			}
+			
+			teleport = category.getGroupTeleports().get(teleIdent);
+		} else {
+			teleport = teleporter.getCommandChannelTeleports().get(teleIdent);
+		}
+		
+		if (teleport == null) {
+			debug(player, "Invalid teleport ident: " + teleIdent);
+			return false;
+		}
+		
+		_showTeleportHtml(player, teleporter, teleport, npc, "cc_teleport.html");
+		return true;
+	}
+	
+	// ////////////////////////////////////
+	// TELEPORT COMMANDS
+	// ////////////////////////////////////
+	private void _makeTeleport(SoloTeleport teleport, L2PcInstance initiator) {
+		if (!_takeTeleportItems(teleport, initiator)) {
+			return;
+		}
+		
+		InstanceWorld world = null;
+		if (!teleport.getInstance().isEmpty()) {
+			world = _createInstance(teleport.getInstance());
+			world.addAllowed(initiator.getObjectId());
+		}
+		
+		initiator.teleToLocation(teleport.getX(), teleport.getY(), teleport.getZ(), teleport.getHeading(), world != null ? world.getInstanceId() : initiator.getInstanceId(), teleport.getRandomOffset());
+	}
+	
+	private void _makeGroupTeleport(GroupTeleport teleport, L2PcInstance initiator, AbstractPlayerGroup group) {
+		final L2PcInstance leader = group.getLeader();
+		if (leader != initiator) {
+			initiator.sendMessage("You are not the leader!");
+			return;
+		}
+		
+		final int memberCount = group.getMemberCount();
+		if (group.getMemberCount() < teleport.getMinMembers()) {
+			group.broadcastString("Not enough members!");
+			return;
+		}
+		
+		final int leaderInstanceId = leader.getInstanceId();
+		final ArrayList<L2PcInstance> membersInRange = new ArrayList<>(memberCount);
+		membersInRange.add(leader);
+		
+		for (L2PcInstance member : group.getMembers()) {
+			if ((member != leader) && ((member.getInstanceId() != leaderInstanceId) || (member.calculateDistance(leader, false, false) > teleport.getMaxDistance()))) {
+				continue;
+			}
+			
+			membersInRange.add(member);
+		}
+		
+		if (membersInRange.size() < memberCount) {
+			if (!teleport.getAllowIncomplete()) {
+				group.broadcastString("Your group is not together!");
+				return;
+			} else if (membersInRange.size() < teleport.getMinMembers()) {
+				group.broadcastString("Not enough members around!");
+				return;
+			}
+		}
+		
+		if (membersInRange.size() > teleport.getMaxMembers()) {
+			group.broadcastString("Too many members!");
+			return;
+		}
+		
+		if (!_takeTeleportItems(teleport, initiator)) {
+			return;
+		}
+		
+		InstanceWorld world = null;
+		int instanceId = initiator.getInstanceId();
+		if (!teleport.getInstance().isEmpty()) {
+			world = _createInstance(teleport.getInstance());
+			instanceId = world.getInstanceId();
+		}
+		
+		for (L2PcInstance member : membersInRange) {
+			if (world != null) {
+				world.addAllowed(member.getObjectId());
+			}
+			member.teleToLocation(teleport.getX(), teleport.getY(), teleport.getZ(), teleport.getHeading(), instanceId, teleport.getRandomOffset());
+		}
+	}
+	
+	private void _teleportSolo(L2PcInstance player, AbstractTeleporter teleporter, String teleId, String catId) {
+		SoloTeleport teleport = null;
+		if (catId != null && !catId.isEmpty()) {
+			SoloTeleportCategory category = teleporter.getSoloTeleportCategories().get(catId);
+			if (category == null) {
+				debug(player, "Invalid category ident: " + catId);
+				return;
+			}
+			
+			teleport = category.getSoloTeleports().get(teleId);
+		} else {
+			teleport = teleporter.getSoloTeleports().get(teleId);
+		}
+		
+		if (teleport == null) {
+			debug(player, "Invalid solo teleport id: " + teleId);
+			return;
+		}
+		
+		_makeTeleport(teleport, player);
+	}
+	
+	private void _teleportParty(L2PcInstance player, AbstractTeleporter teleporter, String teleId, String catId) {
+		GroupTeleport teleport = null;
+		if (catId != null && !catId.isEmpty()) {
+			GroupTeleportCategory category = teleporter.getPartyTeleportCategories().get(catId);
+			if (category == null) {
+				debug(player, "Invalid category ident: " + catId);
+				return;
+			}
+			
+			teleport = category.getGroupTeleports().get(teleId);
+		} else {
+			teleport = teleporter.getPartyTeleports().get(teleId);
+		}
+		
+		if (teleport == null) {
+			debug(player, "Invalid party teleport id: " + teleId);
+			return;
+		}
+		
+		final L2Party party = player.getParty();
+		if (party == null) {
+			player.sendMessage("You are not in a party!");
+			return;
+		}
+		
+		_makeGroupTeleport(teleport, player, party);
+	}
+	
+	private void _teleportCommandChannel(L2PcInstance player, AbstractTeleporter teleporter, String teleId, String catId) {
+		GroupTeleport teleport = null;
+		if (catId != null && !catId.isEmpty()) {
+			GroupTeleportCategory category = teleporter.getCommandChannelTeleportCategories().get(catId);
+			if (category == null) {
+				debug(player, "Invalid category ident: " + catId);
+				return;
+			}
+			
+			teleport = category.getGroupTeleports().get(teleId);
+		} else {
+			teleport = teleporter.getCommandChannelTeleports().get(teleId);
+		}
+		
+		if (teleport == null) {
+			debug(player, "Invalid command channel teleport id: " + teleId);
+			return;
+		}
+		
+		final L2Party party = player.getParty();
+		if (party == null) {
+			player.sendMessage("You are not in a party!");
+			return;
+		}
+		
+		final L2CommandChannel commandChannel = party.getCommandChannel();
+		if (commandChannel == null) {
+			player.sendMessage("Your party is not in a command channel!");
+			return;
+		}
+		
+		_makeGroupTeleport(teleport, player, commandChannel);
+	}
+	
+	private void _executeTeleportCommand(L2PcInstance player, AbstractTeleporter teleporter, CommandProcessor command) {
+		if (command.matchAndRemove("solo ", "s ")) {
+			String[] args = command.splitRemaining(" ");
+			_teleportSolo(player, teleporter, args[0], args.length > 1 ? args[1] : null);
+		} else if (command.matchAndRemove("party ", "p ")) {
+			String[] args = command.splitRemaining(" ");
+			_teleportParty(player, teleporter, args[0], args.length > 1 ? args[1] : null);
+		} else if (command.matchAndRemove("command_channel ", "cc ")) {
+			String[] args = command.splitRemaining(" ");
+			_teleportCommandChannel(player, teleporter, args[0], args.length > 1 ? args[1] : null);
+		}
+	}
+	
+	//
+	// //////////////////////////////
+	
+	@Override
+	protected boolean executeHtmlCommand(L2PcInstance player, L2Npc npc, CommandProcessor command) {
+		AbstractTeleporter teleporter = getConfig().determineTeleporter(npc, player);
+		if (teleporter == null) {
+			player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_NOT_FOUND).addString("Teleporter"));
+			return false;
+		}
+		
+		if (command.matchAndRemove("main", "m")) {
+			return _showMainHtml(player, teleporter, npc);
+		} else if (command.matchAndRemove("solo_category_list", "scl")) {
+			return _showSoloCategoryList(player, teleporter, npc);
+		} else if (command.matchAndRemove("party_category_list", "pcl")) {
+			return _showPartyCategoryList(player, teleporter, npc);
+		} else if (command.matchAndRemove("command_channel_category_list", "cccl")) {
+			return _showCommandChannelCategoryList(player, teleporter, npc);
+		} else if (command.matchAndRemove("solo_list ", "sl ")) {
+			return _showSoloListHtml(player, teleporter, npc, command.getRemaining());
+		} else if (command.matchAndRemove("party_list ", "pl ")) {
+			return _showPartyListHtml(player, teleporter, npc, command.getRemaining());
+		} else if (command.matchAndRemove("command_channel_list ", "ccl ")) {
+			return _showCommandChannelListHtml(player, teleporter, npc, command.getRemaining());
+		} else if (command.matchAndRemove("solo_list", "sl")) {
+			return _showSoloListHtml(player, teleporter, npc, null);
+		} else if (command.matchAndRemove("party_list", "pl")) {
+			return _showPartyListHtml(player, teleporter, npc, null);
+		} else if (command.matchAndRemove("command_channel_list", "ccl")) {
+			return _showCommandChannelListHtml(player, teleporter, npc, null);
+		} else if (command.matchAndRemove("solo_teleport ", "st ")) {
+			String[] args = command.splitRemaining(" ");
+			return _showSoloTeleportHtml(player, teleporter, npc, args[0], args.length > 1 ? args[1] : null);
+		} else if (command.matchAndRemove("party_teleport ", "pt ")) {
+			String[] args = command.splitRemaining(" ");
+			return _showPartyTeleportHtml(player, teleporter, npc, args[0], args.length > 1 ? args[1] : null);
+		} else if (command.matchAndRemove("command_channel_teleport ", "cct ")) {
+			String[] args = command.splitRemaining(" ");
+			return _showCommandChannelTeleportHtml(player, teleporter, npc, args[0], args.length > 1 ? args[1] : null);
+		}
+		
+		return false;
+	}
+	
+	@Override
+	protected boolean executeActionCommand(L2PcInstance player, L2Npc npc, CommandProcessor command) {
+		SystemMessage abortSysMsg = null;
+		AbstractTeleporter teleporter = null;
+		
+		if (player.isDead() || player.isAlikeDead()) {
+			abortSysMsg = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
+			abortSysMsg.addString("Teleporter");
+		} else if (isInsideAnyZoneOf(player, Configuration.teleporterService().getForbidInZones())) {
+			abortSysMsg = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
+			abortSysMsg.addString("Teleporter");
+		} else if (Configuration.teleporterService().getForbidInEvents() && ((player.getEventStatus() != null) || (player.getBlockCheckerArena() != -1) || player.isOnEvent() || player.isInOlympiadMode() || TvTEvent.isPlayerParticipant(player.getObjectId()))) {
+			abortSysMsg = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
+			abortSysMsg.addString("Teleporter");
+		} else if (Configuration.teleporterService().getForbidInDuell() && player.isInDuel()) {
+			abortSysMsg = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
+			abortSysMsg.addString("Teleporter");
+		} else if (Configuration.teleporterService().getForbidInFight() && AttackStanceTaskManager.getInstance().hasAttackStanceTask(player)) {
+			abortSysMsg = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
+			abortSysMsg.addString("Teleporter");
+		} else if (Configuration.teleporterService().getForbidInPvp() && (player.getPvpFlag() == 1)) {
+			abortSysMsg = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
+			abortSysMsg.addString("Teleporter");
+		} else if (Configuration.teleporterService().getForbidForChaoticPlayers() && player.getKarma() > 0) {
+			abortSysMsg = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
+			abortSysMsg.addString("Teleporter");
+		} else {
+			teleporter = getConfig().determineTeleporter(npc, player);
+			if (teleporter == null) {
+				abortSysMsg = SystemMessage.getSystemMessage(SystemMessageId.S1_NOT_FOUND);
+				abortSysMsg.addString("Teleporter");
+			}
+		}
+		
+		if (abortSysMsg != null) {
+			player.sendPacket(abortSysMsg);
+			return false;
+		}
+		
+		if (command.matchAndRemove("teleport ", "t ")) {
+			_executeTeleportCommand(player, teleporter, command);
+			return false;
+		}
+		
+		return true;
+	}
+	
+	@Override
+	protected boolean isDebugEnabled() {
+		return Configuration.teleporterService().getDebug();
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterServiceBypassHandler.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterServiceBypassHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..373ed346405baa24866b3f56ecf261457ee5946f
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterServiceBypassHandler.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter;
+
+import com.l2jserver.gameserver.handler.IBypassHandler;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * Teleporter service bypass handler.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public class TeleporterServiceBypassHandler implements IBypassHandler {
+	
+	public static final String BYPASS = "TeleporterService";
+	private static final String[] BYPASS_LIST = new String[] {
+		BYPASS
+	};
+	
+	private TeleporterServiceBypassHandler() {
+	}
+	
+	@Override
+	public boolean useBypass(String command, L2PcInstance activeChar, L2Character target) {
+		if ((target == null) || !target.isNpc()) {
+			return false;
+		}
+		
+		TeleporterService.getService().executeCommand(activeChar, (L2Npc) target, command.substring(BYPASS.length()).trim());
+		return true;
+	}
+	
+	@Override
+	public String[] getBypassList() {
+		return BYPASS_LIST;
+	}
+	
+	static TeleporterServiceBypassHandler getInstance() {
+		return SingletonHolder.INSTANCE;
+	}
+	
+	private static final class SingletonHolder {
+		protected static final TeleporterServiceBypassHandler INSTANCE = new TeleporterServiceBypassHandler();
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterServiceItemHandler.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterServiceItemHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3e297ac9fb5b85b0273c6caeb14f63a243ff6ad
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterServiceItemHandler.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter;
+
+import com.l2jserver.gameserver.handler.IItemHandler;
+import com.l2jserver.gameserver.model.actor.L2Playable;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
+
+/**
+ * Teleporter service item handler.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public final class TeleporterServiceItemHandler implements IItemHandler {
+	
+	private TeleporterServiceItemHandler() {
+	}
+	
+	@Override
+	public boolean useItem(L2Playable playable, L2ItemInstance item, boolean forceUse) {
+		if (!playable.isPlayer()) {
+			return false;
+		}
+		
+		TeleporterService.getService().executeCommand((L2PcInstance) playable, null, null);
+		return true;
+	}
+	
+	static TeleporterServiceItemHandler getInstance() {
+		return SingletonHolder.INSTANCE;
+	}
+	
+	private static final class SingletonHolder {
+		protected static final TeleporterServiceItemHandler INSTANCE = new TeleporterServiceItemHandler();
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterServiceVoicedCommandHandler.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterServiceVoicedCommandHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..ddfd18c7865e2c64ecca5b5a95cd06df1cfc8702
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/TeleporterServiceVoicedCommandHandler.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter;
+
+import com.l2jserver.gameserver.config.Configuration;
+import com.l2jserver.gameserver.handler.IVoicedCommandHandler;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * Teleporter service voiced command handler.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public final class TeleporterServiceVoicedCommandHandler implements IVoicedCommandHandler {
+	private static final String[] COMMANDS = new String[] {
+		Configuration.teleporterService().getVoicedCommand()
+	};
+	
+	private TeleporterServiceVoicedCommandHandler() {
+	}
+	
+	@Override
+	public boolean useVoicedCommand(String command, L2PcInstance activeChar, String params) {
+		TeleporterService.getService().executeCommand(activeChar, null, params);
+		return true;
+	}
+	
+	@Override
+	public String[] getVoicedCommandList() {
+		return COMMANDS;
+	}
+	
+	static TeleporterServiceVoicedCommandHandler getInstance() {
+		return SingletonHolder.INSTANCE;
+	}
+	
+	private static final class SingletonHolder {
+		protected static final TeleporterServiceVoicedCommandHandler INSTANCE = new TeleporterServiceVoicedCommandHandler();
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/GlobalConfig.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/GlobalConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f404dcbf58bbdf1e64005a09706242d64a22f1d
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/GlobalConfig.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model;
+
+import java.util.Map;
+
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.GroupTeleport;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.GroupTeleportCategory;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.SoloTeleport;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.SoloTeleportCategory;
+
+/**
+ * Global configuration.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public class GlobalConfig {
+	private Map<String, SoloTeleport> soloTeleports;
+	private Map<String, GroupTeleport> groupTeleports;
+	
+	private Map<String, SoloTeleportCategory> soloTeleportCategories;
+	private Map<String, GroupTeleportCategory> groupTeleportCategories;
+	
+	public void afterDeserialize(TeleporterConfig config) {
+		for (SoloTeleport teleport : soloTeleports.values()) {
+			teleport.afterDeserialize(config);
+		}
+		
+		for (GroupTeleport teleport : groupTeleports.values()) {
+			teleport.afterDeserialize(config);
+		}
+		
+		for (SoloTeleportCategory soloCat : soloTeleportCategories.values()) {
+			soloCat.afterDeserialize(config);
+		}
+		
+		for (GroupTeleportCategory groupCat : groupTeleportCategories.values()) {
+			groupCat.afterDeserialize(config);
+		}
+	}
+	
+	public Map<String, SoloTeleport> getSoloTeleports() {
+		return soloTeleports;
+	}
+	
+	public Map<String, GroupTeleport> getGroupTeleports() {
+		return groupTeleports;
+	}
+	
+	public Map<String, SoloTeleportCategory> getSoloTeleportCategories() {
+		return soloTeleportCategories;
+	}
+	
+	public Map<String, GroupTeleportCategory> getGroupTeleportCategories() {
+		return groupTeleportCategories;
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/TeleporterConfig.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/TeleporterConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..0973bf986bf2b563454116acf9d5b0dd6c1d1a10
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/TeleporterConfig.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonSyntaxException;
+import com.l2jserver.datapack.custom.service.teleporter.TeleporterService;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.AbstractTeleporter;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.NpcTeleporter;
+import com.l2jserver.datapack.custom.service.teleporter.model.entity.VoicedTeleporter;
+import com.l2jserver.gameserver.config.Configuration;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * Teleporter config.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public class TeleporterConfig {
+	private final GlobalConfig global;
+	private final VoicedTeleporter voiced;
+	private final Map<Integer, NpcTeleporter> npcs;
+	
+	public TeleporterConfig() throws JsonSyntaxException, JsonIOException, IOException {
+		Gson gson = new Gson();
+		
+		Path jsonPath = Paths.get(Configuration.server().getDatapackRoot().getAbsolutePath(), "data", TeleporterService.SCRIPT_PATH.toString(), "json");
+		
+		global = gson.fromJson(Files.newBufferedReader(jsonPath.resolve("global.json")), GlobalConfig.class);
+		voiced = gson.fromJson(Files.newBufferedReader(jsonPath.resolve("voiced.json")), VoicedTeleporter.class);
+		npcs = new HashMap<>();
+		
+		Path npcsDir = Paths.get(jsonPath.toString(), "npcs");
+		try (var dirStream = Files.newDirectoryStream(npcsDir, "*.json")) {
+			for (Path entry : dirStream) {
+				if (!Files.isRegularFile(entry)) {
+					continue;
+				}
+				
+				NpcTeleporter npc = gson.fromJson(Files.newBufferedReader(entry), NpcTeleporter.class);
+				npcs.put(npc.getId(), npc);
+			}
+		}
+		
+		global.afterDeserialize(this);
+		voiced.afterDeserialize(this);
+		for (NpcTeleporter npc : npcs.values()) {
+			npc.afterDeserialize(this);
+		}
+	}
+	
+	public AbstractTeleporter determineTeleporter(L2Npc npc, L2PcInstance player) {
+		if (npc == null) {
+			if (!Configuration.teleporterService().getVoicedEnable() || ((Configuration.teleporterService().getVoicedRequiredItem() > 0) && (player.getInventory().getAllItemsByItemId(Configuration.teleporterService().getVoicedRequiredItem()) == null))) {
+				return null;
+			}
+			return voiced;
+		}
+		return npcs.get(npc.getId());
+	}
+	
+	public void registerNpcs(TeleporterService scriptInstance) {
+		for (NpcTeleporter npc : npcs.values()) {
+			if (npc.getDirectFirstTalk()) {
+				scriptInstance.addFirstTalkId(npc.getId());
+			}
+			scriptInstance.addStartNpc(npc.getId());
+			scriptInstance.addTalkId(npc.getId());
+		}
+	}
+	
+	public GlobalConfig getGlobal() {
+		return global;
+	}
+	
+	public VoicedTeleporter getVoiced() {
+		return voiced;
+	}
+	
+	public Map<Integer, NpcTeleporter> getNpcs() {
+		return npcs;
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/AbstractTeleportCategory.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/AbstractTeleportCategory.java
new file mode 100644
index 0000000000000000000000000000000000000000..a34b4e2c4b990d070b1ee4ce3995bf0f77e7d9ae
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/AbstractTeleportCategory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model.entity;
+
+import com.l2jserver.datapack.custom.service.base.model.entity.Refable;
+import com.l2jserver.datapack.custom.service.teleporter.model.TeleporterConfig;
+
+/**
+ * Base class for teleporter categories.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public abstract class AbstractTeleportCategory extends Refable {
+	private String name;
+	
+	public void afterDeserialize(TeleporterConfig config) {
+		super.afterDeserialize();
+		
+		getPlaceholder().addChild("name", name);
+	}
+	
+	public final String getName() {
+		return name;
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/AbstractTeleporter.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/AbstractTeleporter.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7360c0c60983628a73d0a8da6fe8a96cd0a2cf2
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/AbstractTeleporter.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model.entity;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.l2jserver.datapack.custom.service.base.model.entity.CustomServiceServer;
+import com.l2jserver.datapack.custom.service.base.util.htmltmpls.HTMLTemplatePlaceholder;
+import com.l2jserver.datapack.custom.service.teleporter.model.TeleporterConfig;
+
+/**
+ * Base class for teleporter service types.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public abstract class AbstractTeleporter extends CustomServiceServer {
+	private List<String> soloTeleports;
+	private List<String> partyTeleports;
+	private List<String> commandChannelTeleports;
+	
+	private List<String> soloTeleportCategories;
+	private List<String> partyTeleportCategories;
+	private List<String> commandChannelTeleportCategories;
+	
+	public transient Map<String, SoloTeleport> soloTeleportsMap;
+	public transient Map<String, GroupTeleport> partyTeleportsMap;
+	public transient Map<String, GroupTeleport> commandChannelTeleportsMap;
+	
+	private transient Map<String, SoloTeleportCategory> soloTeleportCategoriesMap;
+	private transient Map<String, GroupTeleportCategory> partyTeleportCategoriesMap;
+	private transient Map<String, GroupTeleportCategory> commandChannelTeleportCategoriesMap;
+	
+	public AbstractTeleporter(String bypassPrefix) {
+		super(bypassPrefix, "teleporter");
+		
+		soloTeleportsMap = new LinkedHashMap<>();
+		partyTeleportsMap = new LinkedHashMap<>();
+		commandChannelTeleportsMap = new LinkedHashMap<>();
+		
+		soloTeleportCategoriesMap = new LinkedHashMap<>();
+		partyTeleportCategoriesMap = new LinkedHashMap<>();
+		commandChannelTeleportCategoriesMap = new LinkedHashMap<>();
+	}
+	
+	public void afterDeserialize(TeleporterConfig config) {
+		super.afterDeserialize();
+		
+		for (String id : soloTeleports) {
+			soloTeleportsMap.put(id, config.getGlobal().getSoloTeleports().get(id));
+		}
+		for (String id : partyTeleports) {
+			partyTeleportsMap.put(id, config.getGlobal().getGroupTeleports().get(id));
+		}
+		for (String id : commandChannelTeleports) {
+			commandChannelTeleportsMap.put(id, config.getGlobal().getGroupTeleports().get(id));
+		}
+		
+		for (String id : soloTeleportCategories) {
+			soloTeleportCategoriesMap.put(id, config.getGlobal().getSoloTeleportCategories().get(id));
+		}
+		for (String id : partyTeleportCategories) {
+			partyTeleportCategoriesMap.put(id, config.getGlobal().getGroupTeleportCategories().get(id));
+		}
+		for (String id : commandChannelTeleportCategories) {
+			commandChannelTeleportCategoriesMap.put(id, config.getGlobal().getGroupTeleportCategories().get(id));
+		}
+		
+		if (!soloTeleports.isEmpty()) {
+			HTMLTemplatePlaceholder telePlaceholder = getPlaceholder().addChild("solo_teleports", null).getChild("solo_teleports");
+			for (Entry<String, SoloTeleport> soloTeleport : soloTeleportsMap.entrySet()) {
+				telePlaceholder.addAliasChild(String.valueOf(telePlaceholder.getChildrenSize()), soloTeleport.getValue().getPlaceholder());
+			}
+		}
+		if (!partyTeleports.isEmpty()) {
+			HTMLTemplatePlaceholder telePlaceholder = getPlaceholder().addChild("party_teleports", null).getChild("party_teleports");
+			for (Entry<String, GroupTeleport> partyTeleport : partyTeleportsMap.entrySet()) {
+				telePlaceholder.addAliasChild(String.valueOf(telePlaceholder.getChildrenSize()), partyTeleport.getValue().getPlaceholder());
+			}
+		}
+		if (!commandChannelTeleports.isEmpty()) {
+			HTMLTemplatePlaceholder telePlaceholder = getPlaceholder().addChild("command_channel_teleports", null).getChild("command_channel_teleports");
+			for (Entry<String, GroupTeleport> commandChannelTeleport : commandChannelTeleportsMap.entrySet()) {
+				telePlaceholder.addAliasChild(String.valueOf(telePlaceholder.getChildrenSize()), commandChannelTeleport.getValue().getPlaceholder());
+			}
+		}
+		
+		if (!soloTeleportCategories.isEmpty()) {
+			HTMLTemplatePlaceholder catsPlaceholder = getPlaceholder().addChild("solo_categories", null).getChild("solo_categories");
+			for (Entry<String, SoloTeleportCategory> soloTeleportCategories : soloTeleportCategoriesMap.entrySet()) {
+				catsPlaceholder.addAliasChild(String.valueOf(catsPlaceholder.getChildrenSize()), soloTeleportCategories.getValue().getPlaceholder());
+			}
+		}
+		if (!partyTeleportCategories.isEmpty()) {
+			HTMLTemplatePlaceholder catsPlaceholder = getPlaceholder().addChild("party_categories", null).getChild("party_categories");
+			for (Entry<String, GroupTeleportCategory> partyTeleportCategories : partyTeleportCategoriesMap.entrySet()) {
+				catsPlaceholder.addAliasChild(String.valueOf(catsPlaceholder.getChildrenSize()), partyTeleportCategories.getValue().getPlaceholder());
+			}
+		}
+		if (!commandChannelTeleportCategories.isEmpty()) {
+			HTMLTemplatePlaceholder catsPlaceholder = getPlaceholder().addChild("command_channel_categories", null).getChild("command_channel_categories");
+			for (Entry<String, GroupTeleportCategory> commandChannelTeleportCategories : commandChannelTeleportCategoriesMap.entrySet()) {
+				catsPlaceholder.addAliasChild(String.valueOf(catsPlaceholder.getChildrenSize()), commandChannelTeleportCategories.getValue().getPlaceholder());
+			}
+		}
+	}
+	
+	public final Map<String, SoloTeleport> getSoloTeleports() {
+		return soloTeleportsMap;
+	}
+	
+	public final Map<String, GroupTeleport> getPartyTeleports() {
+		return partyTeleportsMap;
+	}
+	
+	public final Map<String, GroupTeleport> getCommandChannelTeleports() {
+		return commandChannelTeleportsMap;
+	}
+	
+	public final Map<String, SoloTeleportCategory> getSoloTeleportCategories() {
+		return soloTeleportCategoriesMap;
+	}
+	
+	public final Map<String, GroupTeleportCategory> getPartyTeleportCategories() {
+		return partyTeleportCategoriesMap;
+	}
+	
+	public final Map<String, GroupTeleportCategory> getCommandChannelTeleportCategories() {
+		return commandChannelTeleportCategoriesMap;
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/GroupTeleport.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/GroupTeleport.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1e76a3068ce3ef5a4edd2e07c906e2d0059c733
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/GroupTeleport.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model.entity;
+
+import com.l2jserver.datapack.custom.service.teleporter.model.TeleporterConfig;
+
+/**
+ * Group teleport.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public class GroupTeleport extends SoloTeleport {
+	private int minMembers;
+	private int maxMembers;
+	private int maxDistance;
+	private boolean allowIncomplete;
+	
+	public GroupTeleport() {
+	}
+	
+	@Override
+	public void afterDeserialize(TeleporterConfig config) {
+		super.afterDeserialize(config);
+		
+		getPlaceholder().addChild("min_members", String.valueOf(minMembers)).addChild("max_members", String.valueOf(maxMembers)).addChild("max_distance", String.valueOf(maxDistance));
+	}
+	
+	public int getMinMembers() {
+		return minMembers;
+	}
+	
+	public int getMaxMembers() {
+		return maxMembers;
+	}
+	
+	public int getMaxDistance() {
+		return maxDistance;
+	}
+	
+	public boolean getAllowIncomplete() {
+		return allowIncomplete;
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/GroupTeleportCategory.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/GroupTeleportCategory.java
new file mode 100644
index 0000000000000000000000000000000000000000..27cbb5b65ae2f68565c39318a27184b73fe4774a
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/GroupTeleportCategory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model.entity;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.l2jserver.datapack.custom.service.base.util.htmltmpls.HTMLTemplatePlaceholder;
+import com.l2jserver.datapack.custom.service.teleporter.model.TeleporterConfig;
+
+/**
+ * Group teleport category.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public class GroupTeleportCategory extends AbstractTeleportCategory {
+	private List<String> groupTeleports;
+	
+	private transient Map<String, GroupTeleport> groupTeleportsMap;
+	
+	public GroupTeleportCategory() {
+		groupTeleportsMap = new LinkedHashMap<>();
+	}
+	
+	@Override
+	public void afterDeserialize(TeleporterConfig config) {
+		super.afterDeserialize(config);
+		
+		for (String id : groupTeleports) {
+			groupTeleportsMap.put(id, config.getGlobal().getGroupTeleports().get(id));
+		}
+		
+		if (!groupTeleports.isEmpty()) {
+			HTMLTemplatePlaceholder telePlaceholder = getPlaceholder().addChild("teleports", null).getChild("teleports");
+			for (Entry<String, GroupTeleport> groupTeleport : groupTeleportsMap.entrySet()) {
+				telePlaceholder.addAliasChild(String.valueOf(telePlaceholder.getChildrenSize()), groupTeleport.getValue().getPlaceholder());
+			}
+		}
+	}
+	
+	public Map<String, GroupTeleport> getGroupTeleports() {
+		return groupTeleportsMap;
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/NpcTeleporter.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/NpcTeleporter.java
new file mode 100644
index 0000000000000000000000000000000000000000..b09a58d06968c6df7a173c3df8cfafa5b3f3d43f
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/NpcTeleporter.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model.entity;
+
+import com.l2jserver.datapack.custom.service.base.model.entity.IRefable;
+import com.l2jserver.datapack.custom.service.teleporter.TeleporterServiceBypassHandler;
+import com.l2jserver.datapack.custom.service.teleporter.model.TeleporterConfig;
+import com.l2jserver.gameserver.data.xml.impl.NpcData;
+import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
+
+/**
+ * Npc teleporter.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public final class NpcTeleporter extends AbstractTeleporter implements IRefable<Integer> {
+	private int npcId;
+	private boolean directFirstTalk;
+	
+	public NpcTeleporter() {
+		super(TeleporterServiceBypassHandler.BYPASS);
+	}
+	
+	@Override
+	public void afterDeserialize(TeleporterConfig config) {
+		super.afterDeserialize(config);
+		
+		getPlaceholder().addChild("ident", String.valueOf(npcId));
+	}
+	
+	public L2NpcTemplate getNpc() {
+		return NpcData.getInstance().getTemplate(npcId);
+	}
+	
+	public int getNpcId() {
+		return npcId;
+	}
+	
+	public boolean getDirectFirstTalk() {
+		return directFirstTalk;
+	}
+	
+	@Override
+	public final String getName() {
+		return getNpc().getName();
+	}
+	
+	@Override
+	public final Integer getId() {
+		return npcId;
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/SoloTeleport.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/SoloTeleport.java
new file mode 100644
index 0000000000000000000000000000000000000000..2dd0e2b4d9ee32da2f89001551f88c7bc5771317
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/SoloTeleport.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model.entity;
+
+import com.l2jserver.datapack.custom.service.base.model.entity.CustomServiceProduct;
+import com.l2jserver.datapack.custom.service.teleporter.model.TeleporterConfig;
+
+/**
+ * Solo teleport.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public class SoloTeleport extends CustomServiceProduct {
+	private String name;
+	private int x;
+	private int y;
+	private int z;
+	private int heading;
+	private int randomOffset;
+	private String instance;
+	
+	public SoloTeleport() {
+	}
+	
+	public void afterDeserialize(TeleporterConfig config) {
+		super.afterDeserialize();
+		
+		getPlaceholder().addChild("name", name);
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public int getRandomOffset() {
+		return randomOffset;
+	}
+	
+	public int getHeading() {
+		return heading;
+	}
+	
+	public String getInstance() {
+		return instance;
+	}
+	
+	public int getZ() {
+		return z;
+	}
+	
+	public int getY() {
+		return y;
+	}
+	
+	public int getX() {
+		return x;
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/SoloTeleportCategory.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/SoloTeleportCategory.java
new file mode 100644
index 0000000000000000000000000000000000000000..a98212b23c4eb669d00bc2eaf7b482660efdf39a
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/SoloTeleportCategory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model.entity;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.l2jserver.datapack.custom.service.base.util.htmltmpls.HTMLTemplatePlaceholder;
+import com.l2jserver.datapack.custom.service.teleporter.model.TeleporterConfig;
+
+/**
+ * Solo teleport category.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public class SoloTeleportCategory extends AbstractTeleportCategory {
+	private List<String> soloTeleports;
+	
+	private transient Map<String, SoloTeleport> soloTeleportsMap;
+	
+	public SoloTeleportCategory() {
+		soloTeleportsMap = new LinkedHashMap<>();
+	}
+	
+	@Override
+	public void afterDeserialize(TeleporterConfig config) {
+		super.afterDeserialize(config);
+		
+		for (String id : soloTeleports) {
+			soloTeleportsMap.put(id, config.getGlobal().getSoloTeleports().get(id));
+		}
+		
+		if (!soloTeleports.isEmpty()) {
+			HTMLTemplatePlaceholder telePlaceholder = getPlaceholder().addChild("teleports", null).getChild("teleports");
+			for (Entry<String, SoloTeleport> soloTeleport : soloTeleportsMap.entrySet()) {
+				telePlaceholder.addAliasChild(String.valueOf(telePlaceholder.getChildrenSize()), soloTeleport.getValue().getPlaceholder());
+			}
+		}
+	}
+	
+	public Map<String, SoloTeleport> getSoloTeleports() {
+		return soloTeleportsMap;
+	}
+}
diff --git a/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/VoicedTeleporter.java b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/VoicedTeleporter.java
new file mode 100644
index 0000000000000000000000000000000000000000..81e4b1bd2151412ad54e22da7f127210b255a21c
--- /dev/null
+++ b/src/main/java/com/l2jserver/datapack/custom/service/teleporter/model/entity/VoicedTeleporter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2004-2021 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.custom.service.teleporter.model.entity;
+
+import com.l2jserver.datapack.custom.service.teleporter.model.TeleporterConfig;
+import com.l2jserver.gameserver.config.Configuration;
+import com.l2jserver.gameserver.datatables.ItemTable;
+import com.l2jserver.gameserver.model.items.L2Item;
+
+/**
+ * Voiced teleporter.
+ * @author HorridoJoho
+ * @version 2.6.2.0
+ */
+public final class VoicedTeleporter extends AbstractTeleporter {
+	public VoicedTeleporter() {
+		super("voice ." + Configuration.teleporterService().getVoicedCommand());
+	}
+	
+	@Override
+	public void afterDeserialize(TeleporterConfig config) {
+		super.afterDeserialize(config);
+	}
+	
+	public L2Item getRequiredItem() {
+		return ItemTable.getInstance().getTemplate(Configuration.teleporterService().getVoicedRequiredItem());
+	}
+	
+	@Override
+	public String getName() {
+		return Configuration.teleporterService().getVoicedName();
+	}
+}
diff --git a/src/main/resources/data/scripts.cfg b/src/main/resources/data/scripts.cfg
index 1e10f9add1f5c4ac17b49e435875252abdc15ca2..03779dd64faf0b595c1fd0e8eab0b78592b18fe0 100644
--- a/src/main/resources/data/scripts.cfg
+++ b/src/main/resources/data/scripts.cfg
@@ -9,6 +9,7 @@ com/l2jserver/datapack/features/SkillTransfer/SkillTransfer.java
 # Custom
 com/l2jserver/datapack/custom/Validators/SubClassSkills.java
 com/l2jserver/datapack/custom/service/buffer/BufferService.java
+com/l2jserver/datapack/custom/service/teleporter/TeleporterService.java
 com/l2jserver/datapack/custom/service/discord/DiscordBot.java
 
 # Custom Events
diff --git a/src/main/resources/data/service/teleporter/html/npc/cc_category_list.html b/src/main/resources/data/service/teleporter/html/npc/cc_category_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..bf1347f037dc1f77044c413815d3eb303ecda125
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/html/npc/cc_category_list.html
@@ -0,0 +1,6 @@
+<html><title>%teleporter.name%</title><body>
+<a action="%teleporter.bypass_prefix%">Home</a>&nbsp;> <font color=LEVEL>Command Channel Teleports</font><br>
+[FOREACH(teleport IN teleporter.command_channel_teleports DO <a action="%teleporter.bypass_prefix% t cc %teleport.ident%" msg="811;%teleport.name%">%teleport.name% (%teleport.min_members% - %teleport.max_members%, [FOREACH(item IN teleport.items DO %item.amount% %item.name%)ENDEACH])</a><br1>)ENDEACH]
+<br1><center>
+[FOREACH(category IN teleporter.command_channel_categories DO <button width=200 height=34 fore=L2UI_CT1.Button_DF back=L2UI_CT1.Button_DF_Down value="%category.name%" action="%teleporter.bypass_prefix% h ccl %category.ident%"><br1>)ENDEACH]
+</center></body></html>
\ No newline at end of file
diff --git a/src/main/resources/data/service/teleporter/html/npc/cc_teleport_list.html b/src/main/resources/data/service/teleporter/html/npc/cc_teleport_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..3d9dfc3899df1fb735c4bcd87f024c289124ea72
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/html/npc/cc_teleport_list.html
@@ -0,0 +1,7 @@
+<html><title>%teleporter.name%</title><body>
+<a action="%teleporter.bypass_prefix%">Home</a>&nbsp;>&nbsp;<a action="%teleporter.bypass_prefix% h cccl">Command Channel Teleports</a>[EXISTS(category,&nbsp;> <font color=LEVEL>%category.name%</font>)]<br>
+[EXISTS(category,
+    [FOREACH(teleport IN teleporter.command_channel_teleports DO <a action="%teleporter.bypass_prefix% t cc %teleport.ident%" msg="811;%teleport.name%">%teleport.name% (%teleport.min_members% - %teleport.max_members%, [FOREACH(item IN teleport.items DO %item.amount% %item.name%)ENDEACH])</a><br1>)ENDEACH]
+)ENDEXISTS]
+[FOREACH(teleport IN category.teleports DO <a action="%teleporter.bypass_prefix% t cc %teleport.ident% %category.ident%" msg="811;%teleport.name%" msg="811;%teleport.name%">%teleport.name% (%teleport.min_members% - %teleport.max_members%, [FOREACH(item IN teleport.items DO %item.amount% %item.name%)ENDEACH])</a><br1>)ENDEACH]
+</body></html>
\ No newline at end of file
diff --git a/src/main/resources/data/service/teleporter/html/npc/main.html b/src/main/resources/data/service/teleporter/html/npc/main.html
new file mode 100644
index 0000000000000000000000000000000000000000..bb99021e48172d8cf8497b45ba29941cd5fa6f0f
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/html/npc/main.html
@@ -0,0 +1,5 @@
+<html noscrollbar><title>%teleporter.name%</title><body><center>
+<button width=200 height=34 fore=L2UI_CT1.Button_DF back=L2UI_CT1.Button_DF_Down value="Solo Teleports" action="%teleporter.bypass_prefix% h scl"><br>
+<button width=200 height=34 fore=L2UI_CT1.Button_DF back=L2UI_CT1.Button_DF_Down value="Party Teleports" action="%teleporter.bypass_prefix% h pcl"><br>
+<button width=200 height=34 fore=L2UI_CT1.Button_DF back=L2UI_CT1.Button_DF_Down value="Command Channel Teleports" action="%teleporter.bypass_prefix% h cccl">
+</center></body></html>
\ No newline at end of file
diff --git a/src/main/resources/data/service/teleporter/html/npc/p_category_list.html b/src/main/resources/data/service/teleporter/html/npc/p_category_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..6e4400e63732348c9a80f64b63002ed9299e2ea8
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/html/npc/p_category_list.html
@@ -0,0 +1,6 @@
+<html><title>%teleporter.name%</title><body>
+<a action="%teleporter.bypass_prefix%">Home</a>&nbsp;> <font color=LEVEL>Party Teleports</font><br>
+[FOREACH(teleport IN teleporter.party_teleports DO <a action="%teleporter.bypass_prefix% t p %teleport.ident%" msg="811;%teleport.name%">%teleport.name% (%teleport.min_members% - %teleport.max_members%, [FOREACH(item IN teleport.items DO %item.amount% %item.name%)ENDEACH])</a><br1>)ENDEACH]
+<br1><center>
+[FOREACH(category IN teleporter.party_categories DO <button width=200 height=34 fore=L2UI_CT1.Button_DF back=L2UI_CT1.Button_DF_Down value="%category.name%" action="%teleporter.bypass_prefix% h pl %category.ident%"><br1>)ENDEACH]
+</center></body></html>
diff --git a/src/main/resources/data/service/teleporter/html/npc/p_teleport_list.html b/src/main/resources/data/service/teleporter/html/npc/p_teleport_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..2271959422a1b4692b0a4d7a2c6f1963e370ae2b
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/html/npc/p_teleport_list.html
@@ -0,0 +1,7 @@
+<html><title>%teleporter.name%</title><body>
+<a action="%teleporter.bypass_prefix%">Home</a>&nbsp;>&nbsp;<a action="%teleporter.bypass_prefix% h pcl">Party Teleports</a>[EXISTS(category,&nbsp;> <font color=LEVEL>%category.name%</font>)]<br>
+[EXISTS(!category,
+    [FOREACH(teleport IN teleporter.party_teleports DO <a action="%teleporter.bypass_prefix% t p %teleport.ident%">%teleport.name% (%teleport.min_members% - %teleport.max_members%, [FOREACH(item IN teleport.items DO %item.amount% %item.name%)ENDEACH])</a><br1>)ENDEACH]
+)ENDEXISTS]
+[FOREACH(teleport IN category.teleports DO <a action="%teleporter.bypass_prefix% t p %teleport.ident% %category.ident%" msg="811;%teleport.name%">%teleport.name% (%teleport.min_members% - %teleport.max_members%, [FOREACH(item IN teleport.items DO %item.amount% %item.name%)ENDEACH])</a><br1>)ENDEACH]
+</body></html>
\ No newline at end of file
diff --git a/src/main/resources/data/service/teleporter/html/npc/solo_category_list.html b/src/main/resources/data/service/teleporter/html/npc/solo_category_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..3ffecfd35ceaa2352d81bfe6f859b06041aad0bc
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/html/npc/solo_category_list.html
@@ -0,0 +1,6 @@
+<html><title>%teleporter.name%</title><body>
+<a action="%teleporter.bypass_prefix%">Home</a>&nbsp;> <font color=LEVEL>Solo Teleports</font><br>
+[FOREACH(teleport IN teleporter.solo_teleports DO <a action="%teleporter.bypass_prefix% t s %teleport.ident%" msg="811;%teleport.name%">%teleport.name% ([FOREACH(item IN teleport.items DO %item.amount% %item.name%)ENDEACH])</a><br1>)ENDEACH]
+<br1><center>
+[FOREACH(category IN teleporter.solo_categories DO <button width=200 height=34 fore=L2UI_CT1.Button_DF back=L2UI_CT1.Button_DF_Down value="%category.name%" action="%teleporter.bypass_prefix% h sl %category.ident%"><br1>)ENDEACH]
+</center></body></html>
\ No newline at end of file
diff --git a/src/main/resources/data/service/teleporter/html/npc/solo_teleport_list.html b/src/main/resources/data/service/teleporter/html/npc/solo_teleport_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..b097eeca0008ae17021c14084df73e0cbdacdf7a
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/html/npc/solo_teleport_list.html
@@ -0,0 +1,7 @@
+<html><title>%teleporter.name%</title><body>
+<a action="%teleporter.bypass_prefix%">Home</a>&nbsp;>&nbsp;<a action="%teleporter.bypass_prefix% h scl">Solo Teleports</a>[EXISTS(category,&nbsp;> <font color=LEVEL>%category.name%</font>)ENDEXISTS]<br>
+[EXISTS(!category,
+	[FOREACH(teleport IN teleporter.solo_teleports DO<a action="%teleporter.bypass_prefix% t s %teleport.ident%" msg="811;%teleport.name%">%teleport.name% ([FOREACH(item IN teleport.items DO %item.amount% %item.name%)ENDEACH])</a><br1>)ENDEACH]
+)ENDEXISTS]
+[FOREACH(teleport IN category.teleports DO <a action="%teleporter.bypass_prefix% t s %teleport.ident% %category.ident%" msg="811;%teleport.name%">%teleport.name% ([FOREACH(item IN teleport.items DO %item.amount% %item.name%)ENDEACH])</a><br1>)ENDEACH]
+</body></html>
\ No newline at end of file
diff --git a/src/main/resources/data/service/teleporter/json/documentation.txt b/src/main/resources/data/service/teleporter/json/documentation.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f25688c7ff5f5d76c014b6d1ea60a97e14f0760b
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/json/documentation.txt
@@ -0,0 +1,128 @@
+################################################################################
+# TeleporterService - JSON Docs                                                #
+################################################################################
+
+###############
+# global.json #
+###############
+
+    {
+        "soloTeleports": {
+            "<soloTeleportId>": {
+                "id": "<soloTeleportId>",
+                "name": (string),
+                "x": (number),
+                "y": (number),
+                "z"; (number),
+                "heading": (number),
+                "randomOffset": (number),
+                "instance": (string),
+                "items" : [
+                    { "id":(number), "amount":(number) },
+                    ....
+                ]
+            },
+            ....
+        },
+
+        "groupTeleports": {
+            "<groupTeleportId>": {
+                "id": "<groupTeleportId>",
+                "name": (string),
+                "x": (number),
+                "y": (number),
+                "z"; (number),
+                "heading": (number),
+                "randomOffset": (number),
+                "instance": (string),
+                "minMembers": (number),
+                "maxMembers": (number),
+                "maxDistance": (number),
+                "allowIncomplete": (boolean),
+                "items" : [
+                    { "id":(number), "amount":(number) },
+                    ....
+                ]
+            },
+            ....
+        },
+        
+        "soloTeleportCategories": {
+            "<soloTeleportCategoryId>": {
+                "id": "<soloTeleportCategoryId>",
+                "name": (string),
+                "soloTeleports": ["<soloTeleportId>",...]
+            },
+            ...
+        },
+        
+        "groupTeleportCategories": {
+            "<groupTeleportCategoryId>": {
+                "id": "<groupTeleportCategoryId>",
+                "name": (string),
+                "groupTeleports": ["<groupTeleportId>",...]
+            },
+            ...
+        }
+    }
+
+    Notes:
+    • solo-/groupTeleports: An object where each property represents a solo/group teleport (the "id" property must match the key in "solo-/groupTeleports").
+    • solo-/groupTeleports.name: the display name
+    • solo-/groupTeleports.randomOffset: a random offset is applied to the specified teleport location for each group member but the leader
+    • solo-/groupTeleports.<solo-/groupTeleportId>.instance: an instance is created from the specified instance definition xml and the players are teleported into that instance
+    • groupTeleports.<groupTeleportId>.minMembers: minimum members in the group, including leader
+    • groupTeleports.<groupTeleportId>.maxMembers: maximum members in the group, including leader
+    • groupTeleports.<groupTeleportId>.maxDistance: max distance of party members to the leader
+    • groupTeleports.<groupTeleportId>.allowIncomplete: allow an incomplete group to teleport; when not all group members are in maxDistance range to the party leader, only teleport the members which are in range, if the amount of members is at least minMembers
+    • solo-/groupTeleports.<solo-/groupTeleportId>.items: An array of item objects
+    • solo-/groupTeleportCategories.<solo-/groupTeleportCategoryId>: An object where each property represents a solo/group teleport category (the "id" property must match the key in solo-/groupTeleportCategories.<solo-/groupTeleportCategoryId>)
+    • solo-/groupTeleportCategories.<solo-/groupTeleportCategoryId>.name: Display name of the category 
+    • solo-/groupTeleportCategories.<solo-/groupTeleportCategoryId>.groupTeleports: Array of solo-/groupTeleport id's
+
+
+###############
+# voiced.json #
+###############
+
+    {
+        "dialogType": "NPC" or "COMMUNITY",
+        "htmlFolder": (string),
+        
+        "soloTeleports": ["<soloTeleportId>", ...],
+        "partyTeleports": ["<groupTeleportId>", ...],
+        "commandChannelTeleports": ["<groupTeleportId>", ...],
+    
+        "soloTeleportCategories": ["<soloTeleportCategoryId>",...],
+        "partyTeleportCategories": ["<groupTeleportCategoryId>",...],
+        "commandChannelTeleportCategories": ["<groupTeleportCategoryId>",...]
+    }
+
+    Notes:
+    • dialogType: NPC opens npc html window, COMMUNITY opens community board
+    • htmlFolder: where to load htmls from
+    • solo-/party-/commandChannelTeleports: array of solo-/groupTeleportId
+    • solo-/party-/commandChannelTeleportCategories: array of solo-/groupTeleportCategoryId
+
+
+#####################
+# npcs/<npcId>.json #
+#####################
+
+    {
+        "npcId": "<npcId>",
+        "directFirstTalk": (boolean),
+        "dialogType": "NPC" or "COMMUNITY",
+        "htmlFolder": (string),
+        
+        "soloTeleports": ["<soloTeleportId>", ...],
+        "partyTeleports": ["<groupTeleportId>", ...],
+        "commandChannelTeleports": ["<groupTeleportId>", ...],
+    
+        "soloTeleportCategories": ["<soloTeleportCategoryId>",...],
+        "partyTeleportCategories": ["<groupTeleportCategoryId>",...],
+        "commandChannelTeleportCategories": ["<groupTeleportCategoryId>",...]
+    }
+
+    Notes:
+    • see notes from voiced.json
\ No newline at end of file
diff --git a/src/main/resources/data/service/teleporter/json/global.json b/src/main/resources/data/service/teleporter/json/global.json
new file mode 100644
index 0000000000000000000000000000000000000000..6dba438eaf3b9c4691ff9673990e3f3cecd8cdbe
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/json/global.json
@@ -0,0 +1,425 @@
+{
+    "soloTeleports": {
+		"S_GIRAN": {"id":"S_GIRAN", "name":"Giran", "x":82698, "y":148638, "z":-3473, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GODDARD": {"id":"S_GODDARD", "name":"Goddard", "x":147725, "y":-56517, "z":-2780, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DION": {"id":"S_DION", "name":"Dion", "x":18748, "y":145437, "z":-3132, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GLUDIO": {"id":"S_GLUDIO", "name":"Gludio", "x":-14225, "y":123540, "z":-3121, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SCHUTTGART": {"id":"S_SCHUTTGART", "name":"Schutgart", "x":87358, "y":-141982, "z":-1341, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HUNTERS": {"id":"S_HUNTERS", "name":"Hunters", "x":116589, "y":76268, "z":-2734, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ADEN": {"id":"S_ADEN", "name":"Aden", "x":147450, "y":27064, "z":-2208, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_RUNE": {"id":"S_RUNE", "name":"Rune", "x":44070, "y":-50243, "z":-796, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_OREN": {"id":"S_OREN", "name":"Oren", "x":82321, "y":55139, "z":-1529, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GLUDIN": {"id":"S_GLUDIN", "name":"Gludin", "x":-83063, "y":150791, "z":-3133, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HEINE": {"id":"S_HEINE", "name":"Heine", "x":111115, "y":219017, "z":-3547, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FLORAN": {"id":"S_FLORAN", "name":"Floran", "x":17144, "y":170156, "z":-3502, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HUMAN": {"id":"S_HUMAN", "name":"Human", "x":-82687, "y":243157, "z":-3734, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ORC": {"id":"S_ORC", "name":"Orc", "x":-44133, "y":-113911, "z":-244, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ELVEN": {"id":"S_ELVEN", "name":"Elven", "x":45873, "y":49288, "z":-3064, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DWARVEN": {"id":"S_DWARVEN", "name":"Dwarven", "x":116551, "y":-182493, "z":-1525, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DARK_ELVEN": {"id":"S_DARK_ELVEN", "name":"Dark Elven", "x":12428, "y":16551, "z":-4588, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_KAMAEL": {"id":"S_KAMAEL", "name":"Kamael", "x":-116934, "y":46616, "z":368, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_ADEN_CASTLE": {"id":"S_ADEN_CASTLE", "name":"Aden Castle", "x":147457, "y":10843, "z":-736, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GODDARD_CASTLE": {"id":"S_GODDARD_CASTLE", "name":"Goddard Castle", "x":147482, "y":-45026, "z":-2084, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DION_CASTLE": {"id":"S_DION_CASTLE", "name":"Dion Castle", "x":22306, "y":156027, "z":-2953, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_RUNE_CASTLE": {"id":"S_RUNE_CASTLE", "name":"Rune Castle", "x":19118, "y":-49136, "z":-1266, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_INNADRIL_CASTLE": {"id":"S_INNADRIL_CASTLE", "name":"Innadril Castle", "x":244631, "y":27064, "z":-1057, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GIRAN_CASTLE": {"id":"S_GIRAN_CASTLE", "name":"Giran Castle", "x":112122, "y":144855, "z":-2751, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_OREN_CASTLE": {"id":"S_OREN_CASTLE", "name":"Oren Castle", "x":78116, "y":36961, "z":-2458, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GLUDIO_CASTLE": {"id":"S_GLUDIO_CASTLE", "name":"Gludio Castle", "x":-18361, "y":113887, "z":-2767, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SCHUTTGART_CASTLE": {"id":"S_SCHUTTGART_CASTLE", "name":"Schuttgart Castle", "x":77540, "y":-149114, "z":-352, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_SAINTS": {"id":"S_SAINTS", "name":"Saint's", "x":82623, "y":209258, "z":-5439, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DISCIPLES": {"id":"S_DISCIPLES", "name":"Disciple's", "x":171880, "y":-17657, "z":-4901, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_MARTYRDOM": {"id":"S_MARTYRDOM", "name":"Martyrdom", "x":117788, "y":132785, "z":-4830, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DEVOTION": {"id":"S_DEVOTION", "name":"Devotion", "x":-52850, "y":79044, "z":-4741, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PATRIOTS": {"id":"S_PATRIOTS", "name":"Patriot's", "x":-22219, "y":77315, "z":-5173, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WORSHIP": {"id":"S_WORSHIP", "name":"Worship", "x":110663, "y":174008, "z":-5444, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PILGRIMS": {"id":"S_PILGRIMS", "name":"Pilgrim", "x":45221, "y":124407, "z":-5412, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SACRAFICE": {"id":"S_SACRAFICE", "name":"Sacrifice", "x":-41562, "y":209253, "z":-5086, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_DARK_OMENS": {"id":"S_DARK_OMENS", "name":"Dark Omens", "x":-19979, "y":13528, "z":-4900, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FORBIDDEN_PATH": {"id":"S_FORBIDDEN_PATH", "name":"Forbidden Path", "x":113434, "y":84523, "z":-6540, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WITCH": {"id":"S_WITCH", "name":"Witch", "x":140011, "y":79709, "z":-5428, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_APOSTATE": {"id":"S_APOSTATE", "name":"Apostate", "x":77199, "y":78370, "z":-5114, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_BRANDED": {"id":"S_BRANDED", "name":"Branded", "x":45605, "y":170296, "z":-4986, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HERETIC": {"id":"S_HERETIC", "name":"Heretic", "x":42504, "y":143934, "z":-5381, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_FORTRESS_OF_RESISTANCE": {"id":"S_FORTRESS_OF_RESISTANCE", "name":"Fortress of Resistance", "x":45556, "y":109807, "z":-1990, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_BANDIT_STRONGHOLD": {"id":"S_BANDIT_STRONGHOLD", "name":"Bandit Stronghold", "x":86575, "y":-19745, "z":-1931, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DEVASTATED_CASTLE": {"id":"S_DEVASTATED_CASTLE", "name":"Devastated Castle", "x":178342, "y":-14003, "z":-2255, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WILD_BEAST_RESERVE": {"id":"S_WILD_BEAST_RESERVE", "name":"Wild Beast Reserve", "x":53556, "y":-94063, "z":-1630, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_RAINDBOW_SPRINGS_CHATEAU": {"id":"S_RAINDBOW_SPRINGS_CHATEAU", "name":"Rainbow Springs Chateau", "x":140997, "y":-123379, "z":-1906, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FORTRESS_OF_THE_DEAD": {"id":"S_FORTRESS_OF_THE_DEAD", "name":"Fortress of the Dead", "x":57960, "y":-30188, "z":-501, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_EXECUTION_GROUNDS": {"id":"S_EXECUTION_GROUNDS", "name":"Execution Grounds", "x":38291, "y":148029, "z":-3696, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PARTISANS_HIDEAWAY": {"id":"S_PARTISANS_HIDEAWAY", "name":"Partisan's Hideaway", "x":50081, "y":116859, "z":-2176, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CRUMA_MARSHLANDS": {"id":"S_CRUMA_MARSHLANDS", "name":"Cruma Marshlands", "x":5106, "y":126916, "z":-3664, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_TANOR_CANYON": {"id":"S_TANOR_CANYON", "name":"Tanor Canyon", "x":58316, "y":163851, "z":-2816, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_BEE_HIVE": {"id":"S_BEE_HIVE", "name":"Bee Hive", "x":34475, "y":188095, "z":-2976, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DION_HILLS": {"id":"S_DION_HILLS", "name":"Dion Hills", "x":29928, "y":151415, "z":2392, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FLORAN_AGRICULTURAL_AREA": {"id":"S_FLORAN_AGRICULTURAL_AREA", "name":"Floran Agricultural Area", "x":10610, "y":156322, "z":-2472, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PLAINS_OF_DION": {"id":"S_PLAINS_OF_DION", "name":"Plains of Dion", "x":630, "y":179184, "z":-3720, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CRUMA_TOWER": {"id":"S_CRUMA_TOWER", "name":"Cruma Tower", "x":17225, "y":114173, "z":-3440, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CRUMA_TOWER_1ST": {"id":"S_CRUMA_TOWER_1ST", "name":"Cruma Tower 1st Floor", "x":17724, "y":114004, "z":-11672, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CRUMA_TOWER_2ND": {"id":"S_CRUMA_TOWER_2ND", "name":"Cruma Tower 2nd Floor", "x":17730, "y":108301, "z":-9057, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CRUMA_TOWER_3RD": {"id":"S_CRUMA_TOWER_3RD", "name":"Cruma Tower 3rd Floor", "x":17719, "y":115430, "z":-6582, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_RUINS_OF_DESPAIR": {"id":"S_RUINS_OF_DESPAIR", "name":"Ruins of Despair", "x":-19120, "y":136816, "z":-3762, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_RUINS_OF_AGONY": {"id":"S_RUINS_OF_AGONY", "name":"Ruins of Agony", "x":-42628, "y":119766, "z":-3528, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WASTELAND": {"id":"S_WASTELAND", "name":"Wasteland", "x":-16526, "y":208032, "z":-3664, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ABANDONED_CAMP": {"id":"S_ABANDONED_CAMP", "name":"Abandoned Camp", "x":-49853, "y":147089, "z":-2784, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ORC_BARRACKS": {"id":"S_ORC_BARRACKS", "name":"Orc Barracks", "x":-89763, "y":105359, "z":-3576, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WINDY_HILL": {"id":"S_WINDY_HILL", "name":"Windy Hill", "x":-88539, "y":83389, "z":-2864, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_RED_ROCK_RIDGE": {"id":"S_RED_ROCK_RIDGE", "name":"Red Rock Ridge", "x":-44829, "y":188171, "z":-3256, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_LANGK_LIZARDMEN_DWELLINGS": {"id":"S_LANGK_LIZARDMEN_DWELLINGS", "name":"Langk Lizardmen Dwellings", "x":-44763, "y":203497, "z":-3592, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_MAILLE_LIZARDMEN_BARRACKS": {"id":"S_MAILLE_LIZARDMEN_BARRACKS", "name":"Maille Lizardmen Barracks", "x":-25283, "y":106820, "z":-3416, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_TALKING_ISLAND_NORTHERN_TERRITORY": {"id":"S_TALKING_ISLAND_NORTHERN_TERRITORY", "name":"Talking Island, Northern Territory", "x":-104344, "y":226217, "z":-3616, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_TALKING_ISLAND_EASTERN_TERRITORY": {"id":"S_TALKING_ISLAND_EASTERN_TERRITORY", "name":"Talking Island, Eastern Territory", "x":-95336, "y":240478, "z":-3264, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FELLMERE_HARVESTING_GROUNDS": {"id":"S_FELLMERE_HARVESTING_GROUNDS", "name":"Fellmere Harvesting Grounds", "x":-63736, "y":101522, "z":-3552, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WINDMILL_HILL": {"id":"S_WINDMILL_HILL", "name":"Windmill Hill", "x":-75437, "y":168800, "z":-3632, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_EVIL_HUNTING_GROUNDS": {"id":"S_EVIL_HUNTING_GROUNDS", "name":"Evil Hunting Grounds", "x":-6989, "y":109503, "z":-3040, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WINDAWOOD_MANOR": {"id":"S_WINDAWOOD_MANOR", "name":"Windawood Manor", "x":-28327, "y":155125, "z":-3496, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_OL_MAHUM_CHECKPOINT": {"id":"S_OL_MAHUM_CHECKPOINT", "name":"Ol Mahum Checkpoint", "x":-6661, "y":201880, "z":-3632, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_NEUTRAL_ZONE": {"id":"S_THE_NEUTRAL_ZONE", "name":"The Neutral Zone", "x":-10612, "y":75881, "z":-3592, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_ANT_NEST": {"id":"S_THE_ANT_NEST", "name":"The Ant Nest", "x":-9959, "y":176184, "z":-4160, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FORGOTTEN_TEMPLE": {"id":"S_FORGOTTEN_TEMPLE", "name":"Forgotten Temple", "x":-53001, "y":191425, "z":-3568, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ELVEN_RUINS": {"id":"S_ELVEN_RUINS", "name":"Elven Ruins", "x":-112367, "y":234703, "z":-3688, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ANT_INCUBATOR": {"id":"S_ANT_INCUBATOR", "name":"Ant Incubator", "x":-26489, "y":195307, "z":-3928, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GLUDIN_HARBOR": {"id":"S_GLUDIN_HARBOR", "name":"Gludin Harbor", "x":-91101, "y":150344, "z":-3624, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_TALKING_ISLAND_HARBOR": {"id":"S_TALKING_ISLAND_HARBOR", "name":"Talking Island Harbor", "x":-96811, "y":259153, "z":-3616, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GLUDIN_ARENA": {"id":"S_GLUDIN_ARENA", "name":"Gludin Arena", "x":-87328, "y":142266, "z":-3640, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FELLMERE_LAKE": {"id":"S_FELLMERE_LAKE", "name":"Fellmere Lake", "x":-57798, "y":127629, "z":-2928, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_OBELISK_OF_VICTORY": {"id":"S_OBELISK_OF_VICTORY", "name":"Obelisk of Victory", "x":-99586, "y":237637, "z":-3568, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SINGING_WATERFALL": {"id":"S_SINGING_WATERFALL", "name":"Singing Waterfall", "x":-111728, "y":244330, "z":-3448, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HELLBOUND_ENTRANCE": {"id":"S_HELLBOUND_ENTRANCE", "name":"Hellbound Entrance", "x":-11802, "y":236360, "z":-3271, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GLUDIO_AIRSHIP_FIELD": {"id":"S_GLUDIO_AIRSHIP_FIELD", "name":"Gludio AirShip Field", "x":-149365, "y":255309, "z":-86, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_BLAZING_SWAMP": {"id":"S_BLAZING_SWAMP", "name":"Blazing Swamp", "x":155310, "y":-16339, "z":-3320, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_FORBIDDEN_GATEWAY": {"id":"S_THE_FORBIDDEN_GATEWAY", "name":"The Forbidden Gateway", "x":188611, "y":20588, "z":-3696, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_ENCHANTED_VALLEY": {"id":"S_THE_ENCHANTED_VALLEY", "name":"The Enchanted Valley", "x":124904, "y":61992, "z":-3973, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_CEMETERY": {"id":"S_THE_CEMETERY", "name":"The Cemetery", "x":167047, "y":20304, "z":-3328, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_FOREST_OF_MIRRORS": {"id":"S_THE_FOREST_OF_MIRRORS", "name":"The Forest of Mirrors", "x":142065, "y":81300, "z":-3000, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ANCIENT_BATTLEGROUND": {"id":"S_ANCIENT_BATTLEGROUND", "name":"Ancient Battleground", "x":106517, "y":-2871, "z":-3454, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FORSAKEN_PLAINS": {"id":"S_FORSAKEN_PLAINS", "name":"Forsaken Plains", "x":168217, "y":37990, "z":-4072, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SILENT_VALLEY": {"id":"S_SILENT_VALLEY", "name":"Silent Valley", "x":170838, "y":55776, "z":-5280, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HUNTERS_VALLEY": {"id":"S_HUNTERS_VALLEY", "name":"Hunters Valley", "x":114306, "y":86573, "z":-3112, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PLAINS_OF_GLORY": {"id":"S_PLAINS_OF_GLORY", "name":"Plains of Glory", "x":135580, "y":19467, "z":-3424, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FIELDS_OF_MASSACRE": {"id":"S_FIELDS_OF_MASSACRE", "name":"Fields of Massacre", "x":183543, "y":-14974, "z":-2768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WAR-TORN_PLAINS": {"id":"S_WAR-TORN_PLAINS", "name":"War-Torn Plains", "x":156898, "y":11217, "z":-4032, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ISLE_OF_SOULS": {"id":"S_ISLE_OF_SOULS", "name":"Isle of Souls", "x":-121436, "y":56288, "z":-1586, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_MIMIRS_FOREST": {"id":"S_MIMIRS_FOREST", "name":"Mimir's Forest", "x":-103032, "y":46457, "z":-1136, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HILLS_OF_GOLD": {"id":"S_HILLS_OF_GOLD", "name":"Hills of Gold", "x":-116114, "y":87005, "z":-3544, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_TOWER_OF_INSOLENCE": {"id":"S_TOWER_OF_INSOLENCE", "name":"Tower of Insolence", "x":114649, "y":11115, "z":-5120, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_GIANTS_CAVE": {"id":"S_THE_GIANTS_CAVE", "name":"The Giant's Cave", "x":181737, "y":46469, "z":-4276, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_NORNILS_GARDEN": {"id":"S_NORNILS_GARDEN", "name":"Nornil's Garden", "x":-84728, "y":60089, "z":-2576, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_NORNILS_CAVE": {"id":"S_NORNILS_CAVE", "name":"Nornil's Cave", "x":-86961, "y":43356, "z":-2680, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_COLISEUM": {"id":"S_COLISEUM", "name":"Coliseum", "x":146440, "y":46723, "z":-3400, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ANGHEL_WATERFALL": {"id":"S_ANGHEL_WATERFALL", "name":"Anghel Waterfall", "x":166182, "y":91560, "z":-3168, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_EASTERN_BORDER_OUTPOST": {"id":"S_EASTERN_BORDER_OUTPOST", "name":"Eastern Border Outpost", "x":158141, "y":-24543, "z":-1288, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_NARSELL_LAKE": {"id":"S_NARSELL_LAKE", "name":"Narsell Lake", "x":146440, "y":46723, "z":-3400, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WESTERN_BORDER_OUTPOST": {"id":"S_WESTERN_BORDER_OUTPOST", "name":"Western Border Outpost", "x":112405, "y":-16607, "z":-1864, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CAVE_OF_SOULS": {"id":"S_CAVE_OF_SOULS", "name":"Cave of Souls", "x":-123842, "y":38117, "z":1176, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_VALLEY_OF_HEROES": {"id":"S_VALLEY_OF_HEROES", "name":"Valley of Heroes", "x":-39347, "y":-107274, "z":-2072, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_IMMORTAL_PLATEAU_NORTHERN_REGION": {"id":"S_IMMORTAL_PLATEAU_NORTHERN_REGION", "name":"Immortal Plateau, Northern Region", "x":-10983, "y":-117484, "z":-2464, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_IMMORTAL_PLATEAU_SOUTHERN_REGION": {"id":"S_IMMORTAL_PLATEAU_SOUTHERN_REGION", "name":"Immortal Plateau, Southern Region", "x":-4190, "y":-80040, "z":-2696, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FROZEN_VALLEY": {"id":"S_FROZEN_VALLEY", "name":"Frozen Valley", "x":112971, "y":-174924, "z":-608, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WESTERN_MINING_ZONE": {"id":"S_WESTERN_MINING_ZONE", "name":"Western Mining Zone", "x":128527, "y":-204036, "z":-3408, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_EASTERN_MINING_ZONE": {"id":"S_EASTERN_MINING_ZONE", "name":"Eastern Mining Zone", "x":175836, "y":-205837, "z":-3384, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PLUNDEROUS_PLAINS": {"id":"S_PLUNDEROUS_PLAINS", "name":"Plunderous Plains", "x":111965, "y":-154172, "z":-1528, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FROZEN_LABYRINTH": {"id":"S_FROZEN_LABYRINTH", "name":"Frozen Labyrinth", "x":113903, "y":-108752, "z":-884, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FREYAS_GARDEN": {"id":"S_FREYAS_GARDEN", "name":"Freya's Garden", "x":102728, "y":-126242, "z":-2840, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PAVEL_RUINS": {"id":"S_PAVEL_RUINS", "name":"Pavel Ruins", "x":91280, "y":-117152, "z":-3952, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DEN_OF_EVIL": {"id":"S_DEN_OF_EVIL", "name":"Den of Evil", "x":68693, "y":-110438, "z":-1946, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CRYPTS_OF_DISGRACE": {"id":"S_CRYPTS_OF_DISGRACE", "name":"Crypts of Disgrace", "x":47692, "y":-115745, "z":-3744, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SKY_WAGON_RELIC": {"id":"S_SKY_WAGON_RELIC", "name":"Sky Wagon Relic", "x":121618, "y":-141554, "z":-1496, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CAVE_OF_TRIALS": {"id":"S_CAVE_OF_TRIALS", "name":"Cave of Trials", "x":9340, "y":-112509, "z":-2536, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ABANDONED_COAL_MINES": {"id":"S_ABANDONED_COAL_MINES", "name":"Abandoned Coal Mines", "x":139714, "y":-177456, "z":-1536, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_MITHRIL_MINES": {"id":"S_MITHRIL_MINES", "name":"Mithril Mines", "x":171946, "y":-173352, "z":3440, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ARCHAIC_LABORATORY": {"id":"S_ARCHAIC_LABORATORY", "name":"Archaic Laboratory", "x":90418, "y":-107317, "z":-3328, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FROZEN_WATERFALLS": {"id":"S_FROZEN_WATERFALLS", "name":"Frozen Waterfalls", "x":8652, "y":-139941, "z":-1144, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_STRIP_MINE": {"id":"S_STRIP_MINE", "name":"Strip Mine", "x":106561, "y":-173949, "z":-400, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SPINE_MOUNTAINS": {"id":"S_SPINE_MOUNTAINS", "name":"Spine Mountains", "x":147493, "y":-200840, "z":192, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_MINING_ZONE_PASSAGE": {"id":"S_MINING_ZONE_PASSAGE", "name":"Mining Zone Passage", "x":113826, "y":-171150, "z":-160, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CARONS_DUNGEON": {"id":"S_CARONS_DUNGEON", "name":"Caron's Dungeon", "x":76021, "y":-110477, "z":-1704, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_VALLEY_OF_THE_LORDS": {"id":"S_VALLEY_OF_THE_LORDS", "name":"Valley of the Lords", "x":32173, "y":-122954, "z":-792, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FROST_LAKE": {"id":"S_FROST_LAKE", "name":"Frost Lake", "x":107577, "y":-122392, "z":-3632, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ICE_MERCHANT_CABIN": {"id":"S_ICE_MERCHANT_CABIN", "name":"Ice Merchant Cabin", "x":113750, "y":-109163, "z":-832, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_BRIGAND_STRONGHOLD": {"id":"S_BRIGAND_STRONGHOLD", "name":"Brigand Stronghold", "x":126272, "y":-159336, "z":-1232, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GRAVEROBBER_HIDEOUT": {"id":"S_GRAVEROBBER_HIDEOUT", "name":"Graverobber Hideout", "x":48336, "y":-107734, "z":-1577, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_GARDEN_OF_BEASTS": {"id":"S_GARDEN_OF_BEASTS", "name":"Garden of Beasts", "x":132997, "y":-60608, "z":-2960, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HOT_SPRINGS": {"id":"S_HOT_SPRINGS", "name":"Hot Springs", "x":144880, "y":-113468, "z":-2560, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_KETRA_ORC_OUTPOST": {"id":"S_KETRA_ORC_OUTPOST", "name":"Ketra Orc Outpost", "x":146990, "y":-67128, "z":-3640, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WALL_OF_ARGOS": {"id":"S_WALL_OF_ARGOS", "name":"Wall of Argos", "x":165054, "y":-47861, "z":-3560, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SHRINE_OF_LOYALTY": {"id":"S_SHRINE_OF_LOYALTY", "name":"Shrine of Loyalty", "x":190112, "y":61776, "z":-2944, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_VARKA_SILENOS_BARRACKS": {"id":"S_VARKA_SILENOS_BARRACKS", "name":"Varka Silenos Barracks", "x":125740, "y":-40864, "z":-3736, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DEVILS_PASS": {"id":"S_DEVILS_PASS", "name":"Devil's Pass", "x":42504, "y":-61870, "z":-2904, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FORGE_OF_THE_GODS": {"id":"S_FORGE_OF_THE_GODS", "name":"Forge of the Gods", "x":168902, "y":-116703, "z":-2417, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HALL_OF_FLAMES": {"id":"S_HALL_OF_FLAMES", "name":"Hall of Flames", "x":189964, "y":-116820, "z":-1624, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_IMPERIAL_TOMB": {"id":"S_IMPERIAL_TOMB", "name":"Imperial Tomb", "x":186699, "y":-75915, "z":-2826, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FOUR_SEPULCHERS": {"id":"S_FOUR_SEPULCHERS", "name":"Four Sepulchers", "x":178127, "y":-84435, "z":-7215, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_KETRA_ORC_VILLAGE": {"id":"S_KETRA_ORC_VILLAGE", "name":"Ketra Orc Village", "x":149548, "y":-82014, "z":-5592, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_VARKA_SILENOS_VILLAGE": {"id":"S_VARKA_SILENOS_VILLAGE", "name":"Varka Silenos Village", "x":108155, "y":-53670, "z":-2472, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HOT_SPRINGS_ARENA": {"id":"S_HOT_SPRINGS_ARENA", "name":"Hot Springs Arena", "x":152180, "y":-126093, "z":-2282, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_DRAGON_VALLEY": {"id":"S_DRAGON_VALLEY", "name":"Dragon Valley", "x":73024, "y":118485, "z":-3720, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DEATH_PASS": {"id":"S_DEATH_PASS", "name":"Death Pass", "x":67933, "y":117045, "z":-3544, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_BREKAS_STRONGHOLD": {"id":"S_BREKAS_STRONGHOLD", "name":"Breka's Stronghold", "x":85546, "y":131328, "z":-3672, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GORGON_FLOWER_GARDEN": {"id":"S_GORGON_FLOWER_GARDEN", "name":"Gorgon Flower Garden", "x":113553, "y":134813, "z":-3540, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ANTHARAS_LAIR": {"id":"S_ANTHARAS_LAIR", "name":"Antharas' Lair", "x":131557, "y":114509, "z":-3712, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DEVILS_ISLE": {"id":"S_DEVILS_ISLE", "name":"Devil's Isle", "x":43408, "y":206881, "z":-3752, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HARDINS_ACADEMY": {"id":"S_HARDINS_ACADEMY", "name":"Hardin's Academy", "x":105918, "y":109759, "z":-3170, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GIRAN_HARBOR": {"id":"S_GIRAN_HARBOR", "name":"Giran Harbor", "x":47938, "y":186864, "z":-3420, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GIRAN_ARENA": {"id":"S_GIRAN_ARENA", "name":"Giran Arena", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PIRATE_TUNNEL": {"id":"S_PIRATE_TUNNEL", "name":"Pirate Tunnel", "x":41528, "y":198358, "z":-4648, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ANTHARAS_HEART": {"id":"S_ANTHARAS_HEART", "name":"Antharas' Heart", "x":154623, "y":121134, "z":-3809, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_ELVEN_FOREST": {"id":"S_ELVEN_FOREST", "name":"Elven Forest", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SHADOW_OF_THE_MOTHER_TREE": {"id":"S_SHADOW_OF_THE_MOTHER_TREE", "name":"Shadow of the Mother Tree", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_DARK_FOREST": {"id":"S_THE_DARK_FOREST", "name":"The Dark Forest", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SWAMPLAND": {"id":"S_SWAMPLAND", "name":"Swampland", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SEA_OF_SPORES": {"id":"S_SEA_OF_SPORES", "name":"Sea of Spores", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PLAINS_OF_THE_LIZARDMEN": {"id":"S_PLAINS_OF_THE_LIZARDMEN", "name":"Palins of the Lizardmen", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SEL_MAHUM_TRAINING_GROUNDS": {"id":"S_SEL_MAHUM_TRAINING_GROUNDS", "name":"Sel Mahum Training Grounds", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SHILENS_GARDEN": {"id":"S_SHILENS_GARDEN", "name":"Shilens Garden", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_BLACK_ROCK_HILL": {"id":"S_BLACK_ROCK_HILL", "name":"Black Rock Hill", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SPIDER_NEST": {"id":"S_SPIDER_NEST", "name":"Spider Nest", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_TIMAK_OUTPOST": {"id":"S_TIMAK_OUTPOST", "name":"Timak Outpost", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_IVORY_TOWER_CRATER": {"id":"S_IVORY_TOWER_CRATER", "name":"Ivory Tower Crater", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FOREST_OF_EVIL": {"id":"S_FOREST_OF_EVIL", "name":"Forest of Evil", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_OUTLAW_FOREST": {"id":"S_OUTLAW_FOREST", "name":"Outlaw Forest", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ELVEN_FORTRESS": {"id":"S_ELVEN_FORTRESS", "name":"Elven Fortress", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SCHOOL_OF_DARK_ARTS": {"id":"S_SCHOOL_OF_DARK_ARTS", "name":"School of Dark Arts", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_IVORY_TOWER": {"id":"S_IVORY_TOWER", "name":"Ivory Tower", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_IRIS_LAKE": {"id":"S_IRIS_LAKE", "name":"Iris Lake", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ALTAR_OF_RITES": {"id":"S_ALTAR_OF_RITES", "name":"Altar of Rites", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_MISTY_MOUNTAINS": {"id":"S_MISTY_MOUNTAINS", "name":"Misty Mountains", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_STARLIGHT_WATERFALL": {"id":"S_STARLIGHT_WATERFALL", "name":"Starlight Waterfall", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_UNDINE_WATERFALL": {"id":"S_UNDINE_WATERFALL", "name":"Undine Waterfall", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_GODS_FALLS": {"id":"S_THE_GODS_FALLS", "name":"The Gods Falls", "x":73579, "y":142709, "z":-3768, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_FIELD_OF_SILENCE": {"id":"S_FIELD_OF_SILENCE", "name":"Field of Silence", "x":91088, "y":182384, "z":-3192, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FIELD_OF_WHISPERS": {"id":"S_FIELD_OF_WHISPERS", "name":"Field of Whispers", "x":74592, "y":207656, "z":-3032, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ALLIGATOR_ISLAND": {"id":"S_ALLIGATOR_ISLAND", "name":"Alligator Island", "x":115583, "y":192261, "z":-3488, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ALLIGATOR_BEACH": {"id":"S_ALLIGATOR_BEACH", "name":"Alligator Beach", "x":116267, "y":201177, "z":-3432, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ISLE_OF_PRAYER": {"id":"S_ISLE_OF_PRAYER", "name":"Isle of Prayer", "x":145159, "y":189247, "z":-3756, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PARNASSUS": {"id":"S_PARNASSUS", "name":"Parnassus", "x":149363, "y":172341, "z":-946, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CHROMATIC_HIGHLANDS": {"id":"S_CHROMATIC_HIGHLANDS", "name":"Chromatic Highlands", "x":148444, "y":160914, "z":-3102, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GARDEN_OF_EVA": {"id":"S_GARDEN_OF_EVA", "name":"Garden of Eva", "x":84413, "y":234334, "z":-3656, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GARDEN_OF_EVA_1ST_FLOOR": {"id":"S_GARDEN_OF_EVA_1ST_FLOOR", "name":"Garden of Eva 1st Floor", "x":80688, "y":245566, "z":-8926, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GARDEN_OF_EVA_2ND_FLOOR": {"id":"S_GARDEN_OF_EVA_2ND_FLOOR", "name":"Garden of Eva 2nd Floor", "x":80629, "y":246420, "z":-9331, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GARDEN_OF_EVA_3RD_FLOOR": {"id":"S_GARDEN_OF_EVA_3RD_FLOOR", "name":"Garden of Eva 3rd Floor", "x":87750, "y":252422, "z":-9851, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GARDEN_OF_EVA_4TH_FLOOR": {"id":"S_GARDEN_OF_EVA_4TH_FLOOR", "name":"Garden of Eva 4th Floor", "x":82506, "y":255978, "z":-10363, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_GARDEN_OF_EVA_5TH_FLOOR": {"id":"S_GARDEN_OF_EVA_5TH_FLOOR", "name":"Garden of Eva 5th Floor", "x":82158, "y":252376, "z":-10592, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_TOUR_BOAT_DOCK": {"id":"S_TOUR_BOAT_DOCK", "name":"Tour Boat Dock", "x":111418, "y":225960, "z":-3624, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CORAL_REEF": {"id":"S_CORAL_REEF", "name":"Coral Reef", "x":160074, "y":167893, "z":-3538, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_BEAST_FARM": {"id":"S_BEAST_FARM", "name":"Beast Farm", "x":43805, "y":-88010, "z":-2780, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_VALLEY_OF_SAINTS": {"id":"S_VALLEY_OF_SAINTS", "name":"Valley of Saints", "x":65797, "y":-71510, "z":-3744, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FOREST_OF_THE_DEAD": {"id":"S_FOREST_OF_THE_DEAD", "name":"Forest of the Dead", "x":52107, "y":-54328, "z":-3158, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SWAMP_OF_SCREAMS": {"id":"S_SWAMP_OF_SCREAMS", "name":"Swamp of Screams", "x":69340, "y":-50203, "z":-3314, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_MONASTERY_OF_SILENCE": {"id":"S_MONASTERY_OF_SILENCE", "name":"Monastery of Silence", "x":106414, "y":-87799, "z":-2949, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_THE_PAGAN_TEMPLE": {"id":"S_THE_PAGAN_TEMPLE", "name":"The Pagan Temple", "x":35630, "y":-49748, "z":-760, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_STAKATO_NEST": {"id":"S_STAKATO_NEST", "name":"Stakato Nest", "x":88969, "y":-45307, "z":-2112, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CURSED_VILLAGE": {"id":"S_CURSED_VILLAGE", "name":"Cursed Village", "x":57670, "y":-41672, "z":-3154, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_RUNE_HARBOR": {"id":"S_RUNE_HARBOR", "name":"Rune Harbor", "x":36839, "y":-38435, "z":-3640, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_PRIMEVAL_ISLE_WHARF": {"id":"S_PRIMEVAL_ISLE_WHARF", "name":"Primeval Isle Wharf", "x":10448, "y":-24960, "z":-3664, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WINDTAIL_WATERFALL": {"id":"S_WINDTAIL_WATERFALL", "name":"Windtail Waterfall", "x":40723, "y":-94881, "z":-2096, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_AARU_FORT": {"id":"S_AARU_FORT", "name":"Aaru", "x":72889, "y":188048, "z":-2580, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ANTHARAS_FORT": {"id":"S_ANTHARAS_FORT", "name":"Antharas'", "x":77910, "y":89232, "z":-2883, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_ARCHAIC_FORT": {"id":"S_ARCHAIC_FORT", "name":"Archaic ", "x":111798, "y":-141743, "z":-2927, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_BAYOU_FORT": {"id":"S_BAYOU_FORT", "name":"Bayou", "x":189897, "y":36705, "z":-3407, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_BORDERLAND_FORT": {"id":"S_BORDERLAND_FORT", "name":"Borderland", "x":157008, "y":-68935, "z":-2861, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_CLOUD_MOUNTAIN_FORT": {"id":"S_CLOUD_MOUNTAIN_FORT", "name":"Cloud Mountain", "x":-54316, "y":89187, "z":-2819, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DEMON_FORT": {"id":"S_DEMON_FORT", "name":"Demon", "x":98822, "y":-56465, "z":-649, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DRAGONSPINE_FORT": {"id":"S_DRAGONSPINE_FORT", "name":"Dragonspine", "x":10527, "y":96849, "z":-3424, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_FLORAN_FORT": {"id":"S_FLORAN_FORT", "name":"Floran", "x":7690, "y":150721, "z":-2887, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HIVE_FORT": {"id":"S_HIVE_FORT", "name":"Hive", "x":15447, "y":186169, "z":-2921, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_HUNTERS_FORT": {"id":"S_HUNTERS_FORT", "name":"Hunter's", "x":124188, "y":93295, "z":-2142, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_IVORY_FORT": {"id":"S_IVORY_FORT", "name":"Ivory", "x":71419, "y":6187, "z":-3036, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_MONASTIC_FORT": {"id":"S_MONASTIC_FORT", "name":"Monastic", "x":71894, "y":-92615, "z":-1420, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_NARSELL_FORT": {"id":"S_NARSELL_FORT", "name":"Narsell", "x":156707, "y":53966, "z":-3251, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SHANTY_FORT": {"id":"S_SHANTY_FORT", "name":"Shanty", "x":-55004, "y":157132, "z":-2050, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SOUTHERN_FORT": {"id":"S_SOUTHERN_FORT", "name":"Southern", "x":-25348, "y":219856, "z":-3249, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SWAMP_FORT": {"id":"S_SWAMP_FORT", "name":"Swamp", "x":68731, "y":-63848, "z":-2783, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_TANOR_FORT": {"id":"S_TANOR_FORT", "name":"Tanor", "x":58948, "y":137927, "z":-1752, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_VALLEY_FORT": {"id":"S_VALLEY_FORT", "name":"Valley", "x":126064, "y":120508, "z":-2583, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WESTERN_FORT": {"id":"S_WESTERN_FORT", "name":"Western", "x":112350, "y":-17183, "z":-992, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_WHITE_SANDS_FORT": {"id":"S_WHITE_SANDS_FORT", "name":"White Sands", "x":116400, "y":203804, "z":-3331, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_SEED_OF_DESTRUCTION": {"id":"S_SEED_OF_DESTRUCTION", "name":"Seed of Destruction", "x":-248140, "y":250678, "z":4331, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SEED_OF_INFINITY": {"id":"S_SEED_OF_INFINITY", "name":"Seed of Infinity", "x":-212843, "y":209695, "z":4280, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_SEED_OF_ANNIHILATION": {"id":"S_SEED_OF_ANNIHILATION", "name":"Seed of Annihilation", "x":-178480, "y":153561, "z":2471, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+		"S_DARKCLOUD_MANSION": {"id":"S_DARKCLOUD_MANSION", "name":"Darkcloud Mansion", "x":140007, "y":150467, "z":-3112, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]},
+
+		"S_FANTASY_ISLAND": {"id":"S_FANTASY_ISLAND", "name":"Fantasy Island", "x":-59103, "y":-56895, "z":-2038, "heading":0, "randomOffset":0, "instance":"", "items":[{"id":57, "amount":100}]}
+	},
+
+    "groupTeleports": {
+	},
+
+	"soloTeleportCategories": {
+		"STC_TOWN_AREAS": {
+			"id":"STC_TOWN_AREAS",
+			"name":"Town Areas",
+			"soloTeleports": [
+				"S_GIRAN", "S_GODDARD", "S_DION", "S_GLUDIO", "S_SCHUTTGART", "S_HUNTERS", "S_ADEN", "S_RUNE", "S_OREN",
+				"S_GLUDIN", "S_HEINE", "S_FLORAN", "S_HUMAN", "S_ORC", "S_ELVEN", "S_DWARVEN", "S_DARK_ELVEN",
+				"S_KAMAEL"
+			]
+		},
+		"STC_CASTLE_AREAS": {
+			"id":"STC_CASTLE_AREAS",
+			"name":"Castle Areas",
+			"soloTeleports": [
+				"S_ADEN_CASTLE", "S_GODDARD_CASTLE", "S_DION_CASTLE", "S_RUNE_CASTLE", "S_INNADRIL_CASTLE",
+				"S_GIRAN_CASTLE", "S_OREN_CASTLE", "S_GLUDIO_CASTLE", "S_SCHUTTGART_CASTLE"
+			]
+		},
+		"STC_NECROPOLIS": {
+			"id":"STC_NECROPOLIS",
+			"name":"Necropolis",
+			"soloTeleports": [
+				"S_SAINTS", "S_DISCIPLES", "S_MARTYRDOM", "S_DEVOTION", "S_PATRIOTS", "S_WORSHIP", "S_PILGRIMS",
+				"S_SACRAFICE"
+			]
+		},
+		"STC_CATACOMBS": {
+			"id":"STC_CATACOMBS",
+			"name":"Catacombs",
+			"soloTeleports": ["S_DARK_OMENS", "S_FORBIDDEN_PATH", "S_WITCH", "S_APOSTATE", "S_BRANDED", "S_HERETIC"]
+		},
+		"STC_CONQUERABLE_CLAN_HALLS": {
+			"id":"STC_CONQUERABLE_CLAN_HALLS",
+			"name":"Conquerable Clan Halls",
+			"soloTeleports": [
+				"S_FORTRESS_OF_RESISTANCE", "S_BANDIT_STRONGHOLD", "S_DEVASTATED_CASTLE", "S_WILD_BEAST_RESERVE",
+				"S_RAINDBOW_SPRINGS_CHATEAU", "S_FORTRESS_OF_THE_DEAD"
+			]
+		},
+		"STC_WORLD_AREAS_DION": {
+			"id":"STC_WORLD_AREAS_DION",
+			"name":"Dion Territory",
+			"soloTeleports": [
+				"S_EXECUTION_GROUNDS", "S_PARTISANS_HIDEAWAY", "S_CRUMA_MARSHLANDS", "S_TANOR_CANYON", "S_BEE_HIVE",
+				"S_DION_HILLS", "S_FLORAN_AGRICULTURAL_AREA", "S_PLAINS_OF_DION", "S_CRUMA_TOWER", "S_CRUMA_TOWER_1ST",
+				"S_CRUMA_TOWER_2ND", "S_CRUMA_TOWER_3RD"
+			]
+		},
+		"STC_WORLD_AREAS_GLUDIO": {
+			"id":"STC_WORLD_AREAS_GLUDIO",
+			"name":"Gludio  Territory",
+			"soloTeleports": [
+				"S_RUINS_OF_DESPAIR", "S_RUINS_OF_AGONY", "S_WASTELAND", "S_ABANDONED_CAMP", "S_ORC_BARRACKS",
+				"S_WINDY_HILL", "S_RED_ROCK_RIDGE", "S_LANGK_LIZARDMEN_DWELLINGS", "S_MAILLE_LIZARDMEN_BARRACKS",
+				"S_TALKING_ISLAND_NORTHERN_TERRITORY", "S_TALKING_ISLAND_EASTERN_TERRITORY",
+				"S_FELLMERE_HARVESTING_GROUNDS", "S_WINDMILL_HILL", "S_EVIL_HUNTING_GROUNDS", "S_WINDAWOOD_MANOR",
+				"S_OL_MAHUM_CHECKPOINT", "S_THE_NEUTRAL_ZONE", "S_THE_ANT_NEST", "S_FORGOTTEN_TEMPLE", "S_ELVEN_RUINS",
+				"S_ANT_INCUBATOR", "S_GLUDIN_HARBOR", "S_TALKING_ISLAND_HARBOR", "S_GLUDIN_ARENA", "S_FELLMERE_LAKE",
+				"S_OBELISK_OF_VICTORY", "S_SINGING_WATERFALL", "S_HELLBOUND_ENTRANCE", "S_GLUDIO_AIRSHIP_FIELD"
+			]
+		},
+		"STC_WORLD_AREAS_ADEN": {
+			"id":"STC_WORLD_AREAS_ADEN",
+			"name":"Aden Territory",
+			"soloTeleports": [
+				"S_BLAZING_SWAMP", "S_THE_FORBIDDEN_GATEWAY", "S_THE_ENCHANTED_VALLEY", "S_THE_CEMETERY",
+				"S_THE_FOREST_OF_MIRRORS", "S_ANCIENT_BATTLEGROUND", "S_FORSAKEN_PLAINS", "S_SILENT_VALLEY",
+				"S_HUNTERS_VALLEY", "S_PLAINS_OF_GLORY", "S_FIELDS_OF_MASSACRE", "S_WAR-TORN_PLAINS", "S_ISLE_OF_SOULS",
+				"S_MIMIRS_FOREST", "S_HILLS_OF_GOLD", "S_TOWER_OF_INSOLENCE", "S_THE_GIANTS_CAVE",
+				"S_NORNILS_GARDEN", "S_NORNILS_CAVE", "S_COLISEUM", "S_ANGHEL_WATERFALL", "S_EASTERN_BORDER_OUTPOST",
+				"S_NARSELL_LAKE", "S_WESTERN_BORDER_OUTPOST", "S_CAVE_OF_SOULS"
+			]
+		},
+		"STC_WORLD_AREAS_SCHUTTGART": {
+			"id":"STC_WORLD_AREAS_SCHUTTGART",
+			"name":"Schuttgart Territory",
+			"soloTeleports": [
+				"S_VALLEY_OF_HEROES", "S_IMMORTAL_PLATEAU_NORTHERN_REGION", "S_IMMORTAL_PLATEAU_SOUTHERN_REGION",
+				"S_FROZEN_VALLEY", "S_WESTERN_MINING_ZONE", "S_EASTERN_MINING_ZONE", "S_PLUNDEROUS_PLAINS",
+				"S_FROZEN_LABYRINTH", "S_FREYAS_GARDEN", "S_PAVEL_RUINS", "S_DEN_OF_EVIL", "S_CRYPTS_OF_DISGRACE",
+				"S_SKY_WAGON_RELIC", "S_CAVE_OF_TRIALS", "S_ABANDONED_COAL_MINES", "S_MITHRIL_MINES",
+				"S_ARCHAIC_LABORATORY", "S_FROZEN_WATERFALLS", "S_STRIP_MINE", "S_SPINE_MOUNTAINS",
+				"S_MINING_ZONE_PASSAGE", "S_CARONS_DUNGEON", "S_VALLEY_OF_THE_LORDS", "S_FROST_LAKE",
+				"S_ICE_MERCHANT_CABIN", "S_BRIGAND_STRONGHOLD", "S_GRAVEROBBER_HIDEOUT"
+			]
+		},
+		"STC_WORLD_AREAS_GODDARD": {
+			"id":"STC_WORLD_AREAS_GODDARD",
+			"name":"Goddard Territory",
+			"soloTeleports": [
+				"S_GARDEN_OF_BEASTS", "S_HOT_SPRINGS", "S_KETRA_ORC_OUTPOST", "S_WALL_OF_ARGOS", "S_SHRINE_OF_LOYALTY",
+				"S_VARKA_SILENOS_BARRACKS", "S_DEVILS_PASS", "S_FORGE_OF_THE_GODS", "S_HALL_OF_FLAMES",
+				"S_IMPERIAL_TOMB", "S_FOUR_SEPULCHERS", "S_KETRA_ORC_VILLAGE", "S_VARKA_SILENOS_VILLAGE",
+				"S_HOT_SPRINGS_ARENA"
+			]
+		},
+		"STC_WORLD_AREAS_GIRAN": {
+			"id":"STC_WORLD_AREAS_GIRAN",
+			"name":"Giran Territory",
+			"soloTeleports": [
+				"S_DRAGON_VALLEY", "S_DEATH_PASS", "S_BREKAS_STRONGHOLD", "S_GORGON_FLOWER_GARDEN", "S_ANTHARAS_LAIR",
+				"S_DEVILS_ISLE", "S_HARDINS_ACADEMY", "S_GIRAN_HARBOR", "S_GIRAN_ARENA", "S_PIRATE_TUNNEL",
+				"S_ANTHARAS_HEART"
+			]
+		},
+		"STC_WORLD_AREAS_OREN": {
+			"id":"STC_WORLD_AREAS_OREN",
+			"name":"Oren Territory",
+			"soloTeleports": [
+				"S_ELVEN_FOREST", "S_SHADOW_OF_THE_MOTHER_TREE", "S_THE_DARK_FOREST", "S_SWAMPLAND", "S_SEA_OF_SPORES",
+				"S_PLAINS_OF_THE_LIZARDMEN", "S_SEL_MAHUM_TRAINING_GROUNDS", "S_SHILENS_GARDEN", "S_BLACK_ROCK_HILL",
+				"S_SPIDER_NEST", "S_TIMAK_OUTPOST", "S_IVORY_TOWER_CRATER", "S_FOREST_OF_EVIL", "S_OUTLAW_FOREST",
+				"S_ELVEN_FORTRESS", "S_SCHOOL_OF_DARK_ARTS", "S_IVORY_TOWER", "S_IRIS_LAKE", "S_ALTAR_OF_RITES",
+				"S_MISTY_MOUNTAINS", "S_STARLIGHT_WATERFALL", "S_UNDINE_WATERFALL", "S_THE_GODS_FALLS"
+			]
+		},
+		"STC_WORLD_AREAS_INNADRIL": {
+			"id":"STC_WORLD_AREAS_INNADRIL",
+			"name":"Innadril Territory",
+			"soloTeleports": [
+				"S_FIELD_OF_SILENCE", "S_FIELD_OF_WHISPERS", "S_ALLIGATOR_ISLAND", "S_ALLIGATOR_BEACH", "S_ISLE_OF_PRAYER",
+				"S_PARNASSUS", "S_CHROMATIC_HIGHLANDS", "S_GARDEN_OF_EVA", "S_GARDEN_OF_EVA_1ST_FLOOR",
+				"S_GARDEN_OF_EVA_2ND_FLOOR", "S_GARDEN_OF_EVA_3RD_FLOOR", "S_GARDEN_OF_EVA_4TH_FLOOR",
+				"S_GARDEN_OF_EVA_5TH_FLOOR", "S_TOUR_BOAT_DOCK", "S_CORAL_REEF"
+			]
+		},
+		"STC_WORLD_AREAS_RUNE": {
+			"id":"STC_WORLD_AREAS_RUNE",
+			"name":"Rune Territory",
+			"soloTeleports": [
+				"S_BEAST_FARM", "S_VALLEY_OF_SAINTS", "S_FOREST_OF_THE_DEAD", "S_SWAMP_OF_SCREAMS", "S_MONASTERY_OF_SILENCE",
+				"S_THE_PAGAN_TEMPLE", "S_STAKATO_NEST", "S_CURSED_VILLAGE", "S_RUNE_HARBOR", "S_PRIMEVAL_ISLE_WHARF",
+				"S_WINDTAIL_WATERFALL"
+			]
+		},		
+		"STC_FORTRESS": {
+			"id":"STC_FORTRESS",
+			"name":"Fortress",
+			"soloTeleports": [
+				"S_AARU_FORT", "S_ANTHARAS_FORT", "S_ARCHAIC_FORT", "S_BAYOU_FORT", "S_BORDERLAND_FORT", "S_CLOUD_MOUNTAIN_FORT",
+				"S_DEMON_FORT", "S_DRAGONSPINE_FORT", "S_FLORAN_FORT", "S_HIVE_FORT", "S_HUNTERS_FORT", "S_IVORY_FORT",
+				"S_MONASTIC_FORT", "S_NARSELL_FORT", "S_SHANTY_FORT", "S_SOUTHERN_FORT", "S_SWAMP_FORT", "S_TANOR_FORT",
+				"S_VALLEY_FORT", "S_WESTERN_FORT", "S_WHITE_SANDS_FORT"
+			]
+		},
+		"STC_INSTANCES": {
+			"id":"STC_INSTANCES",
+			"name":"Instances",
+			"soloTeleports": [
+				"S_SEED_OF_DESTRUCTION", "S_SEED_OF_INFINITY", "S_SEED_OF_ANNIHILATION", "S_DARKCLOUD_MANSION"
+			]
+		},
+		"STC_OTHER_LOCATIONS": {
+			"id":"STC_OTHER_LOCATIONS",
+			"name":"Other Locations",
+			"soloTeleports": ["S_FANTASY_ISLAND"]
+		}
+	},
+
+	"groupTeleportCategories": {
+	}
+}
\ No newline at end of file
diff --git a/src/main/resources/data/service/teleporter/json/npcs/60002.json b/src/main/resources/data/service/teleporter/json/npcs/60002.json
new file mode 100644
index 0000000000000000000000000000000000000000..70efaec188d8f1979599500f08b78560903e52e6
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/json/npcs/60002.json
@@ -0,0 +1,14 @@
+{
+    "npcId":60002,
+    "directFirstTalk":true,
+    "dialogType":"NPC",
+    "htmlFolder":"npc",
+    
+    "soloTeleports": [],
+    "partyTeleports": [],
+    "commandChannelTeleports": [],
+    
+    "soloTeleportCategories": ["STC_TOWN_AREAS", "STC_CASTLE_AREAS", "STC_NECROPOLIS", "STC_CATACOMBS", "STC_CONQUERABLE_CLAN_HALLS", "STC_WORLD_AREAS_DION", "STC_WORLD_AREAS_GLUDIO", "STC_WORLD_AREAS_ADEN", "STC_WORLD_AREAS_SCHUTTGART", "STC_WORLD_AREAS_GODDARD", "STC_WORLD_AREAS_GIRAN", "STC_WORLD_AREAS_OREN", "STC_WORLD_AREAS_INNADRIL", "STC_WORLD_AREAS_RUNE", "STC_FORTRESS", "STC_INSTANCES", "STC_OTHER_LOCATIONS"],
+    "partyTeleportCategories": [],
+    "commandChannelTeleportCategories": []
+}
\ No newline at end of file
diff --git a/src/main/resources/data/service/teleporter/json/voiced.json b/src/main/resources/data/service/teleporter/json/voiced.json
new file mode 100644
index 0000000000000000000000000000000000000000..fcdc7ff36482eb0222b0e1a26e4c3fa40e761e24
--- /dev/null
+++ b/src/main/resources/data/service/teleporter/json/voiced.json
@@ -0,0 +1,12 @@
+{
+    "dialogType":"NPC",
+    "htmlFolder":"npc",
+    
+    "soloTeleports": [],
+    "partyTeleports": [],
+    "commandChannelTeleports": [],
+    
+    "soloTeleportCategories": ["STC_TOWN_AREAS", "STC_CASTLE_AREAS", "STC_NECROPOLIS", "STC_CATACOMBS", "STC_CONQUERABLE_CLAN_HALLS", "STC_WORLD_AREAS_DION", "STC_WORLD_AREAS_GLUDIO", "STC_WORLD_AREAS_ADEN", "STC_WORLD_AREAS_SCHUTTGART", "STC_WORLD_AREAS_GODDARD", "STC_WORLD_AREAS_GIRAN", "STC_WORLD_AREAS_OREN", "STC_WORLD_AREAS_INNADRIL", "STC_WORLD_AREAS_RUNE", "STC_FORTRESS", "STC_INSTANCES", "STC_OTHER_LOCATIONS"],
+    "partyTeleportCategories": [],
+    "commandChannelTeleportCategories": []
+}
\ No newline at end of file
diff --git a/src/main/resources/data/stats/npcs/custom/custom_teleporterservice.xml b/src/main/resources/data/stats/npcs/custom/custom_teleporterservice.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b5d2a8f2845920c9fc4e0eeaa54d4f2d34f64bcd
--- /dev/null
+++ b/src/main/resources/data/stats/npcs/custom/custom_teleporterservice.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/npcs.xsd">
+    <npc id="60002" displayId="32226" name="Selanta" usingServerSideName="true" title="Teleporter" usingServerSideTitle="true" type="L2Npc">
+        <collision>
+            <radius normal="11" />
+            <height normal="22.25" />
+        </collision>
+    </npc>
+</list>
\ No newline at end of file