Reduced move task delay and addition of proper targeted NPC support.
This commit is contained in:
parent
f8a5bad1cc
commit
8f335f289e
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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),
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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),
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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),
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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),
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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),
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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),
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<Integer> _targetedNpcIds = new ArrayList<>();
|
||||
private final Map<String, WalkRoute> _routes = new HashMap<>(); // all available routes
|
||||
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
|
||||
private final Map<Integer, NpcRoutesHolder> _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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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),
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user