HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > ПРОГРАММИРОВАНИЕ > Общие вопросы программирования
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 06.04.2016, 03:29
Wolfer
Участник форума
Регистрация: 05.04.2016
Сообщений: 222
С нами: 5318817

Репутация: 0
По умолчанию

DefaultAI.java

Цитата:
Сообщение от Спойлер  


PHP:


Код:
package l2p.gameserver.ai;

import l2p.commons.collections.CollectionUtils;
import l2p.commons.collections.LazyArrayList;
import l2p.commons.lang.reference.HardReference;
import l2p.commons.math.random.RndSelector;
import l2p.commons.threading.RunnableImpl;
import l2p.commons.util.Rnd;
import l2p.gameserver.configs.Config;
import l2p.gameserver.ThreadPoolManager;
import l2p.gameserver.configs.proprties.AIConfig;
import l2p.gameserver.data.xml.holder.NpcHolder;
import l2p.gameserver.geodata.GeoEngine;
import l2p.gameserver.model.AggroList.AggroInfo;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.MinionList;
import l2p.gameserver.model.Playable;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.Skill;
import l2p.gameserver.model.World;
import l2p.gameserver.model.WorldRegion;
import l2p.gameserver.model.Zone.ZoneType;
import l2p.gameserver.model.entity.SevenSigns;
import l2p.gameserver.model.instances.MinionInstance;
import l2p.gameserver.model.instances.MonsterInstance;
import l2p.gameserver.model.instances.NpcInstance;
import l2p.gameserver.model.quest.QuestEventType;
import l2p.gameserver.model.quest.QuestState;
import l2p.gameserver.serverpackets.MagicSkillUse;
import l2p.gameserver.serverpackets.StatusUpdate;
import l2p.gameserver.stats.Stats;
import l2p.gameserver.taskmanager.AiTaskManager;
import l2p.gameserver.utils.Location;
import l2p.gameserver.utils.NpcUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;

public class DefaultAI extends CharacterAI
{
    protected static final Logger _log = LoggerFactory.getLogger(DefaultAI.class);

    public static enum TaskType
    {
        MOVE,
        ATTACK,
        CAST,
        BUFF
    }

    public static final int TaskDefaultWeight = 10000;

    public static class Task
    {
        public TaskType type;
        public Skill skill;
        public HardReference
 target;
        public Location loc;
        public boolean pathfind;
        public int weight = TaskDefaultWeight;
    }

    public void addTaskCast(Creature target, Skill skill)
    {
        Task task = new Task();
        task.type = TaskType.CAST;
        task.target = target.getRef();
        task.skill = skill;
        _tasks.add(task);
        _def_think = true;
    }

    public void addTaskBuff(Creature target, Skill skill)
    {
        Task task = new Task();
        task.type = TaskType.BUFF;
        task.target = target.getRef();
        task.skill = skill;
        _tasks.add(task);
        _def_think = true;
    }

    public void addTaskAttack(Creature target)
    {
        Task task = new Task();
        task.type = TaskType.ATTACK;
        task.target = target.getRef();
        _tasks.add(task);
        _def_think = true;
    }

    public void addTaskAttack(Creature target, Skill skill, int weight)
    {
        Task task = new Task();
        task.type = skill.isOffensive() ? TaskType.CAST : TaskType.BUFF;
        task.target = target.getRef();
        task.skill = skill;
        task.weight = weight;
        _tasks.add(task);
        _def_think = true;
    }

    public void addTaskMove(Location loc, boolean pathfind)
    {
        Task task = new Task();
        task.type = TaskType.MOVE;
        task.loc = loc;
        task.pathfind = pathfind;
        _tasks.add(task);
        _def_think = true;
    }

    protected void addTaskMove(int locX, int locY, int locZ, boolean pathfind)
    {
        addTaskMove(new Location(locX, locY, locZ), pathfind);
    }

    private static class TaskComparator implements Comparator
    {
        private static final Comparator instance = new TaskComparator();

        public static Comparator getInstance()
        {
            return instance;
        }

        @Override
        public int compare(Task o1, Task o2)
        {
            if(o1 == null || o2 == null)
                return 0;
            return o2.weight - o1.weight;
        }
    }

    protected class Teleport extends RunnableImpl
    {
        Location _destination;

        public Teleport(Location destination)
        {
            _destination = destination;
        }

        @Override
        public void runImpl() throws Exception
        {
            NpcInstance actor = getActor();
            if(actor != null)
                actor.teleToLocation(_destination);
        }
    }

    protected class RunningTask extends RunnableImpl
    {
        @Override
        public void runImpl() throws Exception
        {
            NpcInstance actor = getActor();
            if(actor != null)
                actor.setRunning();
            _runningTask = null;
        }
    }

    protected class MadnessTask extends RunnableImpl
    {
        @Override
        public void runImpl() throws Exception
        {
            NpcInstance actor = getActor();
            if(actor != null)
                actor.stopConfused();
            _madnessTask = null;
        }
    }

    protected class NearestTargetComparator implements Comparator
    {
        private final Creature actor;

        public NearestTargetComparator(Creature actor)
        {
            this.actor = actor;
        }

        @Override
        public int compare(Creature o1, Creature o2)
        {
            double diff = actor.getDistance3D(o1) - actor.getDistance3D(o2);
            if(diff  0 ? 1 : 0;
        }
    }

    protected long AI_TASK_ATTACK_DELAY = AIConfig.AiTaskDelay;
    protected long AI_TASK_ACTIVE_DELAY = AIConfig.AiTaskActiveDelay;
    protected long AI_TASK_DELAY_CURRENT = AI_TASK_ACTIVE_DELAY;
    protected int MAX_PURSUE_RANGE;

    protected ScheduledFuture
_aiTask;

    protected ScheduledFuture
 _runningTask;
    protected ScheduledFuture
_madnessTask;

    /** The flag used to indicate that a thinking action is in progress */
    private boolean _thinking = false;
    /** Показывает, есть ли задания */
    protected boolean _def_think = false;

    /** The L2NpcInstance aggro counter */
    protected long _globalAggro;

    protected long _randomAnimationEnd;
    protected int _pathfindFails;

    /** Список заданий */
    protected final NavigableSet

_tasks = new ConcurrentSkipListSet<>(TaskComparator.getInstance());

    protected final Skill[] _damSkills, _dotSkills, _debuffSkills, _healSkills, _buffSkills, _stunSkills;

    protected long _lastActiveCheck;
    protected long _checkAggroTimestamp = 0;
    /** Время актуальности состояния атаки */
    protected long _attackTimeout;

    protected long _lastFactionNotifyTime = 0;
    protected long _minFactionNotifyInterval = 10000;

    protected final Comparator

_nearestTargetComparator;

    public DefaultAI(NpcInstance actor)
    {
        super(actor);

        setAttackTimeout(Long.MAX_VALUE);

        NpcInstance npc = getActor();
        _damSkills = npc.getTemplate().getDamageSkills();
        _dotSkills = npc.getTemplate().getDotSkills();
        _debuffSkills = npc.getTemplate().getDebuffSkills();
        _buffSkills = npc.getTemplate().getBuffSkills();
        _stunSkills = npc.getTemplate().getStunSkills();
        _healSkills = npc.getTemplate().getHealSkills();

        _nearestTargetComparator = new NearestTargetComparator(actor);

        // Preload some AI params
        MAX_PURSUE_RANGE = actor.getParameter("MaxPursueRange", actor.isRaid() ? AIConfig.MaxPursueRangeRaid : npc.isUnderground() ? AIConfig.MaxPursueUnderGroundRange : AIConfig.MaxPursueRange);
        _minFactionNotifyInterval = actor.getParameter("FactionNotifyInterval", 10000);
    }

    @Override
    public void runImpl() throws Exception
    {
        if(_aiTask == null)
            return;
        // проверяем, если NPC вышел в неактивный регион, отключаем AI
        if(!isGlobalAI() && System.currentTimeMillis() - _lastActiveCheck > 60000L)
        {
            _lastActiveCheck = System.currentTimeMillis();
            NpcInstance actor = getActor();
            WorldRegion region = actor == null ? null : actor.getCurrentRegion();
            if(region == null || !region.isActive())
            {
                stopAITask();
                return;
            }
        }
        onEvtThink();
    }

    @Override
    //public final synchronized void startAITask()
    public synchronized void startAITask()
    {
        if(_aiTask == null)
        {
            AI_TASK_DELAY_CURRENT = AI_TASK_ACTIVE_DELAY;
            _aiTask = AiTaskManager.getInstance().scheduleAtFixedRate(this, 0L, AI_TASK_DELAY_CURRENT);
        }
    }

    //protected final synchronized void switchAITask(long NEW_DELAY)
    protected synchronized void switchAITask(long NEW_DELAY)
    {
        if(_aiTask == null)
            return;

        if(AI_TASK_DELAY_CURRENT != NEW_DELAY)
        {
            _aiTask.cancel(false);
            AI_TASK_DELAY_CURRENT = NEW_DELAY;
            _aiTask = AiTaskManager.getInstance().scheduleAtFixedRate(this, 0L, AI_TASK_DELAY_CURRENT);
        }
    }

    @Override
    public final synchronized void stopAITask()
    {
        if(_aiTask != null)
        {
            _aiTask.cancel(false);
            _aiTask = null;
        }
    }

    /**
     * Определяет, может ли этот тип АИ видеть персонажей в режиме Silent Move.
     * @param target L2Playable цель
     * @return true если цель видна в режиме Silent Move
     */
    protected boolean canSeeInSilentMove(Playable target) {
        return getActor().getParameter("canSeeInSilentMove", false) || !target.isSilentMoving();
    }

    protected boolean canSeeInHide(Playable target)
    {
        return getActor().getParameter("canSeeInHide", false) || !target.isInvisible();
    }

    protected boolean checkAggression(Creature target)
    {
        NpcInstance actor = getActor();
        if(getIntention() != CtrlIntention.AI_INTENTION_ACTIVE || !isGlobalAggro())
            return false;
        if(target.isAlikeDead())
            return false;

        if(target.isNpc() && target.isInvul())
            return false;

        if(target.isPlayer() && target.getPlayer().isInAwayingMode() && !Config.AWAY_PLAYER_TAKE_AGGRO)
            return false;

        if(target.isPlayable())
        {
            if(!canSeeInSilentMove((Playable) target))
                return false;
            if(!canSeeInHide((Playable) target))
                return false;
            if(actor.getFaction().getName().equalsIgnoreCase("varka_silenos_clan") && target.getPlayer().getVarka() > 0)
                return false;
            if(actor.getFaction().getName().equalsIgnoreCase("ketra_orc_clan") && target.getPlayer().getKetra() > 0)
                return false;
            /*if(target.isFollow && !target.isPlayer() && target.getFollowTarget() != null && target.getFollowTarget().isPlayer())
                    return;*/
            if(target.isPlayer() && ((Player) target).isGM() && target.isInvisible())
                return false;
            if(((Playable) target).getNonAggroTime() > System.currentTimeMillis())
                return false;
            if(target.isPlayer() && !target.getPlayer().isActive())
                return false;
            if(actor.isMonster() && target.isInZonePeace())
                return false;
        }

        AggroInfo ai = actor.getAggroList().get(target);
        if(ai != null && ai.hate > 0)
        {
            if(!target.isInRangeZ(actor.getSpawnedLoc(), MAX_PURSUE_RANGE))
                return false;
        }
        else if(!actor.isAggressive() || !target.isInRangeZ(actor.getSpawnedLoc(), actor.getAggroRange()))
            return false;

        if(!canAttackCharacter(target))
            return false;
        if(!GeoEngine.canSeeTarget(actor, target, false))
            return false;

        actor.getAggroList().addDamageHate(target, 0, 2);

        if((target.isSummon() || target.isPet()))
            actor.getAggroList().addDamageHate(target.getPlayer(), 0, 1);

        startRunningTask(AI_TASK_ATTACK_DELAY);
        setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);

        return true;
    }

    protected void setIsInRandomAnimation(long time)
    {
        _randomAnimationEnd = System.currentTimeMillis() + time;
    }

    protected boolean randomAnimation()
    {
        NpcInstance actor = getActor();

        if(actor.getParameter("noRandomAnimation", false))
            return false;

        if(actor.hasRandomAnimation() && !actor.isActionsDisabled() && !actor.isMoving && !actor.isInCombat() && Rnd.chance(AIConfig.RndAnimationRate))
        {
            setIsInRandomAnimation(3000);
            actor.onRandomAnimation();
            return true;
        }
        return false;
    }

    protected boolean randomWalk() {
        NpcInstance actor = getActor();

        return !actor.getParameter("noRandomWalk", false) && !actor.isMoving && maybeMoveToHome();
    }

    /**
     * @return true если действие выполнено, false если нет
     */
    protected boolean thinkActive() {
        NpcInstance actor = getActor();
        if (actor.isActionsDisabled())
            return true;

        if (_randomAnimationEnd > System.currentTimeMillis())
            return true;

        if (_def_think) {
            if (doTask())
                clearTasks();
            return true;
        }

        long now = System.currentTimeMillis();
        if (now - _checkAggroTimestamp > AIConfig.AggroCheckInterval) {
            _checkAggroTimestamp = now;

            boolean aggressive = Rnd.chance(actor.getParameter("SelfAggressive", actor.isAggressive() ? 100 : 0));
            if (!actor.getAggroList().isEmpty() || aggressive) {
                List

chars = World.getAroundCharacters(actor);
                CollectionUtils.eqSort(chars, _nearestTargetComparator);
                for (Creature cha : chars) {
                    if (aggressive || actor.getAggroList().get(cha) != null)
                        if (checkAggression(cha))
                            return true;
                }
            }
        }

        if (actor.isMinion()) {
            MonsterInstance leader = ((MinionInstance) actor).getLeader();
            if (leader != null) {
                double distance = actor.getDistance(leader.getX(), leader.getY());
                if (distance > 1000)
                    actor.teleToLocation(leader.getMinionPosition());
                else if (distance > 200)
                    addTaskMove(leader.getMinionPosition(), false);
                return true;
            }
        }

        return randomAnimation() || randomWalk();
    }

    @Override
    protected void onIntentionIdle()
    {
        NpcInstance actor = getActor();

        // Удаляем все задания
        clearTasks();

        actor.stopMove();
        actor.getAggroList().clear(true);
        setAttackTimeout(Long.MAX_VALUE);
        setAttackTarget(null);

        changeIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
    }

    @Override
    protected void onIntentionActive()
    {
        NpcInstance actor = getActor();

        actor.stopMove();
        setAttackTimeout(Long.MAX_VALUE);

        if(getIntention() != CtrlIntention.AI_INTENTION_ACTIVE)
        {
            switchAITask(AI_TASK_ACTIVE_DELAY);
            changeIntention(CtrlIntention.AI_INTENTION_ACTIVE, null, null);
        }

        onEvtThink();
    }

    @Override
    protected void onIntentionAttack(Creature target)
    {
        NpcInstance actor = getActor();

        // Удаляем все задания
        clearTasks();

        actor.stopMove();
        setAttackTarget(target);
        setAttackTimeout(getMaxAttackTimeout() + System.currentTimeMillis());
        setGlobalAggro(0);

        if(getIntention() != CtrlIntention.AI_INTENTION_ATTACK)
        {
            changeIntention(CtrlIntention.AI_INTENTION_ATTACK, target, null);
            switchAITask(AI_TASK_ATTACK_DELAY);
        }

        onEvtThink();
    }

    protected boolean canAttackCharacter(Creature target)
    {
        return target.isPlayable();
    }

    protected boolean checkTarget(Creature target, int range)
    {
        NpcInstance actor = getActor();
        if(target == null || target.isAlikeDead() || !actor.isInRangeZ(target, range))
            return false;

        // если не видим чаров в хайде - не атакуем их
        final boolean hided = target.isPlayable() && !canSeeInHide((Playable)target);

        if(!hided && actor.isConfused())
            return true;

        //В состоянии атаки атакуем всех, на кого у нас есть хейт
        if(getIntention() == CtrlIntention.AI_INTENTION_ATTACK)
        {
            AggroInfo ai = actor.getAggroList().get(target);
            if (ai != null)
            {
                if (hided)
                {
                    ai.hate = 0; // очищаем хейт
                    return false;
                }
                return ai.hate > 0;
            }
            return false;
        }

        return canAttackCharacter(target);
    }

    public void setAttackTimeout(long time)
    {
        _attackTimeout = time;
    }

    protected long getAttackTimeout()
    {
        return _attackTimeout;
    }

