فهرست منبع

BETA: The Hellbound Core part 2!

Zoey76 13 سال پیش
والد
کامیت
c70fa9a4df

+ 428 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/instancemanager/WalkingManager.java

@@ -0,0 +1,428 @@
+/*
+ * This program 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.
+ * 
+ * This program 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.gameserver.instancemanager;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.Announcements;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.ai.CtrlIntention;
+import com.l2jserver.gameserver.model.L2CharPosition;
+import com.l2jserver.gameserver.model.L2NpcWalkerNode;
+import com.l2jserver.gameserver.model.L2WalkRoute;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.network.NpcStringId;
+import com.l2jserver.util.Rnd;
+
+import java.io.File;
+import java.util.concurrent.ScheduledFuture;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.List;
+import java.util.Map;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javolution.util.FastList;
+import javolution.util.FastMap;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * This class manages walking monsters.
+ * @author GKR
+ */
+public class WalkingManager
+{
+	private static final Logger _log = Logger.getLogger(WalkingManager.class.getName());
+	
+	//Repeat style: 0 - go back, 1 - go to first point (circle style), 2 - teleport to first point (conveyor style), 3 - random walking between points.
+	private static final byte REPEAT_GO_BACK = 0;
+	private static final byte REPEAT_GO_FIRST = 1;
+	private static final byte REPEAT_TELE_FIRST = 2;
+	private static final byte REPEAT_RANDOM = 3;
+	
+	private Map<Integer, L2WalkRoute> _routes; //all available routes
+	private Map<Integer, WalkInfo> _activeRoutes; //each record represents NPC, moving by predefined route from _routes, and moving progress
+	
+	private class WalkInfo
+	{
+		private ScheduledFuture<?> _walkCheckTask;
+		private boolean _blocked = false;
+		private boolean _suspended = false;
+		private boolean _nodeArrived = false;
+		private int _currentNode  = 0;
+		private boolean _forward = true; //Determines first --> last or first <-- last direction
+		private int _routeId;
+		
+		public WalkInfo(int routeId)
+		{
+			_routeId = routeId;
+		}
+		
+		private L2WalkRoute getRoute()
+		{
+			return _routes.get(_routeId);
+		}
+		
+		private L2NpcWalkerNode getCurrentNode()
+		{
+			return getRoute().getNodeList().get(_currentNode); 
+		}
+	}
+	
+	public static final WalkingManager getInstance()
+	{
+		return SingletonHolder._instance;
+	}
+	
+	private WalkingManager()
+	{
+		_routes = new FastMap<Integer, L2WalkRoute>();
+		_activeRoutes = new FastMap<Integer, WalkInfo>();
+		load();
+	}
+	
+	private final void load()
+	{
+		_log.info("WalkingManager: Loading walking routes...");
+		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+		factory.setValidating(false);
+		factory.setIgnoringComments(true);
+		File file = new File(Config.DATAPACK_ROOT, "data/Routes.xml");
+		Document doc = null;
+		if (file.exists())
+		{
+			try
+			{
+				doc = factory.newDocumentBuilder().parse(file);
+			}
+			catch (Exception e)
+			{
+				_log.log(Level.WARNING, "Could not parse Routes.xml file: " + e.getMessage(), e);
+			}
+			
+			Node n = doc.getFirstChild();
+			for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
+			{
+				if (d.getNodeName().equals("route"))
+				{
+					boolean debug = false;
+					int routeId = Integer.parseInt(d.getAttributes().getNamedItem("id").getNodeValue());
+					boolean repeat = Boolean.parseBoolean(d.getAttributes().getNamedItem("repeat").getNodeValue());
+					String repeatStyle = d.getAttributes().getNamedItem("repeatStyle").getNodeValue();
+					byte repeatType;
+					
+					if (repeatStyle.equalsIgnoreCase("back"))
+						repeatType = REPEAT_GO_BACK;
+					else if (repeatStyle.equalsIgnoreCase("cycle"))
+						repeatType = REPEAT_GO_FIRST;
+					else if (repeatStyle.equalsIgnoreCase("conveyor"))
+						repeatType = REPEAT_TELE_FIRST;
+					else if (repeatStyle.equalsIgnoreCase("random"))
+						repeatType = REPEAT_RANDOM;
+					else
+						repeatType = -1;
+					
+					List<L2NpcWalkerNode> list = new FastList<L2NpcWalkerNode>();
+					for (Node r = d.getFirstChild(); r != null; r = r.getNextSibling())
+					{
+						if (r.getNodeName().equals("point"))
+						{
+							NamedNodeMap attrs = r.getAttributes();
+							int x = Integer.parseInt(attrs.getNamedItem("X").getNodeValue());
+							int y = Integer.parseInt(attrs.getNamedItem("Y").getNodeValue());
+							int z = Integer.parseInt(attrs.getNamedItem("Z").getNodeValue());
+							int delay = Integer.parseInt(attrs.getNamedItem("delay").getNodeValue());
+							
+							String chatString = null;
+							NpcStringId npcString = null;
+							Node node = attrs.getNamedItem("string");
+							if (node != null)
+								chatString = node.getNodeValue();
+							else
+							{
+								node = attrs.getNamedItem("npcString");
+								if (node != null)
+								{
+									npcString = NpcStringId.getNpcStringId(node.getNodeValue());
+									if (npcString == null)
+									{
+										_log.log(Level.WARNING, "NpcWalkerRoutersTable: Unknown npcstring '" + node.getNodeValue() + ".");
+										continue;
+									}
+								}
+								else
+								{
+									node = attrs.getNamedItem("npcStringId");
+									if (node != null)
+									{
+										npcString = NpcStringId.getNpcStringId(Integer.parseInt(node.getNodeValue()));
+										if (npcString == null)
+										{
+											_log.log(Level.WARNING, "NpcWalkerRoutersTable: Unknown npcstring '" + node.getNodeValue() + ".");
+											continue;
+										}
+									}
+								}
+							}
+							
+							boolean running = Boolean.parseBoolean(attrs.getNamedItem("run").getNodeValue());
+							list.add(new L2NpcWalkerNode(0, npcString, chatString, x, y, z, delay, running));
+						}
+						else if (r.getNodeName().equals("stat"))
+						{
+							NamedNodeMap attrs = r.getAttributes();
+							String name = attrs.getNamedItem("name").getNodeValue();
+							String val = attrs.getNamedItem("val").getNodeValue();
+							
+							if (name.equalsIgnoreCase("debug"))
+								debug = Boolean.parseBoolean(val);
+						}
+					
+					}
+					L2WalkRoute newRoute = new L2WalkRoute(routeId, list, repeat, false, repeatType);
+					newRoute.setDebug(debug);
+					_routes.put(routeId, newRoute);
+				}
+			}
+		}
+		_log.info("WalkingManager: loaded " + _routes.size() + " walking routes.");
+	}
+	
+	public boolean isRegistered(L2Npc npc)
+	{
+		return _activeRoutes.containsKey(npc.getObjectId());
+	}
+	
+	public void startMoving(final L2Npc npc, final int routeId)
+	{
+		if (_routes.containsKey(routeId) && npc != null && !npc.isDead()) //check, if these route and NPC present
+		{
+			if (!_activeRoutes.containsKey(npc.getObjectId())) //new walk task
+			{
+ 				//only if not already moved / not engaged in battle... should not happens if called on spawn
+				if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE || npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE)
+				{
+					WalkInfo walk = new WalkInfo(routeId);
+					//walk._lastActionTime = System.currentTimeMillis();
+					L2NpcWalkerNode node = walk.getCurrentNode();
+					
+					if (!npc.isInsideRadius(node.getMoveX(), node.getMoveY(), node.getMoveZ(), 3000, true, false)) //too far from first point, decline further operations
+						return;
+					
+					//Announcements.getInstance().announceToAll("Start to move!");
+					npc.setIsRunning(node.getRunning());
+					npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(node.getMoveX(), node.getMoveY(), node.getMoveZ(), 0));
+					walk._walkCheckTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new Runnable() {
+					@Override
+					public void run() 
+					{
+						startMoving(npc, routeId);
+					}
+					}, 60000, 60000); //start walk check task, for resuming walk after fight
+					
+					npc.getKnownList().startTrackingTask();
+					
+					_activeRoutes.put(npc.getObjectId(), walk); //register route
+				}
+				else //try a bit later
+					ThreadPoolManager.getInstance().scheduleGeneral(new Runnable() {
+					@Override
+					public void run() 
+					{
+						startMoving(npc, routeId);
+					}
+					}, 60000);
+			}
+			else //walk was stopped due to some reason (arrived to node, script action, fight or something else), resume it
+			{
+				//Announcements.getInstance().announceToAll("Here_1!");
+				if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE || npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE)
+				{
+					//Announcements.getInstance().announceToAll("Here_2!");
+					WalkInfo walk = _activeRoutes.get(npc.getObjectId());
+					//Announcements.getInstance().announceToAll("X = " + Integer.toString(npc.getX()) + ", Y = " +  Integer.toString(npc.getY()) + ", node = " + Integer.toString(walk._currentNode));
+					
+					//Prevent call simultaneosly from scheduled task and onArrived() or temporarily stop walking for resuming in future
+					if (walk._blocked || walk._suspended)
+						return;
+					
+					//Announcements.getInstance().announceToAll("Continue move!");
+					walk._blocked = true;
+					//Check this first, within the bounds of random moving, we have no conception of "first" or "last" node
+					if (walk.getRoute().getRepeatType() == REPEAT_RANDOM && walk._nodeArrived)
+					{
+						int newNode = walk._currentNode;
+						
+						while (newNode == walk._currentNode)
+							newNode = Rnd.get(walk.getRoute().getNodesCount());
+						
+						walk._currentNode = newNode;
+						walk._nodeArrived = false;
+					}
+					
+					else if (walk._currentNode == walk.getRoute().getNodesCount()) //Last node arrived
+					{
+						if (walk.getRoute().debug())
+							Announcements.getInstance().announceToAll("Last node arrived!");
+						
+						if (!walk.getRoute().repeatWalk())
+						{
+							//Announcements.getInstance().announceToAll("Stoppping!");
+							cancelMoving(npc);
+							return;
+						}
+						
+						switch (walk.getRoute().getRepeatType())
+						{
+							case REPEAT_GO_BACK:
+								walk._forward = false;
+								walk._currentNode -=2;
+								break;
+							case REPEAT_GO_FIRST:
+								walk._currentNode = 0;
+								break;
+							case REPEAT_TELE_FIRST:
+								npc.teleToLocation(npc.getSpawn().getLocx(),npc.getSpawn().getLocy(),npc.getSpawn().getLocz());
+								walk._currentNode = 0;
+						}
+					}
+					
+					else if (walk._currentNode == -1) //First node arrived, when direction is first <-- last
+					{
+						walk._currentNode = 1;
+						walk._forward = true;
+					}
+					
+					L2NpcWalkerNode node = walk.getCurrentNode();
+					npc.setIsRunning(node.getRunning());
+					
+					if (walk.getRoute().debug())
+						Announcements.getInstance().announceToAll("Continue to node " + Integer.toString(walk._currentNode));
+					
+					npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(node.getMoveX(), node.getMoveY(), node.getMoveZ(), 0));
+					walk._blocked = false;
+				}
+			}
+		}
+	}
+	
+	public void cancelMoving(L2Npc npc)
+	{
+		if (_activeRoutes.containsKey(npc.getObjectId()))
+		{
+			_activeRoutes.get(npc.getObjectId())._walkCheckTask.cancel(true);
+			_activeRoutes.remove(npc.getObjectId());
+			npc.getKnownList().stopTrackingTask();
+			//Announcements.getInstance().announceToAll("Moving cancelled!");
+		}
+	}
+	
+	public void resumeMoving(final L2Npc npc)
+	{
+		if (!_activeRoutes.containsKey(npc.getObjectId()))
+			return;
+		
+		WalkInfo walk = _activeRoutes.get(npc.getObjectId());
+		walk._suspended = false;
+		startMoving(npc, walk.getRoute().getId());
+	}
+	
+	public void stopMoving(L2Npc npc, boolean suspend)
+	{
+		if (!_activeRoutes.containsKey(npc.getObjectId()))
+			return; 
+		
+		WalkInfo walk = _activeRoutes.get(npc.getObjectId());
+		walk._suspended = suspend;
+		npc.stopMove(null);
+		npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
+	}
+	
+	public void onArrived(final L2Npc npc)
+	{
+		if (_activeRoutes.containsKey(npc.getObjectId()))
+		{
+			WalkInfo walk = _activeRoutes.get(npc.getObjectId());
+			
+			//Opposite should not happen... but happens sometime
+			if (walk._currentNode >= 0 && walk._currentNode < walk.getRoute().getNodesCount())
+			{
+				L2NpcWalkerNode node = walk.getRoute().getNodeList().get(walk._currentNode);
+				if (node.getMoveX() == npc.getX() && node.getMoveY() == npc.getY())
+				{ 
+					if (walk.getRoute().debug())
+					{
+						Announcements.getInstance().announceToAll("Arrived to node " + Integer.toString(walk._currentNode));
+						//Announcements.getInstance().announceToAll("Done in " + Long.toString((System.currentTimeMillis() - walk._lastActionTime) / 1000) + " s.");
+					}
+					
+					walk._nodeArrived = true;
+					if (walk.getRoute().getRepeatType() != REPEAT_RANDOM)
+					{
+						if (walk._forward)
+							walk._currentNode++;
+						else
+							walk._currentNode--;
+					}
+					
+					int delay;
+					
+					if (walk._currentNode >= walk.getRoute().getNodesCount())
+						delay = walk.getRoute().getLastNode().getDelay();
+					else if (walk._currentNode < 0)
+						delay = walk.getRoute().getNodeList().get(0).getDelay();
+					else
+						delay = walk.getCurrentNode().getDelay();
+					
+					walk._blocked = true; //prevents to be ran from walk check task, if there is delay in this node.
+					//walk._lastActionTime = System.currentTimeMillis();
+					ThreadPoolManager.getInstance().scheduleGeneral(new ArrivedTask(npc, walk), 100 + delay * 1000L);
+				}
+			}
+		}
+	}
+	
+	public void onDeath(L2Npc npc)
+	{
+		if (_activeRoutes.containsKey(npc.getObjectId()))
+			cancelMoving(npc);
+	}
+	
+	private class ArrivedTask implements Runnable
+	{
+		WalkInfo _walk;
+		L2Npc _npc;
+		
+		public ArrivedTask(L2Npc npc, WalkInfo walk)
+		{
+			_npc = npc;
+			_walk = walk;
+		}
+		
+		@Override
+		public void run() 
+		{
+			_walk._blocked = false;
+			startMoving(_npc,_walk. getRoute().getId());
+		}
+	}
+	
+	@SuppressWarnings("synthetic-access")
+	private static class SingletonHolder
+	{
+		protected static final WalkingManager _instance = new WalkingManager();
+	}
+}

