瀏覽代碼

BETA: Moving some npc instances to DP:
* L2CastleBlacksmithInstance
* L2CastleTeleporterInstance
* L2CastleWarehouseInstance
* L2TownPetInstance

* Added onRouteFinished quest trigger
* Thanks to Zoey76 for suggestion

Reviewed by: UnAfraid

malyelfik 12 年之前
父節點
當前提交
381ce98cad

+ 2 - 2
L2J_Server_BETA/dist/game/config/NPC.properties

@@ -193,5 +193,5 @@ GrandChaosTime = 10
 MinionChaosTime = 10
 
 # A comma separated list of all NPCs who have no dialog, i.e. double-clicking on them doesn't open a chat window
-# Default: 18684,18685,18686,18687,18688,18689,18690,19691,18692,31557,31606,31671,31672,31673,31674,32026,32030,32031,32032,32306,32619,32620,32621
-NonTalkingNpcs = 18684,18685,18686,18687,18688,18689,18690,19691,18692,31557,31606,31671,31672,31673,31674,32026,32030,32031,32032,32306,32619,32620,32621
+# Default: 18684,18685,18686,18687,18688,18689,18690,19691,18692,31202,31203,31204,31205,31206,31207,31208,31209,31266,31557,31593,31606,31671,31672,31673,31674,31758,31955,32026,32030,32031,32032,32306,32619,32620,32621
+NonTalkingNpcs = 18684,18685,18686,18687,18688,18689,18690,19691,18692,31202,31203,31204,31205,31206,31207,31208,31209,31266,31557,31593,31606,31671,31672,31673,31674,31758,31955,32026,32030,32031,32032,32306,32619,32620,32621

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/Config.java

@@ -2218,7 +2218,7 @@ public final class Config
 			INVENTORY_MAXIMUM_PET = Integer.parseInt(NPC.getProperty("MaximumSlotsForPet", "12"));
 			PET_HP_REGEN_MULTIPLIER = Double.parseDouble(NPC.getProperty("PetHpRegenMultiplier", "100")) / 100;
 			PET_MP_REGEN_MULTIPLIER = Double.parseDouble(NPC.getProperty("PetMpRegenMultiplier", "100")) / 100;
-			split = NPC.getProperty("NonTalkingNpcs", "18684,18685,18686,18687,18688,18689,18690,19691,18692,31557,31606,31671,31672,31673,31674,32026,32030,32031,32032,32306,32619,32620,32621").split(",");
+			split = NPC.getProperty("NonTalkingNpcs", "18684,18685,18686,18687,18688,18689,18690,19691,18692,31202,31203,31204,31205,31206,31207,31208,31209,31266,31557,31593,31606,31671,31672,31673,31674,31758,31955,32026,32030,32031,32032,32306,32619,32620,32621").split(",");
 			NON_TALKING_NPCS = new ArrayList<>(split.length);
 			for (String npcId : split)
 			{

+ 8 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/instancemanager/WalkingManager.java

@@ -163,7 +163,6 @@ public class WalkingManager extends DocumentParser
 				_currentNode = newNode;
 				npc.sendDebugMessage("Route: " + getRoute().getName() + ", next random node is " + _currentNode);
 			}
-			
 			else
 			{
 				if (_forward)
@@ -177,6 +176,14 @@ public class WalkingManager extends DocumentParser
 				
 				if (_currentNode == getRoute().getNodesCount()) // Last node arrived
 				{
+					// Notify quest
+					if (npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_ROUTE_FINISHED) != null)
+					{
+						for (Quest quest : npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_ROUTE_FINISHED))
+						{
+							quest.notifyRouteFinished(npc);
+						}
+					}
 					npc.sendDebugMessage("Route: " + getRoute().getName() + ", last node arrived");
 					
 					if (!getRoute().repeatWalk())

+ 0 - 5
L2J_Server_BETA/java/com/l2jserver/gameserver/model/L2Object.java

