From 8f335f289ed06b49f9770a8dfe60279604c5fc88 Mon Sep 17 00:00:00 2001 From: MobiusDevelopment <8391001+MobiusDevelopment@users.noreply.github.com> Date: Sat, 14 Dec 2019 15:06:40 +0000 Subject: [PATCH] Reduced move task delay and addition of proper targeted NPC support. --- .../instancemanager/WalkingManager.java | 126 ++++++++---------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 126 ++++++++---------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 126 ++++++++---------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 126 ++++++++---------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 126 ++++++++---------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 126 ++++++++---------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 126 ++++++++---------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 126 ++++++++---------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 36 ++++- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 36 ++++- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../instancemanager/WalkingManager.java | 125 +++++++++-------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../gameserver/model/events/EventType.java | 2 + .../creature/npc/OnNpcMoveNodeArrived.java | 45 +++++++ .../instancemanager/WalkingManager.java | 125 +++++++++-------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../gameserver/model/events/EventType.java | 2 + .../creature/npc/OnNpcMoveNodeArrived.java | 45 +++++++ .../instancemanager/WalkingManager.java | 125 +++++++++-------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../gameserver/model/events/EventType.java | 2 + .../creature/npc/OnNpcMoveNodeArrived.java | 45 +++++++ .../instancemanager/WalkingManager.java | 125 +++++++++-------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../gameserver/model/events/EventType.java | 2 + .../creature/npc/OnNpcMoveNodeArrived.java | 45 +++++++ .../instancemanager/WalkingManager.java | 125 +++++++++-------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../gameserver/model/events/EventType.java | 2 + .../creature/npc/OnNpcMoveNodeArrived.java | 45 +++++++ .../instancemanager/WalkingManager.java | 125 +++++++++-------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../gameserver/model/events/EventType.java | 2 + .../creature/npc/OnNpcMoveNodeArrived.java | 45 +++++++ .../instancemanager/WalkingManager.java | 125 +++++++++-------- .../org/l2jmobius/gameserver/model/Spawn.java | 3 +- .../l2jmobius/gameserver/model/actor/Npc.java | 2 +- .../gameserver/model/events/EventType.java | 2 + .../creature/npc/OnNpcMoveNodeArrived.java | 45 +++++++ 65 files changed, 1326 insertions(+), 1043 deletions(-) create mode 100644 L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java create mode 100644 L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java create mode 100644 L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java create mode 100644 L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java create mode 100644 L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java create mode 100644 L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java create mode 100644 L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java diff --git a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index c9f563dd9b..d835fd551a 100644 --- a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -67,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -89,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -191,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -214,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -246,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -290,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -307,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -319,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -393,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -435,38 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - // Notify quest - EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); - - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Npc.java index 2e15a248de..e37377e00d 100644 --- a/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_1.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index c9f563dd9b..d835fd551a 100644 --- a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -67,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -89,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -191,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -214,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -246,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -290,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -307,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -319,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -393,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -435,38 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - // Notify quest - EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); - - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/Npc.java index ad451d1f30..dc2aed5eae 100644 --- a/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_2.5_Underground/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index c9f563dd9b..d835fd551a 100644 --- a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -67,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -89,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -191,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -214,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -246,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -290,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -307,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -319,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -393,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -435,38 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - // Notify quest - EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); - - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/Npc.java index ad451d1f30..dc2aed5eae 100644 --- a/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_3.0_Helios/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index c9f563dd9b..d835fd551a 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -67,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -89,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -191,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -214,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -246,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -290,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -307,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -319,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -393,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -435,38 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - // Notify quest - EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); - - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Npc.java index ad451d1f30..dc2aed5eae 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index c9f563dd9b..d835fd551a 100644 --- a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -67,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -89,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -191,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -214,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -246,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -290,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -307,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -319,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -393,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -435,38 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - // Notify quest - EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); - - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Npc.java index ad451d1f30..dc2aed5eae 100644 --- a/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_5.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index c9f563dd9b..d835fd551a 100644 --- a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -67,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -89,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -191,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -214,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -246,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -290,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -307,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -319,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -393,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -435,38 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - // Notify quest - EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); - - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Npc.java index ad451d1f30..dc2aed5eae 100644 --- a/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_5.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index c9f563dd9b..d835fd551a 100644 --- a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -67,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -89,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -191,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -214,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -246,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -290,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -307,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -319,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -393,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -435,38 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - // Notify quest - EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); - - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Npc.java index ad451d1f30..dc2aed5eae 100644 --- a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index c9f563dd9b..d835fd551a 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -67,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -89,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -191,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -214,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -246,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -290,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -307,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -319,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -393,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -435,38 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - // Notify quest - EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); - - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Npc.java index ad451d1f30..dc2aed5eae 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index 8ce4e53947..ed59eeb0fa 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledFuture; +import java.util.logging.Logger; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; @@ -31,6 +32,7 @@ import org.w3c.dom.Node; import org.l2jmobius.commons.concurrent.ThreadPool; import org.l2jmobius.commons.util.IXmlReader; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.enums.ChatType; import org.l2jmobius.gameserver.instancemanager.tasks.StartMovingTask; import org.l2jmobius.gameserver.model.Location; @@ -51,6 +53,8 @@ import org.l2jmobius.gameserver.network.NpcStringId; */ public class WalkingManager implements IXmlReader { + private static final Logger LOGGER = Logger.getLogger(WalkingManager.class.getName()); + // Repeat style: // -1 - no repeat // 0 - go back @@ -63,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -181,9 +186,21 @@ public class WalkingManager implements IXmlReader final int y = Integer.parseInt(attrs.getNamedItem("spawnY").getNodeValue()); final int z = Integer.parseInt(attrs.getNamedItem("spawnZ").getNodeValue()); - final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); - holder.addRoute(routeName, new Location(x, y, z)); - _routesToAttach.put(npcId, holder); + if (NpcData.getInstance().getTemplate(npcId) != null) + { + final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); + holder.addRoute(routeName, new Location(x, y, z)); + _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } + } + else + { + LOGGER.warning(getClass().getSimpleName() + ": NPC with id " + npcId + " for route '" + routeName + "' does not exist."); + } } catch (Exception e) { @@ -217,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -278,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -290,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/Spawn.java index a9116607d1..e4f40857a0 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/Spawn.java @@ -29,6 +29,7 @@ import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.datatables.NpcPersonalAIData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; @@ -386,7 +387,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, getInstanceId()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, getInstanceId()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Npc.java index 23d0e87696..448ba71452 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1276,7 +1276,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index 8ce4e53947..ed59eeb0fa 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledFuture; +import java.util.logging.Logger; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; @@ -31,6 +32,7 @@ import org.w3c.dom.Node; import org.l2jmobius.commons.concurrent.ThreadPool; import org.l2jmobius.commons.util.IXmlReader; import org.l2jmobius.gameserver.ai.CtrlIntention; +import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.enums.ChatType; import org.l2jmobius.gameserver.instancemanager.tasks.StartMovingTask; import org.l2jmobius.gameserver.model.Location; @@ -51,6 +53,8 @@ import org.l2jmobius.gameserver.network.NpcStringId; */ public class WalkingManager implements IXmlReader { + private static final Logger LOGGER = Logger.getLogger(WalkingManager.class.getName()); + // Repeat style: // -1 - no repeat // 0 - go back @@ -63,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -181,9 +186,21 @@ public class WalkingManager implements IXmlReader final int y = Integer.parseInt(attrs.getNamedItem("spawnY").getNodeValue()); final int z = Integer.parseInt(attrs.getNamedItem("spawnZ").getNodeValue()); - final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); - holder.addRoute(routeName, new Location(x, y, z)); - _routesToAttach.put(npcId, holder); + if (NpcData.getInstance().getTemplate(npcId) != null) + { + final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); + holder.addRoute(routeName, new Location(x, y, z)); + _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } + } + else + { + LOGGER.warning(getClass().getSimpleName() + ": NPC with id " + npcId + " for route '" + routeName + "' does not exist."); + } } catch (Exception e) { @@ -217,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -278,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -290,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/Spawn.java index 2eeadd94db..fa6efa2f62 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/Spawn.java @@ -29,6 +29,7 @@ import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.datatables.NpcPersonalAIData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; @@ -386,7 +387,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, getInstanceId()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, getInstanceId()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Npc.java index 23d0e87696..448ba71452 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1276,7 +1276,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index 0fd352482e..d835fd551a 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -42,6 +42,8 @@ import org.l2jmobius.gameserver.model.WalkRoute; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.tasks.npc.walker.ArrivedTask; +import org.l2jmobius.gameserver.model.events.EventDispatcher; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.holders.NpcRoutesHolder; import org.l2jmobius.gameserver.network.NpcStringId; @@ -65,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -87,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -189,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -212,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -244,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -288,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -305,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -317,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -391,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -433,35 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Npc.java index dd46604fd7..23109d6601 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/events/EventType.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/events/EventType.java index e511968d44..588c91e4cd 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/events/EventType.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/events/EventType.java @@ -50,6 +50,7 @@ import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcFirstTalk; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcManorBypass; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMenuSelect; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveFinished; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveRouteFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillSee; @@ -189,6 +190,7 @@ public enum EventType ON_NPC_FIRST_TALK(OnNpcFirstTalk.class, void.class), ON_NPC_HATE(OnAttackableHate.class, void.class, TerminateReturn.class), ON_NPC_MOVE_FINISHED(OnNpcMoveFinished.class, void.class), + ON_NPC_MOVE_NODE_ARRIVED(OnNpcMoveNodeArrived.class, void.class), ON_NPC_MOVE_ROUTE_FINISHED(OnNpcMoveRouteFinished.class, void.class), ON_NPC_QUEST_START(null, void.class), ON_NPC_SKILL_FINISHED(OnNpcSkillFinished.class, void.class), diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java new file mode 100644 index 0000000000..634f998d0d --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java @@ -0,0 +1,45 @@ +/* + * This file is part of the L2J Mobius project. + * + * 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 . + */ +package org.l2jmobius.gameserver.model.events.impl.creature.npc; + +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.events.EventType; +import org.l2jmobius.gameserver.model.events.impl.IBaseEvent; + +/** + * @author UnAfraid + */ +public class OnNpcMoveNodeArrived implements IBaseEvent +{ + private final Npc _npc; + + public OnNpcMoveNodeArrived(Npc npc) + { + _npc = npc; + } + + public Npc getNpc() + { + return _npc; + } + + @Override + public EventType getType() + { + return EventType.ON_NPC_MOVE_NODE_ARRIVED; + } +} diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index 0fd352482e..d835fd551a 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -42,6 +42,8 @@ import org.l2jmobius.gameserver.model.WalkRoute; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.tasks.npc.walker.ArrivedTask; +import org.l2jmobius.gameserver.model.events.EventDispatcher; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.holders.NpcRoutesHolder; import org.l2jmobius.gameserver.network.NpcStringId; @@ -65,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -87,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -189,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -212,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -244,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -288,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -305,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -317,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -391,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -433,35 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Npc.java index dd46604fd7..23109d6601 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/events/EventType.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/events/EventType.java index e511968d44..588c91e4cd 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/events/EventType.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/events/EventType.java @@ -50,6 +50,7 @@ import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcFirstTalk; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcManorBypass; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMenuSelect; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveFinished; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveRouteFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillSee; @@ -189,6 +190,7 @@ public enum EventType ON_NPC_FIRST_TALK(OnNpcFirstTalk.class, void.class), ON_NPC_HATE(OnAttackableHate.class, void.class, TerminateReturn.class), ON_NPC_MOVE_FINISHED(OnNpcMoveFinished.class, void.class), + ON_NPC_MOVE_NODE_ARRIVED(OnNpcMoveNodeArrived.class, void.class), ON_NPC_MOVE_ROUTE_FINISHED(OnNpcMoveRouteFinished.class, void.class), ON_NPC_QUEST_START(null, void.class), ON_NPC_SKILL_FINISHED(OnNpcSkillFinished.class, void.class), diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java new file mode 100644 index 0000000000..634f998d0d --- /dev/null +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java @@ -0,0 +1,45 @@ +/* + * This file is part of the L2J Mobius project. + * + * 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 . + */ +package org.l2jmobius.gameserver.model.events.impl.creature.npc; + +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.events.EventType; +import org.l2jmobius.gameserver.model.events.impl.IBaseEvent; + +/** + * @author UnAfraid + */ +public class OnNpcMoveNodeArrived implements IBaseEvent +{ + private final Npc _npc; + + public OnNpcMoveNodeArrived(Npc npc) + { + _npc = npc; + } + + public Npc getNpc() + { + return _npc; + } + + @Override + public EventType getType() + { + return EventType.ON_NPC_MOVE_NODE_ARRIVED; + } +} diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index 0fd352482e..d835fd551a 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -42,6 +42,8 @@ import org.l2jmobius.gameserver.model.WalkRoute; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.tasks.npc.walker.ArrivedTask; +import org.l2jmobius.gameserver.model.events.EventDispatcher; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.holders.NpcRoutesHolder; import org.l2jmobius.gameserver.network.NpcStringId; @@ -65,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -87,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -189,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -212,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -244,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -288,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -305,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -317,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -391,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -433,35 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Npc.java index dd46604fd7..23109d6601 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/events/EventType.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/events/EventType.java index e511968d44..588c91e4cd 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/events/EventType.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/events/EventType.java @@ -50,6 +50,7 @@ import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcFirstTalk; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcManorBypass; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMenuSelect; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveFinished; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveRouteFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillSee; @@ -189,6 +190,7 @@ public enum EventType ON_NPC_FIRST_TALK(OnNpcFirstTalk.class, void.class), ON_NPC_HATE(OnAttackableHate.class, void.class, TerminateReturn.class), ON_NPC_MOVE_FINISHED(OnNpcMoveFinished.class, void.class), + ON_NPC_MOVE_NODE_ARRIVED(OnNpcMoveNodeArrived.class, void.class), ON_NPC_MOVE_ROUTE_FINISHED(OnNpcMoveRouteFinished.class, void.class), ON_NPC_QUEST_START(null, void.class), ON_NPC_SKILL_FINISHED(OnNpcSkillFinished.class, void.class), diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java new file mode 100644 index 0000000000..634f998d0d --- /dev/null +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java @@ -0,0 +1,45 @@ +/* + * This file is part of the L2J Mobius project. + * + * 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 . + */ +package org.l2jmobius.gameserver.model.events.impl.creature.npc; + +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.events.EventType; +import org.l2jmobius.gameserver.model.events.impl.IBaseEvent; + +/** + * @author UnAfraid + */ +public class OnNpcMoveNodeArrived implements IBaseEvent +{ + private final Npc _npc; + + public OnNpcMoveNodeArrived(Npc npc) + { + _npc = npc; + } + + public Npc getNpc() + { + return _npc; + } + + @Override + public EventType getType() + { + return EventType.ON_NPC_MOVE_NODE_ARRIVED; + } +} diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index 0fd352482e..d835fd551a 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -42,6 +42,8 @@ import org.l2jmobius.gameserver.model.WalkRoute; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.tasks.npc.walker.ArrivedTask; +import org.l2jmobius.gameserver.model.events.EventDispatcher; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.holders.NpcRoutesHolder; import org.l2jmobius.gameserver.network.NpcStringId; @@ -65,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -87,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -189,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -212,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -244,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -288,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -305,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -317,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -391,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -433,35 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Npc.java index d2652a95bc..444bd51521 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1042,7 +1042,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/events/EventType.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/events/EventType.java index d23cccca9d..c2f033444f 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/events/EventType.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/events/EventType.java @@ -51,6 +51,7 @@ import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcFirstTalk; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcManorBypass; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMenuSelect; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveFinished; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveRouteFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillSee; @@ -191,6 +192,7 @@ public enum EventType ON_NPC_FIRST_TALK(OnNpcFirstTalk.class, void.class), ON_NPC_HATE(OnAttackableHate.class, void.class, TerminateReturn.class), ON_NPC_MOVE_FINISHED(OnNpcMoveFinished.class, void.class), + ON_NPC_MOVE_NODE_ARRIVED(OnNpcMoveNodeArrived.class, void.class), ON_NPC_MOVE_ROUTE_FINISHED(OnNpcMoveRouteFinished.class, void.class), ON_NPC_QUEST_START(null, void.class), ON_NPC_SKILL_FINISHED(OnNpcSkillFinished.class, void.class), diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java new file mode 100644 index 0000000000..634f998d0d --- /dev/null +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java @@ -0,0 +1,45 @@ +/* + * This file is part of the L2J Mobius project. + * + * 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 . + */ +package org.l2jmobius.gameserver.model.events.impl.creature.npc; + +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.events.EventType; +import org.l2jmobius.gameserver.model.events.impl.IBaseEvent; + +/** + * @author UnAfraid + */ +public class OnNpcMoveNodeArrived implements IBaseEvent +{ + private final Npc _npc; + + public OnNpcMoveNodeArrived(Npc npc) + { + _npc = npc; + } + + public Npc getNpc() + { + return _npc; + } + + @Override + public EventType getType() + { + return EventType.ON_NPC_MOVE_NODE_ARRIVED; + } +} diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index 0fd352482e..d835fd551a 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -42,6 +42,8 @@ import org.l2jmobius.gameserver.model.WalkRoute; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.tasks.npc.walker.ArrivedTask; +import org.l2jmobius.gameserver.model.events.EventDispatcher; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.holders.NpcRoutesHolder; import org.l2jmobius.gameserver.network.NpcStringId; @@ -65,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -87,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -189,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -212,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -244,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -288,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -305,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -317,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -391,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -433,35 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Npc.java index d2652a95bc..444bd51521 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1042,7 +1042,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/events/EventType.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/events/EventType.java index d23cccca9d..c2f033444f 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/events/EventType.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/events/EventType.java @@ -51,6 +51,7 @@ import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcFirstTalk; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcManorBypass; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMenuSelect; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveFinished; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveRouteFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillSee; @@ -191,6 +192,7 @@ public enum EventType ON_NPC_FIRST_TALK(OnNpcFirstTalk.class, void.class), ON_NPC_HATE(OnAttackableHate.class, void.class, TerminateReturn.class), ON_NPC_MOVE_FINISHED(OnNpcMoveFinished.class, void.class), + ON_NPC_MOVE_NODE_ARRIVED(OnNpcMoveNodeArrived.class, void.class), ON_NPC_MOVE_ROUTE_FINISHED(OnNpcMoveRouteFinished.class, void.class), ON_NPC_QUEST_START(null, void.class), ON_NPC_SKILL_FINISHED(OnNpcSkillFinished.class, void.class), diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java new file mode 100644 index 0000000000..634f998d0d --- /dev/null +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java @@ -0,0 +1,45 @@ +/* + * This file is part of the L2J Mobius project. + * + * 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 . + */ +package org.l2jmobius.gameserver.model.events.impl.creature.npc; + +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.events.EventType; +import org.l2jmobius.gameserver.model.events.impl.IBaseEvent; + +/** + * @author UnAfraid + */ +public class OnNpcMoveNodeArrived implements IBaseEvent +{ + private final Npc _npc; + + public OnNpcMoveNodeArrived(Npc npc) + { + _npc = npc; + } + + public Npc getNpc() + { + return _npc; + } + + @Override + public EventType getType() + { + return EventType.ON_NPC_MOVE_NODE_ARRIVED; + } +} diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index 0fd352482e..d835fd551a 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -42,6 +42,8 @@ import org.l2jmobius.gameserver.model.WalkRoute; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.tasks.npc.walker.ArrivedTask; +import org.l2jmobius.gameserver.model.events.EventDispatcher; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.holders.NpcRoutesHolder; import org.l2jmobius.gameserver.network.NpcStringId; @@ -65,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -87,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -189,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -212,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -244,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -288,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -305,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -317,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -391,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -433,35 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Npc.java index d2652a95bc..444bd51521 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1042,7 +1042,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/events/EventType.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/events/EventType.java index d23cccca9d..c2f033444f 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/events/EventType.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/events/EventType.java @@ -51,6 +51,7 @@ import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcFirstTalk; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcManorBypass; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMenuSelect; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveFinished; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveRouteFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillSee; @@ -191,6 +192,7 @@ public enum EventType ON_NPC_FIRST_TALK(OnNpcFirstTalk.class, void.class), ON_NPC_HATE(OnAttackableHate.class, void.class, TerminateReturn.class), ON_NPC_MOVE_FINISHED(OnNpcMoveFinished.class, void.class), + ON_NPC_MOVE_NODE_ARRIVED(OnNpcMoveNodeArrived.class, void.class), ON_NPC_MOVE_ROUTE_FINISHED(OnNpcMoveRouteFinished.class, void.class), ON_NPC_QUEST_START(null, void.class), ON_NPC_SKILL_FINISHED(OnNpcSkillFinished.class, void.class), diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java new file mode 100644 index 0000000000..634f998d0d --- /dev/null +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java @@ -0,0 +1,45 @@ +/* + * This file is part of the L2J Mobius project. + * + * 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 . + */ +package org.l2jmobius.gameserver.model.events.impl.creature.npc; + +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.events.EventType; +import org.l2jmobius.gameserver.model.events.impl.IBaseEvent; + +/** + * @author UnAfraid + */ +public class OnNpcMoveNodeArrived implements IBaseEvent +{ + private final Npc _npc; + + public OnNpcMoveNodeArrived(Npc npc) + { + _npc = npc; + } + + public Npc getNpc() + { + return _npc; + } + + @Override + public EventType getType() + { + return EventType.ON_NPC_MOVE_NODE_ARRIVED; + } +} diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java index 0fd352482e..d835fd551a 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/instancemanager/WalkingManager.java @@ -42,6 +42,8 @@ import org.l2jmobius.gameserver.model.WalkRoute; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.tasks.npc.walker.ArrivedTask; +import org.l2jmobius.gameserver.model.events.EventDispatcher; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.holders.NpcRoutesHolder; import org.l2jmobius.gameserver.network.NpcStringId; @@ -65,6 +67,7 @@ public class WalkingManager implements IXmlReader public static final byte REPEAT_TELE_FIRST = 2; public static final byte REPEAT_RANDOM = 3; + private final List _targetedNpcIds = new ArrayList<>(); private final Map _routes = new HashMap<>(); // all available routes private final Map _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress private final Map _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it @@ -87,8 +90,7 @@ public class WalkingManager implements IXmlReader @Override public void parseDocument(Document doc, File f) { - final Node n = doc.getFirstChild(); - for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) + for (Node d = doc.getFirstChild().getFirstChild(); d != null; d = d.getNextSibling()) { if (d.getNodeName().equals("route")) { @@ -189,6 +191,11 @@ public class WalkingManager implements IXmlReader final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder(); holder.addRoute(routeName, new Location(x, y, z)); _routesToAttach.put(npcId, holder); + + if (!_targetedNpcIds.contains(npcId)) + { + _targetedNpcIds.add(npcId); + } } else { @@ -212,31 +219,14 @@ public class WalkingManager implements IXmlReader */ public boolean isOnWalk(Npc npc) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } - + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { return false; } final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId()); - if (walk.isStoppedByAttack() || walk.isSuspended()) - { - return false; - } - return true; + return !walk.isStoppedByAttack() && !walk.isSuspended(); } public WalkRoute getRoute(String route) @@ -244,6 +234,15 @@ public class WalkingManager implements IXmlReader return _routes.get(route); } + /** + * @param npc NPC to check + * @return {@code true} if given NPC id is registered as a route target. + */ + public boolean isTargeted(Npc npc) + { + return _targetedNpcIds.contains(npc.getId()); + } + /** * @param npc NPC to check * @return {@code true} if given NPC controlled by Walking Manager. @@ -288,7 +287,7 @@ public class WalkingManager implements IXmlReader if (!npc.isInsideRadius3D(node, 3000)) { - LOGGER.warning("Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); + LOGGER.warning(getClass().getSimpleName() + ": " + "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance3D(node) + "). Teleporting to proper location."); npc.teleToLocation(node); } @@ -305,7 +304,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _repeatMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000); + final ScheduledFuture newTask = ThreadPool.scheduleAtFixedRate(new StartMovingTask(npc, routeName), 10000, 10000); _repeatMoveTasks.put(npc, newTask); walk.setWalkCheckTask(newTask); // start walk check task, for resuming walk after fight } @@ -317,7 +316,7 @@ public class WalkingManager implements IXmlReader final ScheduledFuture task = _startMoveTasks.get(npc); if ((task == null) || task.isCancelled() || task.isDone()) { - _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 60000)); + _startMoveTasks.put(npc, ThreadPool.schedule(new StartMovingTask(npc, routeName), 10000)); } } } @@ -391,19 +390,7 @@ public class WalkingManager implements IXmlReader */ public void stopMoving(Npc npc, boolean suspend, boolean stoppedByAttack) { - MonsterInstance monster = null; - - if (npc.isMonster()) - { - if (((MonsterInstance) npc).getLeader() == null) - { - monster = (MonsterInstance) npc; - } - else - { - monster = ((MonsterInstance) npc).getLeader(); - } - } + final MonsterInstance monster = npc.isMonster() ? ((MonsterInstance) npc).getLeader() == null ? (MonsterInstance) npc : ((MonsterInstance) npc).getLeader() : null; if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc)) { @@ -433,35 +420,43 @@ public class WalkingManager implements IXmlReader */ public void onArrived(Npc npc) { - if (_activeRoutes.containsKey(npc.getObjectId())) + if (!_activeRoutes.containsKey(npc.getObjectId())) { - final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); - - // Opposite should not happen... but happens sometime - if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount())) - { - final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); - if (npc.isInsideRadius2D(node, 10)) - { - walk.calculateNextNode(npc); - walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. - - if (node.getNpcString() != null) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); - } - else if (!node.getChatText().isEmpty()) - { - npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); - } - - final ScheduledFuture task = _arriveTasks.get(npc); - if ((task == null) || task.isCancelled() || task.isDone()) - { - _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); - } - } - } + return; + } + + // Notify quest + EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc); + + final WalkInfo walk = _activeRoutes.get(npc.getObjectId()); + // Opposite should not happen... but happens sometime + if ((walk.getCurrentNodeId() < 0) || (walk.getCurrentNodeId() >= walk.getRoute().getNodesCount())) + { + return; + } + + final NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId()); + if (!npc.isInsideRadius2D(node, 10)) + { + return; + } + + walk.calculateNextNode(npc); + walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node. + + if (node.getNpcString() != null) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString()); + } + else if (!node.getChatText().isEmpty()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText()); + } + + final ScheduledFuture task = _arriveTasks.get(npc); + if ((task == null) || task.isCancelled() || task.isDone()) + { + _arriveTasks.put(npc, ThreadPool.schedule(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000))); } } diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/Spawn.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/Spawn.java index 71c9231cda..a07c1e4cd0 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/Spawn.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/Spawn.java @@ -27,6 +27,7 @@ import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.xml.impl.NpcData; import org.l2jmobius.gameserver.geoengine.GeoEngine; +import org.l2jmobius.gameserver.instancemanager.WalkingManager; import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; @@ -392,7 +393,7 @@ public class Spawn extends Location implements IIdentifiable, INamable final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); - if (npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) + if (npc.isMonster() && !npc.isQuestMonster() && !WalkingManager.getInstance().isTargeted(npc) && !npc.isInsideZone(ZoneId.NO_BOOKMARK) && (getInstanceId() == 0) && GeoEngine.getInstance().canMoveToTarget(newlocx, newlocy, newlocz, randX, randY, newlocz, npc.getInstanceWorld()) && !getTemplate().isUndying() && !npc.isRaid() && !npc.isRaidMinion() && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getId())) { newlocx = randX; newlocy = randY; diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Npc.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Npc.java index dd46604fd7..23109d6601 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Npc.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Npc.java @@ -1030,7 +1030,7 @@ public class Npc extends Creature _spiritshotamount = getTemplate().getSpiritShot(); _killingBlowWeaponId = 0; _isRandomAnimationEnabled = getTemplate().isRandomAnimationEnabled(); - _isRandomWalkingEnabled = getTemplate().isRandomWalkEnabled(); + _isRandomWalkingEnabled = !WalkingManager.getInstance().isTargeted(this) && getTemplate().isRandomWalkEnabled(); if (isTeleporting()) { diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/events/EventType.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/events/EventType.java index e511968d44..588c91e4cd 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/events/EventType.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/events/EventType.java @@ -50,6 +50,7 @@ import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcFirstTalk; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcManorBypass; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMenuSelect; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveFinished; +import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveNodeArrived; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcMoveRouteFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillFinished; import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnNpcSkillSee; @@ -189,6 +190,7 @@ public enum EventType ON_NPC_FIRST_TALK(OnNpcFirstTalk.class, void.class), ON_NPC_HATE(OnAttackableHate.class, void.class, TerminateReturn.class), ON_NPC_MOVE_FINISHED(OnNpcMoveFinished.class, void.class), + ON_NPC_MOVE_NODE_ARRIVED(OnNpcMoveNodeArrived.class, void.class), ON_NPC_MOVE_ROUTE_FINISHED(OnNpcMoveRouteFinished.class, void.class), ON_NPC_QUEST_START(null, void.class), ON_NPC_SKILL_FINISHED(OnNpcSkillFinished.class, void.class), diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java new file mode 100644 index 0000000000..634f998d0d --- /dev/null +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/events/impl/creature/npc/OnNpcMoveNodeArrived.java @@ -0,0 +1,45 @@ +/* + * This file is part of the L2J Mobius project. + * + * 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 . + */ +package org.l2jmobius.gameserver.model.events.impl.creature.npc; + +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.events.EventType; +import org.l2jmobius.gameserver.model.events.impl.IBaseEvent; + +/** + * @author UnAfraid + */ +public class OnNpcMoveNodeArrived implements IBaseEvent +{ + private final Npc _npc; + + public OnNpcMoveNodeArrived(Npc npc) + { + _npc = npc; + } + + public Npc getNpc() + { + return _npc; + } + + @Override + public EventType getType() + { + return EventType.ON_NPC_MOVE_NODE_ARRIVED; + } +}