/* * Copyright (C) 2004-2015 L2J Server * * This file is part of L2J Server. * * L2J Server is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * L2J Server is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.l2jserver.gameserver.model.actor.tasks.cubics; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; import com.l2jserver.Config; import com.l2jserver.gameserver.model.actor.L2Character; import com.l2jserver.gameserver.model.actor.L2Summon; import com.l2jserver.gameserver.model.actor.instance.L2CubicInstance; import com.l2jserver.gameserver.model.effects.L2EffectType; import com.l2jserver.gameserver.model.skills.BuffInfo; import com.l2jserver.gameserver.model.skills.Skill; import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse; import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager; import com.l2jserver.util.Rnd; /** * Cubic action task. * @author Zoey76 */ public final class CubicAction implements Runnable { private static final Logger _log = Logger.getLogger(CubicAction.class.getName()); private final L2CubicInstance _cubic; private final AtomicInteger _currentCount = new AtomicInteger(); private final int _chance; public CubicAction(L2CubicInstance cubic, int chance) { _cubic = cubic; _chance = chance; } @Override public void run() { if (_cubic == null) { return; } try { if (_cubic.getOwner().isDead() || !_cubic.getOwner().isOnline()) { _cubic.stopAction(); _cubic.getOwner().getCubics().remove(_cubic.getId()); _cubic.getOwner().broadcastUserInfo(); _cubic.cancelDisappear(); return; } if (!AttackStanceTaskManager.getInstance().hasAttackStanceTask(_cubic.getOwner())) { if (_cubic.getOwner().hasSummon()) { for (L2Summon servitor : _cubic.getOwner().getServitors().values()) { if (!AttackStanceTaskManager.getInstance().hasAttackStanceTask(servitor)) { _cubic.stopAction(); return; } } } else { _cubic.stopAction(); return; } } // The cubic has already reached its limit and it will stay idle until its duration ends. if ((_cubic.getCubicMaxCount() > -1) && (_currentCount.get() >= _cubic.getCubicMaxCount())) { _cubic.stopAction(); return; } // Smart Cubic debuff cancel is 100% boolean useCubicCure = false; if ((_cubic.getId() >= L2CubicInstance.SMART_CUBIC_EVATEMPLAR) && (_cubic.getId() <= L2CubicInstance.SMART_CUBIC_SPECTRALMASTER)) { for (BuffInfo info : _cubic.getOwner().getEffectList().getDebuffs().values()) { if (info.getSkill().canBeDispeled()) { useCubicCure = true; info.getEffected().getEffectList().stopSkillEffects(true, info.getSkill()); } } } if (useCubicCure) { // Smart Cubic debuff cancel is needed, no other skill is used in this activation period MagicSkillUse msu = new MagicSkillUse(_cubic.getOwner(), _cubic.getOwner(), L2CubicInstance.SKILL_CUBIC_CURE, 1, 0, 0); _cubic.getOwner().broadcastPacket(msu); // The cubic has done an action, increase the current count _currentCount.incrementAndGet(); } else if (Rnd.get(1, 100) < _chance) { Skill skill = _cubic.getSkills().get(Rnd.get(_cubic.getSkills().size())); if (skill != null) { if (skill.getId() == L2CubicInstance.SKILL_CUBIC_HEAL) { // friendly skill, so we look a target in owner's party _cubic.cubicTargetForHeal(); } else { // offensive skill, we look for an enemy target _cubic.getCubicTarget(); if (!L2CubicInstance.isInCubicRange(_cubic.getOwner(), _cubic.getTarget())) { _cubic.setTarget(null); } } L2Character target = _cubic.getTarget(); if ((target != null) && !target.isDead()) { if (Config.DEBUG) { _log.info("L2CubicInstance: Action.run();"); _log.info("Cubic ID: " + _cubic.getId() + " Target: " + target.getName() + " distance: " + target.calculateDistance(_cubic.getOwner(), true, false)); } _cubic.getOwner().broadcastPacket(new MagicSkillUse(_cubic.getOwner(), target, skill.getId(), skill.getLevel(), 0, 0)); L2Character[] targets = { target }; if (skill.isContinuous()) { if (Config.DEBUG) { _log.info("L2CubicInstance: Action.run() skill " + skill); } _cubic.useCubicContinuous(skill, targets); } else { skill.activateSkill(_cubic.getOwner(), targets); if (Config.DEBUG) { _log.info("L2CubicInstance: Action.run(); other handler"); } } if (skill.hasEffectType(L2EffectType.MAGICAL_ATTACK)) { if (Config.DEBUG) { _log.info("L2CubicInstance: Action.run() skill " + skill); } _cubic.useCubicMdam(_cubic, skill, targets); } else if (skill.hasEffectType(L2EffectType.HP_DRAIN)) { if (Config.DEBUG) { _log.info("L2CubicInstance: Action.run() skill " + skill); } _cubic.useCubicDrain(_cubic, skill, targets); } else if (skill.hasEffectType(L2EffectType.STUN, L2EffectType.ROOT, L2EffectType.PARALYZE)) { if (Config.DEBUG) { _log.info("L2CubicInstance: Action.run() skill " + skill); } _cubic.useCubicDisabler(skill, targets); } else if (skill.hasEffectType(L2EffectType.DMG_OVER_TIME, L2EffectType.DMG_OVER_TIME_PERCENT)) { if (Config.DEBUG) { _log.info("L2CubicInstance: Action.run() skill " + skill); } _cubic.useCubicContinuous(skill, targets); } else if (skill.hasEffectType(L2EffectType.AGGRESSION)) { if (Config.DEBUG) { _log.info("L2CubicInstance: Action.run() skill " + skill); } _cubic.useCubicDisabler(skill, targets); } // The cubic has done an action, increase the current count _currentCount.incrementAndGet(); } } } } catch (Exception e) { _log.log(Level.SEVERE, "", e); } } }