@@ -104,7 +104,6 @@ public abstract class L2Object
 		L2FeedableBeastInstance(L2MonsterInstance),
 		L2TamedBeastInstance(L2FeedableBeastInstance),
 		L2FriendlyMobInstance(L2Attackable),
-		L2PenaltyMonsterInstance(L2MonsterInstance),
 		L2RiftInvaderInstance(L2MonsterInstance),
 		L2RaidBossInstance(L2MonsterInstance),
 		L2GrandBossInstance(L2RaidBossInstance),
@@ -135,11 +134,8 @@ public abstract class L2Object
 		L2FortBallistaInstance(L2Npc),
 		L2FortCommanderInstance(L2DefenderInstance),
 		// Castle NPCs
-		L2CastleBlacksmithInstance(L2NpcInstance),
 		L2CastleChamberlainInstance(L2MerchantInstance),
 		L2CastleMagicianInstance(L2NpcInstance),
-		L2CastleTeleporterInstance(L2Npc),
-		L2CastleWarehouseInstance(L2WarehouseInstance),
 		L2MercManagerInstance(L2MerchantInstance),
 		// Fort NPCs
 		L2FortEnvoyInstance(L2Npc),
@@ -167,7 +163,6 @@ public abstract class L2Object
 		L2RaceManagerInstance(L2Npc),
 		L2SymbolMakerInstance(L2Npc),
 		L2TeleporterInstance(L2Npc),
-		L2TownPetInstance(L2Npc),
 		L2TrainerInstance(L2NpcInstance),
 		L2TrainerHealersInstance(L2TrainerInstance),
 		L2TransformManagerInstance(L2MerchantInstance),

+ 0 - 154
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2CastleBlacksmithInstance.java

@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2004-2013 L2J Server
- * 
- * This file is part of L2J Server.
- * 
- * L2J Server 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 Server 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.instancemanager.CastleManorManager;
-import com.l2jserver.gameserver.model.L2Clan;
-import com.l2jserver.gameserver.model.PcCondOverride;
-import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
-import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
-
-/**
- * @author l3x
- */
-public class L2CastleBlacksmithInstance extends L2NpcInstance
-{
-	protected static final int COND_ALL_FALSE = 0;
-	protected static final int COND_BUSY_BECAUSE_OF_SIEGE = 1;
-	protected static final int COND_OWNER = 2;
-	
-	public L2CastleBlacksmithInstance(int objectId, L2NpcTemplate template)
-	{
-		super(objectId, template);
-		setInstanceType(InstanceType.L2CastleBlacksmithInstance);
-	}
-	
-	@Override
-	public void onBypassFeedback(L2PcInstance player, String command)
-	{
-		if (CastleManorManager.getInstance().isDisabled())
-		{
-			NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
-			html.setFile(player.getHtmlPrefix(), "data/html/npcdefault.htm");
-			html.replace("%objectId%", String.valueOf(getObjectId()));
-			html.replace("%npcname%", getName());
-			player.sendPacket(html);
-			return;
-		}
-		
-		int condition = validateCondition(player);
-		if (condition <= COND_ALL_FALSE)
-		{
-			return;
-		}
-		else if (condition == COND_BUSY_BECAUSE_OF_SIEGE)
-		{
-			return;
-		}
-		else if (condition == COND_OWNER)
-		{
-			if (command.startsWith("Chat"))
-			{
-				int val = 0;
-				try
-				{
-					val = Integer.parseInt(command.substring(5));
-				}
-				catch (IndexOutOfBoundsException ioobe)
-				{
-				}
-				catch (NumberFormatException nfe)
-				{
-				}
-				showChatWindow(player, val);
-				return;
-			}
-			super.onBypassFeedback(player, command);
-		}
-	}
-	
-	@Override
-	public void showChatWindow(L2PcInstance player, int val)
-	{
-		if (CastleManorManager.getInstance().isDisabled())
-		{
-			NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
-			html.setFile(player.getHtmlPrefix(), "data/html/npcdefault.htm");
-			html.replace("%objectId%", String.valueOf(getObjectId()));
-			html.replace("%npcname%", getName());
-			player.sendPacket(html);
-			return;
-		}
-		
-		String filename = "data/html/castleblacksmith/castleblacksmith-no.htm";
-		
-		int condition = validateCondition(player);
-		if (condition > COND_ALL_FALSE)
-		{
-			if (condition == COND_BUSY_BECAUSE_OF_SIEGE)
-			{
-				filename = "data/html/castleblacksmith/castleblacksmith-busy.htm"; // Busy because of siege
-			}
-			else if (condition == COND_OWNER) // Clan owns castle
-			{
-				if (val == 0)
-				{
-					filename = "data/html/castleblacksmith/castleblacksmith.htm";
-				}
-				else
-				{
-					filename = "data/html/castleblacksmith/castleblacksmith-" + val + ".htm";
-				}
-			}
-		}
-		
-		NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
-		html.setFile(player.getHtmlPrefix(), filename);
-		html.replace("%objectId%", String.valueOf(getObjectId()));
-		html.replace("%npcname%", getName());
-		html.replace("%castleid%", Integer.toString(getCastle().getCastleId()));
-		player.sendPacket(html);
-	}
-	
-	protected int validateCondition(L2PcInstance player)
-	{
-		if (player.canOverrideCond(PcCondOverride.CASTLE_CONDITIONS))
-		{
-			return COND_OWNER;
-		}
-		
-		if ((getCastle() != null) && (getCastle().getCastleId() > 0))
-		{
-			if (player.getClan() != null)
-			{
-				if (getCastle().getZone().isActive())
-				{
-					return COND_BUSY_BECAUSE_OF_SIEGE; // Busy because of siege
-				}
-				else if ((getCastle().getOwnerId() == player.getClanId() // Clan owns castle
-				) && ((player.getClanPrivileges() & L2Clan.CP_CS_MANOR_ADMIN) == L2Clan.CP_CS_MANOR_ADMIN))
-				{
-					return COND_OWNER; // Owner
-				}
-			}
-		}
-		
-		return COND_ALL_FALSE;
-	}
-}

