/*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If
* not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jfrozen.gameserver.model.actor.instance;
import java.util.List;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import com.l2jfrozen.Config;
import com.l2jfrozen.gameserver.ai.CtrlEvent;
import com.l2jfrozen.gameserver.datatables.SkillTable;
import com.l2jfrozen.gameserver.handler.ISkillHandler;
import com.l2jfrozen.gameserver.handler.SkillHandler;
import com.l2jfrozen.gameserver.managers.DuelManager;
import com.l2jfrozen.gameserver.model.L2Attackable;
import com.l2jfrozen.gameserver.model.L2Character;
import com.l2jfrozen.gameserver.model.L2Effect;
import com.l2jfrozen.gameserver.model.L2Object;
import com.l2jfrozen.gameserver.model.L2Party;
import com.l2jfrozen.gameserver.model.L2Skill;
import com.l2jfrozen.gameserver.model.L2Skill.SkillType;
import com.l2jfrozen.gameserver.model.entity.olympiad.Olympiad;
import com.l2jfrozen.gameserver.network.SystemMessageId;
import com.l2jfrozen.gameserver.network.serverpackets.MagicSkillUser;
import com.l2jfrozen.gameserver.network.serverpackets.SystemMessage;
import com.l2jfrozen.gameserver.skills.Formulas;
import com.l2jfrozen.gameserver.skills.l2skills.L2SkillDrain;
import com.l2jfrozen.gameserver.taskmanager.AttackStanceTaskManager;
import com.l2jfrozen.gameserver.thread.ThreadPoolManager;
import com.l2jfrozen.util.random.Rnd;
/**
* The Class L2CubicInstance.
*/
public class L2CubicInstance
{
/** The Constant _log. */
protected static final Logger _log = Logger.getLogger(L2CubicInstance.class.getName());
// Type of Cubics
/** The Constant STORM_CUBIC. */
public static final int STORM_CUBIC = 1;
/** The Constant VAMPIRIC_CUBIC. */
public static final int VAMPIRIC_CUBIC = 2;
/** The Constant LIFE_CUBIC. */
public static final int LIFE_CUBIC = 3;
/** The Constant VIPER_CUBIC. */
public static final int VIPER_CUBIC = 4;
/** The Constant POLTERGEIST_CUBIC. */
public static final int POLTERGEIST_CUBIC = 5;
/** The Constant BINDING_CUBIC. */
public static final int BINDING_CUBIC = 6;
/** The Constant AQUA_CUBIC. */
public static final int AQUA_CUBIC = 7;
/** The Constant SPARK_CUBIC. */
public static final int SPARK_CUBIC = 8;
/** The Constant ATTRACT_CUBIC. */
public static final int ATTRACT_CUBIC = 9;
/** The Constant SMART_CUBIC_EVATEMPLAR. */
public static final int SMART_CUBIC_EVATEMPLAR = 10;
/** The Constant SMART_CUBIC_SHILLIENTEMPLAR. */
public static final int SMART_CUBIC_SHILLIENTEMPLAR = 11;
/** The Constant SMART_CUBIC_ARCANALORD. */
public static final int SMART_CUBIC_ARCANALORD = 12;
/** The Constant SMART_CUBIC_ELEMENTALMASTER. */
public static final int SMART_CUBIC_ELEMENTALMASTER = 13;
/** The Constant SMART_CUBIC_SPECTRALMASTER. */
public static final int SMART_CUBIC_SPECTRALMASTER = 14;
// Max range of cubic skills
// TODO: Check/fix the max range
/** The Constant MAX_MAGIC_RANGE. */
public static final int MAX_MAGIC_RANGE = 900;
// Cubic skills
/** The Constant SKILL_CUBIC_HEAL. */
public static final int SKILL_CUBIC_HEAL = 4051;
/** The Constant SKILL_CUBIC_CURE. */
public static final int SKILL_CUBIC_CURE = 5579;
/** The _owner. */
protected L2PcInstance _owner;
/** The _target. */
protected L2Character _target;
/** The _id. */
protected int _id;
/** The _matk. */
protected int _matk;
/** The _activationtime. */
protected int _activationtime;
/** The _activationchance. */
protected int _activationchance;
/** The _active. */
protected boolean _active;
/** The _given by other. */
private boolean _givenByOther;
/** The _skills. */
protected List<L2Skill> _skills = new FastList<L2Skill>();
/** The _disappear task. */
private Future<?> _disappearTask;
/** The _action task. */
private Future<?> _actionTask;
/**
* Instantiates a new l2 cubic instance.
*
* @param owner the owner
* @param id the id
* @param level the level
* @param mAtk the m atk
* @param activationtime the activationtime
* @param activationchance the activationchance
* @param totallifetime the totallifetime
* @param givenByOther the given by other
*/
public L2CubicInstance(L2PcInstance owner, int id, int level, int mAtk, int activationtime,
int activationchance, int totallifetime, boolean givenByOther)
{
_owner = owner;
_id = id;
_matk = mAtk;
_activationtime = activationtime * 1000;
_activationchance = activationchance;
_active = false;
_givenByOther = givenByOther;
switch (_id)
{
case STORM_CUBIC:
_skills.add(SkillTable.getInstance().getInfo(4049, level));
break;
case VAMPIRIC_CUBIC:
_skills.add(SkillTable.getInstance().getInfo(4050, level));
break;
case LIFE_CUBIC:
_skills.add(SkillTable.getInstance().getInfo(4051, level));
doAction();
break;
case VIPER_CUBIC:
_skills.add(SkillTable.getInstance().getInfo(4052, level));
break;
case POLTERGEIST_CUBIC:
_skills.add(SkillTable.getInstance().getInfo(4053, level));
_skills.add(SkillTable.getInstance().getInfo(4054, level));
_skills.add(SkillTable.getInstance().getInfo(4055, level));
break;
case BINDING_CUBIC:
_skills.add(SkillTable.getInstance().getInfo(4164, level));
break;
case AQUA_CUBIC:
_skills.add(SkillTable.getInstance().getInfo(4165, level));
break;
case SPARK_CUBIC:
_skills.add(SkillTable.getInstance().getInfo(4166, level));
break;
case ATTRACT_CUBIC:
_skills.add(SkillTable.getInstance().getInfo(5115, level));
_skills.add(SkillTable.getInstance().getInfo(5116, level));
break;
case SMART_CUBIC_ARCANALORD:
// _skills.add(SkillTable.getInstance().getInfo(4049,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4050,7)); no animation
_skills.add(SkillTable.getInstance().getInfo(4051, 7)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(4052,6)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4053,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4054,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4055,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4164,9)); no animation
_skills.add(SkillTable.getInstance().getInfo(4165, 9)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(4166,9)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5115,4)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5116,4)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5579,4)); no need to add to the
// cubic skills list
break;
case SMART_CUBIC_ELEMENTALMASTER:
_skills.add(SkillTable.getInstance().getInfo(4049, 8)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(4050,7)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4051,7)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4052,6)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4053,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4054,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4055,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4164,9)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4165,9)); no animation
_skills.add(SkillTable.getInstance().getInfo(4166, 9)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(5115,4)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5116,4)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5579,4)); no need to add to the
// cubic skills list
break;
case SMART_CUBIC_SPECTRALMASTER:
_skills.add(SkillTable.getInstance().getInfo(4049, 8)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(4050,7)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4051,7)); no animation
_skills.add(SkillTable.getInstance().getInfo(4052, 6)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(4053,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4054,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4055,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4164,9)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4165,9)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4166,9)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5115,4)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5116,4)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5579,4)); no need to add to the
// cubic skills list
break;
case SMART_CUBIC_EVATEMPLAR:
// _skills.add(SkillTable.getInstance().getInfo(4049,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4050,7)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4051,7)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4052,6)); no animation
_skills.add(SkillTable.getInstance().getInfo(4053, 8)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(4054,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4055,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4164,9)); no animation
_skills.add(SkillTable.getInstance().getInfo(4165, 9)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(4166,9)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5115,4)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5116,4)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5579,4)); no need to add to the
// cubic skills list
break;
case SMART_CUBIC_SHILLIENTEMPLAR:
_skills.add(SkillTable.getInstance().getInfo(4049, 8)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(4050,7)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4051,7)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4052,6)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4053,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4054,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4055,8)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4164,9)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4165,9)); no animation
// _skills.add(SkillTable.getInstance().getInfo(4166,9)); no animation
_skills.add(SkillTable.getInstance().getInfo(5115, 4)); // have animation
// _skills.add(SkillTable.getInstance().getInfo(5116,4)); no animation
// _skills.add(SkillTable.getInstance().getInfo(5579,4)); no need to add to the
// cubic skills list
break;
}
_disappearTask = ThreadPoolManager.getInstance().scheduleGeneral(new Disappear(), totallifetime); // disappear
}
/**
* Do action.
*/
public synchronized void doAction()
{
if (_active)
return;
_active = true;
switch (_id)
{
case AQUA_CUBIC:
case BINDING_CUBIC:
case SPARK_CUBIC:
case STORM_CUBIC:
case POLTERGEIST_CUBIC:
case VAMPIRIC_CUBIC:
case VIPER_CUBIC:
case ATTRACT_CUBIC:
case SMART_CUBIC_ARCANALORD:
case SMART_CUBIC_ELEMENTALMASTER:
case SMART_CUBIC_SPECTRALMASTER:
case SMART_CUBIC_EVATEMPLAR:
case SMART_CUBIC_SHILLIENTEMPLAR:
_actionTask = ThreadPoolManager.getInstance().scheduleEffectAtFixedRate(new Action(_activationchance), 0, _activationtime);
break;
case LIFE_CUBIC:
_actionTask = ThreadPoolManager.getInstance().scheduleEffectAtFixedRate(new Heal(), 0, _activationtime);
break;
}
}
/**
* Gets the id.
*
* @return the id
*/
public int getId()
{
return _id;
}
/**
* Gets the owner.
*
* @return the owner
*/
public L2PcInstance getOwner()
{
return _owner;
}
/**
* Gets the m critical hit.
*
* @param target the target
* @param skill the skill
* @return the m critical hit
*/
public final int getMCriticalHit(L2Character target, L2Skill skill)
{
// TODO: Temporary now mcrit for cubics is the baseMCritRate of its owner
return _owner.getTemplate().baseMCritRate;
}
/**
* Gets the m atk.
*
* @return the m atk
*/
public int getMAtk()
{
return _matk;
}
/**
* Stop action.
*/
public void stopAction()
{
_target = null;
if (_actionTask != null)
{
if(!_actionTask.isCancelled())
_actionTask.cancel(true);
_actionTask = null;
}
_active = false;
}
/**
* Cancel disappear.
*/
public void cancelDisappear()
{
if (_disappearTask != null)
{
_disappearTask.cancel(true);
_disappearTask = null;
}
}
/**
* this sets the enemy target for a cubic.
*/
public void getCubicTarget()
{
try
{
_target = null;
L2Object ownerTarget = _owner.getTarget();
if (ownerTarget == null)
return;
// Duel targeting
if (_owner.isInDuel())
{
L2PcInstance PlayerA = DuelManager.getInstance().getDuel(_owner.getDuelId()).getPlayerA();
L2PcInstance PlayerB = DuelManager.getInstance().getDuel(_owner.getDuelId()).getPlayerB();
if (DuelManager.getInstance().getDuel(_owner.getDuelId()).isPartyDuel())
{
L2Party partyA = PlayerA.getParty();
L2Party partyB = PlayerB.getParty();
L2Party partyEnemy = null;
if (partyA != null)
{
if (partyA.getPartyMembers().contains(_owner))
if (partyB != null)
partyEnemy = partyB;
else
_target = PlayerB;
else
partyEnemy = partyA;
}
else
{
if (PlayerA == _owner)
if (partyB != null)
partyEnemy = partyB;
else
_target = PlayerB;
else
_target = PlayerA;
}
if (_target == PlayerA || _target == PlayerB)
if (_target == ownerTarget)
return;
if (partyEnemy != null)
{
if (partyEnemy.getPartyMembers().contains(ownerTarget))
_target = (L2Character) ownerTarget;
return;
}
}
if (PlayerA != _owner && ownerTarget == PlayerA)
{
_target = PlayerA;
return;
}
if (PlayerB != _owner && ownerTarget == PlayerB)
{
_target = PlayerB;
return;
}
_target = null;
return;
}
// Olympiad targeting
if (_owner.isInOlympiadMode())
{
if (_owner.isOlympiadStart())
{
L2PcInstance[] players = Olympiad.getInstance().getPlayers(_owner.getOlympiadGameId());
if (players != null)
{
if (_owner.getOlympiadSide() == 1)
{
if (ownerTarget == players[1])
_target = players[1];
else if (players[1].getPet() != null
&& ownerTarget == players[1].getPet())
_target = players[1].getPet();
}
else
{
if (ownerTarget == players[0])
_target = players[0];
else if (players[0].getPet() != null
&& ownerTarget == players[0].getPet())
_target = players[0].getPet();
}
}
}
return;
}
// test owners target if it is valid then use it
if (ownerTarget instanceof L2Character && ownerTarget != _owner.getPet()
&& ownerTarget != _owner)
{
// target mob which has aggro on you or your summon
if (ownerTarget instanceof L2Attackable)
{
if (((L2Attackable) ownerTarget).getAggroList().get(_owner) != null
&& !((L2Attackable) ownerTarget).isDead())
{
_target = (L2Character) ownerTarget;
return;
}
if (_owner.getPet() != null)
if (((L2Attackable) ownerTarget).getAggroList().get(_owner.getPet()) != null
&& !((L2Attackable) ownerTarget).isDead())
{
_target = (L2Character) ownerTarget;
return;
}
}
// get target in pvp or in siege
L2PcInstance enemy = null;
if ((_owner.getPvpFlag() > 0
&& !_owner.isInsideZone(L2Character.ZONE_PEACE))
|| _owner.isInsideZone(L2Character.ZONE_PVP))
{
if (!((L2Character) ownerTarget).isDead() && ownerTarget instanceof L2PcInstance)
enemy = (L2PcInstance)ownerTarget;
if (enemy != null)
{
boolean targetIt = true;
if (_owner.getParty() != null)
{
if (_owner.getParty().getPartyMembers().contains(enemy))
targetIt = false;
else if (_owner.getParty().getCommandChannel() != null)
{
if (_owner.getParty().getCommandChannel().getMembers().contains(enemy))
targetIt = false;
}
}
if (_owner.getClan() != null && !_owner.isInsideZone(L2Character.ZONE_PVP))
{
if (_owner.getClan().isMember(enemy.getName()))
targetIt = false;
if (_owner.getAllyId() > 0 && enemy.getAllyId() > 0)
{
if (_owner.getAllyId() == enemy.getAllyId())
targetIt = false;
}
}
if (enemy.getPvpFlag() == 0 && !enemy.isInsideZone(L2Character.ZONE_PVP))
targetIt = false;
if (enemy.isInsideZone(L2Character.ZONE_PEACE))
targetIt = false;
if (_owner.getSiegeState() > 0
&& _owner.getSiegeState() == enemy.getSiegeState())
targetIt = false;
if (!enemy.isVisible())
targetIt = false;
if (targetIt)
{
_target = enemy;
return;
}
}
}
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "", e);
}
}
/**
* The Class Action.
*/
private class Action implements Runnable
{
/** The _chance. */
private int _chance;
/**
* Instantiates a new action.
*
* @param chance the chance
*/
Action(int chance)
{
_chance = chance;
// run task
}
@Override
public void run()
{
try
{
final L2PcInstance owner = _owner;
if (owner == null)
{
stopAction();
cancelDisappear();
return;
}
if (owner.isDead() || (owner.isOnline() == 0))
{
stopAction();
owner.delCubic(_id);
owner.broadcastUserInfo();
cancelDisappear();
return;
}
if (!AttackStanceTaskManager.getInstance().getAttackStanceTask(owner))
{
if (owner.getPet() != null)
{
if (!AttackStanceTaskManager.getInstance().getAttackStanceTask(owner.getPet()))
{
stopAction();
return;
}
}
else
{
stopAction();
return;
}
}
// Smart Cubic debuff cancel is 100%
boolean UseCubicCure = false;
L2Skill skill = null;
if (_id >= SMART_CUBIC_EVATEMPLAR && _id <= SMART_CUBIC_SPECTRALMASTER)
{
L2Effect[] effects = owner.getAllEffects();
for (L2Effect e : effects)
{
if (e != null && e.getSkill().isOffensive())
{
UseCubicCure = true;
e.exit(true);
}
}
}
if (UseCubicCure)
{
// Smart Cubic debuff cancel is needed, no other skill is used in this
// activation period
MagicSkillUser msu = new MagicSkillUser(owner, owner, SKILL_CUBIC_CURE, 1, 0, 0);
owner.broadcastPacket(msu);
}
else if (Rnd.get(100) < _chance)
{
skill = _skills.get(Rnd.get(_skills.size()));
if (skill != null)
{
if (skill.getId() == SKILL_CUBIC_HEAL)
{
// friendly skill, so we look a target in owner's party
cubicTargetForHeal();
}
else
{
// offensive skill, we look for an enemy target
getCubicTarget();
if (_target == owner || !isInCubicRange(owner, _target))
_target = null;
}
final L2Character target = _target;
if ((target != null) && (!target.isDead()))
{
if (Config.DEBUG)
{
_log.info("L2CubicInstance: Action.run();");
_log.info("Cubic Id: "
+ _id
+ " Target: "
+ target.getName()
+ " distance: "
+ Math.sqrt(target.getDistanceSq(owner.getX(), owner.getY(), owner.getZ())));
}
owner.broadcastPacket(new MagicSkillUser(owner, target, skill.getId(), skill.getLevel(), 0, 0));
SkillType type = skill.getSkillType();
ISkillHandler handler = SkillHandler.getInstance().getSkillHandler(skill.getSkillType());
L2Character[] targets = { target };
if ((type == SkillType.PARALYZE) || (type == SkillType.STUN)
|| (type == SkillType.ROOT)
|| (type == SkillType.AGGDAMAGE))
{
if (Config.DEBUG)
_log.info("L2CubicInstance: Action.run() handler " + type);
useCubicDisabler(type, L2CubicInstance.this, skill, targets);
}
else if (type == SkillType.MDAM)
{
if (Config.DEBUG)
_log.info("L2CubicInstance: Action.run() handler " + type);
useCubicMdam(L2CubicInstance.this, skill, targets);
}
else if ((type == SkillType.POISON)
|| (type == SkillType.DEBUFF)
|| (type == SkillType.DOT))
{
if (Config.DEBUG)
_log.info("L2CubicInstance: Action.run() handler " + type);
useCubicContinuous(L2CubicInstance.this, skill, targets);
}
else if (type == SkillType.DRAIN)
{
if (Config.DEBUG)
_log.info("L2CubicInstance: Action.run() skill " + type);
((L2SkillDrain) skill).useCubicSkill(L2CubicInstance.this, targets);
}
else
{
handler.useSkill(owner, skill, targets);
if (Config.DEBUG)
_log.info("L2CubicInstance: Action.run(); other handler");
}
}
}
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "", e);
}
}
}
/**
* Use cubic continuous.
*
* @param activeCubic the active cubic
* @param skill the skill
* @param targets the targets
*/
public void useCubicContinuous(L2CubicInstance activeCubic, L2Skill skill, L2Object[] targets)
{
for (L2Character target: (L2Character[]) targets)
{
if (target == null || target.isDead())
continue;
if (skill.isOffensive())
{
boolean acted = Formulas.calcCubicSkillSuccess(activeCubic, target, skill);
if (!acted)
{
activeCubic.getOwner().sendPacket(new SystemMessage(SystemMessageId.ATTACK_FAILED));
continue;
}
}
// if this is a debuff let the duel manager know about it
// so the debuff can be removed after the duel
// (player & target must be in the same duel)
if (target instanceof L2PcInstance && ((L2PcInstance) target).isInDuel() && skill.getSkillType() == SkillType.DEBUFF && activeCubic.getOwner().getDuelId() == ((L2PcInstance) target).getDuelId())
{
DuelManager dm = DuelManager.getInstance();
for (L2Effect debuff : skill.getEffects(activeCubic.getOwner(), target))
if (debuff != null)
dm.onBuff(((L2PcInstance) target), debuff);
}
else
skill.getEffects(activeCubic.getOwner(), target);
}
}
/**
* Use cubic mdam.
*
* @param activeCubic the active cubic
* @param skill the skill
* @param targets the targets
*/
public void useCubicMdam(L2CubicInstance activeCubic, L2Skill skill, L2Object[] targets)
{
for (L2Character target: (L2Character[]) targets)
{
if (target == null)
continue;
if (target.isAlikeDead())
{
if (target instanceof L2PcInstance)
target.stopFakeDeath(null);
else
continue;
}
boolean mcrit = Formulas.calcMCrit(activeCubic.getMCriticalHit(target, skill));
int damage = (int) Formulas.calcMagicDam(activeCubic, target, skill, mcrit);
if (Config.DEBUG)
_log.info("L2SkillMdam: useCubicSkill() -> damage = " + damage);
if (damage > 0)
{
// Manage attack or cast break of the target (calculating rate, sending message...)
if (!target.isRaid() && Formulas.calcAtkBreak(target, damage))
{
target.breakAttack();
target.breakCast();
}
activeCubic.getOwner().sendDamageMessage(target, damage, mcrit, false, false);
if (skill.hasEffects())
{
// activate attacked effects, if any
target.stopSkillEffects(skill.getId());
if (target.getFirstEffect(skill) != null)
target.removeEffect(target.getFirstEffect(skill));
if (Formulas.calcCubicSkillSuccess(activeCubic, target, skill))
skill.getEffects(activeCubic.getOwner(), target);
}
target.reduceCurrentHp(damage, activeCubic.getOwner());
}
}
}
/**
* Use cubic disabler.
*
* @param type the type
* @param activeCubic the active cubic
* @param skill the skill
* @param targets the targets
*/
public void useCubicDisabler(SkillType type, L2CubicInstance activeCubic, L2Skill skill, L2Object[] targets)
{
if (Config.DEBUG)
_log.info("Disablers: useCubicSkill()");
for (L2Character target : (L2Character[]) targets)
{
if (target == null || target.isDead()) // bypass if target is null or dead
continue;
switch (type)
{
case STUN:
{
if (Formulas.calcCubicSkillSuccess(activeCubic, target, skill))
{
// if this is a debuff let the duel manager know about it
// so the debuff can be removed after the duel
// (player & target must be in the same duel)
if (target instanceof L2PcInstance
&& ((L2PcInstance) target).isInDuel()
&& skill.getSkillType() == SkillType.DEBUFF
&& activeCubic.getOwner().getDuelId() == ((L2PcInstance) target).getDuelId())
{
DuelManager dm = DuelManager.getInstance();
for (L2Effect debuff : skill.getEffects(activeCubic.getOwner(), target))
if (debuff != null)
dm.onBuff(((L2PcInstance) target), debuff);
}
else
skill.getEffects(activeCubic.getOwner(), target);
if (Config.DEBUG)
_log.info("Disablers: useCubicSkill() -> success");
}
else
{
if (Config.DEBUG)
_log.info("Disablers: useCubicSkill() -> failed");
}
break;
}
case PARALYZE: // use same as root for now
{
if (Formulas.calcCubicSkillSuccess(activeCubic, target, skill))
{
// if this is a debuff let the duel manager know about it
// so the debuff can be removed after the duel
// (player & target must be in the same duel)
if (target instanceof L2PcInstance
&& ((L2PcInstance) target).isInDuel()
&& skill.getSkillType() == SkillType.DEBUFF
&& activeCubic.getOwner().getDuelId() == ((L2PcInstance) target).getDuelId())
{
DuelManager dm = DuelManager.getInstance();
for (L2Effect debuff : skill.getEffects(activeCubic.getOwner(), target))
if (debuff != null)
dm.onBuff(((L2PcInstance) target), debuff);
}
else
skill.getEffects(activeCubic.getOwner(), target);
if (Config.DEBUG)
_log.info("Disablers: useCubicSkill() -> success");
}
else
{
if (Config.DEBUG)
_log.info("Disablers: useCubicSkill() -> failed");
}
break;
}
case CANCEL:
{
L2Effect[] effects = target.getAllEffects();
if (effects == null || effects.length == 0)
break;
int max_negated_effects = 3;
int count = 0;
for (L2Effect e : effects)
{
if (e.getSkill().isOffensive() && count < max_negated_effects)
{
// Do not remove raid curse skills
if (e.getSkill().getId() != 4215 && e.getSkill().getId() != 4515
&& e.getSkill().getId() != 4082)
{
e.exit(true);
if (count > -1)
count++;
}
}
}
break;
}
case ROOT:
{
if (Formulas.calcCubicSkillSuccess(activeCubic, target, skill))
{
// if this is a debuff let the duel manager know about it
// so the debuff can be removed after the duel
// (player & target must be in the same duel)
if (target instanceof L2PcInstance
&& ((L2PcInstance) target).isInDuel()
&& skill.getSkillType() == SkillType.DEBUFF
&& activeCubic.getOwner().getDuelId() == ((L2PcInstance) target).getDuelId())
{
DuelManager dm = DuelManager.getInstance();
for (L2Effect debuff : skill.getEffects(activeCubic.getOwner(), target))
if (debuff != null)
dm.onBuff(((L2PcInstance) target), debuff);
}
else
skill.getEffects(activeCubic.getOwner(), target);
if (Config.DEBUG)
_log.info("Disablers: useCubicSkill() -> success");
}
else
{
if (Config.DEBUG)
_log.info("Disablers: useCubicSkill() -> failed");
}
break;
}
case AGGDAMAGE:
{
if (Formulas.calcCubicSkillSuccess(activeCubic, target, skill))
{
if (target instanceof L2Attackable)
target.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, activeCubic.getOwner(), (int) ((150 * skill.getPower()) / (target.getLevel() + 7)));
skill.getEffects(activeCubic.getOwner(), target);
if (Config.DEBUG)
_log.info("Disablers: useCubicSkill() -> success");
}
else
{
if (Config.DEBUG)
_log.info("Disablers: useCubicSkill() -> failed");
}
break;
}
}
}
}
/**
* returns true if the target is inside of the owner's max Cubic range.
*
* @param owner the owner
* @param target the target
* @return true, if is in cubic range
*/
public boolean isInCubicRange(L2Character owner, L2Character target)
{
if (owner == null || target == null)
return false;
int x, y, z;
// temporary range check until real behavior of cubics is known/coded
int range = MAX_MAGIC_RANGE;
x = (owner.getX() - target.getX());
y = (owner.getY() - target.getY());
z = (owner.getZ() - target.getZ());
return ((x * x) + (y * y) + (z * z) <= (range * range));
}
/**
* this sets the friendly target for a cubic.
*/
public void cubicTargetForHeal()
{
L2Character target = null;
double percentleft = 100.0;
L2Party party = _owner.getParty();
// if owner is in a duel but not in a party duel, then it is the same as he does not have a
// party
if (_owner.isInDuel())
if (!DuelManager.getInstance().getDuel(_owner.getDuelId()).isPartyDuel())
party = null;
if (party != null && !_owner.isInOlympiadMode())
{
// Get all visible objects in a spheric area near the L2Character
// Get a list of Party Members
List<L2PcInstance> partyList = party.getPartyMembers();
for (L2Character partyMember : partyList)
{
if (!partyMember.isDead())
{
// if party member not dead, check if he is in castrange of heal cubic
if (isInCubicRange(_owner, partyMember))
{
// member is in cubic casting range, check if he need heal and if he have
// the lowest HP
if (partyMember.getCurrentHp() < partyMember.getMaxHp())
{
if (percentleft > (partyMember.getCurrentHp() / partyMember.getMaxHp()))
{
percentleft = (partyMember.getCurrentHp() / partyMember.getMaxHp());
target = partyMember;
}
}
}
}
if (partyMember.getPet() != null)
{
if (partyMember.getPet().isDead())
continue;
// if party member's pet not dead, check if it is in castrange of heal cubic
if (!isInCubicRange(_owner, partyMember.getPet()))
continue;
// member's pet is in cubic casting range, check if he need heal and if he have
// the lowest HP
if (partyMember.getPet().getCurrentHp() < partyMember.getPet().getMaxHp())
{
if (percentleft > (partyMember.getPet().getCurrentHp() / partyMember.getPet().getMaxHp()))
{
percentleft = (partyMember.getPet().getCurrentHp() / partyMember.getPet().getMaxHp());
target = partyMember.getPet();
}
}
}
}
}
else
{
if (_owner.getCurrentHp() < _owner.getMaxHp())
{
percentleft = (_owner.getCurrentHp() / _owner.getMaxHp());
target = _owner;
}
if (_owner.getPet() != null)
if (!_owner.getPet().isDead()
&& _owner.getPet().getCurrentHp() < _owner.getPet().getMaxHp()
&& percentleft > (_owner.getPet().getCurrentHp() / _owner.getPet().getMaxHp())
&& isInCubicRange(_owner, _owner.getPet()))
{
target = _owner.getPet();
}
}
_target = target;
}
/**
* Given by other.
*
* @return true, if successful
*/
public boolean givenByOther()
{
return _givenByOther;
}
/**
* The Class Heal.
*/
private class Heal implements Runnable
{
/**
* Instantiates a new heal.
*/
Heal()
{
// run task
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
if (_owner.isDead() || _owner.isOnline()==0)
{
stopAction();
_owner.delCubic(_id);
_owner.broadcastUserInfo();
cancelDisappear();
return;
}
try
{
L2Skill skill = null;
for (L2Skill sk : _skills)
{
if (sk.getId() == SKILL_CUBIC_HEAL)
{
skill = sk;
break;
}
}
if (skill != null)
{
cubicTargetForHeal();
L2Character target = _target;
if (target != null && !target.isDead())
{
if (target.getMaxHp() - target.getCurrentHp() > skill.getPower())
{
L2Character[] targets = { target };
ISkillHandler handler = SkillHandler.getInstance().getSkillHandler(skill.getSkillType());
if (handler != null)
{
handler.useSkill(_owner, skill, targets);
}
else
{
skill.useSkill(_owner, targets);
}
MagicSkillUser msu = new MagicSkillUser(_owner, target, skill.getId(), skill.getLevel(), 0, 0);
_owner.broadcastPacket(msu);
}
}
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "", e);
}
}
}
/**
* The Class Disappear.
*/
private class Disappear implements Runnable
{
/**
* Instantiates a new disappear.
*/
Disappear()
{
// run task
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
stopAction();
_owner.delCubic(_id);
_owner.broadcastUserInfo();
}
}
}