/*
* Copyright (C) 2004-2013 L2J Server
*
* This file is part of L2J Server.
*
* L2J Server is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* L2J Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package com.l2jserver.gameserver.ai;
import java.util.List;
import com.l2jserver.Config;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.datatables.NpcWalkerRoutesData;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2NpcWalkerNode;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.instance.L2NpcWalkerInstance;
import com.l2jserver.gameserver.network.NpcStringId;
public class L2NpcWalkerAI extends L2CharacterAI implements Runnable
{
private static final int DEFAULT_MOVE_DELAY = 0;
private long _nextMoveTime;
private boolean _walkingToNextPoint = false;
/**
* home points for xyz
*/
int _homeX, _homeY, _homeZ;
/**
* route of the current npc
*/
private List _route;
/**
* current node
*/
private int _currentPos;
/**
* Constructor of L2CharacterAI.
* @param accessor The AI accessor of the L2Character
*/
public L2NpcWalkerAI(L2Character.AIAccessor accessor)
{
super(accessor);
if (!Config.ALLOW_NPC_WALKERS)
{
return;
}
_route = NpcWalkerRoutesData.getInstance().getRouteForNpc(getActor().getNpcId());
// Here we need 1 second initial delay cause getActor().hasAI() will return null...
// Constructor of L2NpcWalkerAI is called faster then ai object is attached in L2NpcWalkerInstance
if (_route != null)
{
ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 1000, 1000);
}
else
{
_log.warning(getClass().getSimpleName() + ": Missing route data! Npc: " + _actor);
}
}
@Override
public void run()
{
onEvtThink();
}
@Override
protected void onEvtThink()
{
if (!Config.ALLOW_NPC_WALKERS)
{
return;
}
if (isWalkingToNextPoint())
{
checkArrived();
return;
}
if (_nextMoveTime < System.currentTimeMillis())
{
walkToLocation();
}
}
/**
* If npc can't walk to it's target then just teleport to next point
* @param blocked_at_pos ignoring it
*/
@Override
protected void onEvtArrivedBlocked(L2CharPosition blocked_at_pos)
{
_log.warning(getClass().getSimpleName() + ": " + getActor().getNpcId() + ": Blocked at rote position [" + _currentPos + "], coords: " + blocked_at_pos.x + ", " + blocked_at_pos.y + ", " + blocked_at_pos.z + ". Teleporting to next point");
int destinationX = _route.get(_currentPos).getMoveX();
int destinationY = _route.get(_currentPos).getMoveY();
int destinationZ = _route.get(_currentPos).getMoveZ();
getActor().teleToLocation(destinationX, destinationY, destinationZ, false);
super.onEvtArrivedBlocked(blocked_at_pos);
}
private void checkArrived()
{
int destinationX = _route.get(_currentPos).getMoveX();
int destinationY = _route.get(_currentPos).getMoveY();
int destinationZ = _route.get(_currentPos).getMoveZ();
if (getActor().isInsideRadius(destinationX, destinationY, destinationZ, 5, false, false))
{
NpcStringId npcString = _route.get(_currentPos).getNpcString();
String chat = null;
if (npcString == null)
{
chat = _route.get(_currentPos).getChatText();
}
if ((npcString != null) || ((chat != null) && !chat.isEmpty()))
{
getActor().broadcastChat(chat, npcString);
}
// time in millis
long delay = _route.get(_currentPos).getDelay() * 1000;
// sleeps between each move
if (delay < 0)
{
delay = DEFAULT_MOVE_DELAY;
if (Config.DEVELOPER)
{
_log.warning(getClass().getSimpleName() + ": Wrong Delay Set in Npc Walker Functions = " + delay + " secs, using default delay: " + DEFAULT_MOVE_DELAY + " secs instead.");
}
}
_nextMoveTime = System.currentTimeMillis() + delay;
setWalkingToNextPoint(false);
}
}
private void walkToLocation()
{
if (_currentPos < (_route.size() - 1))
{
_currentPos++;
}
else
{
_currentPos = 0;
}
boolean moveType = _route.get(_currentPos).getRunning();
/**
* false - walking true - Running
*/
if (moveType)
{
getActor().setRunning();
}
else
{
getActor().setWalking();
}
// now we define destination
int destinationX = _route.get(_currentPos).getMoveX();
int destinationY = _route.get(_currentPos).getMoveY();
int destinationZ = _route.get(_currentPos).getMoveZ();
// notify AI of MOVE_TO
setWalkingToNextPoint(true);
setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(destinationX, destinationY, destinationZ, 0));
}
@Override
public L2NpcWalkerInstance getActor()
{
return (L2NpcWalkerInstance) super.getActor();
}
public int getHomeX()
{
return _homeX;
}
public int getHomeY()
{
return _homeY;
}
public int getHomeZ()
{
return _homeZ;
}
public void setHomeX(int homeX)
{
_homeX = homeX;
}
public void setHomeY(int homeY)
{
_homeY = homeY;
}
public void setHomeZ(int homeZ)
{
_homeZ = homeZ;
}
public boolean isWalkingToNextPoint()
{
return _walkingToNextPoint;
}
public void setWalkingToNextPoint(boolean value)
{
_walkingToNextPoint = value;
}
}