+ 0 - 172
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2CastleTeleporterInstance.java

@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2004-2013 L2J Server
- * 
- * This file is part of L2J Server.
- * 
- * L2J Server 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 Server 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 java.util.StringTokenizer;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.l2jserver.gameserver.ThreadPoolManager;
-import com.l2jserver.gameserver.instancemanager.MapRegionManager;
-import com.l2jserver.gameserver.model.L2World;
-import com.l2jserver.gameserver.model.actor.L2Npc;
-import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
-import com.l2jserver.gameserver.network.NpcStringId;
-import com.l2jserver.gameserver.network.clientpackets.Say2;
-import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
-import com.l2jserver.gameserver.network.serverpackets.NpcSay;
-
-import gnu.trove.procedure.TObjectProcedure;
-
-/**
- * @author Kerberos
- */
-public final class L2CastleTeleporterInstance extends L2Npc
-{
-	public static final Logger _log = Logger.getLogger(L2CastleTeleporterInstance.class.getName());
-	
-	private boolean _currentTask = false;
-	
-	/**
-	 * @param objectId
-	 * @param template
-	 */
-	public L2CastleTeleporterInstance(int objectId, L2NpcTemplate template)
-	{
-		super(objectId, template);
-		setInstanceType(InstanceType.L2CastleTeleporterInstance);
-	}
-	
-	@Override
-	public void onBypassFeedback(L2PcInstance player, String command)
-	{
-		StringTokenizer st = new StringTokenizer(command, " ");
-		String actualCommand = st.nextToken(); // Get actual command
-		
-		if (actualCommand.equalsIgnoreCase("tele"))
-		{
-			int delay;
-			if (!getTask())
-			{
-				if (getCastle().getSiege().getIsInProgress() && (getCastle().getSiege().getControlTowerCount() == 0))
-				{
-					delay = 480000;
-				}
-				else
-				{
-					delay = 30000;
-				}
-				
-				setTask(true);
-				ThreadPoolManager.getInstance().scheduleGeneral(new oustAllPlayers(), delay);
-			}
-			
-			String filename = "data/html/castleteleporter/MassGK-1.htm";
-			NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
-			html.setFile(player.getHtmlPrefix(), filename);
-			player.sendPacket(html);
-			return;
-		}
-		super.onBypassFeedback(player, command);
-	}
-	
-	@Override
-	public void showChatWindow(L2PcInstance player)
-	{
-		String filename;
-		if (!getTask())
-		{
-			if (getCastle().getSiege().getIsInProgress() && (getCastle().getSiege().getControlTowerCount() == 0))
-			{
-				filename = "data/html/castleteleporter/MassGK-2.htm";
-			}
-			else
-			{
-				filename = "data/html/castleteleporter/MassGK.htm";
-			}
-		}
-		else
-		{
-			filename = "data/html/castleteleporter/MassGK-1.htm";
-		}
-		
-		NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
-		html.setFile(player.getHtmlPrefix(), filename);
-		html.replace("%objectId%", String.valueOf(getObjectId()));
-		player.sendPacket(html);
-	}
-	
-	void oustAllPlayers()
-	{
-		getCastle().oustAllPlayers();
-	}
-	
-	class oustAllPlayers implements Runnable
-	{
-		@Override
-		public void run()
-		{
-			try
-			{
-				NpcSay cs = new NpcSay(getObjectId(), Say2.NPC_SHOUT, getNpcId(), NpcStringId.THE_DEFENDERS_OF_S1_CASTLE_WILL_BE_TELEPORTED_TO_THE_INNER_CASTLE);
-				cs.addStringParameter(getCastle().getName());
-				int region = MapRegionManager.getInstance().getMapRegionLocId(getX(), getY());
-				L2World.getInstance().forEachPlayer(new ForEachPlayerInRegionSendPacket(region, cs));
-				oustAllPlayers();
-				setTask(false);
-			}
-			catch (NullPointerException e)
-			{
-				_log.log(Level.WARNING, "" + e.getMessage(), e);
-			}
-		}
-	}
-	
-	private final class ForEachPlayerInRegionSendPacket implements TObjectProcedure<L2PcInstance>
-	{
-		int _region;
-		NpcSay _cs;
-		
-		protected ForEachPlayerInRegionSendPacket(int region, NpcSay cs)
-		{
-			_region = region;
-			_cs = cs;
-		}
-		
-		@Override
-		public final boolean execute(final L2PcInstance player)
-		{
-			if (_region == MapRegionManager.getInstance().getMapRegionLocId(player.getX(), player.getY()))
-			{
-				player.sendPacket(_cs);
-			}
-			return true;
-		}
-	}
-	
-	public boolean getTask()
-	{
-		return _currentTask;
-	}
-	
-	public void setTask(boolean state)
-	{
-		_currentTask = state;
-	}
-}