+ 85 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/L2WalkRoute.java

@@ -0,0 +1,85 @@
+/*
+ * This program 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.
+ * 
+ * This program 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.gameserver.model;
+
+import java.util.List;
+
+/**
+ * @author GKR
+ */
+public class L2WalkRoute
+{
+	private final int _id;
+	private final List<L2NpcWalkerNode> _nodeList; // List of nodes
+	private final boolean _repeatWalk; // Does repeat walk, after arriving into last point in list, or not
+	private boolean _stopAfterCycle; // Make only one cycle or endlessly
+	private final byte _repeatType; // Repeat style: 0 - go back, 1 - go to first point (circle style), 2 - teleport to first point (conveyor style), 3 - random walking between points
+	private boolean _debug;
+	
+	public L2WalkRoute(int id, List<L2NpcWalkerNode> route, boolean repeat, boolean once, byte repeatType)
+	{
+		
+		_id = id;
+		_nodeList = route;
+		_repeatType = repeatType;
+		_repeatWalk = ((_repeatType >= 0) && (_repeatType <= 2)) ? repeat : false;
+		_debug = false;
+	}
+	
+	public int getId()
+	{
+		return _id;
+	}
+	
+	public List<L2NpcWalkerNode> getNodeList()
+	{
+		return _nodeList;
+	}
+	
+	public L2NpcWalkerNode getLastNode()
+	{
+		return _nodeList.get(_nodeList.size() - 1);
+	}
+	
+	public boolean repeatWalk()
+	{
+		return _repeatWalk;
+	}
+	
+	public boolean doOnce()
+	{
+		return _stopAfterCycle;
+	}
+	
+	public byte getRepeatType()
+	{
+		return _repeatType;
+	}
+	
+	public int getNodesCount()
+	{
+		return _nodeList.size();
+	}
+	
+	public void setDebug(boolean val)
+	{
+		_debug = val;
+	}
+	
+	public boolean debug()
+	{
+		return _debug;
+	}
+}

