Merged with released L2J-Unity files.
This commit is contained in:
273
trunk/java/com/l2jmobius/gameserver/ai/DoppelgangerAI.java
Normal file
273
trunk/java/com/l2jmobius/gameserver/ai/DoppelgangerAI.java
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user