+ 0 - 107
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2CastleWarehouseInstance.java

@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2004-2013 L2J Server
- * 
- * This file is part of L2J Server.
- * 
- * L2J Server 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 Server 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.model.PcCondOverride;
-import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
-import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
-import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
-
-/**
- * @author l3x
- */
-public class L2CastleWarehouseInstance extends L2WarehouseInstance
-{
-	protected static final int COND_ALL_FALSE = 0;
-	protected static final int COND_BUSY_BECAUSE_OF_SIEGE = 1;
-	protected static final int COND_OWNER = 2;
-	
-	/**
-	 * @param objectId
-	 * @param template
-	 */
-	public L2CastleWarehouseInstance(int objectId, L2NpcTemplate template)
-	{
-		super(objectId, template);
-		setInstanceType(InstanceType.L2CastleWarehouseInstance);
-	}
-	
-	@Override
-	public boolean isWarehouse()
-	{
-		return true;
-	}
-	
-	@Override
-	public void showChatWindow(L2PcInstance player, int val)
-	{
-		player.sendPacket(ActionFailed.STATIC_PACKET);
-		String filename = "data/html/castlewarehouse/castlewarehouse-no.htm";
-		
-		int condition = validateCondition(player);
-		
-		if (condition > COND_ALL_FALSE)
-		{
-			if (condition == COND_BUSY_BECAUSE_OF_SIEGE)
-			{
-				filename = "data/html/castlewarehouse/castlewarehouse-busy.htm";
-			}
-			else if (condition == COND_OWNER)
-			{
-				if (val == 0)
-				{
-					filename = "data/html/castlewarehouse/castlewarehouse.htm";
-				}
-				else
-				{
-					filename = "data/html/castlewarehouse/castlewarehouse-" + val + ".htm";
-				}
-			}
-		}
-		NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
-		html.setFile(player.getHtmlPrefix(), filename);
-		html.replace("%objectId%", String.valueOf(getObjectId()));
-		html.replace("%npcname%", getName());
-		player.sendPacket(html);
-	}
-	
-	protected int validateCondition(L2PcInstance player)
-	{
-		if (player.canOverrideCond(PcCondOverride.CASTLE_CONDITIONS))
-		{
-			return COND_OWNER;
-		}
-		
-		if ((getCastle() != null) && (getCastle().getCastleId() > 0))
-		{
-			if (player.getClan() != null)
-			{
-				if (getCastle().getZone().isActive())
-				{
-					return COND_BUSY_BECAUSE_OF_SIEGE;
-				}
-				else if (getCastle().getOwnerId() == player.getClanId())
-				{
-					return COND_OWNER;
-				}
-			}
-		}
-		return COND_ALL_FALSE;
-	}
-}