+ 109 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2QuestGuardInstance.java

@@ -0,0 +1,109 @@
+/*
+ * This program 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.
+ * 
+ * This program 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.gameserver.model.actor.instance;
+
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.L2Attackable;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.quest.Quest;
+import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
+
+/**
+ * This class extends Guard class for quests, that require tracking of onAttack and onKill events from monsters' attacks.
+ * @author GKR
+ */
+public final class L2QuestGuardInstance extends L2GuardInstance
+{
+	private boolean _isAutoAttackable = true;
+	private boolean _isPassive = false;
+	
+	public L2QuestGuardInstance(int objectId, L2NpcTemplate template)
+	{
+		super(objectId, template);
+		setInstanceType(InstanceType.L2QuestGuardInstance);
+	}
+	
+	@Override
+	public void addDamage(L2Character attacker, int damage, L2Skill skill)
+	{
+		super.addDamage(attacker, damage, skill);
+		
+		if (attacker instanceof L2Attackable)
+		{
+			if (getTemplate().getEventQuests(Quest.QuestEventType.ON_ATTACK) != null)
+			{
+				for (Quest quest : getTemplate().getEventQuests(Quest.QuestEventType.ON_ATTACK))
+				{
+					quest.notifyAttack(this, null, damage, false, skill);
+				}
+			}
+		}
+	}
+	
+	@Override
+	public boolean doDie(L2Character killer)
+	{
+		// Kill the L2NpcInstance (the corpse disappeared after 7 seconds)
+		if (!super.doDie(killer))
+		{
+			return false;
+		}
+		
+		if (killer instanceof L2Attackable)
+		{
+			if (getTemplate().getEventQuests(Quest.QuestEventType.ON_KILL) != null)
+			{
+				for (Quest quest : getTemplate().getEventQuests(Quest.QuestEventType.ON_KILL))
+				{
+					ThreadPoolManager.getInstance().scheduleEffect(new OnKillNotifyTask(this, quest, null, false), _onKillDelay);
+				}
+			}
+		}
+		
+		return true;
+	}
+	
+	@Override
+	public void addDamageHate(L2Character attacker, int damage, int aggro)
+	{
+		if (!_isPassive && !(attacker instanceof L2PcInstance))
+		{
+			super.addDamageHate(attacker, damage, aggro);
+		}
+	}
+	
+	public void setPassive(boolean state)
+	{
+		_isPassive = state;
+	}
+	
+	@Override
+	public boolean isAutoAttackable(L2Character attacker)
+	{
+		return _isAutoAttackable && !(attacker instanceof L2PcInstance);
+	}
+	
+	@Override
+	public void setAutoAttackable(boolean state)
+	{
+		_isAutoAttackable = state;
+	}
+	
+	public boolean isPassive()
+	{
+		return _isPassive;
+	}
+}

