l2j_mobius/trunk/java/com/l2jmobius/gameserver/ai/DoppelgangerAI.java
2016-06-12 01:34:09 +00:00

274 lines
6.5 KiB
Java

/*
* 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 com.l2jmobius.gameserver.ai;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.DoppelgangerInstance;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation;
public class DoppelgangerAI extends L2CharacterAI
{
private volatile boolean _thinking; // to prevent recursive thinking
private volatile boolean _startFollow;
private L2Character _lastAttack = null;
public DoppelgangerAI(DoppelgangerInstance clone)
{
super(clone);
}
@Override
protected void onIntentionIdle()
{
stopFollow();
_startFollow = false;
onIntentionActive();
}
@Override
protected void onIntentionActive()
{
if (_startFollow)
{
setIntention(AI_INTENTION_FOLLOW, getActor().getSummoner());
}
else
{
super.onIntentionActive();
}
}
private void thinkAttack()
{
final L2Object target = getTarget();
final L2Character attackTarget = (target != null) && target.isCharacter() ? (L2Character) target : null;
if (checkTargetLostOrDead(attackTarget))
{
setTarget(null);
return;
}
if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange()))
{
return;
}
clientStopMoving(null);
_actor.doAttack(attackTarget);
}
private void thinkCast()
{
if (_actor.isCastingNow(SkillCaster::isAnyNormalType))
{
return;
}
final L2Object target = _skill.getTarget(_actor, _forceUse, _dontMove, false);
if (checkTargetLost(target))
{
setTarget(null);
return;
}
final boolean val = _startFollow;
if (maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill)))
{
return;
}
getActor().followSummoner(false);
setIntention(AI_INTENTION_IDLE);
_startFollow = val;
_actor.doCast(_skill, _item, _forceUse, _dontMove);
}
private void thinkInteract()
{
final L2Object target = getTarget();
if (checkTargetLost(target))
{
return;
}
if (maybeMoveToPawn(target, 36))
{
return;
}
setIntention(AI_INTENTION_IDLE);
}
@Override
protected void onEvtThink()
{
if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
{
return;
}
_thinking = true;
try
{
switch (getIntention())
{
case AI_INTENTION_ATTACK:
thinkAttack();
break;
case AI_INTENTION_CAST:
thinkCast();
break;
case AI_INTENTION_INTERACT:
thinkInteract();
break;
}
}
finally
{
_thinking = false;
}
}
@Override
protected void onEvtFinishCasting()
{
if (_lastAttack == null)
{
getActor().followSummoner(_startFollow);
}
else
{
setIntention(CtrlIntention.AI_INTENTION_ATTACK, _lastAttack);
_lastAttack = null;
}
}
public void notifyFollowStatusChange()
{
_startFollow = !_startFollow;
switch (getIntention())
{
case AI_INTENTION_ACTIVE:
case AI_INTENTION_FOLLOW:
case AI_INTENTION_IDLE:
case AI_INTENTION_MOVE_TO:
case AI_INTENTION_PICK_UP:
getActor().followSummoner(_startFollow);
}
}
public void setStartFollowController(boolean val)
{
_startFollow = val;
}
@Override
protected void onIntentionCast(Skill skill, L2Object target, L2ItemInstance item, boolean forceUse, boolean dontMove)
{
if (getIntention() == AI_INTENTION_ATTACK)
{
_lastAttack = (getTarget() != null) && getTarget().isCharacter() ? (L2Character) getTarget() : null;
}
else
{
_lastAttack = null;
}
super.onIntentionCast(skill, target, item, forceUse, dontMove);
}
@Override
protected void moveToPawn(L2Object pawn, int offset)
{
// Check if actor can move
if (!_actor.isMovementDisabled() && (_actor.getMoveSpeed() > 0))
{
if (offset < 10)
{
offset = 10;
}
// prevent possible extra calls to this function (there is none?),
// also don't send movetopawn packets too often
boolean sendPacket = true;
if (_clientMoving && (getTarget() == pawn))
{
if (_clientMovingToPawnOffset == offset)
{
if (GameTimeController.getInstance().getGameTicks() < _moveToPawnTimeout)
{
return;
}
sendPacket = false;
}
else if (_actor.isOnGeodataPath())
{
// minimum time to calculate new route is 2 seconds
if (GameTimeController.getInstance().getGameTicks() < (_moveToPawnTimeout + 10))
{
return;
}
}
}
// Set AI movement data
_clientMoving = true;
_clientMovingToPawnOffset = offset;
setTarget(pawn);
_moveToPawnTimeout = GameTimeController.getInstance().getGameTicks();
_moveToPawnTimeout += 1000 / GameTimeController.MILLIS_IN_TICK;
if (pawn == null)
{
return;
}
// Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
// _actor.moveToLocation(pawn.getX(), pawn.getY(), pawn.getZ(), offset);
final Location loc = new Location(pawn.getX() + Rnd.get(-offset, offset), pawn.getY() + Rnd.get(-offset, offset), pawn.getZ());
_actor.moveToLocation(loc.getX(), loc.getY(), loc.getZ(), 0);
if (!_actor.isMoving())
{
clientActionFailed();
return;
}
// Doppelgangers always send MoveToLocation packet.
if (sendPacket)
{
_actor.broadcastPacket(new MoveToLocation(_actor));
}
}
else
{
clientActionFailed();
}
}
@Override
public DoppelgangerInstance getActor()
{
return (DoppelgangerInstance) super.getActor();
}
}