+ 0 - 110
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2TownPetInstance.java

@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2004-2013 L2J Server
- * 
- * This file is part of L2J Server.
- * 
- * L2J Server 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 Server 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.Config;
-import com.l2jserver.gameserver.ThreadPoolManager;
-import com.l2jserver.gameserver.ai.CtrlIntention;
-import com.l2jserver.gameserver.model.L2CharPosition;
-import com.l2jserver.gameserver.model.actor.L2Npc;
-import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
-import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
-import com.l2jserver.gameserver.network.serverpackets.MyTargetSelected;
-import com.l2jserver.gameserver.network.serverpackets.ValidateLocation;
-import com.l2jserver.util.Rnd;
-
-/**
- * @author Kerberos
- */
-public class L2TownPetInstance extends L2Npc
-{
-	int randomX, randomY, spawnX, spawnY;
-	
-	public L2TownPetInstance(int objectId, L2NpcTemplate template)
-	{
-		super(objectId, template);
-		setInstanceType(InstanceType.L2TownPetInstance);
-		
-		if (Config.ALLOW_PET_WALKERS)
-		{
-			ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new RandomWalkTask(), 2000, 4000);
-		}
-	}
-	
-	@Override
-	public void onAction(L2PcInstance player, boolean interact)
-	{
-		if (!canTarget(player))
-		{
-			return;
-		}
-		
-		if (this != player.getTarget())
-		{
-			// Set the target of the L2PcInstance player
-			player.setTarget(this);
-			
-			// Send a Server->Client packet MyTargetSelected to the L2PcInstance player
-			// The color to display in the select window is White
-			MyTargetSelected my = new MyTargetSelected(getObjectId(), 0);
-			player.sendPacket(my);
-			
-			// Send a Server->Client packet ValidateLocation to correct the L2ArtefactInstance position and heading on the client
-			player.sendPacket(new ValidateLocation(this));
-		}
-		else if (interact)
-		{
-			// Calculate the distance between the L2PcInstance and the L2NpcInstance
-			if (!canInteract(player))
-			{
-				// Notify the L2PcInstance AI with AI_INTENTION_INTERACT
-				player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);
-			}
-		}
-		// Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
-		player.sendPacket(ActionFailed.STATIC_PACKET);
-	}
-	
-	@Override
-	public void onSpawn()
-	{
-		super.onSpawn();
-		spawnX = getX();
-		spawnY = getY();
-	}
-	
-	public class RandomWalkTask implements Runnable
-	{
-		@Override
-		public void run()
-		{
-			if (!isInActiveRegion())
-			{
-				return; // but rather the AI should be turned off completely..
-			}
-			randomX = (spawnX + Rnd.get(2 * 50)) - 50;
-			randomY = (spawnY + Rnd.get(2 * 50)) - 50;
-			setRunning();
-			if ((randomX != getX()) && (randomY != getY()))
-			{
-				getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(randomX, randomY, getZ(), 0));
-			}
-		}
-	}
-}