    protected void thinkAttack()
    {
        NpcInstance actor = getActor();
        if(actor.isDead())
            return;

        Location loc = actor.getSpawnedLoc();
        if(!actor.isInRange(loc, MAX_PURSUE_RANGE))
        {
            returnHome();
            return;
        }

        if(doTask() && !actor.isAttackingNow() && !actor.isCastingNow())
        {
            if(!createNewTask())
            {
                if(System.currentTimeMillis() > getAttackTimeout())
                    returnHome();
            }
        }
    }

    @Override
    protected void onEvtSpawn()
    {
        setGlobalAggro(System.currentTimeMillis() + getActor().getParameter("globalAggro", 10000L));

        setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
    }

    @Override
    protected void onEvtReadyToAct()
    {
        onEvtThink();
    }

    @Override
    protected void onEvtArrivedTarget()
    {
        onEvtThink();
    }

    @Override
    protected void onEvtArrived()
    {
        onEvtThink();
    }

    protected boolean tryMoveToTarget(Creature target)
    {
        NpcInstance actor = getActor();

        if(target.isInvisible())
        {
            notifyEvent(CtrlEvent.EVT_THINK);
            return false;
        }

        if(!actor.followToCharacter(target, actor.getPhysicalAttackRange(), true))
            _pathfindFails++;

        if(_pathfindFails >= getMaxPathfindFails() && (System.currentTimeMillis() > getAttackTimeout() - getMaxAttackTimeout() + getTeleportTimeout()) && actor.isInRange(target, MAX_PURSUE_RANGE))
        {
            _pathfindFails = 0;

            if(target.isPlayable())
            {
                AggroInfo hate = actor.getAggroList().get(target);
                if(hate == null || hate.hate  System.currentTimeMillis())
            return;

        if(actor.isRaid() && (actor.isInZonePeace() || actor.isInZoneBattle() || actor.isInZone(ZoneType.SIEGE)))
        {
            teleportHome();
            return;
        }

        _thinking = true;
        try
        {
            if(!AIConfig.BlockActiveTasks && getIntention() == CtrlIntention.AI_INTENTION_ACTIVE)
                thinkActive();
            else if(getIntention() == CtrlIntention.AI_INTENTION_ATTACK)
                thinkAttack();
        }
        finally
        {
            _thinking = false;
        }
    }

    @Override
    protected void onEvtDead(Creature killer)
    {
        NpcInstance actor = getActor();

        int transformer = actor.getParameter("transformOnDead", 0);
        int chance = actor.getParameter("transformChance", 100);
        if(transformer > 0 && Rnd.chance(chance))
        {
            NpcInstance npc = NpcUtils.spawnSingle(transformer, actor.getLoc(), actor.getReflection()) ;

            if(killer != null && killer.isPlayable())
            {
                npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, killer, 100);
                killer.setTarget(npc);
                killer.sendPacket(npc.makeStatusUpdate(StatusUpdate.CUR_HP, StatusUpdate.MAX_HP));
            }
        }

        super.onEvtDead(killer);
    }

    @Override
    protected void onEvtClanAttacked(Creature attacked, Creature attacker, int damage)
    {
        if(getIntention() != CtrlIntention.AI_INTENTION_ACTIVE || !isGlobalAggro())
            return;

        notifyEvent(CtrlEvent.EVT_AGGRESSION, attacker, 2);
    }

    @Override
    protected void onEvtAttacked(Creature attacker, int damage)
    {
        NpcInstance actor = getActor();
        if(attacker == null || actor.isDead())
            return;

        int transformer = actor.getParameter("transformOnUnderAttack", 0);
        if(transformer > 0)
        {
            int chance = actor.getParameter("transformChance", 5);
            if(chance == 100 || ((MonsterInstance) actor).getChampion() == 0 && actor.getCurrentHpPercents() > 50 && Rnd.chance(chance))
            {
                MonsterInstance npc = (MonsterInstance) NpcHolder.getInstance().getTemplate(transformer).getNewInstance();
                npc.setSpawnedLoc(actor.getLoc());
                npc.setReflection(actor.getReflection());
                npc.setChampion(((MonsterInstance) actor).getChampion());
                npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp(), true);
                npc.spawnMe(npc.getSpawnedLoc());
                npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, attacker, 100);
                actor.doDie(actor);
                actor.decayMe();
                attacker.setTarget(npc);
                attacker.sendPacket(npc.makeStatusUpdate(StatusUpdate.CUR_HP, StatusUpdate.MAX_HP));
                return;
            }
        }

        Player player = attacker.getPlayer();

        if(player != null)
        {
            //FIXME [G1ta0] затычка для 7 печатей, при атаке монстра 7 печатей телепортирует персонажа в ближайший город
            if((SevenSigns.getInstance().isSealValidationPeriod() || SevenSigns.getInstance().isCompResultsPeriod()) && actor.isSevenSignsMonster())
            {
                int pcabal = SevenSigns.getInstance().getPlayerCabal(player);
                int wcabal = SevenSigns.getInstance().getCabalHighestScore();
                if(pcabal != wcabal && wcabal != SevenSigns.CABAL_NULL)
                {
                    player.sendMessage("You have been teleported to the nearest town because you not signed for winning cabal.");
                    player.teleToClosestTown();
                    return;
                }
            }

            List

quests = player.getQuestsForEvent(actor, QuestEventType.ATTACKED_WITH_QUEST);
            if(quests != null)
                for(QuestState qs : quests)
                    qs.getQuest().notifyAttack(actor, qs);
        }

        //Добавляем только хейт, урон, если атакующий - игровой персонаж, будет добавлен в L2NpcInstance.onReduceCurrentHp
        actor.getAggroList().addDamageHate(attacker, 0, damage);

        // Обычно 1 хейт добавляется хозяину суммона, чтобы после смерти суммона моб накинулся на хозяина.
        if(damage > 0 && (attacker.isSummon() || attacker.isPet()))
            actor.getAggroList().addDamageHate(attacker.getPlayer(), 0, actor.getParameter("searchingMaster", false) ? damage : 1);

        if(getIntention() != CtrlIntention.AI_INTENTION_ATTACK)
        {
            if(!actor.isRunning())
                startRunningTask(AI_TASK_ATTACK_DELAY);
            setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
        }