+ 138 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/zone/type/L2NoRestartZone.java

@@ -0,0 +1,138 @@
+/*
+ * This program 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.
+ * 
+ * This program 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.gameserver.model.zone.type;
+
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.instancemanager.MapRegionManager;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.zone.L2ZoneType;
+
+/**
+ * A simple no restart zone
+ * @author GKR
+ */
+public class L2NoRestartZone extends L2ZoneType
+{
+	private int _restartAllowedTime = 0;
+	private boolean _enabled = true;
+	
+	public L2NoRestartZone(int id)
+	{
+		super(id);
+	}
+	
+	@Override
+	public void setParameter(String name, String value)
+	{
+		if (name.equalsIgnoreCase("EnabledByDefault"))
+		{
+			_enabled = Boolean.parseBoolean(value);
+		}
+		else if (name.equalsIgnoreCase("restartAllowedTime"))
+		{
+			_restartAllowedTime = Integer.parseInt(value);
+		}
+		else if (name.equalsIgnoreCase("restartTime"))
+		{
+			// Do nothing.
+		}
+		else if (name.equalsIgnoreCase("defaultStatus"))
+		{
+			// Do nothing.
+		}
+		else if (name.equalsIgnoreCase("instanceId"))
+		{
+			// Do nothing.
+		}
+		else
+		{
+			super.setParameter(name, value);
+		}
+	}
+	
+	@Override
+	protected void onEnter(L2Character character)
+	{
+		if (!_enabled)
+		{
+			return;
+		}
+		
+		if (character instanceof L2PcInstance)
+		{
+			character.setInsideZone(L2Character.ZONE_NORESTART, true);
+			L2PcInstance player = (L2PcInstance) character;
+			
+			if ((player.getZoneRestartLimitTime() > 0) && (player.getZoneRestartLimitTime() < System.currentTimeMillis()))
+			{
+				ThreadPoolManager.getInstance().scheduleGeneral(new TeleportTask(player), 2000);
+			}
+			player.setZoneRestartLimitTime(0);
+		}
+	}
+	
+	@Override
+	protected void onExit(L2Character character)
+	{
+		if (!_enabled)
+		{
+			return;
+		}
+		
+		if (character instanceof L2PcInstance)
+		{
+			character.setInsideZone(L2Character.ZONE_NORESTART, false);
+		}
+	}
+	
+	@Override
+	public void onDieInside(L2Character character)
+	{
+		// Do nothing.
+	}
+	
+	@Override
+	public void onReviveInside(L2Character character)
+	{
+		// Do nothing.
+	}
+	
+	public int getRestartAllowedTime()
+	{
+		return _restartAllowedTime;
+	}
+	
+	public void setRestartAllowedTime(int time)
+	{
+		_restartAllowedTime = time;
+	}
+	
+	private static class TeleportTask implements Runnable
+	{
+		private final L2PcInstance _player;
+		
+		public TeleportTask(L2PcInstance player)
+		{
+			_player = player;
+		}
+		
+		@Override
+		public void run()
+		{
+			_player.teleToLocation(MapRegionManager.TeleportWhereType.Town);
+		}
+	}
+}