Sync with L2jServer HighFive Jun 14th 2015.
This commit is contained in:
@@ -328,11 +328,9 @@ public abstract class AbstractAI implements Ctrl
|
||||
/**
|
||||
* Launch the L2CharacterAI onEvt method corresponding to the Event. <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)</B></FONT>
|
||||
* @param evt The event whose the AI must be notified
|
||||
* @param arg0 The first parameter of the Event (optional target)
|
||||
* @param arg1 The second parameter of the Event (optional target)
|
||||
*/
|
||||
@Override
|
||||
public final void notifyEvent(CtrlEvent evt, Object arg0, Object arg1)
|
||||
public final void notifyEvent(CtrlEvent evt, Object... args)
|
||||
{
|
||||
if ((!_actor.isVisible() && !_actor.isTeleporting()) || !_actor.hasAI())
|
||||
{
|
||||
@@ -345,31 +343,31 @@ public abstract class AbstractAI implements Ctrl
|
||||
onEvtThink();
|
||||
break;
|
||||
case EVT_ATTACKED:
|
||||
onEvtAttacked((L2Character) arg0);
|
||||
onEvtAttacked((L2Character) args[0]);
|
||||
break;
|
||||
case EVT_AGGRESSION:
|
||||
onEvtAggression((L2Character) arg0, ((Number) arg1).intValue());
|
||||
onEvtAggression((L2Character) args[0], ((Number) args[1]).intValue());
|
||||
break;
|
||||
case EVT_STUNNED:
|
||||
onEvtStunned((L2Character) arg0);
|
||||
onEvtStunned((L2Character) args[0]);
|
||||
break;
|
||||
case EVT_PARALYZED:
|
||||
onEvtParalyzed((L2Character) arg0);
|
||||
onEvtParalyzed((L2Character) args[0]);
|
||||
break;
|
||||
case EVT_SLEEPING:
|
||||
onEvtSleeping((L2Character) arg0);
|
||||
onEvtSleeping((L2Character) args[0]);
|
||||
break;
|
||||
case EVT_ROOTED:
|
||||
onEvtRooted((L2Character) arg0);
|
||||
onEvtRooted((L2Character) args[0]);
|
||||
break;
|
||||
case EVT_CONFUSED:
|
||||
onEvtConfused((L2Character) arg0);
|
||||
onEvtConfused((L2Character) args[0]);
|
||||
break;
|
||||
case EVT_MUTED:
|
||||
onEvtMuted((L2Character) arg0);
|
||||
onEvtMuted((L2Character) args[0]);
|
||||
break;
|
||||
case EVT_EVADED:
|
||||
onEvtEvaded((L2Character) arg0);
|
||||
onEvtEvaded((L2Character) args[0]);
|
||||
break;
|
||||
case EVT_READY_TO_ACT:
|
||||
if (!_actor.isCastingNow() && !_actor.isCastingSimultaneouslyNow())
|
||||
@@ -378,7 +376,7 @@ public abstract class AbstractAI implements Ctrl
|
||||
}
|
||||
break;
|
||||
case EVT_USER_CMD:
|
||||
onEvtUserCmd(arg0, arg1);
|
||||
onEvtUserCmd(args[0], args[1]);
|
||||
break;
|
||||
case EVT_ARRIVED:
|
||||
// happens e.g. from stopmove but we don't process it if we're casting
|
||||
@@ -395,10 +393,10 @@ public abstract class AbstractAI implements Ctrl
|
||||
}
|
||||
break;
|
||||
case EVT_ARRIVED_BLOCKED:
|
||||
onEvtArrivedBlocked((Location) arg0);
|
||||
onEvtArrivedBlocked((Location) args[0]);
|
||||
break;
|
||||
case EVT_FORGET_OBJECT:
|
||||
onEvtForgetObject((L2Object) arg0);
|
||||
onEvtForgetObject((L2Object) args[0]);
|
||||
break;
|
||||
case EVT_CANCEL:
|
||||
onEvtCancel();
|
||||
@@ -412,6 +410,11 @@ public abstract class AbstractAI implements Ctrl
|
||||
case EVT_FINISH_CASTING:
|
||||
onEvtFinishCasting();
|
||||
break;
|
||||
case EVT_AFRAID:
|
||||
{
|
||||
onEvtAfraid((L2Character) args[0], (Boolean) args[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Do next action.
|
||||
@@ -479,6 +482,8 @@ public abstract class AbstractAI implements Ctrl
|
||||
|
||||
protected abstract void onEvtFinishCasting();
|
||||
|
||||
protected abstract void onEvtAfraid(L2Character effector, boolean start);
|
||||
|
||||
/**
|
||||
* Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor. <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>
|
||||
*/
|
||||
|
@@ -100,8 +100,7 @@ public interface Ctrl
|
||||
/**
|
||||
* Notify an event.
|
||||
* @param evt the event
|
||||
* @param arg0 the arg0
|
||||
* @param arg1 the arg1
|
||||
* @param args the args
|
||||
*/
|
||||
void notifyEvent(CtrlEvent evt, Object arg0, Object arg1);
|
||||
void notifyEvent(CtrlEvent evt, Object... args);
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.l2jserver.Config;
|
||||
import com.l2jserver.gameserver.GameTimeController;
|
||||
@@ -56,6 +57,7 @@ import com.l2jserver.gameserver.model.events.EventDispatcher;
|
||||
import com.l2jserver.gameserver.model.events.impl.character.npc.attackable.OnAttackableFactionCall;
|
||||
import com.l2jserver.gameserver.model.events.impl.character.npc.attackable.OnAttackableHate;
|
||||
import com.l2jserver.gameserver.model.events.returns.TerminateReturn;
|
||||
import com.l2jserver.gameserver.model.skills.AbnormalVisualEffect;
|
||||
import com.l2jserver.gameserver.model.skills.Skill;
|
||||
import com.l2jserver.gameserver.model.skills.targets.L2TargetType;
|
||||
import com.l2jserver.gameserver.model.zone.ZoneId;
|
||||
@@ -67,30 +69,53 @@ import com.l2jserver.util.Rnd;
|
||||
*/
|
||||
public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
{
|
||||
/**
|
||||
* Fear task.
|
||||
* @author Zoey76
|
||||
*/
|
||||
public static class FearTask implements Runnable
|
||||
{
|
||||
private final L2Character _effected;
|
||||
private final L2Character _effector;
|
||||
private boolean _start;
|
||||
|
||||
public FearTask(L2Character effected, L2Character effector, boolean start)
|
||||
{
|
||||
_effected = effected;
|
||||
_effector = effector;
|
||||
_start = start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final int fearTimeLeft = ((L2AttackableAI) _effected.getAI()).getFearTime() - FEAR_TICKS;
|
||||
((L2AttackableAI) _effected.getAI()).setFearTime(fearTimeLeft);
|
||||
_effected.getAI().onEvtAfraid(_effector, _start);
|
||||
_start = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected static final int FEAR_TICKS = 5;
|
||||
private static final int RANDOM_WALK_RATE = 30; // confirmed
|
||||
// private static final int MAX_DRIFT_RANGE = 300;
|
||||
private static final int MAX_ATTACK_TIMEOUT = 1200; // int ticks, i.e. 2min
|
||||
/**
|
||||
* The L2Attackable AI task executed every 1s (call onEvtThink method).
|
||||
*/
|
||||
/** The L2Attackable AI task executed every 1s (call onEvtThink method). */
|
||||
private Future<?> _aiTask;
|
||||
/**
|
||||
* The delay after which the attacked is stopped.
|
||||
*/
|
||||
/** The delay after which the attacked is stopped. */
|
||||
private int _attackTimeout;
|
||||
/**
|
||||
* The L2Attackable aggro counter.
|
||||
*/
|
||||
/** The L2Attackable aggro counter. */
|
||||
private int _globalAggro;
|
||||
/**
|
||||
* The flag used to indicate that a thinking action is in progress, to prevent recursive thinking.
|
||||
*/
|
||||
/** The flag used to indicate that a thinking action is in progress, to prevent recursive thinking. */
|
||||
private boolean _thinking;
|
||||
|
||||
private int timepass = 0;
|
||||
private int chaostime = 0;
|
||||
private int _timePass = 0;
|
||||
private int _chaosTime = 0;
|
||||
private final L2NpcTemplate _skillrender;
|
||||
int lastBuffTick;
|
||||
private int _lastBuffTick;
|
||||
// Fear parameters
|
||||
private int _fearTime;
|
||||
private Future<?> _fearTask = null;
|
||||
|
||||
/**
|
||||
* Constructor of L2AttackableAI.
|
||||
@@ -376,7 +401,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getInstance().getGameTicks();
|
||||
|
||||
// self and buffs
|
||||
if ((lastBuffTick + 30) < GameTimeController.getInstance().getGameTicks())
|
||||
if ((_lastBuffTick + 30) < GameTimeController.getInstance().getGameTicks())
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.BUFF))
|
||||
{
|
||||
@@ -385,13 +410,35 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastBuffTick = GameTimeController.getInstance().getGameTicks();
|
||||
_lastBuffTick = GameTimeController.getInstance().getGameTicks();
|
||||
}
|
||||
|
||||
// Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event
|
||||
super.onIntentionAttack(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAfraid(L2Character effector, boolean start)
|
||||
{
|
||||
if ((_fearTime > 0) && (_fearTask == null))
|
||||
{
|
||||
_fearTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new FearTask(_actor, effector, start), 0, FEAR_TICKS, TimeUnit.SECONDS);
|
||||
_actor.startAbnormalVisualEffect(AbnormalVisualEffect.TURN_FLEE);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.onEvtAfraid(effector, start);
|
||||
|
||||
if ((_fearTime <= 0) && (_fearTask != null))
|
||||
{
|
||||
_fearTask.cancel(true);
|
||||
_fearTask = null;
|
||||
_actor.stopAbnormalVisualEffect(AbnormalVisualEffect.TURN_FLEE);
|
||||
setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void thinkCast()
|
||||
{
|
||||
if (checkTargetLost(getCastTarget()))
|
||||
@@ -898,29 +945,29 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
// BOSS/Raid Minion Target Reconsider
|
||||
if (npc.isRaid() || npc.isRaidMinion())
|
||||
{
|
||||
chaostime++;
|
||||
_chaosTime++;
|
||||
if (npc instanceof L2RaidBossInstance)
|
||||
{
|
||||
if (!((L2MonsterInstance) npc).hasMinions())
|
||||
{
|
||||
if (chaostime > Config.RAID_CHAOS_TIME)
|
||||
if (_chaosTime > Config.RAID_CHAOS_TIME)
|
||||
{
|
||||
if (Rnd.get(100) <= (100 - ((npc.getCurrentHp() * 100) / npc.getMaxHp())))
|
||||
{
|
||||
aggroReconsider();
|
||||
chaostime = 0;
|
||||
_chaosTime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chaostime > Config.RAID_CHAOS_TIME)
|
||||
if (_chaosTime > Config.RAID_CHAOS_TIME)
|
||||
{
|
||||
if (Rnd.get(100) <= (100 - ((npc.getCurrentHp() * 200) / npc.getMaxHp())))
|
||||
{
|
||||
aggroReconsider();
|
||||
chaostime = 0;
|
||||
_chaosTime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -928,25 +975,25 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
else if (npc instanceof L2GrandBossInstance)
|
||||
{
|
||||
if (chaostime > Config.GRAND_CHAOS_TIME)
|
||||
if (_chaosTime > Config.GRAND_CHAOS_TIME)
|
||||
{
|
||||
double chaosRate = 100 - ((npc.getCurrentHp() * 300) / npc.getMaxHp());
|
||||
if (((chaosRate <= 10) && (Rnd.get(100) <= 10)) || ((chaosRate > 10) && (Rnd.get(100) <= chaosRate)))
|
||||
{
|
||||
aggroReconsider();
|
||||
chaostime = 0;
|
||||
_chaosTime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chaostime > Config.MINION_CHAOS_TIME)
|
||||
if (_chaosTime > Config.MINION_CHAOS_TIME)
|
||||
{
|
||||
if (Rnd.get(100) <= (100 - ((npc.getCurrentHp() * 200) / npc.getMaxHp())))
|
||||
{
|
||||
aggroReconsider();
|
||||
chaostime = 0;
|
||||
_chaosTime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2692,7 +2739,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
*/
|
||||
public void setTimepass(int TP)
|
||||
{
|
||||
timepass = TP;
|
||||
_timePass = TP;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2700,11 +2747,21 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
*/
|
||||
public int getTimepass()
|
||||
{
|
||||
return timepass;
|
||||
return _timePass;
|
||||
}
|
||||
|
||||
public L2Attackable getActiveChar()
|
||||
{
|
||||
return (L2Attackable) _actor;
|
||||
}
|
||||
|
||||
public int getFearTime()
|
||||
{
|
||||
return _fearTime;
|
||||
}
|
||||
|
||||
public void setFearTime(int fearTime)
|
||||
{
|
||||
_fearTime = fearTime;
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.l2jserver.Config;
|
||||
import com.l2jserver.gameserver.GameTimeController;
|
||||
import com.l2jserver.gameserver.GeoData;
|
||||
import com.l2jserver.gameserver.ThreadPoolManager;
|
||||
@@ -58,6 +59,7 @@ import com.l2jserver.gameserver.network.SystemMessageId;
|
||||
import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
|
||||
import com.l2jserver.gameserver.network.serverpackets.AutoAttackStop;
|
||||
import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager;
|
||||
import com.l2jserver.gameserver.util.Util;
|
||||
import com.l2jserver.util.Rnd;
|
||||
|
||||
/**
|
||||
@@ -90,6 +92,8 @@ public class L2CharacterAI extends AbstractAI
|
||||
}
|
||||
}
|
||||
|
||||
protected static final int FEAR_RANGE = 500;
|
||||
|
||||
/**
|
||||
* Cast Task
|
||||
* @author Zoey76
|
||||
@@ -276,7 +280,7 @@ public class L2CharacterAI extends AbstractAI
|
||||
stopFollow();
|
||||
|
||||
// Launch the Think Event
|
||||
notifyEvent(CtrlEvent.EVT_THINK, null);
|
||||
notifyEvent(CtrlEvent.EVT_THINK);
|
||||
|
||||
}
|
||||
else
|
||||
@@ -295,7 +299,7 @@ public class L2CharacterAI extends AbstractAI
|
||||
stopFollow();
|
||||
|
||||
// Launch the Think Event
|
||||
notifyEvent(CtrlEvent.EVT_THINK, null);
|
||||
notifyEvent(CtrlEvent.EVT_THINK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +345,7 @@ public class L2CharacterAI extends AbstractAI
|
||||
changeIntention(AI_INTENTION_CAST, skill, target);
|
||||
|
||||
// Launch the Think Event
|
||||
notifyEvent(CtrlEvent.EVT_THINK, null);
|
||||
notifyEvent(CtrlEvent.EVT_THINK);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -955,6 +959,34 @@ public class L2CharacterAI extends AbstractAI
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAfraid(L2Character effector, boolean start)
|
||||
{
|
||||
double radians = Math.toRadians(start ? Util.calculateAngleFrom(effector, _actor) : Util.convertHeadingToDegree(_actor.getHeading()));
|
||||
|
||||
int posX = (int) (_actor.getX() + (FEAR_RANGE * Math.cos(radians)));
|
||||
int posY = (int) (_actor.getY() + (FEAR_RANGE * Math.sin(radians)));
|
||||
int posZ = _actor.getZ();
|
||||
|
||||
if (!_actor.isPet())
|
||||
{
|
||||
_actor.setRunning();
|
||||
}
|
||||
|
||||
// If pathfinding enabled the creature will go to the defined destination (retail like).
|
||||
// Otherwise it will go to the nearest obstacle.
|
||||
final Location destination;
|
||||
if (Config.PATHFINDING > 0)
|
||||
{
|
||||
destination = new Location(posX, posY, posZ, _actor.getInstanceId());
|
||||
}
|
||||
else
|
||||
{
|
||||
destination = GeoData.getInstance().moveCheck(_actor.getX(), _actor.getY(), _actor.getZ(), posX, posY, posZ, _actor.getInstanceId());
|
||||
}
|
||||
setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
|
||||
}
|
||||
|
||||
protected boolean maybeMoveToPosition(ILocational worldPosition, int offset)
|
||||
{
|
||||
if (worldPosition == null)
|
||||
|
Reference in New Issue
Block a user