+ 40 - 8
L2J_Server_BETA/java/com/l2jserver/gameserver/model/quest/Quest.java

@@ -358,7 +358,8 @@ public class Quest extends ManagedScript
 		ON_EVENT_RECEIVED(true), // onEventReceived action, triggered when NPC receiving an event, sent by other NPC
 		ON_MOVE_FINISHED(true), // onMoveFinished action, triggered when NPC stops after moving
 		ON_NODE_ARRIVED(true), // onNodeArrived action, triggered when NPC, controlled by Walking Manager, arrives to next node
-		ON_SEE_CREATURE(true); // onSeeCreature action, triggered when NPC's known list include the character
+		ON_SEE_CREATURE(true), // onSeeCreature action, triggered when NPC's known list include the character
+		ON_ROUTE_FINISHED(true); // onRouteFinished action, triggered when NPC, controlled by Walking Manager, arrives to last node
 		
 		// control whether this event type is allowed for the same npc template in multiple quests
 		// or if the npc must be registered in at most one quest for the specified event
@@ -1104,6 +1105,21 @@ public class Quest extends ManagedScript
 		}
 	}
 	
+	/**
+	 * @param npc
+	 */
+	public final void notifyRouteFinished(L2Npc npc)
+	{
+		try
+		{
+			onRouteFinished(npc);
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.WARNING, "Exception on onRouteFinished() in notifyRouteFinished(): " + e.getMessage(), e);
+		}
+	}
+	
 	// These are methods that java calls to invoke scripts.
 	
 	/**
@@ -1468,21 +1484,28 @@ public class Quest extends ManagedScript
 	/**
 	 * This function is called whenever a NPC finishes moving
 	 * @param npc registered NPC
-	 * @return
 	 */
-	public String onMoveFinished(L2Npc npc)
+	public void onMoveFinished(L2Npc npc)
 	{
-		return null;
+		
 	}
 	
 	/**
 	 * This function is called whenever a walker NPC (controlled by WalkingManager) arrive a walking node
 	 * @param npc registered NPC
-	 * @return
 	 */
-	public String onNodeArrived(L2Npc npc)
+	public void onNodeArrived(L2Npc npc)
 	{
-		return null;
+		
+	}
+	
+	/**
+	 * This function is called whenever a walker NPC (controlled by WalkingManager) arrive to last node
+	 * @param npc registered NPC
+	 */
+	public void onRouteFinished(L2Npc npc)
+	{
+		
 	}
 	
 	/**
@@ -2140,7 +2163,7 @@ public class Quest extends ManagedScript
 	}
 	
 	/**
-	 * Register addNodeArrived trigger for NPC
+	 * Register onNodeArrived trigger for NPC
 	 * @param npcIds id of NPC to register
 	 */
 	public void addNodeArrivedId(int... npcIds)
@@ -2148,6 +2171,15 @@ public class Quest extends ManagedScript
 		addEventId(QuestEventType.ON_NODE_ARRIVED, npcIds);
 	}
 	
+	/**
+	 * Register onRouteFinished trigger for NPC
+	 * @param npcIds id of NPC to register
+	 */
+	public void addRouteFinishedId(int... npcIds)
+	{
+		addEventId(QuestEventType.ON_ROUTE_FINISHED, npcIds);
+	}
+	
 	/**
 	 * Use this method to get a random party member from a player's party.<br>
 	 * Useful when distributing rewards after killing an NPC.