        notifyFriends(attacker, damage);
    }

    @Override
    protected void onEvtAggression(Creature attacker, int aggro)
    {
        NpcInstance actor = getActor();
        if(attacker == null || actor.isDead())
            return;

        actor.getAggroList().addDamageHate(attacker, 0, aggro);

        // Обычно 1 хейт добавляется хозяину суммона, чтобы после смерти суммона моб накинулся на хозяина.
        if(aggro > 0 && (attacker.isSummon() || attacker.isPet()))
            actor.getAggroList().addDamageHate(attacker.getPlayer(), 0, actor.getParameter("searchingMaster", false) ? aggro : 1);

        if(getIntention() != CtrlIntention.AI_INTENTION_ATTACK)
        {
            if(!actor.isRunning())
                startRunningTask(AI_TASK_ATTACK_DELAY);
            setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
        }
    }

    protected boolean maybeMoveToHome()
    {
        NpcInstance actor = getActor();
        if(actor.isDead())
            return false;

        boolean randomWalk = actor.hasRandomWalk();
        Location sloc = actor.getSpawnedLoc();

        // Random walk or not?
        if(randomWalk && (!AIConfig.RndWalk || !Rnd.chance(AIConfig.RndWalkRate)))
            return false;

        boolean isInRange = actor.isInRangeZ(sloc, AIConfig.MaxDriftRange);

        if(!randomWalk && isInRange)
            return false;

        Location pos = Location.findPointToStay(actor, sloc, 0, AIConfig.MaxDriftRange);

        actor.setWalking();

        // Телепортируемся домой, только если далеко от дома
        if(!actor.moveToLocation(pos.x, pos.y, pos.z, 0, true) && !isInRange)
            teleportHome();

        return true;
    }

    protected void returnHome()
    {
        returnHome(true, false);
    }

    protected void teleportHome()
    {
        returnHome(true, true);
    }

    protected void returnHome(boolean clearAggro, boolean teleport)
    {
        NpcInstance actor = getActor();
        Location sloc = actor.getSpawnedLoc();

        // Удаляем все задания
        clearTasks();
        actor.stopMove();

        if(clearAggro)
            actor.getAggroList().clear(true);

        setAttackTimeout(Long.MAX_VALUE);
        setAttackTarget(null);

        changeIntention(CtrlIntention.AI_INTENTION_ACTIVE, null, null);

        if(teleport)
        {
            actor.broadcastPacketToOthers(new MagicSkillUse(actor, actor, 2036, 1, 500, 0));
            actor.teleToLocation(sloc.x, sloc.y, GeoEngine.getHeight(sloc, actor.getGeoIndex()));
        }
        else
        {
            if(!clearAggro)
                actor.setRunning();
            else
                actor.setWalking();

            addTaskMove(sloc, false);
        }
    }

    protected Creature prepareTarget()
    {
        NpcInstance actor = getActor();

        if(actor.isConfused())
            return getAttackTarget();

        // Для "двинутых" боссов, иногда, выбираем случайную цель
        if(Rnd.chance(actor.getParameter("isMadness", 0)))
        {
            Creature randomHated = actor.getAggroList().getRandomHated();
            if(randomHated != null)
            {
                setAttackTarget(randomHated);
                if(_madnessTask == null && !actor.isConfused())
                {
                    actor.startConfused();
                    _madnessTask = ThreadPoolManager.getInstance().schedule(new MadnessTask(), 10000);
                }
                return randomHated;
            }
        }

        // Новая цель исходя из агрессивности
        List

hateList = actor.getAggroList().getHateList();
        Creature hated = null;
        for(Creature cha : hateList)
        {
            // Если у Монстра есть скилл "Searching Master" он должен атаковать хозяина пета в первую очередь.
            if((cha.isPet() || cha.isSummon()) && cha.getPlayer() != null)
                if(getActor().getSkillLevel(6019) == 1 && checkTarget(cha.getPlayer(), MAX_PURSUE_RANGE))
                    cha = cha.getPlayer();

            //Не подходит, очищаем хейт
            if(!checkTarget(cha, MAX_PURSUE_RANGE))
            {
                actor.getAggroList().remove(cha, true);
                continue;
            }
            hated = cha;
            break;
        }

        if(hated != null)
        {
            setAttackTarget(hated);
            return hated;
        }

        return null;
    }

    protected boolean canUseSkill(Skill skill, Creature target, double distance)
    {
        NpcInstance actor = getActor();
        if(skill == null || skill.isNotUsedByAI())
            return false;

        if(skill.getTargetType() == Skill.SkillTargetType.TARGET_SELF && target != actor)
            return false;

        int castRange = skill.getAOECastRange();
        if(castRange  200)
            return false;

        if(actor.isSkillDisabled(skill) || actor.isMuted(skill) || actor.isUnActiveSkill(skill.getId()))
            return false;

        double mpConsume2 = skill.getMpConsume2();
        if(skill.isMagic())
            mpConsume2 = actor.calcStat(Stats.MP_MAGIC_SKILL_CONSUME, mpConsume2, target, skill);
        else
            mpConsume2 = actor.calcStat(Stats.MP_PHYSICAL_SKILL_CONSUME, mpConsume2, target, skill);
        if(actor.getCurrentMp() 
rnd = new RndSelector<>(skills.length);
        double weight;
        for(Skill skill : skills)
        {
            weight = skill.getSimpleDamage(actor, target) * skill.getAOECastRange() / distance;
            if(weight 
rnd = new RndSelector<>(skills.length);
        double weight;
        for(Skill skill : skills)
        {
            if(skill.getSameByStackType(target) != null)
                continue;
            if((weight = 100. * skill.getAOECastRange() / distance) 
rnd = new RndSelector<>(skills.length);
        double weight;
        for(Skill skill : skills)
        {
            if(skill.getSameByStackType(target) != null)
                continue;
            if((weight = skill.getPower()) 
rnd = new RndSelector<>(skills.length);
        double weight;
        for(Skill skill : skills)
        {
            if((weight = Math.abs(skill.getPower() - hpReduced)) 
skillMap, Creature target, double distance, Skill[] skills)
    {
        if(skills == null || skills.length == 0 || target == null)
            return;
        for(Skill sk : skills)
            addDesiredSkill(skillMap, target, distance, sk);
    }

    protected void addDesiredSkill(Map

skillMap, Creature target, double distance, Skill skill)
    {
        if(skill == null || target == null || !canUseSkill(skill, target))
            return;
        int weight = (int) -Math.abs(skill.getAOECastRange() - distance);
        if(skill.getAOECastRange() >= distance)
            weight += 1000000;
        else if(skill.isNotTargetAoE() && skill.getTargets(getActor(), target, false).size() == 0)
            return;
        skillMap.put(skill, weight);
    }

    protected void addDesiredHeal(Map

skillMap, Skill[] skills)
    {
        if(skills == null || skills.length == 0)
            return;
        NpcInstance actor = getActor();
        double hpReduced = actor.getMaxHp() - actor.getCurrentHp();
        double hpPercent = actor.getCurrentHpPercents();
        if(hpReduced 
skillMap, Skill[] skills)
    {
        if(skills == null || skills.length == 0)
            return;
        NpcInstance actor = getActor();
        for(Skill sk : skills)
            if(canUseSkill(sk, actor))
                skillMap.put(sk, 1000000);
    }

    protected Skill selectTopSkill(Map

skillMap)
    {
        if(skillMap == null || skillMap.isEmpty())
            return null;
        int nWeight, topWeight = Integer.MIN_VALUE;
        for(Skill next : skillMap.keySet())
            if((nWeight = skillMap.get(next)) > topWeight)
                topWeight = nWeight;
        if(topWeight == Integer.MIN_VALUE)
            return null;

        Skill[] skills = new Skill[skillMap.size()];
        nWeight = 0;
        for(Map.Entry

e : skillMap.entrySet())
        {
            if(e.getValue()  skill.getAOECastRange() + 60)
            {
                target = null;
                if(skill.isOffensive())
                {
                    LazyArrayList

targets = LazyArrayList.newInstance();
                    for(Creature cha : actor.getAggroList().getHateList())
                    {
                        if(!checkTarget(cha, skill.getAOECastRange() + 60) || !canUseSkill(skill, cha))
                            continue;
                        targets.add(cha);
                    }
                    if(!targets.isEmpty())
                        target = targets.get(Rnd.get(targets.size()));
                    LazyArrayList.recycle(targets);
                }
            }

            if(target == null)
                return false;

            // Добавить новое задание
            if(skill.isOffensive())
                addTaskCast(target, skill);
            else
                addTaskBuff(target, skill);
            return true;
        }

        // Смена цели, если необходимо
        if(actor.isMovementDisabled() && distance > actor.getPhysicalAttackRange() + 40)
        {
            target = null;
            LazyArrayList

targets = LazyArrayList.newInstance();
            for(Creature cha : actor.getAggroList().getHateList())
            {
                if(!checkTarget(cha, actor.getPhysicalAttackRange() + 40))
                    continue;
                targets.add(cha);
            }
            if(!targets.isEmpty())
                target = targets.get(Rnd.get(targets.size()));
            LazyArrayList.recycle(targets);
        }

        if(target == null)
            return false;

        // Добавить новое задание
        addTaskAttack(target);
        return true;
    }

    @Override
    public boolean isActive()
    {
        return _aiTask != null;
    }

    protected void clearTasks()
    {
        _def_think = false;
        _tasks.clear();
    }

    /** переход в режим бега через определенный интервал времени */
    protected void startRunningTask(long interval)
    {
        NpcInstance actor = getActor();
        if(actor != null && _runningTask == null && !actor.isRunning())
            _runningTask = ThreadPoolManager.getInstance().schedule(new RunningTask(), interval);
    }

    protected boolean isGlobalAggro()
    {
        if(_globalAggro == 0)
            return true;
        if(_globalAggro  _minFactionNotifyInterval)
        {
            _lastFactionNotifyTime = System.currentTimeMillis();
            if(actor.isMinion())
            {
                //Оповестить лидера об атаке
                MonsterInstance master = ((MinionInstance) actor).getLeader();
                if(master != null)
                {
                    if(!master.isDead() && master.isVisible())
                        master.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, attacker, damage);

                    //Оповестить минионов лидера об атаке
                    MinionList minionList = master.getMinionList();
                    if(minionList != null)
                        minionList.getAliveMinions().stream().filter(minion -> minion != actor).forEach(minion -> minion.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, attacker, damage));
                }
            }

            //Оповестить своих минионов об атаке
            MinionList minionList = actor.getMinionList();
            if(minionList != null && minionList.hasAliveMinions())
                for(MinionInstance minion : minionList.getAliveMinions())
                    minion.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, attacker, damage);

            //Оповестить социальных мобов
            for(NpcInstance npc : activeFactionTargets())
                npc.getAI().notifyEvent(CtrlEvent.EVT_CLAN_ATTACKED, new Object[] { actor, attacker, damage });
        }
    }

    protected List

activeFactionTargets()
    {
        NpcInstance actor = getActor();
        if(actor.getFaction().isNone())
            return Collections.emptyList();
        return World.getAroundNpc(actor).stream().filter(npc -> !npc.isDead()).filter(npc -> npc.isInFaction(actor)).filter(npc -> npc.isInRangeZ(actor, npc.getFaction().getRange())).filter(npc -> GeoEngine.canSeeTarget(npc, actor, false)).collect(Collectors.toCollection(() -> new LazyArrayList<>()));
    }

    protected boolean defaultThinkBuff(int rateSelf, int rateFriends)
    {
        NpcInstance actor = getActor();
        if(actor.isDead())
            return true;

        //TODO сделать более разумный выбор баффа, сначала выбирать подходящие а потом уже рандомно 1 из них
        if(Rnd.chance(rateSelf))
        {
            double actorHp = actor.getCurrentHpPercents();

            Skill[] skills = actorHp  10 ? Rnd.chance(getRateDEBUFF()) ? selectUsableSkills(target, distance, _debuffSkills) : null : null;
        Skill[] stun = Rnd.chance(getRateSTUN()) ? selectUsableSkills(target, distance, _stunSkills) : null;
        Skill[] heal = actorHp 
rnd = new RndSelector<>();
        if(!actor.isAMuted())
            rnd.add(null, getRatePHYS());
        rnd.add(dam, getRateDAM());
        rnd.add(dot, getRateDOT());
        rnd.add(debuff, getRateDEBUFF());
        rnd.add(heal, getRateHEAL());
        rnd.add(buff, getRateBUFF());
        rnd.add(stun, getRateSTUN());

        Skill[] selected = rnd.select();
        if(selected != null)
        {
            if(selected == dam || selected == dot)
                return chooseTaskAndTargets(selectTopSkillByDamage(actor, target, distance, selected), target, distance);

            if(selected == debuff || selected == stun)
                return chooseTaskAndTargets(selectTopSkillByDebuff(target, distance, selected), target, distance);

            if(selected == buff)
                return chooseTaskAndTargets(selectTopSkillByBuff(actor, selected), actor, distance);

            if(selected == heal)
                return chooseTaskAndTargets(selectTopSkillByHeal(actor, selected), actor, distance);
        }

        // TODO сделать лечение и баф дружественных целей

        return chooseTaskAndTargets(null, target, distance);
    }

    public int getRatePHYS()
    {
        return 100;
    }

    public int getRateDOT()
    {
        return 0;
    }

    public int getRateDEBUFF()
    {
        return 0;
    }

    public int getRateDAM()
    {
        return 0;
    }

    public int getRateSTUN()
    {
        return 0;
    }

    public int getRateBUFF()
    {
        return 0;
    }

    public int getRateHEAL()
    {
        return 0;
    }

    public boolean getIsMobile()
    {
        return !getActor().getParameter("isImmobilized", false);
    }

    public int getMaxPathfindFails()
    {
        return 3;
    }

    /**
     * Задержка, перед переключением в активный режим после атаки, если цель не найдена (вне зоны досягаемости, убита, очищен хейт)
     * @return
     */
    public int getMaxAttackTimeout()
    {
        return 15000;
    }

    /**
     * Задержка, перед телепортом к цели, если не удается дойти
     * @return
     */
    public int getTeleportTimeout()
    {
        return 10000;
    }
}
Цитата:
Сообщение от Спойлер  


PHP:


Код:
package l2p.gameserver.ai;

import static java.lang.Integer.MIN_VALUE;
import static java.lang.Long.MAX_VALUE;
import static java.lang.Math.abs;
import static java.lang.System.currentTimeMillis;
import static java.util.Arrays.copyOf;
import static java.util.Collections.emptyList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;
import static l2p.commons.collections.CollectionUtils.eqSort;
import l2p.commons.collections.LazyArrayList;
import static l2p.commons.collections.LazyArrayList.newInstance;
import static l2p.commons.collections.LazyArrayList.recycle;
import l2p.commons.lang.reference.HardReference;
import l2p.commons.math.random.RndSelector;
import l2p.commons.threading.RunnableImpl;
import static l2p.commons.util.Rnd.chance;
import static l2p.commons.util.Rnd.get;
import static l2p.gameserver.ai.CtrlEvent.EVT_AGGRESSION;
import static l2p.gameserver.ai.CtrlEvent.EVT_CLAN_ATTACKED;
import static l2p.gameserver.ai.CtrlEvent.EVT_THINK;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import static l2p.gameserver.ai.DefaultAI.TaskType.ATTACK;
import static l2p.gameserver.ai.DefaultAI.TaskType.BUFF;
import static l2p.gameserver.ai.DefaultAI.TaskType.CAST;
import static l2p.gameserver.ai.DefaultAI.TaskType.MOVE;
import static l2p.gameserver.configs.Config.AWAY_PLAYER_TAKE_AGGRO;
import static l2p.gameserver.configs.proprties.AIConfig.AggroCheckInterval;
import static l2p.gameserver.configs.proprties.AIConfig.AiTaskActiveDelay;
import static l2p.gameserver.configs.proprties.AIConfig.AiTaskDelay;
import static l2p.gameserver.configs.proprties.AIConfig.BlockActiveTasks;
import static l2p.gameserver.configs.proprties.AIConfig.MaxDriftRange;
import static l2p.gameserver.configs.proprties.AIConfig.MaxPursueRange;
import static l2p.gameserver.configs.proprties.AIConfig.MaxPursueRangeRaid;
import static l2p.gameserver.configs.proprties.AIConfig.MaxPursueUnderGroundRange;
import static l2p.gameserver.configs.proprties.AIConfig.RndAnimationRate;
import static l2p.gameserver.configs.proprties.AIConfig.RndWalk;
import static l2p.gameserver.configs.proprties.AIConfig.RndWalkRate;
import static l2p.gameserver.data.xml.holder.NpcHolder.getInstance;
import static l2p.gameserver.geodata.GeoEngine.canMoveToCoord;
import static l2p.gameserver.geodata.GeoEngine.canSeeTarget;
import static l2p.gameserver.geodata.GeoEngine.getHeight;
import static l2p.gameserver.geodata.GeoEngine.moveCheckForAI;
import l2p.gameserver.model.AggroList.AggroInfo;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.MinionList;
import l2p.gameserver.model.Playable;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.Skill;
import static l2p.gameserver.model.Skill.SkillTargetType.TARGET_AURA;
import static l2p.gameserver.model.Skill.SkillTargetType.TARGET_SELF;
import static l2p.gameserver.model.World.getAroundCharacters;
import static l2p.gameserver.model.World.getAroundNpc;
import l2p.gameserver.model.WorldRegion;
import static l2p.gameserver.model.Zone.ZoneType.SIEGE;
import static l2p.gameserver.model.entity.SevenSigns.CABAL_NULL;
import l2p.gameserver.model.instances.MinionInstance;
import l2p.gameserver.model.instances.MonsterInstance;
import l2p.gameserver.model.instances.NpcInstance;
import static l2p.gameserver.model.quest.QuestEventType.ATTACKED_WITH_QUEST;
import l2p.gameserver.model.quest.QuestState;
import l2p.gameserver.serverpackets.MagicSkillUse;
import static l2p.gameserver.serverpackets.StatusUpdate.CUR_HP;
import static l2p.gameserver.serverpackets.StatusUpdate.MAX_HP;
import static l2p.gameserver.stats.Stats.MP_MAGIC_SKILL_CONSUME;
import static l2p.gameserver.stats.Stats.MP_PHYSICAL_SKILL_CONSUME;
import l2p.gameserver.utils.Location;
import static l2p.gameserver.utils.Location.findPointToStay;
import static l2p.gameserver.utils.NpcUtils.spawnSingle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class DefaultAI extends CharacterAI
{
    protected static final Logger _log = LoggerFactory.getLogger(DefaultAI.class);

    /**
     * @return the AI_TASK_ATTACK_DELAY
     */
    public long getAI_TASK_ATTACK_DELAY() {
        return AI_TASK_ATTACK_DELAY;
    }

    /**
     * @param AI_TASK_ATTACK_DELAY the AI_TASK_ATTACK_DELAY to set
     */
    public void setAI_TASK_ATTACK_DELAY(long AI_TASK_ATTACK_DELAY) {
        this.AI_TASK_ATTACK_DELAY = AI_TASK_ATTACK_DELAY;
    }

    /**
     * @return the AI_TASK_ACTIVE_DELAY
     */
    public long getAI_TASK_ACTIVE_DELAY() {
        return AI_TASK_ACTIVE_DELAY;
    }

    /**
     * @param AI_TASK_ACTIVE_DELAY the AI_TASK_ACTIVE_DELAY to set
     */
    public void setAI_TASK_ACTIVE_DELAY(long AI_TASK_ACTIVE_DELAY) {
        this.AI_TASK_ACTIVE_DELAY = AI_TASK_ACTIVE_DELAY;
    }

    /**
     * @return the AI_TASK_DELAY_CURRENT
     */
    public long getAI_TASK_DELAY_CURRENT() {
        return AI_TASK_DELAY_CURRENT;
    }

    /**
     * @param AI_TASK_DELAY_CURRENT the AI_TASK_DELAY_CURRENT to set
     */
    public void setAI_TASK_DELAY_CURRENT(long AI_TASK_DELAY_CURRENT) {
        this.AI_TASK_DELAY_CURRENT = AI_TASK_DELAY_CURRENT;
    }

    /**
     * @return the MAX_PURSUE_RANGE
     */
    public int getMAX_PURSUE_RANGE() {
        return MAX_PURSUE_RANGE;
    }

    /**
     * @param MAX_PURSUE_RANGE the MAX_PURSUE_RANGE to set
     */
    public void setMAX_PURSUE_RANGE(int MAX_PURSUE_RANGE) {
        this.MAX_PURSUE_RANGE = MAX_PURSUE_RANGE;
    }

    /**
     * @return the _aiTask
     */
    public ScheduledFuture
 getAiTask() {
        return _aiTask;
    }

    /**
     * @param _aiTask the _aiTask to set
     */
    public void setAiTask(ScheduledFuture
_aiTask) {
        this._aiTask = _aiTask;
    }

    /**
     * @return the _runningTask
     */
    public ScheduledFuture
 getRunningTask() {
        return _runningTask;
    }

    /**
     * @param _runningTask the _runningTask to set
     */
    public void setRunningTask(ScheduledFuture
_runningTask) {
        this._runningTask = _runningTask;
    }

    /**
     * @return the _madnessTask
     */
    public ScheduledFuture
 getMadnessTask() {
        return _madnessTask;
    }

    /**
     * @param _madnessTask the _madnessTask to set
     */
    public void setMadnessTask(ScheduledFuture
_madnessTask) {
        this._madnessTask = _madnessTask;
    }

    /**
     * @return the _thinking
     */
    public boolean isThinking() {
        return _thinking;
    }

    /**
     * @param _thinking the _thinking to set
     */
    public void setThinking(boolean _thinking) {
        this._thinking = _thinking;
    }

    /**
     * @return the _def_think
     */
    public boolean isDef_think() {
        return _def_think;
    }

    /**
     * @param _def_think the _def_think to set
     */
    public void setDef_think(boolean _def_think) {
        this._def_think = _def_think;
    }

    /**
     * @return the _globalAggro
     */
    public long getGlobalAggro() {
        return _globalAggro;
    }

    /**
     * @return the _randomAnimationEnd
     */
    public long getRandomAnimationEnd() {
        return _randomAnimationEnd;
    }

    /**
     * @param _randomAnimationEnd the _randomAnimationEnd to set
     */
    public void setRandomAnimationEnd(long _randomAnimationEnd) {
        this._randomAnimationEnd = _randomAnimationEnd;
    }

    /**
     * @return the _pathfindFails
     */
    public int getPathfindFails() {
        return _pathfindFails;
    }

    /**
     * @param _pathfindFails the _pathfindFails to set
     */
    public void setPathfindFails(int _pathfindFails) {
        this._pathfindFails = _pathfindFails;
    }

    /**
     * @return the _tasks
     */
    public NavigableSet

getTasks() {
        return _tasks;
    }

    /**
     * @param _tasks the _tasks to set
     */
    public void setTasks(NavigableSet

_tasks) {
        this._tasks = _tasks;
    }

    /**
     * @return the _damSkills
     */
    public Skill[] getDamSkills() {
        return _damSkills;
    }

    /**
     * @param _damSkills the _damSkills to set
     */
    public void setDamSkills(Skill[] _damSkills) {
        this._damSkills = _damSkills;
    }

    /**
     * @return the _dotSkills
     */
    public Skill[] getDotSkills() {
        return _dotSkills;
    }

    /**
     * @param _dotSkills the _dotSkills to set
     */
    public void setDotSkills(Skill[] _dotSkills) {
        this._dotSkills = _dotSkills;
    }

    /**
     * @return the _debuffSkills
     */
    public Skill[] getDebuffSkills() {
        return _debuffSkills;
    }

    /**
     * @param _debuffSkills the _debuffSkills to set
     */
    public void setDebuffSkills(Skill[] _debuffSkills) {
        this._debuffSkills = _debuffSkills;
    }

    /**
     * @return the _healSkills
     */
    public Skill[] getHealSkills() {
        return _healSkills;
    }

    /**
     * @param _healSkills the _healSkills to set
     */
    public void setHealSkills(Skill[] _healSkills) {
        this._healSkills = _healSkills;
    }

    /**
     * @return the _buffSkills
     */
    public Skill[] getBuffSkills() {
        return _buffSkills;
    }

    /**
     * @param _buffSkills the _buffSkills to set
     */
    public void setBuffSkills(Skill[] _buffSkills) {
        this._buffSkills = _buffSkills;
    }

    /**
     * @return the _stunSkills
     */
    public Skill[] getStunSkills() {
        return _stunSkills;
    }

    /**
     * @param _stunSkills the _stunSkills to set
     */
    public void setStunSkills(Skill[] _stunSkills) {
        this._stunSkills = _stunSkills;
    }

    /**
     * @return the _lastActiveCheck
     */
    public long getLastActiveCheck() {
        return _lastActiveCheck;
    }

    /**
     * @param _lastActiveCheck the _lastActiveCheck to set
     */
    public void setLastActiveCheck(long _lastActiveCheck) {
        this._lastActiveCheck = _lastActiveCheck;
    }

    /**
     * @return the _checkAggroTimestamp
     */
    public long getCheckAggroTimestamp() {
        return _checkAggroTimestamp;
    }

    /**
     * @param _checkAggroTimestamp the _checkAggroTimestamp to set
     */
    public void setCheckAggroTimestamp(long _checkAggroTimestamp) {
        this._checkAggroTimestamp = _checkAggroTimestamp;
    }

    /**
     * @return the _lastFactionNotifyTime
     */
    public long getLastFactionNotifyTime() {
        return _lastFactionNotifyTime;
    }

    /**
     * @param _lastFactionNotifyTime the _lastFactionNotifyTime to set
     */
    public void setLastFactionNotifyTime(long _lastFactionNotifyTime) {
        this._lastFactionNotifyTime = _lastFactionNotifyTime;
    }

    /**
     * @return the _minFactionNotifyInterval
     */
    public long getMinFactionNotifyInterval() {
        return _minFactionNotifyInterval;
    }

    /**
     * @param _minFactionNotifyInterval the _minFactionNotifyInterval to set
     */
    public void setMinFactionNotifyInterval(long _minFactionNotifyInterval) {
        this._minFactionNotifyInterval = _minFactionNotifyInterval;
    }

    /**
     * @return the _nearestTargetComparator
     */
    public Comparator

getNearestTargetComparator() {
        return _nearestTargetComparator;
    }

    /**
     * @param _nearestTargetComparator the _nearestTargetComparator to set
     */
    public void setNearestTargetComparator(Comparator

_nearestTargetComparator) {
        this._nearestTargetComparator = _nearestTargetComparator;
    }

    public static enum TaskType
    {
        MOVE,
        ATTACK,
        CAST,
        BUFF
    }
    
    public static final int TaskDefaultWeight = 10000;

    public static class Task
    {
        private TaskType type;
        private Skill skill;
        private HardReference
 target;
        private Location loc;
        private boolean pathfind;
        private int weight = TaskDefaultWeight;

        /**
         * @return the type
         */
        public TaskType getType() {
            return type;
        }

        /**
         * @param type the type to set
         */
        public void setType(TaskType type) {
            this.type = type;
        }

        /**
         * @return the skill
         */
        public Skill getSkill() {
            return skill;
        }

        /**
         * @param skill the skill to set
         */
        public void setSkill(Skill skill) {
            this.skill = skill;
        }

        /**
         * @return the target
         */
        public HardReference getTarget() {
            return target;
        }

        /**
         * @param target the target to set
         */
        public void setTarget(HardReference target) {
            this.target = target;
        }

        /**
         * @return the loc
         */
        public Location getLoc() {
            return loc;
        }

        /**
         * @param loc the loc to set
         */
        public void setLoc(Location loc) {
            this.loc = loc;
        }

        /**
         * @return the pathfind
         */
        public boolean isPathfind() {
            return pathfind;
        }

        /**
         * @param pathfind the pathfind to set
         */
        public void setPathfind(boolean pathfind) {
            this.pathfind = pathfind;
        }

        /**
         * @return the weight
         */
        public int getWeight() {
            return weight;
        }

        /**
         * @param weight the weight to set
         */
        public void setWeight(int weight) {
            this.weight = weight;
        }
    }

    public void addTaskCast(Creature target, Skill skill)
    {
        Task task = new Task();
                task.setType(CAST);
                task.setTarget(target.getRef());
                task.setSkill(skill);
        getTasks().add(task);
        setDef_think(true);
    }

    public void addTaskBuff(Creature target, Skill skill)
    {
        Task task = new Task();
                task.setType(BUFF);
                task.setTarget(target.getRef());
                task.setSkill(skill);
        getTasks().add(task);
        setDef_think(true);
    }

    public void addTaskAttack(Creature target)
    {
        Task task = new Task();
                task.setType(ATTACK);
                task.setTarget(target.getRef());
        getTasks().add(task);
        setDef_think(true);
    }

    public void addTaskAttack(Creature target, Skill skill, int weight)
    {
        Task task = new Task();
                task.setType(skill.isOffensive() ? CAST : BUFF);
                task.setTarget(target.getRef());
                task.setSkill(skill);
                task.setWeight(weight);
        getTasks().add(task);
        setDef_think(true);
    }

    public void addTaskMove(Location loc, boolean pathfind)
    {
        Task task = new Task();
                task.setType(MOVE);
                task.setLoc(loc);
                task.setPathfind(pathfind);
        getTasks().add(task);
        setDef_think(true);
    }

    protected void addTaskMove(int locX, int locY, int locZ, boolean pathfind)
    {
        addTaskMove(new Location(locX, locY, locZ), pathfind);
    }

    private static class TaskComparator implements Comparator
    {
        private static final Comparator instance = new TaskComparator();

        public static Comparator getInstance()
        {
            return instance;
        }

        @Override
        public int compare(Task o1, Task o2)
        {
            if(o1 == null || o2 == null)
                return 0;
            return o2.getWeight() - o1.getWeight();
        }
    }

    protected class Teleport extends RunnableImpl
    {
        private Location _destination;

        public Teleport(Location destination)
        {
            _destination = destination;
        }

        @Override
        public void runImpl() throws Exception
        {
            NpcInstance actor = getActor();
            if(actor != null)
                actor.teleToLocation(getDestination());
        }

        /**
         * @return the _destination
         */
        public Location getDestination() {
            return _destination;
        }

        /**
         * @param _destination the _destination to set
         */
        public void setDestination(Location _destination) {
            this._destination = _destination;
        }
    }

    protected class RunningTask extends RunnableImpl
    {
        @Override
        public void runImpl() throws Exception
        {
            NpcInstance actor = getActor();
            if(actor != null)
                actor.setRunning();
            setRunningTask(null);
        }
    }

    protected class MadnessTask extends RunnableImpl
    {
        @Override
        public void runImpl() throws Exception
        {
            NpcInstance actor = getActor();
            if(actor != null)
                actor.stopConfused();
            setMadnessTask(null);
        }
    }

    protected class NearestTargetComparator implements Comparator
    {
        private final Creature actor;

        public NearestTargetComparator(Creature actor)
        {
            this.actor = actor;
        }

        @Override
        public int compare(Creature o1, Creature o2)
        {
            double diff = actor.getDistance3D(o1) - actor.getDistance3D(o2);
            if(diff  0 ? 1 : 0;
        }
    }

    private long AI_TASK_ATTACK_DELAY = AiTaskDelay;
    private long AI_TASK_ACTIVE_DELAY = AiTaskActiveDelay;
    private long AI_TASK_DELAY_CURRENT = AI_TASK_ACTIVE_DELAY;
    private int MAX_PURSUE_RANGE;

    private ScheduledFuture
_aiTask;

    private ScheduledFuture
 _runningTask;
    private ScheduledFuture
_madnessTask;

    /** The flag used to indicate that a thinking action is in progress */
    private boolean _thinking = false;
    /** Показывает, есть ли задания */
    private boolean _def_think = false;

    /** The L2NpcInstance aggro counter */
    private long _globalAggro;

    private long _randomAnimationEnd;
    private int _pathfindFails;

    /** Список заданий */
    private NavigableSet

_tasks = new ConcurrentSkipListSet<>(getInstance());

    private Skill[] _damSkills;
    private Skill[] _dotSkills;
    /** Время актуальности состояния атаки */
    private Skill[] _debuffSkills;

    private Skill[] _healSkills;
    private Skill[] _buffSkills;

    private Skill[] _stunSkills;
    private long _lastActiveCheck;
    private long _checkAggroTimestamp = 0;
    private long _attackTimeout;
    private long _lastFactionNotifyTime = 0;
    private long _minFactionNotifyInterval = 10000;
    private Comparator

_nearestTargetComparator;

    public DefaultAI(NpcInstance actor)
    {
        super(actor);

        setAttackTimeout(MAX_VALUE);

        NpcInstance npc = getActor();
        _damSkills = npc.getTemplate().getDamageSkills();
        _dotSkills = npc.getTemplate().getDotSkills();
        _debuffSkills = npc.getTemplate().getDebuffSkills();
        _buffSkills = npc.getTemplate().getBuffSkills();
        _stunSkills = npc.getTemplate().getStunSkills();
        _healSkills = npc.getTemplate().getHealSkills();

        _nearestTargetComparator = new NearestTargetComparator(actor);

        // Preload some AI params
        MAX_PURSUE_RANGE = actor.getParameter("MaxPursueRange", actor.isRaid() ? MaxPursueRangeRaid : npc.isUnderground() ? MaxPursueUnderGroundRange : MaxPursueRange);
        _minFactionNotifyInterval = actor.getParameter("FactionNotifyInterval", 10000);
    }

    @Override
    public void runImpl() throws Exception
    {
        if(getAiTask() == null)
            return;
        // проверяем, если NPC вышел в неактивный регион, отключаем AI
        if(!isGlobalAI() && currentTimeMillis() - getLastActiveCheck() > 60000L)
        {
            setLastActiveCheck(currentTimeMillis());
            NpcInstance actor = getActor();
            WorldRegion region = actor == null ? null : actor.getCurrentRegion();
            if(region == null || !region.isActive())
            {
                stopAITask();
                return;
            }
        }
        onEvtThink();
    }

    @Override
    //public final synchronized void startAITask()
    public synchronized void startAITask()
    {
        if(getAiTask() == null)
        {
            setAI_TASK_DELAY_CURRENT(getAI_TASK_ACTIVE_DELAY());
            setAiTask(getInstance().scheduleAtFixedRate(this, 0L, getAI_TASK_DELAY_CURRENT()));
        }
    }

    //protected final synchronized void switchAITask(long NEW_DELAY)
    protected synchronized void switchAITask(long NEW_DELAY)
    {
        if(getAiTask() == null)
            return;

        if(getAI_TASK_DELAY_CURRENT() != NEW_DELAY)
        {
            getAiTask().cancel(false);
            setAI_TASK_DELAY_CURRENT(NEW_DELAY);
            setAiTask(getInstance().scheduleAtFixedRate(this, 0L, getAI_TASK_DELAY_CURRENT()));
        }
    }

    @Override
    public final synchronized void stopAITask()
    {
        if(getAiTask() != null)
        {
            getAiTask().cancel(false);
            setAiTask(null);
        }
    }

    /**
     * Определяет, может ли этот тип АИ видеть персонажей в режиме Silent Move.
     * @param target L2Playable цель
     * @return true если цель видна в режиме Silent Move
     */
    protected boolean canSeeInSilentMove(Playable target) {
        return getActor().getParameter("canSeeInSilentMove", false) || !target.isSilentMoving();
    }

    protected boolean canSeeInHide(Playable target)
    {
        return getActor().getParameter("canSeeInHide", false) || !target.isInvisible();
    }

    protected boolean checkAggression(Creature target)
    {
        NpcInstance actor = getActor();
        if(getIntention() != AI_INTENTION_ACTIVE || !isGlobalAggro())
            return false;
        if(target.isAlikeDead())
            return false;

        if(target.isNpc() && target.isInvul())
            return false;

        if(target.isPlayer() && target.getPlayer().isInAwayingMode() && !AWAY_PLAYER_TAKE_AGGRO)
            return false;

        if(target.isPlayable())
        {
            if(!canSeeInSilentMove((Playable) target))
                return false;
            if(!canSeeInHide((Playable) target))
                return false;
            if(actor.getFaction().getName().equalsIgnoreCase("varka_silenos_clan") && target.getPlayer().getVarka() > 0)
                return false;
            if(actor.getFaction().getName().equalsIgnoreCase("ketra_orc_clan") && target.getPlayer().getKetra() > 0)
                return false;
            /*if(target.isFollow && !target.isPlayer() && target.getFollowTarget() != null && target.getFollowTarget().isPlayer())
                    return;*/
            if(target.isPlayer() && ((Player) target).isGM() && target.isInvisible())
                return false;
            if(((Playable) target).getNonAggroTime() > currentTimeMillis())
                return false;
            if(target.isPlayer() && !target.getPlayer().isActive())
                return false;
            if(actor.isMonster() && target.isInZonePeace())
                return false;
        }

        AggroInfo ai = actor.getAggroList().get(target);
        if(ai != null && ai.hate > 0)
        {
            if(!target.isInRangeZ(actor.getSpawnedLoc(), MAX_PURSUE_RANGE))
                return false;
        }
        else if(!actor.isAggressive() || !target.isInRangeZ(actor.getSpawnedLoc(), actor.getAggroRange()))
            return false;

        if(!canAttackCharacter(target))
            return false;
        if(!canSeeTarget(actor, target, false))
            return false;

        actor.getAggroList().addDamageHate(target, 0, 2);

        if((target.isSummon() || target.isPet()))
            actor.getAggroList().addDamageHate(target.getPlayer(), 0, 1);

        startRunningTask(getAI_TASK_ATTACK_DELAY());
        setIntention(AI_INTENTION_ATTACK, target);

        return true;
    }

    protected void setIsInRandomAnimation(long time)
    {
        setRandomAnimationEnd(currentTimeMillis() + time);
    }

    protected boolean randomAnimation()
    {
        NpcInstance actor = getActor();

        if(actor.getParameter("noRandomAnimation", false))
            return false;

        if(actor.hasRandomAnimation() && !actor.isActionsDisabled() && !actor.isMoving && !actor.isInCombat() && chance(RndAnimationRate))
        {
            setIsInRandomAnimation(3000);
            actor.onRandomAnimation();
            return true;
        }
        return false;
    }

    protected boolean randomWalk() {
        NpcInstance actor = getActor();

        return !actor.getParameter("noRandomWalk", false) && !actor.isMoving && maybeMoveToHome();
    }

    /**
     * @return true если действие выполнено, false если нет
     */
    protected boolean thinkActive() {
        NpcInstance actor = getActor();
        if (actor.isActionsDisabled())
            return true;

        if (getRandomAnimationEnd() > currentTimeMillis())
            return true;

        if (isDef_think()) {
            if (doTask())
                clearTasks();
            return true;
        }

        long now = currentTimeMillis();
        if (now - getCheckAggroTimestamp() > AggroCheckInterval) {
            setCheckAggroTimestamp(now);

            boolean aggressive = chance(actor.getParameter("SelfAggressive", actor.isAggressive() ? 100 : 0));
            if (!actor.getAggroList().isEmpty() || aggressive) {
                List

chars = getAroundCharacters(actor);
                eqSort(chars, getNearestTargetComparator());
                for (Creature cha : chars) {
                    if (aggressive || actor.getAggroList().get(cha) != null)
                        if (checkAggression(cha))
                            return true;
                }
            }
        }

        if (actor.isMinion()) {
            MonsterInstance leader = ((MinionInstance) actor).getLeader();
            if (leader != null) {
                double distance = actor.getDistance(leader.getX(), leader.getY());
                if (distance > 1000)
                    actor.teleToLocation(leader.getMinionPosition());
                else if (distance > 200)
                    addTaskMove(leader.getMinionPosition(), false);
                return true;
            }
        }

        return randomAnimation() || randomWalk();
    }

    @Override
    protected void onIntentionIdle()
    {
        NpcInstance actor = getActor();

        // Удаляем все задания
        clearTasks();

        actor.stopMove();
        actor.getAggroList().clear(true);
        setAttackTimeout(MAX_VALUE);
        setAttackTarget(null);

        changeIntention(AI_INTENTION_IDLE, null, null);
    }

    @Override
    protected void onIntentionActive()
    {
        NpcInstance actor = getActor();

        actor.stopMove();
        setAttackTimeout(MAX_VALUE);

        if(getIntention() != AI_INTENTION_ACTIVE)
        {
            switchAITask(getAI_TASK_ACTIVE_DELAY());
            changeIntention(AI_INTENTION_ACTIVE, null, null);
        }

        onEvtThink();
    }

    @Override
    protected void onIntentionAttack(Creature target)
    {
        NpcInstance actor = getActor();

        // Удаляем все задания
        clearTasks();

        actor.stopMove();
        setAttackTarget(target);
        setAttackTimeout(getMaxAttackTimeout() + currentTimeMillis());
        setGlobalAggro(0);

        if(getIntention() != AI_INTENTION_ATTACK)
        {
            changeIntention(AI_INTENTION_ATTACK, target, null);
            switchAITask(getAI_TASK_ATTACK_DELAY());
        }

        onEvtThink();
    }

    protected boolean canAttackCharacter(Creature target)
    {
        return target.isPlayable();
    }

    protected boolean checkTarget(Creature target, int range)
    {
        NpcInstance actor = getActor();
        if(target == null || target.isAlikeDead() || !actor.isInRangeZ(target, range))
            return false;

        // если не видим чаров в хайде - не атакуем их
        final boolean hided = target.isPlayable() && !canSeeInHide((Playable)target);

        if(!hided && actor.isConfused())
            return true;

        //В состоянии атаки атакуем всех, на кого у нас есть хейт
        if(getIntention() == AI_INTENTION_ATTACK)
        {
            AggroInfo ai = actor.getAggroList().get(target);
            if (ai != null)
            {
                if (hided)
                {
                    ai.hate = 0; // очищаем хейт
                    return false;
                }
                return ai.hate > 0;
            }
            return false;
        }

        return canAttackCharacter(target);
    }

    public void setAttackTimeout(long time)
    {
        _attackTimeout = time;
    }

    protected long getAttackTimeout()
    {
        return _attackTimeout;
    }

    protected void thinkAttack()
    {
        NpcInstance actor = getActor();
        if(actor.isDead())
            return;

        Location loc = actor.getSpawnedLoc();
        if(!actor.isInRange(loc, MAX_PURSUE_RANGE))
        {
            returnHome();
            return;
        }

        if(doTask() && !actor.isAttackingNow() && !actor.isCastingNow())
        {
            if(!createNewTask())
            {
                if(currentTimeMillis() > getAttackTimeout())
                    returnHome();
            }
        }
    }

    @Override
    protected void onEvtSpawn()
    {
        setGlobalAggro(currentTimeMillis() + getActor().getParameter("globalAggro", 10000L));

        setIntention(AI_INTENTION_ACTIVE);
    }

    @Override
    protected void onEvtReadyToAct()
    {
        onEvtThink();
    }

    @Override
    protected void onEvtArrivedTarget()
    {
        onEvtThink();
    }

    @Override
    protected void onEvtArrived()
    {
        onEvtThink();
    }

    protected boolean tryMoveToTarget(Creature target)
    {
        NpcInstance actor = getActor();

        if(target.isInvisible())
        {
            notifyEvent(EVT_THINK);
            return false;
        }

        if(!actor.followToCharacter(target, actor.getPhysicalAttackRange(), true))
            setPathfindFails(getPathfindFails() + 1);

        if(getPathfindFails() >= getMaxPathfindFails() && (currentTimeMillis() > getAttackTimeout() - getMaxAttackTimeout() + getTeleportTimeout()) && actor.isInRange(target, getMAX_PURSUE_RANGE()))
        {
            setPathfindFails(0);

            if(target.isPlayable())
            {
                AggroInfo hate = actor.getAggroList().get(target);
                if(hate == null || hate.hate  currentTimeMillis())
            return;

        if(actor.isRaid() && (actor.isInZonePeace() || actor.isInZoneBattle() || actor.isInZone(SIEGE)))
        {
            teleportHome();
            return;
        }

        setThinking(true);
        try
        {
            if(!BlockActiveTasks && getIntention() == AI_INTENTION_ACTIVE)
                thinkActive();
            else if(getIntention() == AI_INTENTION_ATTACK)
                thinkAttack();
        }
        finally
        {
            setThinking(false);
        }
    }

    @Override
    protected void onEvtDead(Creature killer)
    {
        NpcInstance actor = getActor();

        int transformer = actor.getParameter("transformOnDead", 0);
        int chance = actor.getParameter("transformChance", 100);
        if(transformer > 0 && chance(chance))
        {
            NpcInstance npc = spawnSingle(transformer, actor.getLoc(), actor.getReflection()) ;

            if(killer != null && killer.isPlayable())
            {
                npc.getAI().notifyEvent(EVT_AGGRESSION, killer, 100);
                killer.setTarget(npc);
                killer.sendPacket(npc.makeStatusUpdate(CUR_HP, MAX_HP));
            }
        }

        super.onEvtDead(killer);
    }

    @Override
    protected void onEvtClanAttacked(Creature attacked, Creature attacker, int damage)
    {
        if(getIntention() != AI_INTENTION_ACTIVE || !isGlobalAggro())
            return;

        notifyEvent(EVT_AGGRESSION, attacker, 2);
    }

    @Override
    protected void onEvtAttacked(Creature attacker, int damage)
    {
        NpcInstance actor = getActor();
        if(attacker == null || actor.isDead())
            return;

        int transformer = actor.getParameter("transformOnUnderAttack", 0);
        if(transformer > 0)
        {
            int chance = actor.getParameter("transformChance", 5);
            if(chance == 100 || ((MonsterInstance) actor).getChampion() == 0 && actor.getCurrentHpPercents() > 50 && chance(chance))
            {
                MonsterInstance npc = (MonsterInstance) getInstance().getTemplate(transformer).getNewInstance();
                npc.setSpawnedLoc(actor.getLoc());
                npc.setReflection(actor.getReflection());
                npc.setChampion(((MonsterInstance) actor).getChampion());
                npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp(), true);
                npc.spawnMe(npc.getSpawnedLoc());
                npc.getAI().notifyEvent(EVT_AGGRESSION, attacker, 100);
                actor.doDie(actor);
                actor.decayMe();
                attacker.setTarget(npc);
                attacker.sendPacket(npc.makeStatusUpdate(CUR_HP, MAX_HP));
                return;
            }
        }

        Player player = attacker.getPlayer();

        if(player != null)
        {
            //FIXME [G1ta0] затычка для 7 печатей, при атаке монстра 7 печатей телепортирует персонажа в ближайший город
            if((getInstance().isSealValidationPeriod() || getInstance().isCompResultsPeriod()) && actor.isSevenSignsMonster())
            {
                int pcabal = getInstance().getPlayerCabal(player);
                int wcabal = getInstance().getCabalHighestScore();
                if(pcabal != wcabal && wcabal != CABAL_NULL)
                {
                    player.sendMessage("You have been teleported to the nearest town because you not signed for winning cabal.");
                    player.teleToClosestTown();
                    return;
                }
            }

            List

quests = player.getQuestsForEvent(actor, ATTACKED_WITH_QUEST);
            if(quests != null)
                for(QuestState qs : quests)
                    qs.getQuest().notifyAttack(actor, qs);
        }

        //Добавляем только хейт, урон, если атакующий - игровой персонаж, будет добавлен в L2NpcInstance.onReduceCurrentHp
        actor.getAggroList().addDamageHate(attacker, 0, damage);

        // Обычно 1 хейт добавляется хозяину суммона, чтобы после смерти суммона моб накинулся на хозяина.
        if(damage > 0 && (attacker.isSummon() || attacker.isPet()))
            actor.getAggroList().addDamageHate(attacker.getPlayer(), 0, actor.getParameter("searchingMaster", false) ? damage : 1);

        if(getIntention() != AI_INTENTION_ATTACK)
        {
            if(!actor.isRunning())
                startRunningTask(getAI_TASK_ATTACK_DELAY());
            setIntention(AI_INTENTION_ATTACK, attacker);
        }

        notifyFriends(attacker, damage);
    }

    @Override
    protected void onEvtAggression(Creature attacker, int aggro)
    {
        NpcInstance actor = getActor();
        if(attacker == null || actor.isDead())
            return;

        actor.getAggroList().addDamageHate(attacker, 0, aggro);

        // Обычно 1 хейт добавляется хозяину суммона, чтобы после смерти суммона моб накинулся на хозяина.
        if(aggro > 0 && (attacker.isSummon() || attacker.isPet()))
            actor.getAggroList().addDamageHate(attacker.getPlayer(), 0, actor.getParameter("searchingMaster", false) ? aggro : 1);

        if(getIntention() != AI_INTENTION_ATTACK)
        {
            if(!actor.isRunning())
                startRunningTask(getAI_TASK_ATTACK_DELAY());
            setIntention(AI_INTENTION_ATTACK, attacker);
        }
    }

    protected boolean maybeMoveToHome()
    {
        NpcInstance actor = getActor();
        if(actor.isDead())
            return false;

        boolean randomWalk = actor.hasRandomWalk();
        Location sloc = actor.getSpawnedLoc();

        // Random walk or not?
        if(randomWalk && (!RndWalk || !chance(RndWalkRate)))
            return false;

        boolean isInRange = actor.isInRangeZ(sloc, MaxDriftRange);

        if(!randomWalk && isInRange)
            return false;

        Location pos = findPointToStay(actor, sloc, 0, MaxDriftRange);

        actor.setWalking();

        // Телепортируемся домой, только если далеко от дома
        if(!actor.moveToLocation(pos.x, pos.y, pos.z, 0, true) && !isInRange)
            teleportHome();

        return true;
    }

    protected void returnHome()
    {
        returnHome(true, false);
    }

    protected void teleportHome()
    {
        returnHome(true, true);
    }

    protected void returnHome(boolean clearAggro, boolean teleport)
    {
        NpcInstance actor = getActor();
        Location sloc = actor.getSpawnedLoc();

        // Удаляем все задания
        clearTasks();
        actor.stopMove();

        if(clearAggro)
            actor.getAggroList().clear(true);

        setAttackTimeout(MAX_VALUE);
        setAttackTarget(null);

        changeIntention(AI_INTENTION_ACTIVE, null, null);

        if(teleport)
        {
            actor.broadcastPacketToOthers(new MagicSkillUse(actor, actor, 2036, 1, 500, 0));
            actor.teleToLocation(sloc.x, sloc.y, getHeight(sloc, actor.getGeoIndex()));
        }
        else
        {
            if(!clearAggro)
                actor.setRunning();
            else
                actor.setWalking();

            addTaskMove(sloc, false);
        }
    }

    protected Creature prepareTarget()
    {
        NpcInstance actor = getActor();

        if(actor.isConfused())
            return getAttackTarget();

        // Для "двинутых" боссов, иногда, выбираем случайную цель
        if(chance(actor.getParameter("isMadness", 0)))
        {
            Creature randomHated = actor.getAggroList().getRandomHated();
            if(randomHated != null)
            {
                setAttackTarget(randomHated);
                if(getMadnessTask() == null && !actor.isConfused())
                {
                    actor.startConfused();
                    setMadnessTask(getInstance().schedule(new MadnessTask(), 10000));
                }
                return randomHated;
            }
        }

        // Новая цель исходя из агрессивности
        List

hateList = actor.getAggroList().getHateList();
        Creature hated = null;
        for(Creature cha : hateList)
        {
            // Если у Монстра есть скилл "Searching Master" он должен атаковать хозяина пета в первую очередь.
            if((cha.isPet() || cha.isSummon()) && cha.getPlayer() != null)
                if(getActor().getSkillLevel(6019) == 1 && checkTarget(cha.getPlayer(), getMAX_PURSUE_RANGE()))
                    cha = cha.getPlayer();

            //Не подходит, очищаем хейт
            if(!checkTarget(cha, MAX_PURSUE_RANGE))
            {
                actor.getAggroList().remove(cha, true);
                continue;
            }
            hated = cha;
            break;
        }

        if(hated != null)
        {
            setAttackTarget(hated);
            return hated;
        }

        return null;
    }

    protected boolean canUseSkill(Skill skill, Creature target, double distance)
    {
        NpcInstance actor = getActor();
        if(skill == null || skill.isNotUsedByAI())
            return false;

        if(skill.getTargetType() == TARGET_SELF && target != actor)
            return false;

        int castRange = skill.getAOECastRange();
        if(castRange  200)
            return false;

        if(actor.isSkillDisabled(skill) || actor.isMuted(skill) || actor.isUnActiveSkill(skill.getId()))
            return false;

        double mpConsume2 = skill.getMpConsume2();
        if(skill.isMagic())
            mpConsume2 = actor.calcStat(MP_MAGIC_SKILL_CONSUME, mpConsume2, target, skill);
        else
            mpConsume2 = actor.calcStat(MP_PHYSICAL_SKILL_CONSUME, mpConsume2, target, skill);
        if(actor.getCurrentMp() 
rnd = new RndSelector<>(skills.length);
        double weight;
        for(Skill skill : skills)
        {
            weight = skill.getSimpleDamage(actor, target) * skill.getAOECastRange() / distance;
            if(weight 
rnd = new RndSelector<>(skills.length);
        double weight;
        for(Skill skill : skills)
        {
            if(skill.getSameByStackType(target) != null)
                continue;
            if((weight = 100. * skill.getAOECastRange() / distance) 
rnd = new RndSelector<>(skills.length);
        double weight;
        for(Skill skill : skills)
        {
            if(skill.getSameByStackType(target) != null)
                continue;
            if((weight = skill.getPower()) 
rnd = new RndSelector<>(skills.length);
        double weight;
        for(Skill skill : skills)
        {
            if((weight = abs(skill.getPower() - hpReduced)) 
skillMap, Creature target, double distance, Skill[] skills)
    {
        if(skills == null || skills.length == 0 || target == null)
            return;
        for(Skill sk : skills)
            addDesiredSkill(skillMap, target, distance, sk);
    }

    protected void addDesiredSkill(Map

skillMap, Creature target, double distance, Skill skill)
    {
        if(skill == null || target == null || !canUseSkill(skill, target))
            return;
        int weight = (int) -abs(skill.getAOECastRange() - distance);
        if(skill.getAOECastRange() >= distance)
            weight += 1000000;
        else if(skill.isNotTargetAoE() && skill.getTargets(getActor(), target, false).isEmpty())
            return;
        skillMap.put(skill, weight);
    }

    protected void addDesiredHeal(Map

skillMap, Skill[] skills)
    {
        if(skills == null || skills.length == 0)
            return;
        NpcInstance actor = getActor();
        double hpReduced = actor.getMaxHp() - actor.getCurrentHp();
        double hpPercent = actor.getCurrentHpPercents();
        if(hpReduced 
skillMap, Skill[] skills)
    {
        if(skills == null || skills.length == 0)
            return;
        NpcInstance actor = getActor();
        for(Skill sk : skills)
            if(canUseSkill(sk, actor))
                skillMap.put(sk, 1000000);
    }

    protected Skill selectTopSkill(Map

skillMap)
    {
        if(skillMap == null || skillMap.isEmpty())
            return null;
        int nWeight, topWeight = MIN_VALUE;
        for(Skill next : skillMap.keySet())
            if((nWeight = skillMap.get(next)) > topWeight)
                topWeight = nWeight;
        if(topWeight == MIN_VALUE)
            return null;

        Skill[] skills = new Skill[skillMap.size()];
        nWeight = 0;
        for(Map.Entry

e : skillMap.entrySet())
        {
            if(e.getValue()  skill.getAOECastRange() + 60)
            {
                target = null;
                if(skill.isOffensive())
                {
                    LazyArrayList

targets = newInstance();
                    for(Creature cha : actor.getAggroList().getHateList())
                    {
                        if(!checkTarget(cha, skill.getAOECastRange() + 60) || !canUseSkill(skill, cha))
                            continue;
                        targets.add(cha);
                    }
                    if(!targets.isEmpty())
                        target = targets.get(get(targets.size()));
                    recycle(targets);
                }
            }

            if(target == null)
                return false;

            // Добавить новое задание
            if(skill.isOffensive())
                addTaskCast(target, skill);
            else
                addTaskBuff(target, skill);
            return true;
        }

        // Смена цели, если необходимо
        if(actor.isMovementDisabled() && distance > actor.getPhysicalAttackRange() + 40)
        {
            target = null;
            LazyArrayList

targets = newInstance();
            for(Creature cha : actor.getAggroList().getHateList())
            {
                if(!checkTarget(cha, actor.getPhysicalAttackRange() + 40))
                    continue;
                targets.add(cha);
            }
            if(!targets.isEmpty())
                target = targets.get(get(targets.size()));
            recycle(targets);
        }

        if(target == null)
            return false;

        // Добавить новое задание
        addTaskAttack(target);
        return true;
    }

    @Override
    public boolean isActive()
    {
        return getAiTask() != null;
    }

    protected void clearTasks()
    {
        setDef_think(false);
        getTasks().clear();
    }

    /** переход в режим бега через определенный интервал времени
     * @param interval */
    protected void startRunningTask(long interval)
    {
        NpcInstance actor = getActor();
        if(actor != null && getRunningTask() == null && !actor.isRunning())
            setRunningTask(getInstance().schedule(new RunningTask(), (int) interval));
    }

    protected boolean isGlobalAggro()
    {
        if(getGlobalAggro() == 0)
            return true;
        if(getGlobalAggro()  getMinFactionNotifyInterval())
        {
            setLastFactionNotifyTime(currentTimeMillis());
            if(actor.isMinion())
            {
                //Оповестить лидера об атаке
                MonsterInstance master = ((MinionInstance) actor).getLeader();
                if(master != null)
                {
                    if(!master.isDead() && master.isVisible())
                        master.getAI().notifyEvent(EVT_AGGRESSION, attacker, damage);

                    //Оповестить минионов лидера об атаке
                    MinionList minionList = master.getMinionList();
                    if(minionList != null)
                        minionList.getAliveMinions().stream().filter(minion -> minion != actor).forEach(minion -> minion.getAI().notifyEvent(EVT_AGGRESSION, attacker, damage));
                }
            }

            //Оповестить своих минионов об атаке
            MinionList minionList = actor.getMinionList();
            if(minionList != null && minionList.hasAliveMinions())
                for(MinionInstance minion : minionList.getAliveMinions())
                    minion.getAI().notifyEvent(EVT_AGGRESSION, attacker, damage);

            //Оповестить социальных мобов
            for(NpcInstance npc : activeFactionTargets())
                npc.getAI().notifyEvent(EVT_CLAN_ATTACKED, new Object[] { actor, attacker, damage });
        }
    }

    protected List

activeFactionTargets()
    {
        NpcInstance actor = getActor();
        if(actor.getFaction().isNone())
            return emptyList();
        return getAroundNpc(actor).stream().filter(npc -> !npc.isDead()).filter(npc -> npc.isInFaction(actor)).filter(npc -> npc.isInRangeZ(actor, npc.getFaction().getRange())).filter(npc -> canSeeTarget(npc, actor, false)).collect(Collectors.toCollection(() -> new LazyArrayList<>()));
    }

    protected boolean defaultThinkBuff(int rateSelf, int rateFriends)
    {
        NpcInstance actor = getActor();
        if(actor.isDead())
            return true;

        //TODO сделать более разумный выбор баффа, сначала выбирать подходящие а потом уже рандомно 1 из них
        if(chance(rateSelf))
        {
            double actorHp = actor.getCurrentHpPercents();

            Skill[] skills = actorHp  10 ? chance(getRateDEBUFF()) ? selectUsableSkills(target, distance, getDebuffSkills()) : null : null;
        Skill[] stun = chance(getRateSTUN()) ? selectUsableSkills(target, distance, getStunSkills()) : null;
        Skill[] heal = actorHp 
rnd = new RndSelector<>();
        if(!actor.isAMuted())
            rnd.add(null, getRatePHYS());
        rnd.add(dam, getRateDAM());
        rnd.add(dot, getRateDOT());
        rnd.add(debuff, getRateDEBUFF());
        rnd.add(heal, getRateHEAL());
        rnd.add(buff, getRateBUFF());
        rnd.add(stun, getRateSTUN());

        Skill[] selected = rnd.select();
        if(selected != null)
        {
            if(selected == dam || selected == dot)
                return chooseTaskAndTargets(selectTopSkillByDamage(actor, target, distance, selected), target, distance);

            if(selected == debuff || selected == stun)
                return chooseTaskAndTargets(selectTopSkillByDebuff(target, distance, selected), target, distance);

            if(selected == buff)
                return chooseTaskAndTargets(selectTopSkillByBuff(actor, selected), actor, distance);

            if(selected == heal)
                return chooseTaskAndTargets(selectTopSkillByHeal(actor, selected), actor, distance);
        }

        // TODO сделать лечение и баф дружественных целей

        return chooseTaskAndTargets(null, target, distance);
    }

    public int getRatePHYS()
    {
        return 100;
    }

    public int getRateDOT()
    {
        return 0;
    }

    public int getRateDEBUFF()
    {
        return 0;
    }

    public int getRateDAM()
    {
        return 0;
    }

    public int getRateSTUN()
    {
        return 0;
    }

    public int getRateBUFF()
    {
        return 0;
    }

    public int getRateHEAL()
    {
        return 0;
    }

    public boolean getIsMobile()
    {
        return !getActor().getParameter("isImmobilized", false);
    }

    public int getMaxPathfindFails()
    {
        return 3;
    }

    /**
     * Задержка, перед переключением в активный режим после атаки, если цель не найдена (вне зоны досягаемости, убита, очищен хейт)
     * @return
     */
    public int getMaxAttackTimeout()
    {
        return 15000;
    }

    /**
     * Задержка, перед телепортом к цели, если не удается дойти
     * @return
     */
    public int getTeleportTimeout()
    {
        return 10000;
    }
 
Ответить с цитированием

  #2  
Старый 06.04.2016, 03:37
Wolfer
Участник форума
Регистрация: 05.04.2016
Сообщений: 222
С нами: 5318817

Репутация: 0
По умолчанию

PlayableAI.java

Цитата:
Сообщение от Спойлер  


PHP:


Код:
package l2p.gameserver.ai;

import l2p.commons.threading.RunnableImpl;
import l2p.gameserver.ThreadPoolManager;
import l2p.gameserver.geodata.GeoEngine;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.GameObject;
import l2p.gameserver.model.Playable;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.Skill;
import l2p.gameserver.model.Skill.NextAction;
import l2p.gameserver.model.Skill.SkillType;
import l2p.gameserver.model.Summon;
import l2p.gameserver.serverpackets.MyTargetSelected;
import l2p.gameserver.serverpackets.components.SystemMsg;
import l2p.gameserver.utils.Location;

import java.util.concurrent.ScheduledFuture;

import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;

public class PlayableAI extends CharacterAI
{
    private volatile int thinking = 0; // to prevent recursive thinking

    protected Object _intention_arg0 = null, _intention_arg1 = null;
    protected Skill _skill;

    private nextAction _nextAction;
    private Object _nextAction_arg0;
    private Object _nextAction_arg1;
    private boolean _nextAction_arg2;
    private boolean _nextAction_arg3;

    protected boolean _forceUse;
    private boolean _dontMove;

    private ScheduledFuture
 _followTask;

    public PlayableAI(Playable actor)
    {
        super(actor);
    }

    public enum nextAction
    {
        ATTACK,
        CAST,
        MOVE,
        REST,
        PICKUP,
        INTERACT
    }

    @Override
    public void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
    {
        super.changeIntention(intention, arg0, arg1);
        _intention_arg0 = arg0;
        _intention_arg1 = arg1;
    }

    @Override
    public void setIntention(CtrlIntention intention, Object arg0, Object arg1)
    {
        _intention_arg0 = null;
        _intention_arg1 = null;
        super.setIntention(intention, arg0, arg1);
    }

    @Override
    protected void onIntentionCast(Skill skill, Creature target)
    {
        _skill = skill;
        super.onIntentionCast(skill, target);
    }

    @Override
    public void setNextAction(nextAction action, Object arg0, Object arg1, boolean arg2, boolean arg3)
    {
        _nextAction = action;
        _nextAction_arg0 = arg0;
        _nextAction_arg1 = arg1;
        _nextAction_arg2 = arg2;
        _nextAction_arg3 = arg3;
    }

    public boolean setNextIntention()
    {
        nextAction nextAction = _nextAction;
        Object nextAction_arg0 = _nextAction_arg0;
        Object nextAction_arg1 = _nextAction_arg1;
        boolean nextAction_arg2 = _nextAction_arg2;
        boolean nextAction_arg3 = _nextAction_arg3;

        Playable actor = getActor();
        if(nextAction == null || actor.isActionsDisabled())
            return false;

        Skill skill;
        Creature target;
        GameObject object;

        switch(nextAction)
        {
            case ATTACK:
                if(nextAction_arg0 == null)
                    return false;
                target = (Creature) nextAction_arg0;
                _forceUse = nextAction_arg2;
                _dontMove = nextAction_arg3;
                clearNextAction();
                setIntention(AI_INTENTION_ATTACK, target);
                break;
            case CAST:
                if(nextAction_arg0 == null || nextAction_arg1 == null)
                    return false;
                skill = (Skill) nextAction_arg0;
                target = (Creature) nextAction_arg1;
                _forceUse = nextAction_arg2;
                _dontMove = nextAction_arg3;
                clearNextAction();
                if(!skill.checkCondition(actor, target, _forceUse, _dontMove, true))
                {
                    if(skill.getNextAction() == NextAction.ATTACK && !actor.equals(target))
                    {
                        setNextAction(PlayableAI.nextAction.ATTACK, target, null, _forceUse, false);
                        return setNextIntention();
                    }
                    return false;
                }
                setIntention(AI_INTENTION_CAST, skill, target);
                break;
            case MOVE:
                if(nextAction_arg0 == null || nextAction_arg1 == null)
                    return false;
                Location loc = (Location) nextAction_arg0;
                Integer offset = (Integer) nextAction_arg1;
                clearNextAction();
                actor.moveToLocation(loc, offset, nextAction_arg2);
                break;
            case REST:
                actor.sitDown(null);
                break;
            case INTERACT:
                if(nextAction_arg0 == null)
                    return false;
                object = (GameObject) nextAction_arg0;
                clearNextAction();
                onIntentionInteract(object);
                break;
            case PICKUP:
                if(nextAction_arg0 == null)
                    return false;
                object = (GameObject) nextAction_arg0;
                clearNextAction();
                onIntentionPickUp(object);
                break;
            default:
                return false;
        }
        return true;
    }

    @Override
    public void clearNextAction()
    {
        _nextAction = null;
        _nextAction_arg0 = null;
        _nextAction_arg1 = null;
        _nextAction_arg2 = false;
        _nextAction_arg3 = false;
    }

    @Override
    protected void onEvtFinishCasting()
    {
        if(!setNextIntention())
            setIntention(AI_INTENTION_ACTIVE);
    }

    @Override
    protected void onEvtReadyToAct()
    {
        if(!setNextIntention())
            onEvtThink();
    }

    @Override
    protected void onEvtArrived()
    {
        if(!setNextIntention())
            if(getIntention() == AI_INTENTION_INTERACT || getIntention() == AI_INTENTION_PICK_UP)
                onEvtThink();
            else
                changeIntention(AI_INTENTION_ACTIVE, null, null);
    }

    @Override
    protected void onEvtArrivedTarget()
    {
        switch(getIntention())
        {
            case AI_INTENTION_ATTACK:
                thinkAttack(false);
                break;
            case AI_INTENTION_CAST:
                thinkCast(false);
                break;
            case AI_INTENTION_FOLLOW:
                thinkFollow();
                break;
            default:
                onEvtThink();
                break;
        }
    }

    @Override
    protected final void onEvtThink()
    {
        Playable actor = getActor();
        if(actor.isActionsDisabled())
            return;

        try
        {
            if(thinking++ > 1)
                return;

            switch(getIntention())
            {
                case AI_INTENTION_ACTIVE:
                    thinkActive();
                    break;
                case AI_INTENTION_ATTACK:
                    thinkAttack(true);
                    break;
                case AI_INTENTION_CAST:
                    thinkCast(true);
                    break;
                case AI_INTENTION_PICK_UP:
                    thinkPickUp();
                    break;
                case AI_INTENTION_INTERACT:
                    thinkInteract();
                    break;
                case AI_INTENTION_FOLLOW:
                    thinkFollow();
                    break;
            }
        }
        catch(Exception e)
        {
            _log.error("Unexpected error in PlayableAI.onEvtThink()", e);
        }
        finally
        {
            thinking--;
        }
    }

    protected void thinkActive()
    {

    }

    protected void thinkFollow()
    {
        Playable actor = getActor();

        Creature target = (Creature) _intention_arg0;
        Integer offset = (Integer) _intention_arg1;

        //Находимся слишком далеко цели, либо цель не пригодна для следования
        if(target == null || target.isAlikeDead() || actor.getDistance(target) > 4000 || offset == null)
        {
            clientActionFailed();
            return;
        }

        //Уже следуем за этой целью
        if(actor.isFollow && actor.getFollowTarget() == target)
        {
            clientActionFailed();
            return;
        }

        //Находимся достаточно близко или не можем двигаться - побежим потом ?
        if(actor.isInRange(target, offset + 20) || actor.isMovementDisabled())
            clientActionFailed();

        if(_followTask != null)
        {
            _followTask.cancel(false);
            _followTask = null;
        }

        _followTask = ThreadPoolManager.getInstance().schedule(new ThinkFollow(), 250L);
    }

    protected class ThinkFollow extends RunnableImpl
    {
        @Override
        public void runImpl() throws Exception
        {
            Playable actor = getActor();

            if(getIntention() != AI_INTENTION_FOLLOW)
            {
                // Если пет прекратил преследование, меняем статус, чтобы не пришлось щелкать на кнопку следования 2 раза.
                if((actor.isPet() || actor.isSummon()) && getIntention() == AI_INTENTION_ACTIVE)
                    ((Summon) actor).setFollowMode(false);
                return;
            }

            Creature target = (Creature) _intention_arg0;
            int offset = _intention_arg1 instanceof Integer ? (Integer) _intention_arg1 : 0;

            if(target == null || !target.isVisible() || target.isAlikeDead() || actor.getDistance(target) > 4000)
            {
                setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
                return;
            }

            Player player = actor.getPlayer();
            if(player == null || player.isLogoutStarted() || (actor.isPet() || actor.isSummon()) && player.getPet() != actor)
            {
                setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
                return;
            }

            if(!actor.isInRange(target, offset + 20) && (!actor.isFollow || actor.getFollowTarget() != target))
                actor.followToCharacter(target, offset, false);
            _followTask = ThreadPoolManager.getInstance().schedule(this, 250L);
        }
    }

    protected class ExecuteFollow extends RunnableImpl
    {
        private Creature _target;
        private int _range;

        public ExecuteFollow(Creature target, int range)
        {
            _target = target;
            _range = range;
        }

        @Override
        public void runImpl()
        {
            if(_target.isDoor())
                _actor.moveToLocation(_target.getLoc(), 40, true);
            else
                _actor.followToCharacter(_target, _range, true);
        }
    }

    @Override
    protected void onIntentionInteract(GameObject object)
    {
        Playable actor = getActor();

        if(actor.isActionsDisabled())
        {
            setNextAction(nextAction.INTERACT, object, null, false, false);
            clientActionFailed();
            return;
        }

        clearNextAction();
        changeIntention(AI_INTENTION_INTERACT, object, null);
        onEvtThink();
    }

    protected void thinkInteract()
    {
        Playable actor = getActor();

        GameObject target = (GameObject) _intention_arg0;

        if(target == null)
        {
            setIntention(AI_INTENTION_ACTIVE);
            return;
        }

        int range = (int) (Math.max(30, actor.getMinDistance(target)) + 20);

        if(actor.isInRangeZ(target, range))
        {
            if(actor.isPlayer())
                ((Player) actor).doInteract(target);
            setIntention(AI_INTENTION_ACTIVE);
        }
        else
        {
            actor.moveToLocation(target.getLoc(), 40, true);
            setNextAction(nextAction.INTERACT, target, null, false, false);
        }
    }

    @Override
    protected void onIntentionPickUp(GameObject object)
    {
        Playable actor = getActor();

        if(actor.isActionsDisabled())
        {
            setNextAction(nextAction.PICKUP, object, null, false, false);
            clientActionFailed();
            return;
        }

        clearNextAction();
        changeIntention(AI_INTENTION_PICK_UP, object, null);
        onEvtThink();
    }

    protected void thinkPickUp()
    {
        final Playable actor = getActor();

        final GameObject target = (GameObject) _intention_arg0;

        if(target == null)
        {
            setIntention(AI_INTENTION_ACTIVE);
            return;
        }

        if(actor.isInRange(target, 30) && Math.abs(actor.getZ() - target.getZ())  200 || Math.abs(actor.getZ() - attack_target.getZ()) > 200))
        {
            actor.sendPacket(SystemMsg.CANNOT_SEE_TARGET);
            setIntention(AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
            return;
        }

        range += actor.getMinDistance(attack_target);

        if(actor.isFakeDeath())
            actor.breakFakeDeath();

        if(actor.isInRangeZ(attack_target, range))
        {
            if(!canSee)
            {
                actor.sendPacket(SystemMsg.CANNOT_SEE_TARGET);
                setIntention(AI_INTENTION_ACTIVE);
                actor.sendActionFailed();
                return;
            }

            clientStopMoving(false);
            actor.doAttack(attack_target);
        }
        else if(!_dontMove)
            ThreadPoolManager.getInstance().execute(new ExecuteFollow(attack_target, range - 20));
        else
            actor.sendActionFailed();
    }

    protected void thinkCast(boolean checkRange)
    {
        Playable actor = getActor();

        Creature target = getAttackTarget();

        if(_skill.getSkillType() == SkillType.CRAFT || _skill.isToggle())
        {
            if(_skill.checkCondition(actor, target, _forceUse, _dontMove, true))
                actor.doCast(_skill, target, _forceUse);
            return;
        }

        if(target == null || target.isDead() != _skill.getCorpse() && !_skill.isNotTargetAoE())
        {
            setIntention(AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
            return;
        }

        if(!checkRange)
        {
            // Если скилл имеет следующее действие, назначим это действие после окончания действия скилла
            if(_skill.getNextAction() == NextAction.ATTACK && !actor.equals(target))
                setNextAction(nextAction.ATTACK, target, null, _forceUse, false);
            else
                clearNextAction();

            clientStopMoving();

            if(_skill.checkCondition(actor, target, _forceUse, _dontMove, true))
                actor.doCast(_skill, target, _forceUse);
            else
            {
                setNextIntention();
                if(getIntention() == CtrlIntention.AI_INTENTION_ATTACK)
                    thinkAttack(true);
            }

            return;
        }

        int range = actor.getMagicalAttackRange(_skill);
        if(range  200 || Math.abs(actor.getZ() - target.getZ()) > 200))
        {
            actor.sendPacket(SystemMsg.CANNOT_SEE_TARGET);
            setIntention(AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
            return;
        }

        range += actor.getMinDistance(target);

        if(actor.isFakeDeath())
            actor.breakFakeDeath();

        if(actor.isInRangeZ(target, range) || noRangeSkill)
        {
            if(!noRangeSkill && !canSee)
            {
                actor.sendPacket(SystemMsg.CANNOT_SEE_TARGET);
                setIntention(AI_INTENTION_ACTIVE);
                actor.sendActionFailed();
                return;
            }

            // Если скилл имеет следующее действие, назначим это действие после окончания действия скилла
            if(_skill.getNextAction() == NextAction.ATTACK && !actor.equals(target) && !_forceUse)
            {
                //clearNextAction();
                setNextAction(nextAction.ATTACK, target, null, _forceUse, false);
            }
            else
                clearNextAction();

            if(_skill.checkCondition(actor, target, _forceUse, _dontMove, true))
            {
                clientStopMoving(false);
                actor.doCast(_skill, target, _forceUse);
            }
            else
            {
                setNextIntention();
                if(getIntention() == CtrlIntention.AI_INTENTION_ATTACK)
                    thinkAttack(true);
            }
        }
        else if(!_dontMove)
            ThreadPoolManager.getInstance().execute(new ExecuteFollow(target, range - 20));
        else
        {
            actor.sendPacket(SystemMsg.YOUR_TARGET_IS_OUT_OF_RANGE);
            setIntention(AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
        }
    }

    @Override
    protected void onEvtDead(Creature killer)
    {
        clearNextAction();
        super.onEvtDead(killer);
    }

    @Override
    protected void onEvtFakeDeath()
    {
        clearNextAction();
        super.onEvtFakeDeath();
    }

    public void lockTarget(Creature target)
    {
        Playable actor = getActor();

        if(target == null || target.isDead())
            actor.setAggressionTarget(null);
        else if(actor.getAggressionTarget() == null)
        {
            GameObject actorStoredTarget = actor.getTarget();
            actor.setAggressionTarget(target);
            actor.setTarget(target);

            clearNextAction();
            // DS: агрессия только перекидывает видимую цель, но не обрывает текущую атаку/каст
            /*if (getIntention() == CtrlIntention.AI_INTENTION_ATTACK)
                setAttackTarget(target);
            switch(getIntention())
            {
                case AI_INTENTION_ATTACK:
                    setAttackTarget(target);
                    break;
                case AI_INTENTION_CAST:
                    L2Skill skill = actor.getCastingSkill();
                    if(skill == null)
                        skill = _skill;
                    if(skill != null && !skill.isUsingWhileCasting())
                        switch(skill.getTargetType())
                        {
                            case TARGET_ONE:
                            case TARGET_AREA:
                            case TARGET_MULTIFACE:
                            case TARGET_TUNNEL:
                                setAttackTarget(target);
                                actor.setCastingTarget(target);
                                break;
                        }
                    break;
            }*/

            if(actorStoredTarget != target)
                actor.sendPacket(new MyTargetSelected(target.getObjectId(), 0));
        }
    }

    @Override
    public void Attack(GameObject target, boolean forceUse, boolean dontMove)
    {
        Playable actor = getActor();

        if(target.isCreature() && (actor.isActionsDisabled() || actor.isAttackingDisabled()))
        {
            // Если не можем атаковать, то атаковать позже
            setNextAction(nextAction.ATTACK, target, null, forceUse, false);
            actor.sendActionFailed();
            return;
        }

        _dontMove = dontMove;
        _forceUse = forceUse;
        clearNextAction();
        setIntention(AI_INTENTION_ATTACK, target);
    }

    @Override
    public void Cast(Skill skill, Creature target, boolean forceUse, boolean dontMove)
    {
        Playable actor = getActor();

        // Если скилл альтернативного типа (например, бутылка на хп),
        // то он может использоваться во время каста других скиллов, или во время атаки, или на бегу.
        // Поэтому пропускаем дополнительные проверки.
        if(skill.altUse() || skill.isToggle())
        {
            if((skill.isToggle() || skill.isHandler()) && (actor.isOutOfControl() || actor.isStunned() || actor.isSleeping() || actor.isParalyzed() || actor.isAlikeDead()))
                clientActionFailed();
            else
                actor.altUseSkill(skill, target);
            return;
        }

        // Если не можем кастовать, то использовать скилл позже
        if(actor.isActionsDisabled())
        {
            //if(!actor.isSkillDisabled(skill.getId()))
            setNextAction(nextAction.CAST, skill, target, forceUse, dontMove);
            clientActionFailed();
            return;
        }

        //_actor.stopMove(null);
        _forceUse = forceUse;
        _dontMove = dontMove;
        clearNextAction();
        setIntention(CtrlIntention.AI_INTENTION_CAST, skill, target);
    }

    @Override
    public Playable getActor()
    {
        return (Playable) super.getActor();
    }
}
Цитата:
Сообщение от Спойлер  


PHP:


Код:
package l2p.gameserver.ai;

import static java.lang.Math.abs;
import static java.lang.Math.max;
import java.util.concurrent.ScheduledFuture;
import l2p.commons.threading.RunnableImpl;
import static l2p.gameserver.ThreadPoolManager.getInstance;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
import static l2p.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
import static l2p.gameserver.ai.PlayableAI.nextAction.ATTACK;
import static l2p.gameserver.ai.PlayableAI.nextAction.CAST;
import static l2p.gameserver.ai.PlayableAI.nextAction.INTERACT;
import static l2p.gameserver.ai.PlayableAI.nextAction.PICKUP;
import static l2p.gameserver.geodata.GeoEngine.canSeeTarget;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.GameObject;
import l2p.gameserver.model.Playable;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.Skill;
import static l2p.gameserver.model.Skill.SkillType.CRAFT;
import static l2p.gameserver.model.Skill.SkillType.TAKECASTLE;
import static l2p.gameserver.model.Skill.SkillType.TAKEFORTRESS;
import l2p.gameserver.model.Summon;
import l2p.gameserver.serverpackets.MyTargetSelected;
import static l2p.gameserver.serverpackets.components.SystemMsg.CANNOT_SEE_TARGET;
import static l2p.gameserver.serverpackets.components.SystemMsg.YOUR_TARGET_IS_OUT_OF_RANGE;
import l2p.gameserver.utils.Location;

public class PlayableAI extends CharacterAI
{
    private volatile int thinking = 0; // to prevent recursive thinking
    private Object _intention_arg0 = null;
    private Object _intention_arg1 = null;
    private Skill _skill;

    private nextAction _nextAction;
    private Object _nextAction_arg0;
    private Object _nextAction_arg1;
    private boolean _nextAction_arg2;
    private boolean _nextAction_arg3;

    private boolean _forceUse;
    private boolean _dontMove;

    private ScheduledFuture
 _followTask;

    public PlayableAI(Playable actor)
    {
        super(actor);
    }

    /**
     * @return the thinking
     */
    public int getThinking() {
        return thinking;
    }

    /**
     * @param thinking the thinking to set
     */
    public void setThinking(int thinking) {
        this.thinking = thinking;
    }

    /**
     * @return the _intention_arg0
     */
    public Object getIntention_arg0() {
        return _intention_arg0;
    }

    /**
     * @param _intention_arg0 the _intention_arg0 to set
     */
    public void setIntention_arg0(Object _intention_arg0) {
        this._intention_arg0 = _intention_arg0;
    }

    /**
     * @return the _intention_arg1
     */
    public Object getIntention_arg1() {
        return _intention_arg1;
    }

    /**
     * @param _intention_arg1 the _intention_arg1 to set
     */
    public void setIntention_arg1(Object _intention_arg1) {
        this._intention_arg1 = _intention_arg1;
    }

    /**
     * @return the _skill
     */
    public Skill getSkill() {
        return _skill;
    }

    /**
     * @param _skill the _skill to set
     */
    public void setSkill(Skill _skill) {
        this._skill = _skill;
    }

    /**
     * @return the _nextAction
     */
    public nextAction getNextAction() {
        return _nextAction;
    }

    /**
     * @param _nextAction the _nextAction to set
     */
    public void setNextAction(nextAction _nextAction) {
        this._nextAction = _nextAction;
    }

    /**
     * @return the _nextAction_arg0
     */
    public Object getNextAction_arg0() {
        return _nextAction_arg0;
    }

    /**
     * @param _nextAction_arg0 the _nextAction_arg0 to set
     */
    public void setNextAction_arg0(Object _nextAction_arg0) {
        this._nextAction_arg0 = _nextAction_arg0;
    }

    /**
     * @return the _nextAction_arg1
     */
    public Object getNextAction_arg1() {
        return _nextAction_arg1;
    }

    /**
     * @param _nextAction_arg1 the _nextAction_arg1 to set
     */
    public void setNextAction_arg1(Object _nextAction_arg1) {
        this._nextAction_arg1 = _nextAction_arg1;
    }

    /**
     * @return the _nextAction_arg2
     */
    public boolean isNextAction_arg2() {
        return _nextAction_arg2;
    }

    /**
     * @param _nextAction_arg2 the _nextAction_arg2 to set
     */
    public void setNextAction_arg2(boolean _nextAction_arg2) {
        this._nextAction_arg2 = _nextAction_arg2;
    }

    /**
     * @return the _nextAction_arg3
     */
    public boolean isNextAction_arg3() {
        return _nextAction_arg3;
    }

    /**
     * @param _nextAction_arg3 the _nextAction_arg3 to set
     */
    public void setNextAction_arg3(boolean _nextAction_arg3) {
        this._nextAction_arg3 = _nextAction_arg3;
    }

    /**
     * @return the _forceUse
     */
    public boolean isForceUse() {
        return _forceUse;
    }

    /**
     * @param _forceUse the _forceUse to set
     */
    public void setForceUse(boolean _forceUse) {
        this._forceUse = _forceUse;
    }

    /**
     * @return the _dontMove
     */
    public boolean isDontMove() {
        return _dontMove;
    }

    /**
     * @param _dontMove the _dontMove to set
     */
    public void setDontMove(boolean _dontMove) {
        this._dontMove = _dontMove;
    }

    /**
     * @return the _followTask
     */
    public ScheduledFuture
getFollowTask() {
        return _followTask;
    }

    /**
     * @param _followTask the _followTask to set
     */
    public void setFollowTask(ScheduledFuture
 _followTask) {
        this._followTask = _followTask;
    }

    public enum nextAction
    {
        ATTACK,
        CAST,
        MOVE,
        REST,
        PICKUP,
        INTERACT
    }

    @Override
    public void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
    {
        super.changeIntention(intention, arg0, arg1);
        setIntention_arg0(arg0);
        setIntention_arg1(arg1);
    }

    @Override
    public void setIntention(CtrlIntention intention, Object arg0, Object arg1)
    {
        setIntention_arg0(null);
        setIntention_arg1(null);
        super.setIntention(intention, arg0, arg1);
    }

    @Override
    protected void onIntentionCast(Skill skill, Creature target)
    {
        setSkill(skill);
        super.onIntentionCast(skill, target);
    }

    @Override
    public void setNextAction(nextAction action, Object arg0, Object arg1, boolean arg2, boolean arg3)
    {
        setNextAction(action);
        setNextAction_arg0(arg0);
        setNextAction_arg1(arg1);
        setNextAction_arg2(arg2);
        setNextAction_arg3(arg3);
    }

    public boolean setNextIntention()
    {
        nextAction nextAction = getNextAction();
        Object nextAction_arg0 = getNextAction_arg0();
        Object nextAction_arg1 = getNextAction_arg1();
        boolean nextAction_arg2 = isNextAction_arg2();
        boolean nextAction_arg3 = isNextAction_arg3();

        Playable actor = getActor();
        if(nextAction == null || actor.isActionsDisabled())
            return false;

        Skill skill;
        Creature target;
        GameObject object;

        switch(nextAction)
        {
            case ATTACK:
                if(nextAction_arg0 == null)
                    return false;
                target = (Creature) nextAction_arg0;
                setForceUse(nextAction_arg2);
                setDontMove(nextAction_arg3);
                clearNextAction();
                setIntention(AI_INTENTION_ATTACK, target);
                break;
            case CAST:
                if(nextAction_arg0 == null || nextAction_arg1 == null)
                    return false;
                skill = (Skill) nextAction_arg0;
                target = (Creature) nextAction_arg1;
                setForceUse(nextAction_arg2);
                setDontMove(nextAction_arg3);
                clearNextAction();
                if(!skill.checkCondition(actor, target, _forceUse, _dontMove, true))
                {
                    if(skill.getNextAction() == ATTACK && !actor.equals(target))
                    {
                        setNextAction(ATTACK, target, null, isForceUse(), false);
                        return setNextIntention();
                    }
                    return false;
                }
                setIntention(AI_INTENTION_CAST, skill, target);
                break;
            case MOVE:
                if(nextAction_arg0 == null || nextAction_arg1 == null)
                    return false;
                Location loc = (Location) nextAction_arg0;
                Integer offset = (Integer) nextAction_arg1;
                clearNextAction();
                actor.moveToLocation(loc, offset, nextAction_arg2);
                break;
            case REST:
                actor.sitDown(null);
                break;
            case INTERACT:
                if(nextAction_arg0 == null)
                    return false;
                object = (GameObject) nextAction_arg0;
                clearNextAction();
                onIntentionInteract(object);
                break;
            case PICKUP:
                if(nextAction_arg0 == null)
                    return false;
                object = (GameObject) nextAction_arg0;
                clearNextAction();
                onIntentionPickUp(object);
                break;
            default:
                return false;
        }
        return true;
    }

    @Override
    public void clearNextAction()
    {
        setNextAction(null);
        setNextAction_arg0(null);
        setNextAction_arg1(null);
        setNextAction_arg2(false);
        setNextAction_arg3(false);
    }

    @Override
    protected void onEvtFinishCasting()
    {
        if(!setNextIntention())
            setIntention(AI_INTENTION_ACTIVE);
    }

    @Override
    protected void onEvtReadyToAct()
    {
        if(!setNextIntention())
            onEvtThink();
    }

    @Override
    protected void onEvtArrived()
    {
        if(!setNextIntention())
            if(getIntention() == AI_INTENTION_INTERACT || getIntention() == AI_INTENTION_PICK_UP)
                onEvtThink();
            else
                changeIntention(AI_INTENTION_ACTIVE, null, null);
    }

    @Override
    protected void onEvtArrivedTarget()
    {
        switch(getIntention())
        {
            case AI_INTENTION_ATTACK:
                thinkAttack(false);
                break;
            case AI_INTENTION_CAST:
                thinkCast(false);
                break;
            case AI_INTENTION_FOLLOW:
                thinkFollow();
                break;
            default:
                onEvtThink();
                break;
        }
    }

    @Override
    protected final void onEvtThink()
    {
        Playable actor = getActor();
        if(actor.isActionsDisabled())
            return;

        try
        {
            if(thinking++ > 1)
                return;

            switch(getIntention())
            {
                case AI_INTENTION_ACTIVE:
                    thinkActive();
                    break;
                case AI_INTENTION_ATTACK:
                    thinkAttack(true);
                    break;
                case AI_INTENTION_CAST:
                    thinkCast(true);
                    break;
                case AI_INTENTION_PICK_UP:
                    thinkPickUp();
                    break;
                case AI_INTENTION_INTERACT:
                    thinkInteract();
                    break;
                case AI_INTENTION_FOLLOW:
                    thinkFollow();
                    break;
            }
        }
        catch(Exception e)
        {
            _log.error("Unexpected error in PlayableAI.onEvtThink()", e);
        }
        finally
        {
            setThinking(getThinking() - 1);
        }
    }

    protected void thinkActive()
    {

    }

    protected void thinkFollow()
    {
        Playable actor = getActor();

        Creature target = (Creature) getIntention_arg0();
        Integer offset = (Integer) getIntention_arg1();

        //Находимся слишком далеко цели, либо цель не пригодна для следования
        if(target == null || target.isAlikeDead() || actor.getDistance(target) > 4000 || offset == null)
        {
            clientActionFailed();
            return;
        }

        //Уже следуем за этой целью
        if(actor.isFollow && actor.getFollowTarget() == target)
        {
            clientActionFailed();
            return;
        }

        //Находимся достаточно близко или не можем двигаться - побежим потом ?
        if(actor.isInRange(target, offset + 20) || actor.isMovementDisabled())
            clientActionFailed();

        if(getFollowTask() != null)
        {
            getFollowTask().cancel(false);
            setFollowTask(null);
        }

        setFollowTask(getInstance().schedule(new ThinkFollow(), 250L));
    }

    protected class ThinkFollow extends RunnableImpl
    {
        @Override
        public void runImpl() throws Exception
        {
            Playable actor = getActor();

            if(getIntention() != AI_INTENTION_FOLLOW)
            {
                // Если пет прекратил преследование, меняем статус, чтобы не пришлось щелкать на кнопку следования 2 раза.
                if((actor.isPet() || actor.isSummon()) && getIntention() == AI_INTENTION_ACTIVE)
                    ((Summon) actor).setFollowMode(false);
                return;
            }

            Creature target = (Creature) getIntention_arg0();
            int offset = getIntention_arg1() instanceof Integer ? (Integer) getIntention_arg1() : 0;

            if(target == null || !target.isVisible() || target.isAlikeDead() || actor.getDistance(target) > 4000)
            {
                setIntention(AI_INTENTION_ACTIVE);
                return;
            }

            Player player = actor.getPlayer();
            if(player == null || player.isLogoutStarted() || (actor.isPet() || actor.isSummon()) && player.getPet() != actor)
            {
                setIntention(AI_INTENTION_ACTIVE);
                return;
            }

            if(!actor.isInRange(target, offset + 20) && (!actor.isFollow || actor.getFollowTarget() != target))
                actor.followToCharacter(target, offset, false);
            setFollowTask(getInstance().schedule(this, 250L));
        }
    }

    protected class ExecuteFollow extends RunnableImpl
    {
        private final Creature _target;
        private final int _range;

        public ExecuteFollow(Creature target, int range)
        {
            _target = target;
            _range = range;
        }

        @Override
        public void runImpl()
        {
            if(_target.isDoor())
                _actor.moveToLocation(_target.getLoc(), 40, true);
            else
                _actor.followToCharacter(_target, _range, true);
        }
    }

    @Override
    protected void onIntentionInteract(GameObject object)
    {
        Playable actor = getActor();

        if(actor.isActionsDisabled())
        {
            setNextAction(INTERACT, object, null, false, false);
            clientActionFailed();
            return;
        }

        clearNextAction();
        changeIntention(AI_INTENTION_INTERACT, object, null);
        onEvtThink();
    }

    protected void thinkInteract()
    {
        Playable actor = getActor();

        GameObject target = (GameObject) getIntention_arg0();

        if(target == null)
        {
            setIntention(AI_INTENTION_ACTIVE);
            return;
        }

        int range = (int) (max(30, actor.getMinDistance(target)) + 20);

        if(actor.isInRangeZ(target, range))
        {
            if(actor.isPlayer())
                ((Player) actor).doInteract(target);
            setIntention(AI_INTENTION_ACTIVE);
        }
        else
        {
            actor.moveToLocation(target.getLoc(), 40, true);
            setNextAction(INTERACT, target, null, false, false);
        }
    }

    @Override
    protected void onIntentionPickUp(GameObject object)
    {
        Playable actor = getActor();

        if(actor.isActionsDisabled())
        {
            setNextAction(PICKUP, object, null, false, false);
            clientActionFailed();
            return;
        }

        clearNextAction();
        changeIntention(AI_INTENTION_PICK_UP, object, null);
        onEvtThink();
    }

    protected void thinkPickUp()
    {
        final Playable actor = getActor();

        final GameObject target = (GameObject) getIntention_arg0();

        if(target == null)
        {
            setIntention(AI_INTENTION_ACTIVE);
            return;
        }

        if(actor.isInRange(target, 30) && abs(actor.getZ() - target.getZ())  200 || abs(actor.getZ() - attack_target.getZ()) > 200))
        {
            actor.sendPacket(CANNOT_SEE_TARGET);
            setIntention(AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
            return;
        }

        range += actor.getMinDistance(attack_target);

        if(actor.isFakeDeath())
            actor.breakFakeDeath();

        if(actor.isInRangeZ(attack_target, range))
        {
            if(!canSee)
            {
                actor.sendPacket(CANNOT_SEE_TARGET);
                setIntention(AI_INTENTION_ACTIVE);
                actor.sendActionFailed();
                return;
            }

            clientStopMoving(false);
            actor.doAttack(attack_target);
        }
        else if(!isDontMove())
            getInstance().execute(new ExecuteFollow(attack_target, range - 20));
        else
            actor.sendActionFailed();
    }

    protected void thinkCast(boolean checkRange)
    {
        Playable actor = getActor();

        Creature target = getAttackTarget();

        if(getSkill().getSkillType() == CRAFT || getSkill().isToggle())
        {
            if(getSkill().checkCondition(actor, target, isForceUse(), isDontMove(), true))
                actor.doCast(getSkill(), target, isForceUse());
            return;
        }

        if(target == null || target.isDead() != getSkill().getCorpse() && !_skill.isNotTargetAoE())
        {
            setIntention(AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
            return;
        }

        if(!checkRange)
        {
            // Если скилл имеет следующее действие, назначим это действие после окончания действия скилла
            if(getSkill().getNextAction() == ATTACK && !actor.equals(target))
                setNextAction(ATTACK, target, null, isForceUse(), false);
            else
                clearNextAction();

            clientStopMoving();

            if(getSkill().checkCondition(actor, target, isForceUse(), isDontMove(), true))
                actor.doCast(getSkill(), target, isForceUse());
            else
            {
                setNextIntention();
                if(getIntention() == AI_INTENTION_ATTACK)
                    thinkAttack(true);
            }

            return;
        }

        int range = actor.getMagicalAttackRange(getSkill());
        if(range  200 || abs(actor.getZ() - target.getZ()) > 200))
        {
            actor.sendPacket(CANNOT_SEE_TARGET);
            setIntention(AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
            return;
        }

        range += actor.getMinDistance(target);

        if(actor.isFakeDeath())
            actor.breakFakeDeath();

        if(actor.isInRangeZ(target, range) || noRangeSkill)
        {
            if(!noRangeSkill && !canSee)
            {
                actor.sendPacket(CANNOT_SEE_TARGET);
                setIntention(AI_INTENTION_ACTIVE);
                actor.sendActionFailed();
                return;
            }

            // Если скилл имеет следующее действие, назначим это действие после окончания действия скилла
            if(getSkill().getNextAction() == ATTACK && !actor.equals(target) && !isForceUse())
            {
                //clearNextAction();
                setNextAction(ATTACK, target, null, isForceUse(), false);
            }
            else
                clearNextAction();

            if(getSkill().checkCondition(actor, target, isForceUse(), isDontMove(), true))
            {
                clientStopMoving(false);
                actor.doCast(getSkill(), target, isForceUse());
            }
            else
            {
                setNextIntention();
                if(getIntention() == AI_INTENTION_ATTACK)
                    thinkAttack(true);
            }
        }
        else if(!isDontMove())
            getInstance().execute(new ExecuteFollow(target, range - 20));
        else
        {
            actor.sendPacket(YOUR_TARGET_IS_OUT_OF_RANGE);
            setIntention(AI_INTENTION_ACTIVE);
            actor.sendActionFailed();
        }
    }

    @Override
    protected void onEvtDead(Creature killer)
    {
        clearNextAction();
        super.onEvtDead(killer);
    }

    @Override
    protected void onEvtFakeDeath()
    {
        clearNextAction();
        super.onEvtFakeDeath();
    }

    public void lockTarget(Creature target)
    {
        Playable actor = getActor();

        if(target == null || target.isDead())
            actor.setAggressionTarget(null);
        else if(actor.getAggressionTarget() == null)
        {
            GameObject actorStoredTarget = actor.getTarget();
            actor.setAggressionTarget(target);
            actor.setTarget(target);

            clearNextAction();
            // DS: агрессия только перекидывает видимую цель, но не обрывает текущую атаку/каст
            /*if (getIntention() == CtrlIntention.AI_INTENTION_ATTACK)
                setAttackTarget(target);
            switch(getIntention())
            {
                case AI_INTENTION_ATTACK:
                    setAttackTarget(target);
                    break;
                case AI_INTENTION_CAST:
                    L2Skill skill = actor.getCastingSkill();
                    if(skill == null)
                        skill = _skill;
                    if(skill != null && !skill.isUsingWhileCasting())
                        switch(skill.getTargetType())
                        {
                            case TARGET_ONE:
                            case TARGET_AREA:
                            case TARGET_MULTIFACE:
                            case TARGET_TUNNEL:
                                setAttackTarget(target);
                                actor.setCastingTarget(target);
                                break;
                        }
                    break;
            }*/

            if(actorStoredTarget != target)
                actor.sendPacket(new MyTargetSelected(target.getObjectId(), 0));
        }
    }

    @Override
    public void Attack(GameObject target, boolean forceUse, boolean dontMove)
    {
        Playable actor = getActor();

        if(target.isCreature() && (actor.isActionsDisabled() || actor.isAttackingDisabled()))
        {
            // Если не можем атаковать, то атаковать позже
            setNextAction(ATTACK, target, null, forceUse, false);
            actor.sendActionFailed();
            return;
        }

        setDontMove(dontMove);
        setForceUse(forceUse);
        clearNextAction();
        setIntention(AI_INTENTION_ATTACK, target);
    }

    @Override
    public void Cast(Skill skill, Creature target, boolean forceUse, boolean dontMove)
    {
        Playable actor = getActor();

        // Если скилл альтернативного типа (например, бутылка на хп),
        // то он может использоваться во время каста других скиллов, или во время атаки, или на бегу.
        // Поэтому пропускаем дополнительные проверки.
        if(skill.altUse() || skill.isToggle())
        {
            if((skill.isToggle() || skill.isHandler()) && (actor.isOutOfControl() || actor.isStunned() || actor.isSleeping() || actor.isParalyzed() || actor.isAlikeDead()))
                clientActionFailed();
            else
                actor.altUseSkill(skill, target);
            return;
        }

        // Если не можем кастовать, то использовать скилл позже
        if(actor.isActionsDisabled())
        {
            //if(!actor.isSkillDisabled(skill.getId()))
            setNextAction(CAST, skill, target, forceUse, dontMove);
            clientActionFailed();
            return;
        }

        //_actor.stopMove(null);
        setForceUse(forceUse);
        setDontMove(dontMove);
        clearNextAction();
        setIntention(AI_INTENTION_CAST, skill, target);
    }

    @Override
    public Playable getActor()
    {
        return (Playable) super.getActor();
    }
}
 
Ответить с цитированием

  #3  
Старый 06.04.2016, 03:46
Wolfer
Участник форума
Регистрация: 05.04.2016
Сообщений: 222
С нами: 5318817

Репутация: 0
По умолчанию

Цитата:
Сообщение от Спойлер  


PHP:


Код:
package ai
;
import l2p
.
commons
.
util
.
Rnd
;
import l2p
.
gameserver
.
ai
.
CtrlIntention
;
import l2p
.
gameserver
.
ai
.
Fighter
;
import l2p
.
gameserver
.
configs
.
proprties
.
ServerConfig
;
import l2p
.
gameserver
.
geodata
.
GeoEngine
;
import l2p
.
gameserver
.
model
.
Creature
;
import l2p
.
gameserver
.
model
.
Playable
;
import l2p
.
gameserver
.
model
.
instances
.
NpcInstance
;
import l2p
.
gameserver
.
tables
.
SkillTable
;
/**
* Created by STIGMATED
* Date: 12.11.11 Time: 12:43
*/
public
class
BossRandomAi
extends
Fighter
{
// private static final int BossId = 91107;
private
int current_point
=
-
1
;
private
long _lastAction
;
// private static final long Teleport_period = 7200000; //30 * 60 * 1000= 30 min
// private long _lastTeleport = System.currentTimeMillis();
String
[
]
_attackText
=
{
"Эй, ты офигел чтоли! "
,
"Эээ.. мне же больно :("
,
"Папа у Васи осёл в математике!"
,
"Советую вам не следовать моим советам."
,
"Мы с тревогой смотрим на будущее, а будущее с тревогой смотрит на нас."
,
"Мне чужого не надо….Но свое я заберу, чье бы оно ни было!!!"
,
"Успокойся и не ной. Всё равно ты будешь мой"
,
"Кстати, а тут все из разных мест? Или из одного?"
,
"Как сервер, стоит играть?"
,
"Ничто так не защищает мои зубы 12 часов днём и 12 часов ночью, как уважительное отношение к окружающим."
,
"Она: Все, я обиделась, тебе на меня наплевать, пойду в интернет и буду изменять тебе в онлайне! Касперского возьми!"
,
"Есть еще похер в похеровницах."
,
"Жизнь нужно прожить так, чтобы Боги в восторге предложили еще одну…"
,
"В погоне за зайцем многие подстреливают волка, испытывая минутное удовольствие, но в целом охота в данном случае является бессмысленной, поскольку они лишили цели волка и не достигли своей."
,
"Неважно, что вам говорят - вам говорят не всю правду"
,
"Все люди братья. Но некоторые сестры"
,
"Начни день весело: улыбни своё лицо!"
,
"Все имеют право на тупость, просто некоторые очень злоупотребляют."
,
"Никто не знает столько, сколько не знаю я!"
,
"Снимаю. Поpчy."
,
"Громче голову поворачивай!"
,
"Что вы на меня свое лицо вытаращили?"
,
"Я вас не спрашиваю, где вы были! Я спрашиваю, откуда вы идете?"
,
"Чтоб не киснуть - надо квасить!"
,
"Смерть застала его живым."
,
"Фаллический символ всегда лучше, чем символический фаллос."
,
"Неудачи преследуют всех. Но догоняют лишь неудачников."
,
"Жизнь прекрасна, рефлексы условны, а истина относительна."
,
"Первая заповедь холостяка: Не трогай пыль и она тебя не тронет."
,
"Спокойно! Уж в грязь лицом я не промахнусь!"
,
"В Китае нет понятия «изменил». Есть понятие «перепутал»."
,
"Труднее всего человеку дается то, что дается не ему."
}
;
public
BossRandomAi
(
Creature actor
)
{
super
(
(
NpcInstance
)
actor
)
;
}
@Override
protected
boolean
thinkActive
(
)
{
return
true
;
}
@Override
protected
void
onEvtAttacked
(
Creature attacker
,
int damage
)
{
NpcInstance actor
=
getActor
(
)
;
if
(
attacker
==
null
||
attacker
.
getPlayer
(
)
==
null
)
return
;
actor
.
startAttackStanceTask
(
)
;
// Ругаемся и кастуем скилл не чаще, чем раз в 3 секунды
if
(
System
.
currentTimeMillis
(
)
-
_lastAction
>
27000
)
{
int chance
=
Rnd
.
get
(
0
,
100
)
;
if
(
chance

400
)
return
false
;
// if ((Functions.getItemCount((L2Playable) target, 32100) != 0) || (Functions.getItemCount((L2Playable) target, 700) != 0))
// return;
if
(
!
GeoEngine
.
canSeeTarget
(
actor
,
target
,
actor
.
isFlying
(
)
)
)
return
false
;
// target.addDamageHate((Creature)actor, 0, 1);
setIntention
(
CtrlIntention
.
AI_INTENTION_ATTACK
,
target
)
;
String lang
=
ServerConfig
.
DefaultLang
;
if
(
lang
.
equalsIgnoreCase
(
"en"
)
)
actor
.
Say
(
"Die, noob!"
)
;
else
{
actor
.
Say
(
"Умри, Умри!"
)
;
}
if
(
(
getIntention
(
)
!=
CtrlIntention
.
AI_INTENTION_ACTIVE
)
&&
(
this
.
current_point
>
-
1
)
)
this
.
current_point
-
=
1
;
return
true
;
}
@Override
protected
void
onEvtDead
(
Creature killer
)
{
NpcInstance actor
=
getActor
(
)
;
if
(
actor
==
null
)
return
;
// actor.deleteMe();
_log
.
info
(
"убили гада"
)
;
super
.
onEvtDead
(
killer
)
;
}
}
 
Ответить с цитированием

  #4  
Старый 06.04.2016, 08:18
ツsmile10ツ
Познавший АНТИЧАТ
Регистрация: 23.02.2015
Сообщений: 1,608
С нами: 5904866

Репутация: 2646


По умолчанию

юзать слф4ж в 2016?
 
Ответить с цитированием

  #5  
Старый 06.04.2016, 14:50
GenCloud
Постоянный
Регистрация: 13.04.2015
Сообщений: 454
С нами: 5834308

Репутация: 2128
По умолчанию

ждо за высер?
 
Ответить с цитированием

  #6  
Старый 06.04.2016, 16:34
kick
Флудер
Регистрация: 20.01.2015
Сообщений: 7,201
С нами: 5952720

Репутация: 6527


По умолчанию

?
 
Ответить с цитированием

  #7  
Старый 06.04.2016, 16:35
kick
Флудер
Регистрация: 20.01.2015
Сообщений: 7,201
С нами: 5952720

Репутация: 6527


По умолчанию

Цитата:
Сообщение от Wolfer  

Для основы взял 2 варианта исходного кода L2jserver и Overworld, оба варианта хроник High Five
Сразу удивило различие в конструктивности и построении основ, что я немного запутался т.к. опыта в этой сфере нет...
И щас какую то хрень пишешь.
 
Ответить с цитированием

  #8  
Старый 06.04.2016, 16:37
6yka
Познавший АНТИЧАТ
Регистрация: 07.11.2015
Сообщений: 1,730
С нами: 5534362

Репутация: 1617


По умолчанию

лыжа и овер несравнимы... даже такой наркОмэн как я это понимаю))))
 
Ответить с цитированием

  #9  
Старый 07.04.2016, 07:00
Wolfer
Участник форума
Регистрация: 05.04.2016
Сообщений: 222
С нами: 5318817

Репутация: 0
По умолчанию

:-D спасибо за конструктивную критику
 
Ответить с цитированием

  #10  
Старый 07.04.2016, 10:29
mAnGoL
Новичок
Регистрация: 21.01.2010
Сообщений: 0
С нами: 8581120

Репутация: 0
По умолчанию

[OFF]Анциент, или растаруев. [/OFF]

Очередные прокси недерландов, львова и других стран.
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.

×

Внести депозит

Введите сумму USDT:

Принимается только USDT TRC20. Fake/Flash USDT не засчитывается.

×

Вывести депозит

Сумма USDT:

Ваш USDT TRC20 кошелек:

Заявка будет отправлена администратору. Комиссия форума: 2%.

×

Создать сделку

Продавец: ник или ID

Название сделки:

Сумма USDT:

Срок сделки, дней:

Кто платит комиссию:

Условия сделки:

После создания сделки средства будут зарезервированы в холде до завершения сделки.

×

Мои сделки

Загрузка...
×

Сделка


Загрузка чата...
×

ESCROW ADMIN PANEL

Загрузка...
Загрузка...