Java tutorial
/* * 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 lineage2.gameserver.model; import static lineage2.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE; import gnu.trove.set.hash.TIntHashSet; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import javolution.util.FastList; import lineage2.commons.collections.LazyArrayList; import lineage2.commons.lang.reference.HardReference; import lineage2.commons.lang.reference.HardReferences; import lineage2.commons.listener.Listener; import lineage2.commons.threading.RunnableImpl; import lineage2.commons.util.Rnd; import lineage2.commons.util.concurrent.atomic.AtomicState; import lineage2.gameserver.Config; import lineage2.gameserver.ThreadPoolManager; import lineage2.gameserver.ai.CharacterAI; import lineage2.gameserver.ai.CtrlEvent; import lineage2.gameserver.ai.CtrlIntention; import lineage2.gameserver.ai.PlayableAI.nextAction; import lineage2.gameserver.cache.Msg; import lineage2.gameserver.geodata.GeoEngine; import lineage2.gameserver.geodata.GeoMove; import lineage2.gameserver.instancemanager.ReflectionManager; import lineage2.gameserver.instancemanager.WorldStatisticsManager; import lineage2.gameserver.model.GameObjectTasks.AltMagicUseTask; import lineage2.gameserver.model.GameObjectTasks.CastEndTimeTask; import lineage2.gameserver.model.GameObjectTasks.HitTask; import lineage2.gameserver.model.GameObjectTasks.MagicLaunchedTask; import lineage2.gameserver.model.GameObjectTasks.MagicUseTask; import lineage2.gameserver.model.GameObjectTasks.NotifyAITask; import lineage2.gameserver.model.Skill.SkillTargetType; import lineage2.gameserver.model.Skill.SkillType; import lineage2.gameserver.model.Zone.ZoneType; import lineage2.gameserver.model.actor.listener.CharListenerList; import lineage2.gameserver.model.actor.recorder.CharStatsChangeRecorder; import lineage2.gameserver.model.base.InvisibleType; import lineage2.gameserver.model.base.TeamType; import lineage2.gameserver.model.entity.Reflection; import lineage2.gameserver.model.instances.MinionInstance; import lineage2.gameserver.model.instances.MonsterInstance; import lineage2.gameserver.model.instances.NpcInstance; import lineage2.gameserver.model.items.ItemInstance; import lineage2.gameserver.model.pledge.Clan; import lineage2.gameserver.model.quest.QuestEventType; import lineage2.gameserver.model.quest.QuestState; import lineage2.gameserver.model.reference.L2Reference; import lineage2.gameserver.model.worldstatistics.CategoryType; import lineage2.gameserver.network.serverpackets.ActionFail; import lineage2.gameserver.network.serverpackets.Attack; import lineage2.gameserver.network.serverpackets.AutoAttackStart; import lineage2.gameserver.network.serverpackets.AutoAttackStop; import lineage2.gameserver.network.serverpackets.ChangeMoveType; import lineage2.gameserver.network.serverpackets.CharMoveToLocation; import lineage2.gameserver.network.serverpackets.ExAbnormalStatusUpdateFromTarget; import lineage2.gameserver.network.serverpackets.ExTeleportToLocationActivate; import lineage2.gameserver.network.serverpackets.FlyToLocation; import lineage2.gameserver.network.serverpackets.FlyToLocation.FlyType; import lineage2.gameserver.network.serverpackets.L2GameServerPacket; import lineage2.gameserver.network.serverpackets.MagicSkillCanceled; import lineage2.gameserver.network.serverpackets.MagicSkillLaunched; import lineage2.gameserver.network.serverpackets.MagicSkillUse; import lineage2.gameserver.network.serverpackets.SetupGauge; import lineage2.gameserver.network.serverpackets.StatusUpdate; import lineage2.gameserver.network.serverpackets.StatusUpdate.StatusUpdateField; import lineage2.gameserver.network.serverpackets.StopMove; import lineage2.gameserver.network.serverpackets.SystemMessage; import lineage2.gameserver.network.serverpackets.TeleportToLocation; import lineage2.gameserver.network.serverpackets.ValidateLocation; import lineage2.gameserver.network.serverpackets.components.CustomMessage; import lineage2.gameserver.network.serverpackets.components.IStaticPacket; import lineage2.gameserver.network.serverpackets.components.SystemMsg; import lineage2.gameserver.skills.AbnormalEffect; import lineage2.gameserver.skills.EffectType; import lineage2.gameserver.skills.TimeStamp; import lineage2.gameserver.skills.effects.EffectTemplate; import lineage2.gameserver.stats.Calculator; import lineage2.gameserver.stats.Env; import lineage2.gameserver.stats.Formulas; import lineage2.gameserver.stats.Formulas.AttackInfo; import lineage2.gameserver.stats.StatFunctions; import lineage2.gameserver.stats.StatTemplate; import lineage2.gameserver.stats.Stats; import lineage2.gameserver.stats.funcs.Func; import lineage2.gameserver.stats.triggers.TriggerInfo; import lineage2.gameserver.stats.triggers.TriggerType; import lineage2.gameserver.taskmanager.LazyPrecisionTaskManager; import lineage2.gameserver.taskmanager.RegenTaskManager; import lineage2.gameserver.templates.CharTemplate; import lineage2.gameserver.templates.item.WeaponTemplate; import lineage2.gameserver.templates.item.WeaponTemplate.WeaponType; import lineage2.gameserver.templates.spawn.WalkerRouteTemplate; import lineage2.gameserver.utils.Location; import lineage2.gameserver.utils.Log; import lineage2.gameserver.utils.PositionUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.napile.primitive.maps.IntObjectMap; import org.napile.primitive.maps.impl.CHashIntObjectMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Mobius * @version $Revision: 1.0 $ */ public abstract class Creature extends GameObject { /** * */ private static final long serialVersionUID = 1L; /** * @author Mobius */ public class MoveNextTask extends RunnableImpl { /** * Field donedist. */ /** * Field alldist. */ private double alldist, donedist; /** * Method setDist. * @param dist double * @return MoveNextTask */ public MoveNextTask setDist(double dist) { alldist = dist; donedist = 0.; return this; } /** * Method runImpl. */ @Override public void runImpl() { if (!isMoving) { return; } moveLock.lock(); try { if (!isMoving) { return; } if (isMovementDisabled()) { stopMove(); return; } Creature follow = null; int speed = getMoveSpeed(); if (speed <= 0) { stopMove(); return; } long now = System.currentTimeMillis(); if (isFollow) { follow = getFollowTarget(); if (follow == null) { stopMove(); return; } if (isInRangeZ(follow, _offset) && GeoEngine.canSeeTarget(Creature.this, follow, false)) { stopMove(); ThreadPoolManager.getInstance() .execute(new NotifyAITask(Creature.this, CtrlEvent.EVT_ARRIVED_TARGET)); return; } } if (alldist <= 0) { moveNext(false); return; } donedist += ((now - _startMoveTime) * _previousSpeed) / 1000.; double done = donedist / alldist; if (done < 0) { done = 0; } if (done >= 1) { moveNext(false); return; } if (isMovementDisabled()) { stopMove(); return; } Location loc = null; int index = (int) (moveList.size() * done); if (index >= moveList.size()) { index = moveList.size() - 1; } if (index < 0) { index = 0; } loc = moveList.get(index).clone().geo2world(); if (!isFlying() && !isInBoat() && !isInWater() && !isBoat()) { if ((loc.z - getZ()) > 256) { String bug_text = "geo bug 1 at: " + getLoc() + " => " + loc.x + "," + loc.y + "," + loc.z + "\tAll path: " + moveList.get(0) + " => " + moveList.get(moveList.size() - 1); Log.add(bug_text, "geo"); stopMove(); return; } } if ((loc == null) || isMovementDisabled()) { stopMove(); return; } setLoc(loc, true); if (isMovementDisabled()) { stopMove(); return; } if (isFollow && ((now - _followTimestamp) > (_forestalling ? 500 : 1000)) && (follow != null) && !follow.isInRange(movingDestTempPos, Math.max(100, _offset))) { if ((Math.abs(getZ() - loc.z) > 1000) && !isFlying()) { sendPacket(SystemMsg.CANNOT_SEE_TARGET); stopMove(); return; } if (buildPathTo(follow.getX(), follow.getY(), follow.getZ(), _offset, follow, true, true)) { movingDestTempPos.set(follow.getX(), follow.getY(), follow.getZ()); } else { stopMove(); return; } moveNext(true); return; } _previousSpeed = speed; _startMoveTime = now; _moveTask = ThreadPoolManager.getInstance().schedule(this, getMoveTickInterval()); } catch (Exception e) { _log.error("", e); } finally { moveLock.unlock(); } } } /** * Field _log. */ private static final Logger _log = LoggerFactory.getLogger(Creature.class); /** * Field HEADINGS_IN_PI. (value is 10430.378350470453) */ public static final double HEADINGS_IN_PI = 10430.378350470452724949566316381; /** * Field INTERACTION_DISTANCE. (value is 200) */ public static final int INTERACTION_DISTANCE = 200; /** * Field _castingSkill. */ private Skill _castingSkill; /** * Field _castInterruptTime. */ private long _castInterruptTime; /** * Field _animationEndTime. */ private long _animationEndTime; /** * Field _scheduledCastCount. */ public int _scheduledCastCount; /** * Field _scheduledCastInterval. */ public int _scheduledCastInterval; /** * Field _skillTask. */ public Future<?> _skillTask; /** * Field _skillLaunchedTask. */ public Future<?> _skillLaunchedTask; /** * Field _skillDoubleTask. */ public Future<?> _skillDoubleTask; /** * Field _skillDoubleLaunchedTask. */ public Future<?> _skillDoubleLaunchedTask; /** * Field _stanceTask. */ private Future<?> _stanceTask; /** * Field _stanceTaskRunnable. */ private Runnable _stanceTaskRunnable; /** * Field _stanceEndTime. */ private long _stanceEndTime; /** * Field CLIENT_BAR_SIZE. (value is 352) */ public final static int CLIENT_BAR_SIZE = 352; /** * Field _lastCpBarUpdate. */ private int _lastCpBarUpdate = -1; /** * Field _lastHpBarUpdate. */ private int _lastHpBarUpdate = -1; /** * Field _lastMpBarUpdate. */ private int _lastMpBarUpdate = -1; /** * Field _currentCp. */ protected double _currentCp = 0; /** * Field _currentHp. */ protected double _currentHp = 1; /** * Field _currentMp. */ protected double _currentMp = 1; /** * Field _abnormalEffects. */ private int _abnormalEffects; /** * Field _abnormalEffects2. */ private int _abnormalEffects2; /** * Field _abnormalEffects3. */ private int _abnormalEffects3; /** * Field _isAttackAborted. */ private final FastList<Integer> _aveList = new FastList<Integer>(); protected boolean _isAttackAborted; /** * Field _attackEndTime. */ protected long _attackEndTime; /** * Field _attackReuseEndTime. */ protected long _attackReuseEndTime; /** * Field _poleAttackCount. */ private int _poleAttackCount = 0; /** * Field POLE_VAMPIRIC_MOD. */ private static final double[] POLE_VAMPIRIC_MOD = { 1, 0.9, 0, 7, 0.2, 0.01 }; /** * Field _skills. */ protected final Map<Integer, Skill> _skills = new ConcurrentSkipListMap<Integer, Skill>(); /** * Field _triggers. */ protected Map<TriggerType, Set<TriggerInfo>> _triggers; /** * Field _skillReuses. */ protected final IntObjectMap<TimeStamp> _skillReuses = new CHashIntObjectMap<TimeStamp>(); /** * Field _effectList. */ protected volatile EffectList _effectList; /** * Field _statsRecorder. */ protected volatile CharStatsChangeRecorder<? extends Creature> _statsRecorder; /** * Field _blockedStats. */ private List<Stats> _blockedStats; /** * Field isDead. */ protected AtomicBoolean isDead = new AtomicBoolean(); /** * Field isTeleporting. */ protected AtomicBoolean isTeleporting = new AtomicBoolean(); /** * Field _skillMastery. */ private Map<Integer, Integer> _skillMastery; /** * Field _isInvul. */ protected boolean _isInvul; /** * Field _fakeDeath. */ private boolean _fakeDeath; /** * Field _isBlessedByNoblesse. */ private boolean _isBlessedByNoblesse; /** * Field _isSalvation. */ private boolean _isSalvation; /** * Field _meditated. */ private boolean _meditated; /** * Field _lockedTarget. */ private boolean _lockedTarget; /** * Field _isTargetable. */ private boolean _isTargetable = true; /** * Field _blocked. */ private boolean _blocked; /** * Field _afraid. */ private final AtomicState _afraid = new AtomicState(); /** * Field _muted. */ private final AtomicState _muted = new AtomicState(); /** * Field _pmuted. */ private final AtomicState _pmuted = new AtomicState(); /** * Field _amuted. */ private final AtomicState _amuted = new AtomicState(); /** * Field _pulled. */ private final AtomicState _pulled = new AtomicState(); /** * Field _airbinded. */ private final AtomicState _airbinded = new AtomicState(); /** * Field _knockbacked. */ private final AtomicState _knockedback = new AtomicState(); /** * Field _knockdowned. */ private final AtomicState _knockeddown = new AtomicState(); /** * Field _paralyzed. */ private final AtomicState _paralyzed = new AtomicState(); /** * Field _rooted. */ private final AtomicState _rooted = new AtomicState(); /** * Field _sleeping. */ private final AtomicState _sleeping = new AtomicState(); /** * Field _stunned. */ private final AtomicState _stunned = new AtomicState(); /** * Field _immobilized. */ private final AtomicState _immobilized = new AtomicState(); /** * Field _confused. */ private final AtomicState _confused = new AtomicState(); /** * Field _frozen. */ private final AtomicState _frozen = new AtomicState(); /** * Field _healBlocked. */ private final AtomicState _healBlocked = new AtomicState(); /** * Field _damageBlocked. */ private final AtomicState _damageBlocked = new AtomicState(); /** * Field _buffImmunity. */ private final AtomicState _buffImmunity = new AtomicState(); /** * Field _debuffImmunity. */ private final AtomicState _debuffImmunity = new AtomicState(); /** * Field _effectImmunity. */ private final AtomicState _effectImmunity = new AtomicState(); /** * Field _weaponEquipBlocked. */ private final AtomicState _weaponEquipBlocked = new AtomicState(); /** * Field _flying. */ private boolean _flying; /** * Field _running. */ private boolean _running; /** * Field isMoving. */ public boolean isMoving; /** * Field isFollow. */ public boolean isFollow; /** * Field moveLock. */ final Lock moveLock = new ReentrantLock(); /** * Field _moveTask. */ Future<?> _moveTask; /** * Field _moveTaskRunnable. */ private MoveNextTask _moveTaskRunnable; /** * Field moveList. */ List<Location> moveList; /** * Field destination. */ private Location destination; /** * Field movingDestTempPos. */ final Location movingDestTempPos = new Location(); /** * Field _offset. */ int _offset; /** * Field _forestalling. */ boolean _forestalling; /** * Field target. */ private volatile HardReference<? extends GameObject> target = HardReferences.emptyRef(); /** * Field castingTarget. */ private volatile HardReference<? extends Creature> castingTarget = HardReferences.emptyRef(); /** * Field followTarget. */ private volatile HardReference<? extends Creature> followTarget = HardReferences.emptyRef(); /** * Field _aggressionTarget. */ private volatile HardReference<? extends Creature> _aggressionTarget = HardReferences.emptyRef(); /** * Field _targetRecorder. */ private final List<List<Location>> _targetRecorder = new ArrayList<List<Location>>(); /** * Field _followTimestamp. */ long _followTimestamp; /** * Field _startMoveTime. */ long _startMoveTime; /** * Field _previousSpeed. */ int _previousSpeed = 0; /** * Field _heading. */ private int _heading; /** * Field _calculators. */ private final Calculator[] _calculators; /** * Field _template. */ protected CharTemplate _template; /** * Field _ai. */ protected volatile CharacterAI _ai; /** * Field _name. */ protected String _name; /** * Field _title. */ protected String _title; /** * Field _team. */ protected TeamType _team = TeamType.NONE; /** * Field _isRegenerating. */ private boolean _isRegenerating; /** * Field regenLock. */ final Lock regenLock = new ReentrantLock(); /** * Field _regenTask. */ private Future<?> _regenTask; /** * Field _regenTaskRunnable. */ private Runnable _regenTaskRunnable; /** * Field _isEnabledDoubleCast. */ public boolean _isEnabledDoubleCast = false; /** * Field _isKnockedDown. */ public boolean _isKnockedDown = false; /** * Field _isKnockedDown. */ public boolean _isAirBind = false; /** * Field _zones. */ private final List<Zone> _zones = new LazyArrayList<Zone>(); /** * Field zonesLock. */ private final ReadWriteLock zonesLock = new ReentrantReadWriteLock(); /** * Field zonesRead. */ private final Lock zonesRead = zonesLock.readLock(); /** * Field zonesWrite. */ private final Lock zonesWrite = zonesLock.writeLock(); /** * Field listeners. */ protected volatile CharListenerList listeners; /** * Field _deathImmune. */ protected boolean _deathImmune = false; private List<Player> _statusListeners; private final Lock statusListenersLock = new ReentrantLock(); /** * Field _walkerRoutesTemplate. */ protected WalkerRouteTemplate _walkerRoutesTemplate = null; /** * Field _storedId. */ protected Long _storedId; /** * Method getStoredId. * @return Long */ public final Long getStoredId() { return _storedId; } /** * Field reference. */ protected HardReference<? extends Creature> reference; /** * Field _transformationId. */ private int _transformationId; /** * Field _transformationTemplate. */ private int _transformationTemplate; /** * Field _transformationName. */ private String _transformationName; /** * Constructor for Creature. * @param objectId int * @param template CharTemplate */ public Creature(int objectId, CharTemplate template) { super(objectId); _template = template; _calculators = new Calculator[Stats.NUM_STATS]; StatFunctions.addPredefinedFuncs(this); reference = new L2Reference<>(this); _storedId = GameObjectsStorage.put(this); } /** * Method getRef. * @return HardReference<? extends Creature> */ @Override public HardReference<? extends Creature> getRef() { return reference; } /** * Method isAttackAborted. * @return boolean */ public boolean isAttackAborted() { return _isAttackAborted; } /** * Method abortAttack. * @param force boolean * @param message boolean */ public final void abortAttack(boolean force, boolean message) { if (isAttackingNow()) { _attackEndTime = 0; if (force) { _isAttackAborted = true; } getAI().setIntention(AI_INTENTION_ACTIVE); if (isPlayer() && message) { sendActionFailed(); sendPacket(new SystemMessage(SystemMessage.C1S_ATTACK_FAILED).addName(this)); } } } /** * Method abortCast. * @param force boolean * @param message boolean */ public final void abortCast(boolean force, boolean message) { if (isCastingNow() && (force || canAbortCast())) { final Skill castingSkill = _castingSkill; final Future<?> skillTask = _skillTask; final Future<?> skillLaunchedTask = _skillLaunchedTask; final Future<?> skillDoubleTask = _skillDoubleTask; final Future<?> skillDoubleLaunchedTask = _skillDoubleLaunchedTask; finishFly(); clearCastVars(); if (skillTask != null) { skillTask.cancel(false); } if (skillLaunchedTask != null) { skillLaunchedTask.cancel(false); } if (skillDoubleTask != null) { skillDoubleTask.cancel(false); } if (skillDoubleLaunchedTask != null) { skillDoubleLaunchedTask.cancel(false); } if (castingSkill != null) { if (castingSkill.isUsingWhileCasting()) { Creature target = getAI().getAttackTarget(); if (target != null) { target.getEffectList().stopEffect(castingSkill.getId()); } } removeSkillMastery(castingSkill.getId()); } broadcastPacket(new MagicSkillCanceled(getObjectId())); getAI().setIntention(AI_INTENTION_ACTIVE); if (isPlayer() && message) { sendPacket(Msg.CASTING_HAS_BEEN_INTERRUPTED); } } } /** * Method canAbortCast. * @return boolean */ public final boolean canAbortCast() { return _castInterruptTime > System.currentTimeMillis(); } /** * Method absorbAndReflect. * @param target Creature * @param skill Skill * @param damage double * @return boolean */ public boolean absorbAndReflect(Creature target, Skill skill, double damage) { if (target.isDead()) { return false; } boolean bow = (getActiveWeaponItem() != null) && ((getActiveWeaponItem().getItemType() == WeaponType.BOW) || (getActiveWeaponItem().getItemType() == WeaponType.CROSSBOW)); double value = 0; if ((skill != null) && skill.isMagic()) { value = target.calcStat(Stats.REFLECT_AND_BLOCK_MSKILL_DAMAGE_CHANCE, 0, this, skill); } else if ((skill != null) && (skill.getCastRange() <= 200)) { value = target.calcStat(Stats.REFLECT_AND_BLOCK_PSKILL_DAMAGE_CHANCE, 0, this, skill); } else if ((skill == null) && !bow) { value = target.calcStat(Stats.REFLECT_AND_BLOCK_DAMAGE_CHANCE, 0, this, null); } if ((value > 0) && Rnd.chance(value)) { reduceCurrentHp(damage, 0, target, null, true, true, false, false, false, false, true); return true; } if ((skill != null) && skill.isMagic()) { value = target.calcStat(Stats.REFLECT_MSKILL_DAMAGE_PERCENT, 0, this, skill) - this.calcStat(Stats.REFLECT_RESISTANCE_PERCENT, 0., target, skill); } else if ((skill != null) && (skill.getCastRange() <= 200)) { value = target.calcStat(Stats.REFLECT_PSKILL_DAMAGE_PERCENT, 0, this, skill) - this.calcStat(Stats.REFLECT_RESISTANCE_PERCENT, 0., target, skill); } else if ((skill == null) && !bow) { value = target.calcStat(Stats.REFLECT_DAMAGE_PERCENT, 0, this, null) - this.calcStat(Stats.REFLECT_RESISTANCE_PERCENT, 0., target, null); } if (value > 0) { if ((target.getCurrentHp() + target.getCurrentCp()) > damage) { reduceCurrentHp((value / 100.) * damage, 0, target, null, true, true, false, false, false, false, true); } } if ((skill != null || bow) && Config.ALT_ABSORB_DAMAGE_ONLY_MEELE) { return false; } damage = (int) (damage - target.getCurrentCp()); if (damage <= 0) { return false; } final double poleMod = _poleAttackCount < POLE_VAMPIRIC_MOD.length ? POLE_VAMPIRIC_MOD[_poleAttackCount] : 0; double absorb = poleMod * calcStat(Stats.ABSORB_DAMAGE_PERCENT, 0, target, null); double limit; if ((absorb > 0) && !target.isDamageBlocked()) { limit = (calcStat(Stats.HP_LIMIT, null, null) * getMaxHp()) / 100.; if (getCurrentHp() < limit) { setCurrentHp(Math.min(_currentHp + ((damage * absorb * Config.ALT_ABSORB_DAMAGE_MODIFIER) / 100.), limit), false); } } absorb = poleMod * calcStat(Stats.ABSORB_DAMAGEMP_PERCENT, 0, target, null); if ((absorb > 0) && !target.isDamageBlocked()) { limit = (calcStat(Stats.MP_LIMIT, null, null) * getMaxMp()) / 100.; if (getCurrentMp() < limit) { setCurrentMp(Math.min(_currentMp + ((damage * absorb * Config.ALT_ABSORB_DAMAGE_MODIFIER) / 100.), limit)); } } return false; } /** * Method absorbToEffector. * @param attacker Creature * @param damage double * @return double */ public double absorbToEffector(Creature attacker, double damage) { double transferToEffectorDam = calcStat(Stats.TRANSFER_TO_EFFECTOR_DAMAGE_PERCENT, 0.); if (transferToEffectorDam > 0) { Effect effect = getEffectList().getEffectByType(EffectType.AbsorbDamageToEffector); if (effect == null) { return damage; } Creature effector = effect.getEffector(); if ((effector == this) || effector.isDead() || !isInRange(effector, 1200)) { return damage; } Player thisPlayer = getPlayer(); Player effectorPlayer = effector.getPlayer(); if ((thisPlayer != null) && (effectorPlayer != null)) { if ((thisPlayer != effectorPlayer) && (!thisPlayer.isOnline() || !thisPlayer.isInParty() || (thisPlayer.getParty() != effectorPlayer.getParty()))) { return damage; } } else { return damage; } double transferDamage = (damage * transferToEffectorDam) * .01; damage -= transferDamage; effector.reduceCurrentHp(transferDamage, 0, effector, null, false, false, !attacker.isPlayable(), false, true, false, true); } return damage; } /** * Method absorbToMp. * @param attacker Creature * @param damage double * @return double */ public double absorbToMp(Creature attacker, double damage) { double transferToMpDamPercent = calcStat(Stats.TRANSFER_TO_MP_DAMAGE_PERCENT, 0.); if (transferToMpDamPercent > 0) { double transferDamage = (damage * transferToMpDamPercent) * .01; double currentMp = getCurrentMp(); if (currentMp > transferDamage) { setCurrentMp(getCurrentMp() - transferDamage); return 0; } if (currentMp > 0) { damage -= currentMp; setCurrentMp(0); sendPacket(SystemMsg.MP_BECAME_0_AND_THE_ARCANE_SHIELD_IS_DISAPPEARING); } getEffectList().stopEffects(EffectType.AbsorbDamageToMp); return damage; } return damage; } /** * Method absorbToSummon. * @param attacker Creature * @param damage double * @return double */ public double absorbToSummon(Creature attacker, double damage) { if (!isPlayer()) { return damage; } double transferToSummonDam = calcStat(Stats.TRANSFER_TO_SUMMON_DAMAGE_PERCENT, 0.); if (transferToSummonDam > 0) { //TRANSFER DAMAGE ALWAYS TO THE FIRST SUMMON Summon summon = null; List<Summon> servitors = ((Player) this).getSummonList().getServitors(); double transferDamage = (damage * transferToSummonDam) * .01; if (servitors.size() > 0) { summon = servitors.get(0); } if (summon != null && !summon.isDead() && summon.getCurrentHp() > transferDamage && summon.isInRangeZ(this, 1200)) { damage -= transferDamage; summon.reduceCurrentHp(transferDamage, 0, summon, null, false, false, false, false, true, false, true); } else { getEffectList().stopEffects(EffectType.AbsorbDamageToSummon); return damage; } /* List<Summon> servitors = ((Player) this).getSummonList().getServitors(); double transferDamage = (damage * transferToSummonDam) * .01; for (Iterator<Summon> it = servitors.iterator(); it.hasNext();) { Summon summon = it.next(); if ((summon == null) || summon.isDead() || (summon.getCurrentHp() < (transferDamage / servitors.size()))) { it.remove(); } } if (servitors.size() > 0) { for (Summon summon : servitors) { if (summon.isInRangeZ(this, 1200)) { damage -= transferDamage; summon.reduceCurrentHp(transferDamage, 0, summon, null, false, false, false, false, true, false, true); } } } else { getEffectList().stopEffects(EffectType.AbsorbDamageToSummon); return damage; } */ } return damage; } /** * Method addBlockStats. * @param stats List<Stats> */ public void addBlockStats(List<Stats> stats) { if (_blockedStats == null) { _blockedStats = new ArrayList<Stats>(); } _blockedStats.addAll(stats); } /** * Method addSkill. * @param newSkill Skill * @return Skill */ public Skill addSkill(Skill newSkill) { if (newSkill == null) { return null; } Skill oldSkill = _skills.get(newSkill.getId()); if ((oldSkill != null) && (oldSkill.getLevel() == newSkill.getLevel())) { return newSkill; } _skills.put(newSkill.getId(), newSkill); if (oldSkill != null) { removeStatsOwner(oldSkill); removeTriggers(oldSkill); } addTriggers(newSkill); addStatFuncs(newSkill.getStatFuncs()); return oldSkill; } /** * Method getCalculators. * @return Calculator[] */ public Calculator[] getCalculators() { return _calculators; } /** * Method addStatFunc. * @param f Func */ public final void addStatFunc(Func f) { if (f == null) { return; } int stat = f.stat.ordinal(); synchronized (_calculators) { if (_calculators[stat] == null) { _calculators[stat] = new Calculator(f.stat, this); } _calculators[stat].addFunc(f); } } /** * Method addStatFuncs. * @param funcs Func[] */ public final void addStatFuncs(Func[] funcs) { for (Func f : funcs) { addStatFunc(f); } } /** * Method removeStatFunc. * @param f Func */ public final void removeStatFunc(Func f) { if (f == null) { return; } int stat = f.stat.ordinal(); synchronized (_calculators) { if (_calculators[stat] != null) { _calculators[stat].removeFunc(f); } } } /** * Method removeStatFuncs. * @param funcs Func[] */ public final void removeStatFuncs(Func[] funcs) { for (Func f : funcs) { removeStatFunc(f); } } /** * Method removeStatsOwner. * @param owner Object */ public final void removeStatsOwner(Object owner) { synchronized (_calculators) { for (Calculator _calculator : _calculators) { if (_calculator != null) { _calculator.removeOwner(owner); } } } } /** * Method altOnMagicUseTimer. * @param aimingTarget Creature * @param skill Skill */ public void altOnMagicUseTimer(Creature aimingTarget, Skill skill) { if (isAlikeDead()) { return; } int magicId = skill.getDisplayId(); int level = Math.max(1, getSkillDisplayLevel(skill.getId())); List<Creature> targets = skill.getTargets(this, aimingTarget, true); broadcastPacket(new MagicSkillLaunched(getObjectId(), magicId, level, targets)); double mpConsume2 = skill.getMpConsume2(); if (mpConsume2 > 0) { if (_currentMp < mpConsume2) { sendPacket(Msg.NOT_ENOUGH_MP); return; } if (skill.isMagic()) { reduceCurrentMp(calcStat(Stats.MP_MAGIC_SKILL_CONSUME, mpConsume2, aimingTarget, skill), null); } else { reduceCurrentMp(calcStat(Stats.MP_PHYSICAL_SKILL_CONSUME, mpConsume2, aimingTarget, skill), null); } } callSkill(skill, targets, false); } /** * Method altUseSkill. * @param skill Skill * @param target Creature */ public void altUseSkill(Skill skill, Creature target) { if (skill == null) { return; } int magicId = skill.getId(); if (isUnActiveSkill(magicId)) { return; } if (isSkillDisabled(skill)) { sendReuseMessage(skill); return; } if (target == null) { target = skill.getAimingTarget(this, getTarget()); if (target == null) { return; } } getListeners().onMagicUse(skill, target, true); int itemConsume[] = skill.getItemConsume(); if (itemConsume[0] > 0) { for (int i = 0; i < itemConsume.length; i++) { if (!consumeItem(skill.getItemConsumeId()[i], itemConsume[i])) { sendPacket(skill.isHandler() ? SystemMsg.INCORRECT_ITEM_COUNT : SystemMsg.THERE_ARE_NOT_ENOUGH_NECESSARY_ITEMS_TO_USE_THE_SKILL); return; } } } if (skill.getReferenceItemId() > 0) { if (!consumeItemMp(skill.getReferenceItemId(), skill.getReferenceItemMpConsume())) { return; } } if (skill.getSoulsConsume() > getConsumedSouls()) { sendPacket(Msg.THERE_IS_NOT_ENOUGHT_SOUL); return; } if (skill.getEnergyConsume() > getAgathionEnergy()) { sendPacket(SystemMsg.THE_SKILL_HAS_BEEN_CANCELED_BECAUSE_YOU_HAVE_INSUFFICIENT_ENERGY); return; } if (skill.getSoulsConsume() > 0) { setConsumedSouls(getConsumedSouls() - skill.getSoulsConsume(), null); } if (skill.getEnergyConsume() > 0) { setAgathionEnergy(getAgathionEnergy() - skill.getEnergyConsume()); } int level = Math.max(1, getSkillDisplayLevel(magicId)); Formulas.calcSkillMastery(skill, this); long reuseDelay = Formulas.calcSkillReuseDelay(this, skill); if (!skill.isToggle() || skill.isAwakeningToggle()) { broadcastPacket( new MagicSkillUse(this, target, skill.getDisplayId(), level, skill.getHitTime(), reuseDelay)); } if (!skill.isHideUseMessage()) { if (skill.getSkillType() == SkillType.PET_SUMMON) { sendPacket(new SystemMessage(SystemMessage.SUMMON_A_PET)); } else if (!skill.isHandler()) { sendPacket(new SystemMessage(SystemMessage.YOU_USE_S1).addSkillName(magicId, level)); } else { sendPacket(new SystemMessage(SystemMessage.YOU_USE_S1).addItemName(skill.getItemConsumeId()[0])); } } if (!skill.isHandler()) { disableSkill(skill, reuseDelay); } ThreadPoolManager.getInstance().schedule(new AltMagicUseTask(this, target, skill), skill.getHitTime()); } /** * Method sendReuseMessage. * @param skill Skill */ public void sendReuseMessage(Skill skill) { } /** * Method broadcastPacket. * @param packets L2GameServerPacket[] */ public void broadcastPacket(L2GameServerPacket... packets) { sendPacket(packets); broadcastPacketToOthers(packets); } /** * Method broadcastPacket. * @param packets List<L2GameServerPacket> */ public void broadcastPacket(List<L2GameServerPacket> packets) { sendPacket(packets); broadcastPacketToOthers(packets); } /** * Method broadcastPacketToOthers. * @param packets L2GameServerPacket[] */ public void broadcastPacketToOthers(L2GameServerPacket... packets) { if (!isVisible() || (packets.length == 0)) { return; } List<Player> players = World.getAroundPlayers(this); Player target; for (int i = 0; i < players.size(); i++) { target = players.get(i); target.sendPacket(packets); } } /** * Method broadcastPacketToOthers. * @param packets List<L2GameServerPacket> */ public void broadcastPacketToOthers(List<L2GameServerPacket> packets) { if (!isVisible() || packets.isEmpty()) { return; } List<Player> players = World.getAroundPlayers(this); Player target; for (int i = 0; i < players.size(); i++) { target = players.get(i); target.sendPacket(packets); } } public void broadcastToStatusListeners(L2GameServerPacket... packets) { if (!isVisible() || (packets.length == 0)) { return; } statusListenersLock.lock(); try { if ((_statusListeners == null) || _statusListeners.isEmpty()) { return; } Player player; for (int i = 0; i < _statusListeners.size(); i++) { player = _statusListeners.get(i); player.sendPacket(packets); } } finally { statusListenersLock.unlock(); } } public void addStatusListener(Player cha) { if (cha == this) { return; } statusListenersLock.lock(); try { if (_statusListeners == null) { _statusListeners = new LazyArrayList<Player>(); } if (!_statusListeners.contains(cha)) { _statusListeners.add(cha); } } finally { statusListenersLock.unlock(); } } public void removeStatusListener(Creature cha) { statusListenersLock.lock(); try { if (_statusListeners == null) { return; } _statusListeners.remove(cha); } finally { statusListenersLock.unlock(); } } public void clearStatusListeners() { statusListenersLock.lock(); try { if (_statusListeners == null) { return; } _statusListeners.clear(); } finally { statusListenersLock.unlock(); } } /** * Method broadcastStatusUpdate. */ public void broadcastStatusUpdate() { if (!needStatusUpdate()) { return; } StatusUpdate statusUpdatePacket = new StatusUpdate(this).addAttribute(StatusUpdateField.CUR_HP, StatusUpdateField.MAX_HP); for (final Player pla : World.getAroundPlayers(this)) { if (pla == null) { continue; } pla.sendPacket(statusUpdatePacket); } } /** * Method calcHeading. * @param x_dest int * @param y_dest int * @return int */ public int calcHeading(int x_dest, int y_dest) { return (int) (Math.atan2(getY() - y_dest, getX() - x_dest) * HEADINGS_IN_PI) + 32768; } /** * Method calcStat. * @param stat Stats * @param init double * @return double */ public final double calcStat(Stats stat, double init) { return calcStat(stat, init, null, null); } /** * Method calcStat. * @param stat Stats * @param init double * @param target Creature * @param skill Skill * @return double */ public final double calcStat(Stats stat, double init, Creature target, Skill skill) { int id = stat.ordinal(); Calculator c = _calculators[id]; if (c == null) { return init; } Env env = new Env(); env.character = this; env.target = target; env.skill = skill; env.value = init; c.calc(env); return env.value; } /** * Method calcStat. * @param stat Stats * @param target Creature * @param skill Skill * @return double */ public final double calcStat(Stats stat, Creature target, Skill skill) { Env env = new Env(this, target, skill); env.value = stat.getInit(); int id = stat.ordinal(); Calculator c = _calculators[id]; if (c != null) { c.calc(env); } return env.value; } /** * Method calculateAttackDelay. * @return int */ public int calculateAttackDelay() { return Formulas.calcPAtkSpd(getPAtkSpd()); } /** * Method callSkill. * @param skill Skill * @param targets List<Creature> * @param useActionSkills boolean */ public void callSkill(Skill skill, List<Creature> targets, boolean useActionSkills) { try { if (useActionSkills && !skill.isUsingWhileCasting() && (_triggers != null)) { if (skill.isOffensive()) { if (skill.isMagic()) { useTriggers(getTarget(), TriggerType.OFFENSIVE_MAGICAL_SKILL_USE, null, skill, 0); } else { useTriggers(getTarget(), TriggerType.OFFENSIVE_PHYSICAL_SKILL_USE, null, skill, 0); } } else if (skill.isMagic()) { final boolean targetSelf = skill.isAoE() || skill.isNotTargetAoE() || (skill.getTargetType() == Skill.SkillTargetType.TARGET_SELF); useTriggers(targetSelf ? this : getTarget(), TriggerType.SUPPORT_MAGICAL_SKILL_USE, null, skill, 0); } } Player pl = getPlayer(); Creature target; Iterator<Creature> itr = targets.iterator(); while (itr.hasNext()) { target = itr.next(); if (skill.isOffensive() && target.isInvul()) { Player pcTarget = target.getPlayer(); if ((!skill.isIgnoreInvul() || ((pcTarget != null) && pcTarget.isGM())) && !target.isArtefact()) { itr.remove(); continue; } } Effect ie = target.getEffectList().getEffectByType(EffectType.IgnoreSkill); if (ie != null) { if (ArrayUtils.contains(ie.getTemplate().getParam().getIntegerArray("skillId"), skill.getId())) { itr.remove(); continue; } } for (EffectTemplate ef : skill.getEffectTemplates()) { if ((target.isAirBinded() || target.isKnockedDown()) && (ef.getEffectType() == EffectType.KnockDown || ef.getEffectType() == EffectType.HellBinding)) { itr.remove(); continue; } } target.getListeners().onMagicHit(skill, this); if (pl != null) { if ((target != null) && target.isNpc()) { NpcInstance npc = (NpcInstance) target; List<QuestState> ql = pl.getQuestsForEvent(npc, QuestEventType.MOB_TARGETED_BY_SKILL, false); if (ql != null) { for (QuestState qs : ql) { qs.getQuest().notifySkillUse(npc, skill, qs); } } } } if (skill.getNegateSkill() > 0) { for (Effect e : target.getEffectList().getAllEffects()) { Skill efs = e.getSkill(); if ((efs.getId() == skill.getNegateSkill()) && e.isCancelable() && ((skill.getNegatePower() <= 0) || (efs.getPower() <= skill.getNegatePower()))) { e.exit(); } } } if (target.getEffectList().getEffectByType(EffectType.DispelOnHit) != null) { target.getEffectList().getEffectByType(EffectType.DispelOnHit).onActionTime(); } if (skill.getCancelTarget() > 0) { if (Rnd.chance(skill.getCancelTarget())) { if (((target.getCastingSkill() == null) || !((target.getCastingSkill().getSkillType() == SkillType.TAKECASTLE) || (target.getCastingSkill().getSkillType() == SkillType.TAKEFORTRESS))) && !target.isRaid()) { target.abortAttack(true, true); target.abortCast(true, true); target.setTarget(null); } } } } if (skill.isOffensive()) { startAttackStanceTask(); } if (!(skill.isNotTargetAoE() && skill.isOffensive() && (targets.size() == 0))) { skill.getEffects(this, this, false, true); } skill.useSkill(this, targets); } catch (Exception e) { _log.error("", e); } } /** * Method useTriggers. * @param target GameObject * @param type TriggerType * @param ex Skill * @param owner Skill * @param damage double */ public void useTriggers(GameObject target, TriggerType type, Skill ex, Skill owner, double damage) { if (_triggers == null) { return; } Set<TriggerInfo> SkillsOnSkillAttack = _triggers.get(type); if (SkillsOnSkillAttack != null) { for (TriggerInfo t : SkillsOnSkillAttack) { if (t.getSkill() != ex) { useTriggerSkill(target == null ? getTarget() : target, null, t, owner, damage); } } } } /** * Method useTriggerSkill. * @param target GameObject * @param targets List<Creature> * @param trigger TriggerInfo * @param owner Skill * @param damage double */ public void useTriggerSkill(GameObject target, List<Creature> targets, TriggerInfo trigger, Skill owner, double damage) { Skill skill = trigger.getSkill(); if ((skill.getReuseDelay() > 0) && isSkillDisabled(skill)) { return; } Creature aimTarget = skill.getAimingTarget(this, target); Creature realTarget = (target != null) && target.isCreature() ? (Creature) target : null; if (Rnd.chance(trigger.getChance()) && trigger.checkCondition(this, realTarget, aimTarget, owner, damage) && skill.checkCondition(this, aimTarget, false, true, true)) { if (targets == null) { targets = skill.getTargets(this, aimTarget, false); } int displayId = 0, displayLevel = 0; if (skill.hasEffects()) { displayId = skill.getEffectTemplates()[0]._displayId; displayLevel = skill.getEffectTemplates()[0]._displayLevel; } if (displayId == 0) { displayId = skill.getDisplayId(); } if (displayLevel == 0) { displayLevel = skill.getDisplayLevel(); } if (trigger.getType() != TriggerType.SUPPORT_MAGICAL_SKILL_USE) { for (Creature cha : targets) { broadcastPacket(new MagicSkillUse(this, cha, displayId, displayLevel, 0, 0)); } } Formulas.calcSkillMastery(skill, this); callSkill(skill, targets, false); disableSkill(skill, skill.getReuseDelay()); } } /** * Method checkBlockedStat. * @param stat Stats * @return boolean */ public boolean checkBlockedStat(Stats stat) { return (_blockedStats != null) && _blockedStats.contains(stat); } /** * Method checkReflectSkill. * @param attacker Creature * @param skill Skill * @return boolean */ public boolean checkReflectSkill(Creature attacker, Skill skill) { if (!skill.isReflectable()) { return false; } if (isInvul() || attacker.isInvul() || !skill.isOffensive()) { return false; } if (skill.isMagic() && (skill.getSkillType() != SkillType.MDAM)) { return false; } if (Rnd.chance(calcStat(skill.isMagic() ? Stats.REFLECT_MAGIC_SKILL : Stats.REFLECT_PHYSIC_SKILL, 0, attacker, skill))) { sendPacket(new SystemMessage(SystemMessage.YOU_COUNTERED_C1S_ATTACK).addName(attacker)); attacker.sendPacket(new SystemMessage(SystemMessage.C1_DODGES_THE_ATTACK).addName(this)); return true; } return false; } /** * Method doCounterAttack. * @param skill Skill * @param attacker Creature * @param blow boolean */ public void doCounterAttack(Skill skill, Creature attacker, boolean blow) { if (isDead()) { return; } if (isDamageBlocked() || attacker.isDamageBlocked()) { return; } if ((skill == null) || skill.hasEffects() || skill.isMagic() || !skill.isOffensive() || (skill.getCastRange() > 200)) { return; } if (Rnd.chance(calcStat(Stats.COUNTER_ATTACK, 0, attacker, skill))) { double damage = (1189 * getPAtk(attacker)) / Math.max(attacker.getPDef(this), 1); attacker.sendPacket(new SystemMessage(SystemMessage.C1S_IS_PERFORMING_A_COUNTERATTACK).addName(this)); if (blow) { sendPacket(new SystemMessage(SystemMessage.C1S_IS_PERFORMING_A_COUNTERATTACK).addName(this)); sendPacket(new SystemMessage(SystemMessage.C1_HAS_GIVEN_C2_DAMAGE_OF_S3).addName(this) .addName(attacker).addNumber((long) damage)); attacker.reduceCurrentHp(damage, damage, this, skill, true, true, false, false, false, false, true); } else { sendPacket(new SystemMessage(SystemMessage.C1S_IS_PERFORMING_A_COUNTERATTACK).addName(this)); } sendPacket(new SystemMessage(SystemMessage.C1_HAS_GIVEN_C2_DAMAGE_OF_S3).addName(this).addName(attacker) .addNumber((long) damage)); attacker.reduceCurrentHp(damage, damage, this, skill, true, true, false, false, false, false, true); } } /** * Method disableSkill. * @param skill Skill * @param delay long */ public void disableSkill(Skill skill, long delay) { _skillReuses.put(skill.hashCode(), new TimeStamp(skill, delay)); } /** * Method isAutoAttackable. * @param attacker Creature * @return boolean */ public abstract boolean isAutoAttackable(Creature attacker); /** * Method doAttack. * @param target Creature */ public void doAttack(Creature target) { if ((target == null) || isAMuted() || isAttackingNow() || isAlikeDead() || target.isAlikeDead() || !isInRange(target, 2000) || (isPlayer() && getPlayer().isInMountTransform())) { return; } getListeners().onAttack(target); int sAtk = Math.max(calculateAttackDelay(), 333); int ssGrade = 0; WeaponTemplate weaponItem = getActiveWeaponItem(); if (weaponItem != null) { if (isPlayer() && (weaponItem.getAttackReuseDelay() > 0)) { int reuse = (int) ((weaponItem.getAttackReuseDelay() * getReuseModifier(target) * 666 * calcStat(Stats.ATK_BASE, 0, target, null)) / 293. / getPAtkSpd()); if (reuse > 0) { sendPacket(new SetupGauge(this, SetupGauge.RED_MINI, reuse)); _attackReuseEndTime = (reuse + System.currentTimeMillis()) - 75; if (reuse > sAtk) { ThreadPoolManager.getInstance() .schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT, null, null), reuse); } } } ssGrade = weaponItem.getCrystalType().externalOrdinal; } _attackEndTime = (sAtk + System.currentTimeMillis()) - 10; _isAttackAborted = false; Attack attack = new Attack(this, target, getChargedSoulShot(), ssGrade); setHeading(PositionUtils.calculateHeadingFrom(this, target)); if (weaponItem == null) { doAttackHitSimple(attack, target, 1., !isPlayer(), sAtk, true); } else { switch (weaponItem.getItemType()) { case BOW: case CROSSBOW: doAttackHitByBow(attack, target, sAtk); break; case POLE: doAttackHitByPole(attack, target, sAtk); break; case DUAL: case DUALFIST: case DUALDAGGER: doAttackHitByDual(attack, target, sAtk); break; default: doAttackHitSimple(attack, target, 1., true, sAtk, true); } } if (attack.hasHits()) { broadcastPacket(attack); } } /** * Method doAttackHitSimple. * @param attack Attack * @param target Creature * @param multiplier double * @param unchargeSS boolean * @param sAtk int * @param notify boolean */ private void doAttackHitSimple(Attack attack, Creature target, double multiplier, boolean unchargeSS, int sAtk, boolean notify) { int damage1 = 0, reflectableDamage1 = 0; boolean shld1 = false; boolean crit1 = false; boolean miss1 = Formulas.calcHitMiss(this, target); if (!miss1) { AttackInfo info = Formulas.calcPhysDam(this, target, null, false, false, attack._soulshot, false); damage1 = (int) (info.damage * multiplier); reflectableDamage1 = (int) (info.reflectableDamage * multiplier); shld1 = info.shld; crit1 = info.crit; } ThreadPoolManager.getInstance().schedule(new HitTask(this, target, damage1, reflectableDamage1, crit1, miss1, attack._soulshot, shld1, unchargeSS, notify), sAtk); attack.addHit(target, damage1, miss1, crit1, shld1); } /** * Method doAttackHitByBow. * @param attack Attack * @param target Creature * @param sAtk int */ private void doAttackHitByBow(Attack attack, Creature target, int sAtk) { WeaponTemplate activeWeapon = getActiveWeaponItem(); if (activeWeapon == null) { return; } int damage1 = 0, damage2 = 0; boolean shld1 = false; boolean crit1 = false; boolean miss1 = Formulas.calcHitMiss(this, target); reduceArrowCount(); if (!miss1) { AttackInfo info = Formulas.calcPhysDam(this, target, null, false, false, attack._soulshot, false); damage1 = (int) info.damage; damage2 = (int) info.reflectableDamage; shld1 = info.shld; crit1 = info.crit; int range = activeWeapon.getAttackRange(); damage1 *= ((Math.min(range, getDistance(target)) / range) * .4) + 0.8; } ThreadPoolManager.getInstance().schedule( new HitTask(this, target, damage1, damage2, crit1, miss1, attack._soulshot, shld1, true, true), sAtk); attack.addHit(target, damage2, miss1, crit1, shld1); } /** * Method doAttackHitByDual. * @param attack Attack * @param target Creature * @param sAtk int */ private void doAttackHitByDual(Attack attack, Creature target, int sAtk) { int damage1 = 0; int damage2 = 0; int reflectableDamage1 = 0, reflectableDamage2 = 0; boolean shld1 = false; boolean shld2 = false; boolean crit1 = false; boolean crit2 = false; boolean miss1 = Formulas.calcHitMiss(this, target); boolean miss2 = Formulas.calcHitMiss(this, target); if (!miss1) { AttackInfo info = Formulas.calcPhysDam(this, target, null, true, false, attack._soulshot, false); damage1 = (int) info.damage; reflectableDamage1 = (int) info.reflectableDamage; shld1 = info.shld; crit1 = info.crit; } if (!miss2) { AttackInfo info = Formulas.calcPhysDam(this, target, null, true, false, attack._soulshot, false); damage2 = (int) info.damage; reflectableDamage2 = (int) info.reflectableDamage; shld2 = info.shld; crit2 = info.crit; } ThreadPoolManager.getInstance().schedule(new HitTask(this, target, damage1, reflectableDamage1, crit1, miss1, attack._soulshot, shld1, true, false), sAtk / 2); ThreadPoolManager.getInstance().schedule(new HitTask(this, target, damage2, reflectableDamage2, crit2, miss2, attack._soulshot, shld2, false, true), sAtk); attack.addHit(target, damage1, miss1, crit1, shld1); attack.addHit(target, damage2, miss2, crit2, shld2); } /** * Method doAttackHitByPole. * @param attack Attack * @param target Creature * @param sAtk int */ private void doAttackHitByPole(Attack attack, Creature target, int sAtk) { int angle = (int) calcStat(Stats.POLE_ATTACK_ANGLE, 90, target, null); int range = (int) calcStat(Stats.POWER_ATTACK_RANGE, getTemplate().getBaseAtkRange(), target, null); int attackcountmax = (int) Math.round(calcStat(Stats.POLE_TARGET_COUNT, 0, target, null)); if (isBoss()) { attackcountmax += 27; } else if (isRaid()) { attackcountmax += 12; } else if (isMonster() && (getLevel() > 0)) { attackcountmax += getLevel() / 7.5; } double mult = 1.; _poleAttackCount = 1; if (!isInZonePeace()) { for (Creature t : getAroundCharacters(range, 200)) { if (_poleAttackCount <= attackcountmax) { if ((t == target) || t.isDead() || !PositionUtils.isFacing(this, t, angle)) { continue; } if (t.isAutoAttackable(this)) { doAttackHitSimple(attack, t, mult, false, sAtk, false); mult *= Config.ALT_POLE_DAMAGE_MODIFIER; _poleAttackCount++; } } else { break; } } } _poleAttackCount = 0; doAttackHitSimple(attack, target, 1., true, sAtk, true); } /** * Method getAnimationEndTime. * @return long */ public long getAnimationEndTime() { return _animationEndTime; } /** * Method doCast. * @param skill Skill * @param target Creature * @param forceUse boolean */ public void doCast(Skill skill, Creature target, boolean forceUse) { if (skill == null) { return; } int itemConsume[] = skill.getItemConsume(); if (itemConsume[0] > 0) { for (int i = 0; i < itemConsume.length; i++) { if (!consumeItem(skill.getItemConsumeId()[i], itemConsume[i])) { sendPacket(skill.isHandler() ? SystemMsg.INCORRECT_ITEM_COUNT : SystemMsg.THERE_ARE_NOT_ENOUGH_NECESSARY_ITEMS_TO_USE_THE_SKILL); return; } } } if (skill.getReferenceItemId() > 0) { if (!consumeItemMp(skill.getReferenceItemId(), skill.getReferenceItemMpConsume())) { return; } } int magicId = skill.getId(); if (target == null) { target = skill.getAimingTarget(this, getTarget()); } if (target == null) { return; } getListeners().onMagicUse(skill, target, false); if (this != target) { setHeading(PositionUtils.calculateHeadingFrom(this, target)); } int level = Math.max(1, getSkillDisplayLevel(magicId)); int skillTime = skill.isSkillTimePermanent() ? skill.getHitTime() : Formulas.calcMAtkSpd(this, skill, skill.getHitTime()); int skillInterruptTime = skill.isMagic() ? Formulas.calcMAtkSpd(this, skill, skill.getSkillInterruptTime()) : 0; int minCastTime = Math.min(Config.SKILLS_CAST_TIME_MIN, skill.getHitTime()); if (skillTime < minCastTime) { skillTime = minCastTime; skillInterruptTime = 0; } _animationEndTime = System.currentTimeMillis() + skillTime; if (skill.isMagic() && !skill.isSkillTimePermanent() && (getChargedSpiritShot() > 0)) { skillTime = (int) (0.70 * skillTime); skillInterruptTime = (int) (0.70 * skillInterruptTime); } Formulas.calcSkillMastery(skill, this); long reuseDelay = Math.max(0, Formulas.calcSkillReuseDelay(this, skill)); broadcastPacket(new MagicSkillUse(this, target, skill.getDisplayId(), level, skillTime, reuseDelay, isDoubleCastingNow())); if (skill.getFlyType() == FlyType.CHARGE) { skillTime = minCastTime; } if (!skill.isHandler()) { disableSkill(skill, reuseDelay); } if (isPlayer()) { if (skill.getSkillType() == SkillType.PET_SUMMON) { sendPacket(Msg.SUMMON_A_PET); } else if (!skill.isHandler()) { if (!skill.isAlterSkill()) sendPacket(new SystemMessage(SystemMessage.YOU_USE_S1).addSkillName(magicId, level)); } else { sendPacket(new SystemMessage(SystemMessage.YOU_USE_S1).addItemName(skill.getItemConsumeId()[0])); } } if (skill.getTargetType() == SkillTargetType.TARGET_HOLY) { target.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, this, 1); } double mpConsume1 = skill.isUsingWhileCasting() ? skill.getMpConsume() : skill.getMpConsume1(); if (mpConsume1 > 0) { if (_currentMp < mpConsume1) { sendPacket(Msg.NOT_ENOUGH_MP); onCastEndTime(false); return; } reduceCurrentMp(mpConsume1, null); } _castingSkill = skill; _castInterruptTime = System.currentTimeMillis() + skillInterruptTime; setCastingTarget(target); if (skill.isUsingWhileCasting()) { callSkill(skill, skill.getTargets(this, target, forceUse), true); } if (isPlayer()) { sendPacket(new SetupGauge(this, SetupGauge.BLUE_DUAL, skillTime)); } _scheduledCastCount = skill.getCastCount(); _scheduledCastInterval = skill.getCastCount() > 0 ? skillTime / _scheduledCastCount : skillTime; if (!isDoubleCastingNow() && IsEnabledDoubleCast()) { _skillDoubleLaunchedTask = ThreadPoolManager.getInstance() .schedule(new MagicLaunchedTask(this, forceUse), skillInterruptTime); _skillDoubleTask = ThreadPoolManager.getInstance().schedule(new MagicUseTask(this, forceUse), skill.getCastCount() > 0 ? skillTime / skill.getCastCount() : skillTime); } else { _skillLaunchedTask = ThreadPoolManager.getInstance().schedule(new MagicLaunchedTask(this, forceUse), skillInterruptTime); _skillTask = ThreadPoolManager.getInstance().schedule(new MagicUseTask(this, forceUse), skill.getCastCount() > 0 ? skillTime / skill.getCastCount() : skillTime); } } /** * Field _flyLoc. */ private Location _flyLoc; /** * Method getFlyLocation. * @param target GameObject * @param skill Skill * @return Location */ public Location getFlyLocation(GameObject target, Skill skill) { if ((target != null) && (target != this)) { Location loc; double radian = PositionUtils.convertHeadingToRadian(target.getHeading()); if (skill.isFlyToBack()) { loc = new Location(target.getX() + (int) (Math.sin(radian) * 40), target.getY() - (int) (Math.cos(radian) * 40), target.getZ()); } else { loc = new Location(target.getX() - (int) (Math.sin(radian) * 40), target.getY() + (int) (Math.cos(radian) * 40), target.getZ()); } if (isFlying()) { if (isPlayer() && ((Player) this).isInFlyingTransform() && ((loc.z <= 0) || (loc.z >= 6000))) { return null; } if (GeoEngine.moveCheckInAir(getX(), getY(), getZ(), loc.x, loc.y, loc.z, getColRadius(), getGeoIndex()) == null) { return null; } } else { loc.correctGeoZ(); if (!GeoEngine.canMoveToCoord(getX(), getY(), getZ(), loc.x, loc.y, loc.z, getGeoIndex())) { loc = target.getLoc(); if (!GeoEngine.canMoveToCoord(getX(), getY(), getZ(), loc.x, loc.y, loc.z, getGeoIndex())) { return null; } } } return loc; } int x1 = 0; int y1 = 0; int z1 = 0; if (skill.getFlyType() == FlyType.THROW_UP) { x1 = 0; y1 = 0; z1 = getZ() + skill.getFlyRadius(); } else { double radian = PositionUtils.convertHeadingToRadian(getHeading()); x1 = -(int) (Math.sin(radian) * skill.getFlyRadius()); y1 = (int) (Math.cos(radian) * skill.getFlyRadius()); } if (isFlying()) { return GeoEngine.moveCheckInAir(getX(), getY(), getZ(), getX() + x1, getY() + y1, getZ() + z1, getColRadius(), getGeoIndex()); } return GeoEngine.moveCheck(getX(), getY(), getZ(), getX() + x1, getY() + y1, getGeoIndex()); } /** * Method doDie. * @param killer Creature */ public final void doDie(Creature killer) { if (!isDead.compareAndSet(false, true)) { return; } onDeath(killer); } /** * Method onDeath. * @param killer Creature */ protected void onDeath(Creature killer) { if (killer != null) { Player killerPlayer = killer.getPlayer(); if (killerPlayer != null) { killerPlayer.getListeners().onKillIgnorePetOrSummon(this); WorldStatisticsManager.getInstance().updateStat(killerPlayer, CategoryType.MONSTERS_KILLED, 1L); } killer.getListeners().onKill(this); if (isPlayer() && killer.isPlayable()) { _currentCp = 0; } } setTarget(null); stopMove(); stopAttackStanceTask(); stopRegeneration(); _currentHp = 0; if (isBlessedByNoblesse() || isSalvation()) { if (isSalvation() && isPlayer() && !getPlayer().isInOlympiadMode()) { getPlayer().reviveRequest(getPlayer(), 100, false); } for (Effect e : getEffectList().getAllEffects()) { if ((e.getEffectType() == EffectType.BlessNoblesse) || (e.getSkill().getId() == Skill.SKILL_FORTUNE_OF_NOBLESSE) || (e.getSkill().getId() == Skill.SKILL_RAID_BLESSING)) { e.exit(); } else if (e.getEffectType() == EffectType.AgathionResurrect) { if (isPlayer()) { getPlayer().setAgathionRes(true); } e.exit(); } } } else { for (Effect e : getEffectList().getAllEffects()) { if ((e.getEffectType() != EffectType.Transformation) && !e.getSkill().isPreservedOnDeath()) { e.exit(); } } } ThreadPoolManager.getInstance().execute(new NotifyAITask(this, CtrlEvent.EVT_DEAD, killer, null)); getListeners().onDeath(killer); updateEffectIcons(); updateStats(); broadcastStatusUpdate(); } /** * Method onRevive. */ protected void onRevive() { } /** * Method enableSkill. * @param skill Skill */ public void enableSkill(Skill skill) { _skillReuses.remove(skill.hashCode()); } /** * Method getAbnormalEffect. * @return integer */ public int getAbnormalEffect() { return _abnormalEffects; } /** * Method getAbnormalEffect2. * @return integer */ public int getAbnormalEffect2() { return _abnormalEffects2; } /** * Method getAbnormalEffect3. * @return integer */ public int getAbnormalEffect3() { return _abnormalEffects3; } /** * Method getAveList. * @return FastList<Integer> */ public FastList<Integer> getAveList() { return _aveList; } public void addToAveList(int aeId) { if (!_aveList.contains(aeId)) { _aveList.add(aeId); } } public void removeFromAveList(int aeId) { if (_aveList.contains(aeId)) { _aveList.remove(_aveList.indexOf(aeId)); } } /** * Method getAccuracy. * @return int */ public int getAccuracy() { return (int) calcStat(Stats.ACCURACY_COMBAT, 0, null, null); } /** * Method getMAccuracy. * @return int */ public int getMAccuracy() { return (int) calcStat(Stats.MACCURACY_COMBAT, 0, null, null); } /** * Method getAllSkills. * @return Collection<Skill> */ public Collection<Skill> getAllSkills() { return _skills.values(); } /** * Method getAllSkillsArray. * @return Skill[] */ public final Skill[] getAllSkillsArray() { Collection<Skill> vals = _skills.values(); return vals.toArray(new Skill[vals.size()]); } /** * Method getAttackSpeedMultiplier. * @return double */ public final double getAttackSpeedMultiplier() { return (1.1 * getPAtkSpd()) / getTemplate().getBasePAtkSpd(); } /** * Method getBuffLimit. * @return int */ public int getBuffLimit() { return (int) calcStat(Stats.BUFF_LIMIT, Config.ALT_BUFF_LIMIT, null, null); } /** * Method getCastingSkill. * @return Skill */ public Skill getCastingSkill() { return _castingSkill; } /** * Method getCriticalHit. * @param target Creature * @param skill Skill * @return int */ public int getCriticalHit(Creature target, Skill skill) { return (int) calcStat(Stats.CRITICAL_BASE, _template.getBaseCritRate(), target, skill); } /** * Method getCriticalDmg. * @param target Creature * @param skill Skill * @return int */ public int getCriticalDmg(Creature target, Skill skill) { return (int) calcStat(Stats.CRITICAL_DAMAGE, target, skill); } /** * Method getMagicCriticalRate. * @param target Creature * @param skill Skill * @return double */ public double getMagicCriticalRate(Creature target, Skill skill) { return (int) calcStat(Stats.MCRITICAL_RATE, target, skill); } /** * Method getMagicCriticalRate. * @param target Creature * @param skill Skill * @return double */ public double getMagicCriticalDmg(Creature target, Skill skill) { return calcStat(Stats.MCRITICAL_DAMAGE, target, skill); } /** * Method getCurrentCp. * @return double */ public final double getCurrentCp() { return _currentCp; } /** * Method getCurrentCpRatio. * @return double */ public final double getCurrentCpRatio() { return getCurrentCp() / getMaxCp(); } /** * Method getCurrentCpPercents. * @return double */ public final double getCurrentCpPercents() { return getCurrentCpRatio() * 100.; } /** * Method isCurrentCpFull. * @return boolean */ public final boolean isCurrentCpFull() { return getCurrentCp() >= getMaxCp(); } /** * Method isCurrentCpZero. * @return boolean */ public final boolean isCurrentCpZero() { return getCurrentCp() < 1; } /** * Method getCurrentHp. * @return double */ public final double getCurrentHp() { return _currentHp; } /** * Method getCurrentHpRatio. * @return double */ public final double getCurrentHpRatio() { return getCurrentHp() / getMaxHp(); } /** * Method getCurrentHpPercents. * @return double */ public final double getCurrentHpPercents() { return getCurrentHpRatio() * 100.; } /** * Method isCurrentHpFull. * @return boolean */ public final boolean isCurrentHpFull() { return getCurrentHp() >= getMaxHp(); } /** * Method isCurrentHpZero. * @return boolean */ public final boolean isCurrentHpZero() { return getCurrentHp() < 1; } /** * Method getCurrentMp. * @return double */ public final double getCurrentMp() { return _currentMp; } /** * Method getCurrentMpRatio. * @return double */ public final double getCurrentMpRatio() { return getCurrentMp() / getMaxMp(); } /** * Method getCurrentMpPercents. * @return double */ public final double getCurrentMpPercents() { return getCurrentMpRatio() * 100.; } /** * Method isCurrentMpFull. * @return boolean */ public final boolean isCurrentMpFull() { return getCurrentMp() >= getMaxMp(); } /** * Method isCurrentMpZero. * @return boolean */ public final boolean isCurrentMpZero() { return getCurrentMp() < 1; } /** * Method getDestination. * @return Location */ public Location getDestination() { return destination; } /** * Method getDEX. * @return int */ public int getDEX() { return (int) calcStat(Stats.STAT_DEX, _template.getBaseAttr().getDEX(), null, null); } /** * Method getCON. * @return int */ public int getCON() { return (int) calcStat(Stats.STAT_CON, _template.getBaseAttr().getCON(), null, null); } /** * Method getINT. * @return int */ public int getINT() { return (int) calcStat(Stats.STAT_INT, _template.getBaseAttr().getINT(), null, null); } /** * Method getMEN. * @return int */ public int getMEN() { return (int) calcStat(Stats.STAT_MEN, _template.getBaseAttr().getMEN(), null, null); } /** * Method getSTR. * @return int */ public int getSTR() { return (int) calcStat(Stats.STAT_STR, _template.getBaseAttr().getSTR(), null, null); } /** * Method getEvasionRate. * @param target Creature * @return int */ public int getEvasionRate(Creature target) { return (int) calcStat(Stats.EVASION_RATE, 0, target, null); } /** * Method getMEvasionRate. * @param target Creature * @return int */ public int getMEvasionRate(Creature target) { return (int) calcStat(Stats.MEVASION_RATE, 0, target, null); } /** * Method getWIT. * @return int */ public int getWIT() { return (int) calcStat(Stats.STAT_WIT, _template.getBaseAttr().getWIT(), null, null); } /** * Method getAroundCharacters. * @param radius int * @param height int * @return List<Creature> */ public List<Creature> getAroundCharacters(int radius, int height) { if (!isVisible()) { return Collections.emptyList(); } return World.getAroundCharacters(this, radius, height); } /** * Method getAroundNpc. * @param range int * @param height int * @return List<NpcInstance> */ public List<NpcInstance> getAroundNpc(int range, int height) { if (!isVisible()) { return Collections.emptyList(); } return World.getAroundNpc(this, range, height); } /** * Method knowsObject. * @param obj GameObject * @return boolean */ public boolean knowsObject(GameObject obj) { return World.getAroundObjectById(this, obj.getObjectId()) != null; } /** * Method getKnownSkill. * @param skillId int * @return Skill */ public final Skill getKnownSkill(int skillId) { return _skills.get(skillId); } /** * Method getMagicalAttackRange. * @param skill Skill * @return int */ public final int getMagicalAttackRange(Skill skill) { if (skill != null) { return (int) calcStat(Stats.MAGIC_ATTACK_RANGE, skill.getCastRange(), null, skill); } return getTemplate().getBaseAtkRange(); } /** * Method getMAtk. * @param target Creature * @param skill Skill * @return int */ public int getMAtk(Creature target, Skill skill) { if ((skill != null) && (skill.getMatak() > 0)) { return skill.getMatak(); } return (int) calcStat(Stats.MAGIC_ATTACK, _template.getBaseMAtk(), target, skill); } /** * Method getMAtkSpd. * @return int */ public int getMAtkSpd() { return (int) (calcStat(Stats.MAGIC_ATTACK_SPEED, _template.getBaseMAtkSpd(), null, null)); } /** * Method getMaxCp. * @return int */ public int getMaxCp() { return (int) calcStat(Stats.MAX_CP, _template.getBaseCpMax(), null, null); } /** * Method getMaxHp. * @return int */ public int getMaxHp() { return (int) calcStat(Stats.MAX_HP, _template.getBaseHpMax(), null, null); } /** * Method getMaxMp. * @return int */ public int getMaxMp() { return (int) calcStat(Stats.MAX_MP, _template.getBaseMpMax(), null, null); } /** * Method getMDef. * @param target Creature * @param skill Skill * @return int */ public int getMDef(Creature target, Skill skill) { return Math.max((int) calcStat(Stats.MAGIC_DEFENCE, _template.getBaseMDef(), target, skill), 1); } /** * Method getMinDistance. * @param obj GameObject * @return double */ public double getMinDistance(GameObject obj) { double distance = getTemplate().getCollisionRadius(); if ((obj != null) && obj.isCreature()) { distance += ((Creature) obj).getTemplate().getCollisionRadius(); } return distance; } /** * Method getMovementSpeedMultiplier. * @return double */ public double getMovementSpeedMultiplier() { return (getRunSpeed() * 1.) / _template.getBaseRunSpd(); } /** * Method getMoveSpeed. * @return int */ @Override public int getMoveSpeed() { if (isRunning()) { return getRunSpeed(); } return getWalkSpeed(); } /** * Method getRunSpeed. * @return int */ public int getRunSpeed() { if (isInWater()) { return getSwimRunSpeed(); } return getSpeed(_template.getBaseRunSpd()); } /** * Method getWalkSpeed. * @return int */ public int getWalkSpeed() { if (isInWater()) { return getSwimWalkSpeed(); } return getSpeed(_template.getBaseWalkSpd()); } /** * Method getSwimRunSpeed. * @return int */ public int getSwimRunSpeed() { return getSpeed(_template.getBaseWaterRunSpd()); } /** * Method getSwimWalkSpeed. * @return int */ public int getSwimWalkSpeed() { return getSpeed(_template.getBaseWaterWalkSpd()); } /** * Method relativeSpeed. * @param target GameObject * @return double */ public double relativeSpeed(GameObject target) { return getMoveSpeed() - (target.getMoveSpeed() * Math.cos(headingToRadians(getHeading()) - headingToRadians(target.getHeading()))); } /** * Method getSpeed. * @param baseSpeed double * @return int */ public int getSpeed(double baseSpeed) { return (int) calcStat(Stats.RUN_SPEED, baseSpeed, null, null); } /** * Method getName. * @return String */ @Override public String getName() { return StringUtils.defaultString(_name); } /** * Method getPAtk. * @param target Creature * @return int */ public int getPAtk(Creature target) { return (int) calcStat(Stats.POWER_ATTACK, _template.getBasePAtk(), target, null); } /** * Method getPAtkSpd. * @return int */ public int getPAtkSpd() { return (int) calcStat(Stats.POWER_ATTACK_SPEED, _template.getBasePAtkSpd(), null, null); } /** * Method getPDef. * @param target Creature * @return int */ public int getPDef(Creature target) { return (int) calcStat(Stats.POWER_DEFENCE, _template.getBasePDef(), target, null); } /** * Method getPhysicalAttackRange. * @return int */ public final int getPhysicalAttackRange() { return (int) calcStat(Stats.POWER_ATTACK_RANGE, getTemplate().getBaseAtkRange(), null, null); } /** * Method getRandomDamage. * @return int */ public int getRandomDamage() { WeaponTemplate weaponItem = getActiveWeaponItem(); if (weaponItem == null) { return 5 + (int) Math.sqrt(getLevel()); } return weaponItem.getRandomDamage(); } /** * Method getReuseModifier. * @param target Creature * @return double */ public double getReuseModifier(Creature target) { return calcStat(Stats.ATK_REUSE, 1, target, null); } /** * Method getShldDef. * @return int */ public final int getShldDef() { if (isPlayer()) { return (int) calcStat(Stats.SHIELD_DEFENCE, 0, null, null); } return (int) calcStat(Stats.SHIELD_DEFENCE, _template.getBaseShldDef(), null, null); } /** * Method getSkillDisplayLevel. * @param skillId Integer * @return int */ public final int getSkillDisplayLevel(Integer skillId) { Skill skill = _skills.get(skillId); if (skill == null) { return -1; } return skill.getDisplayLevel(); } /** * Method getSkillLevel. * @param skillId Integer * @return int */ public final int getSkillLevel(Integer skillId) { switch (skillId) { case 1566: case 1567: case 1568: case 1569: return 1; } return getSkillLevel(skillId, -1); } /** * Method getSkillLevel. * @param skillId Integer * @param def int * @return int */ public final int getSkillLevel(Integer skillId, int def) { Skill skill = _skills.get(skillId); if (skill == null) { return def; } return skill.getLevel(); } /** * Method getSkillMastery. * @param skillId Integer * @return int */ public int getSkillMastery(Integer skillId) { if (_skillMastery == null) { return 0; } Integer val = _skillMastery.get(skillId); return val == null ? 0 : val.intValue(); } /** * Method removeSkillMastery. * @param skillId Integer */ public void removeSkillMastery(Integer skillId) { if (_skillMastery != null) { _skillMastery.remove(skillId); } } /** * Method getSwimSpeed. * @return int */ public int getSwimSpeed() { return (int) calcStat(Stats.RUN_SPEED, Config.SWIMING_SPEED, null, null); } /** * Method getTarget. * @return GameObject */ public GameObject getTarget() { return target.get(); } /** * Method getTargetId. * @return int */ public final int getTargetId() { GameObject target = getTarget(); return target == null ? -1 : target.getObjectId(); } /** * Method getTemplate. * @return CharTemplate */ public CharTemplate getTemplate() { return _template; } /** * Method getTitle. * @return String */ public String getTitle() { return StringUtils.defaultString(_title); } /** * Method headingToRadians. * @param heading int * @return double */ public double headingToRadians(int heading) { return (heading - 32768) / HEADINGS_IN_PI; } /** * Method isAlikeDead. * @return boolean */ public boolean isAlikeDead() { return _fakeDeath || isDead(); } /** * Method isAttackingNow. * @return boolean */ public final boolean isAttackingNow() { return _attackEndTime > System.currentTimeMillis(); } /** * Method isBlessedByNoblesse. * @return boolean */ public final boolean isBlessedByNoblesse() { return _isBlessedByNoblesse; } /** * Method isSalvation. * @return boolean */ public final boolean isSalvation() { return _isSalvation; } /** * Method isEffectImmune. * @return boolean */ public boolean isEffectImmune() { return _effectImmunity.get(); } /** * Method isBuffImmune. * @return boolean */ public boolean isBuffImmune() { return _buffImmunity.get(); } /** * Method isDebuffImmune. * @return boolean */ public boolean isDebuffImmune() { return _debuffImmunity.get(); } /** * Method isDead. * @return boolean */ public boolean isDead() { return (_currentHp < 0.5) || isDead.get(); } /** * Method isFlying. * @return boolean */ @Override public final boolean isFlying() { return _flying; } /** * Method isInCombat. * @return boolean */ public final boolean isInCombat() { return System.currentTimeMillis() < _stanceEndTime; } /** * Method isInvul. * @return boolean */ public boolean isInvul() { return _isInvul; } /** * Method isMageClass. * @return boolean */ public boolean isMageClass() { return getTemplate().getBaseMAtk() > 3; } /** * Method isRunning. * @return boolean */ public final boolean isRunning() { return _running; } /** * Method isSkillDisabled. * @param skill Skill * @return boolean */ public boolean isSkillDisabled(Skill skill) { TimeStamp sts = _skillReuses.get(skill.hashCode()); if (sts == null) { return false; } if (sts.hasNotPassed()) { return true; } _skillReuses.remove(skill.hashCode()); return false; } /** * Method isTeleporting. * @return boolean */ public final boolean isTeleporting() { return isTeleporting.get(); } /** * Method getIntersectionPoint. * @param target Creature * @return Location */ public Location getIntersectionPoint(Creature target) { if (!PositionUtils.isFacing(this, target, 90)) { return new Location(target.getX(), target.getY(), target.getZ()); } double angle = PositionUtils.convertHeadingToDegree(target.getHeading()); double radian = Math.toRadians(angle - 90); double range = target.getMoveSpeed() / 2; return new Location((int) (target.getX() - (range * Math.sin(radian))), (int) (target.getY() + (range * Math.cos(radian))), target.getZ()); } /** * Method applyOffset. * @param point Location * @param offset int * @return Location */ public Location applyOffset(Location point, int offset) { if (offset <= 0) { return point; } long dx = point.x - getX(); long dy = point.y - getY(); long dz = point.z - getZ(); double distance = Math.sqrt((dx * dx) + (dy * dy) + (dz * dz)); if (distance <= offset) { point.set(getX(), getY(), getZ()); return point; } if (distance >= 1) { double cut = offset / distance; point.x -= (int) ((dx * cut) + 0.5); point.y -= (int) ((dy * cut) + 0.5); point.z -= (int) ((dz * cut) + 0.5); if (!isFlying() && !isInBoat() && !isInWater() && !isBoat()) { point.correctGeoZ(); } } return point; } /** * Method applyOffset. * @param points List<Location> * @param offset int * @return List<Location> */ public List<Location> applyOffset(List<Location> points, int offset) { offset = offset >> 4; if (offset <= 0) { return points; } long dx = points.get(points.size() - 1).x - points.get(0).x; long dy = points.get(points.size() - 1).y - points.get(0).y; long dz = points.get(points.size() - 1).z - points.get(0).z; double distance = Math.sqrt((dx * dx) + (dy * dy) + (dz * dz)); if (distance <= offset) { Location point = points.get(0); points.clear(); points.add(point); return points; } if (distance >= 1) { double cut = offset / distance; int num = (int) ((points.size() * cut) + 0.5); for (int i = 1; (i <= num) && (points.size() > 0); i++) { points.remove(points.size() - 1); } } return points; } /** * Method setSimplePath. * @param dest Location * @return boolean */ private boolean setSimplePath(Location dest) { List<Location> moveList = GeoMove.constructMoveList(getLoc(), dest); if (moveList.isEmpty()) { return false; } _targetRecorder.clear(); _targetRecorder.add(moveList); return true; } /** * Method buildPathTo. * @param x int * @param y int * @param z int * @param offset int * @param pathFind boolean * @return boolean */ private boolean buildPathTo(int x, int y, int z, int offset, boolean pathFind) { return buildPathTo(x, y, z, offset, null, false, pathFind); } /** * Method buildPathTo. * @param x int * @param y int * @param z int * @param offset int * @param follow Creature * @param forestalling boolean * @param pathFind boolean * @return boolean */ boolean buildPathTo(int x, int y, int z, int offset, Creature follow, boolean forestalling, boolean pathFind) { int geoIndex = getGeoIndex(); Location dest; if (forestalling && (follow != null) && follow.isMoving) { dest = getIntersectionPoint(follow); } else { dest = new Location(x, y, z); } if (isInBoat() || isBoat() || !Config.ALLOW_GEODATA) { applyOffset(dest, offset); return setSimplePath(dest); } if (isFlying() || isInWater()) { applyOffset(dest, offset); Location nextloc; if (isFlying()) { if (GeoEngine.canSeeCoord(this, dest.x, dest.y, dest.z, true)) { return setSimplePath(dest); } nextloc = GeoEngine.moveCheckInAir(getX(), getY(), getZ(), dest.x, dest.y, dest.z, getColRadius(), geoIndex); if ((nextloc != null) && !nextloc.equals(getX(), getY(), getZ())) { return setSimplePath(nextloc); } } else { int waterZ = getWaterZ(); nextloc = GeoEngine.moveInWaterCheck(getX(), getY(), getZ(), dest.x, dest.y, dest.z, waterZ, geoIndex); if (nextloc == null) { return false; } List<Location> moveList = GeoMove.constructMoveList(getLoc(), nextloc.clone()); _targetRecorder.clear(); if (!moveList.isEmpty()) { _targetRecorder.add(moveList); } int dz = dest.z - nextloc.z; if ((dz > 0) && (dz < 128)) { moveList = GeoEngine.MoveList(nextloc.x, nextloc.y, nextloc.z, dest.x, dest.y, geoIndex, false); if (moveList != null) { if (!moveList.isEmpty()) { _targetRecorder.add(moveList); } } } return !_targetRecorder.isEmpty(); } return false; } List<Location> moveList = GeoEngine.MoveList(getX(), getY(), getZ(), dest.x, dest.y, geoIndex, true); if (moveList != null) { if (moveList.isEmpty()) { return false; } applyOffset(moveList, offset); if (moveList.isEmpty()) { return false; } _targetRecorder.clear(); _targetRecorder.add(moveList); return true; } if (pathFind) { List<List<Location>> targets = GeoMove.findMovePath(getX(), getY(), getZ(), dest.clone(), this, true, geoIndex); if (!targets.isEmpty()) { moveList = targets.remove(targets.size() - 1); applyOffset(moveList, offset); if (!moveList.isEmpty()) { targets.add(moveList); } if (!targets.isEmpty()) { _targetRecorder.clear(); _targetRecorder.addAll(targets); return true; } } } if (follow != null) { return false; } applyOffset(dest, offset); moveList = GeoEngine.MoveList(getX(), getY(), getZ(), dest.x, dest.y, geoIndex, false); if ((moveList != null) && !moveList.isEmpty()) { _targetRecorder.clear(); _targetRecorder.add(moveList); return true; } return false; } /** * Method getFollowTarget. * @return Creature */ public Creature getFollowTarget() { return followTarget.get(); } /** * Method setFollowTarget. * @param target Creature */ public void setFollowTarget(Creature target) { followTarget = target == null ? HardReferences.<Creature>emptyRef() : target.getRef(); } /** * Method followToCharacter. * @param target Creature * @param offset int * @param forestalling boolean * @return boolean */ public boolean followToCharacter(Creature target, int offset, boolean forestalling) { return followToCharacter(target.getLoc(), target, offset, forestalling); } /** * Method followToCharacter. * @param loc Location * @param target Creature * @param offset int * @param forestalling boolean * @return boolean */ public boolean followToCharacter(Location loc, Creature target, int offset, boolean forestalling) { moveLock.lock(); try { if (isMovementDisabled() || (target == null) || (isInBoat() && !isInShuttle()) || isInWater()) { return false; } offset = Math.max(offset, 10); if (isFollow && (target == getFollowTarget()) && (offset == _offset)) { return true; } if ((Math.abs(getZ() - target.getZ()) > 1000) && !isFlying()) { sendPacket(SystemMsg.CANNOT_SEE_TARGET); return false; } getAI().clearNextAction(); stopMove(false, false); if (buildPathTo(loc.x, loc.y, loc.z, offset, target, forestalling, !target.isDoor())) { movingDestTempPos.set(loc.x, loc.y, loc.z); } else { return false; } isMoving = true; isFollow = true; _forestalling = forestalling; _offset = offset; setFollowTarget(target); moveNext(true); return true; } finally { moveLock.unlock(); } } /** * Method moveToLocation. * @param loc Location * @param offset int * @param pathfinding boolean * @return boolean */ public boolean moveToLocation(Location loc, int offset, boolean pathfinding) { return moveToLocation(loc.x, loc.y, loc.z, offset, pathfinding); } /** * Method moveToLocation. * @param x_dest int * @param y_dest int * @param z_dest int * @param offset int * @param pathfinding boolean * @return boolean */ public boolean moveToLocation(int x_dest, int y_dest, int z_dest, int offset, boolean pathfinding) { moveLock.lock(); try { offset = Math.max(offset, 0); Location dst_geoloc = new Location(x_dest, y_dest, z_dest).world2geo(); if (isMoving && !isFollow && movingDestTempPos.equals(dst_geoloc)) { sendActionFailed(); return true; } if (isMovementDisabled()) { getAI().setNextAction(nextAction.MOVE, new Location(x_dest, y_dest, z_dest), offset, pathfinding, false); sendActionFailed(); return false; } getAI().clearNextAction(); if (isPlayer()) { getAI().changeIntention(AI_INTENTION_ACTIVE, null, null); } stopMove(false, false); if (buildPathTo(x_dest, y_dest, z_dest, offset, pathfinding)) { movingDestTempPos.set(dst_geoloc); } else { sendActionFailed(); return false; } isMoving = true; moveNext(true); return true; } finally { moveLock.unlock(); } } /** * Method moveNext. * @param firstMove boolean */ void moveNext(boolean firstMove) { if (!isMoving || isMovementDisabled()) { stopMove(); return; } _previousSpeed = getMoveSpeed(); if (_previousSpeed <= 0) { stopMove(); return; } if (!firstMove) { Location dest = destination; if (dest != null) { setLoc(dest, true); } } if (_targetRecorder.isEmpty()) { CtrlEvent ctrlEvent = isFollow ? CtrlEvent.EVT_ARRIVED_TARGET : CtrlEvent.EVT_ARRIVED; stopMove(false, true); ThreadPoolManager.getInstance().execute(new NotifyAITask(this, ctrlEvent)); return; } moveList = _targetRecorder.remove(0); Location begin = moveList.get(0).clone().geo2world(); Location end = moveList.get(moveList.size() - 1).clone().geo2world(); destination = end; double distance = (isFlying() || isInWater()) ? begin.distance3D(end) : begin.distance(end); if (distance != 0) { setHeading(PositionUtils.calculateHeadingFrom(getX(), getY(), destination.x, destination.y)); } broadcastMove(); _startMoveTime = _followTimestamp = System.currentTimeMillis(); if (_moveTaskRunnable == null) { _moveTaskRunnable = new MoveNextTask(); } _moveTask = ThreadPoolManager.getInstance().schedule(_moveTaskRunnable.setDist(distance), getMoveTickInterval()); } /** * Method getMoveTickInterval. * @return int */ public int getMoveTickInterval() { return (isPlayer() ? 16000 : 32000) / Math.max(getMoveSpeed(), 1); } /** * Method broadcastMove. */ private void broadcastMove() { validateLocation(isPlayer() ? 2 : 1); broadcastPacket(movePacket()); } /** * Method stopMove. */ public void stopMove() { stopMove(true, true); } /** * Method stopMove. * @param validate boolean */ public void stopMove(boolean validate) { stopMove(true, validate); } /** * Method stopMove. * @param stop boolean * @param validate boolean */ public void stopMove(boolean stop, boolean validate) { if (!isMoving) { return; } moveLock.lock(); try { if (!isMoving) { return; } isMoving = false; isFollow = false; if (_moveTask != null) { _moveTask.cancel(false); _moveTask = null; } destination = null; moveList = null; _targetRecorder.clear(); if (validate) { validateLocation(isPlayer() ? 2 : 1); } if (stop) { broadcastPacket(stopMovePacket()); } } finally { moveLock.unlock(); } } /** * Method getWaterZ. * @return int */ public int getWaterZ() { if (!isInWater()) { return Integer.MIN_VALUE; } int waterZ = Integer.MIN_VALUE; zonesRead.lock(); try { Zone zone; for (int i = 0; i < _zones.size(); i++) { zone = _zones.get(i); if (zone.getType() == ZoneType.water) { if ((waterZ == Integer.MIN_VALUE) || (waterZ < zone.getTerritory().getZmax())) { waterZ = zone.getTerritory().getZmax(); } } } } finally { zonesRead.unlock(); } return waterZ; } /** * Method stopMovePacket. * @return L2GameServerPacket */ protected L2GameServerPacket stopMovePacket() { return new StopMove(this); } /** * Method movePacket. * @return L2GameServerPacket */ public L2GameServerPacket movePacket() { return new CharMoveToLocation(this); } /** * Method updateZones. */ public void updateZones() { if (isInObserverMode()) { return; } Zone[] zones = isVisible() ? getCurrentRegion().getZones() : Zone.EMPTY_L2ZONE_ARRAY; LazyArrayList<Zone> entering = null; LazyArrayList<Zone> leaving = null; Zone zone; zonesWrite.lock(); try { if (!_zones.isEmpty()) { leaving = LazyArrayList.newInstance(); for (int i = 0; i < _zones.size(); i++) { zone = _zones.get(i); if (!ArrayUtils.contains(zones, zone) || !zone.checkIfInZone(getX(), getY(), getZ(), getReflection())) { leaving.add(zone); } } if (!leaving.isEmpty()) { for (int i = 0; i < leaving.size(); i++) { zone = leaving.get(i); _zones.remove(zone); } } } if (zones.length > 0) { entering = LazyArrayList.newInstance(); for (Zone zone2 : zones) { zone = zone2; if (!_zones.contains(zone) && zone.checkIfInZone(getX(), getY(), getZ(), getReflection())) { entering.add(zone); } } if (!entering.isEmpty()) { for (int i = 0; i < entering.size(); i++) { zone = entering.get(i); _zones.add(zone); } } } } finally { zonesWrite.unlock(); } onUpdateZones(leaving, entering); if (leaving != null) { LazyArrayList.recycle(leaving); } if (entering != null) { LazyArrayList.recycle(entering); } } /** * Method onUpdateZones. * @param leaving List<Zone> * @param entering List<Zone> */ protected void onUpdateZones(List<Zone> leaving, List<Zone> entering) { Zone zone; if ((leaving != null) && !leaving.isEmpty()) { for (int i = 0; i < leaving.size(); i++) { zone = leaving.get(i); zone.doLeave(this); } } if ((entering != null) && !entering.isEmpty()) { for (int i = 0; i < entering.size(); i++) { zone = entering.get(i); zone.doEnter(this); } } } /** * Method isInZonePeace. * @return boolean */ public boolean isInZonePeace() { return isInZone(ZoneType.peace_zone) && !isInZoneBattle(); } /** * Method isInZoneBattle. * @return boolean */ public boolean isInZoneBattle() { return isInZone(ZoneType.battle_zone); } /** * Method isInWater. * @return boolean */ public boolean isInWater() { return isInZone(ZoneType.water) && !(isInBoat() || isBoat() || isFlying()); } /** * Method isInZone. * @param type ZoneType * @return boolean */ public boolean isInZone(ZoneType type) { zonesRead.lock(); try { Zone zone; for (Zone _zone : _zones) { zone = _zone; if (zone.getType() == type) { return true; } } } finally { zonesRead.unlock(); } return false; } /** * Method isInZone. * @param name String * @return boolean */ public boolean isInZone(String name) { zonesRead.lock(); try { Zone zone; for (int i = 0; i < _zones.size(); i++) { zone = _zones.get(i); if (zone.getName().equals(name)) { return true; } } } finally { zonesRead.unlock(); } return false; } /** * Method isInZone. * @param zone Zone * @return boolean */ public boolean isInZone(Zone zone) { zonesRead.lock(); try { return _zones.contains(zone); } finally { zonesRead.unlock(); } } /** * Method getZone. * @param type ZoneType * @return Zone */ public Zone getZone(ZoneType type) { zonesRead.lock(); try { Zone zone; for (int i = 0; i < _zones.size(); i++) { zone = _zones.get(i); if (zone.getType() == type) { return zone; } } } finally { zonesRead.unlock(); } return null; } /** * Method getRestartPoint. * @return Location */ public Location getRestartPoint() { zonesRead.lock(); try { Zone zone; for (int i = 0; i < _zones.size(); i++) { zone = _zones.get(i); if (zone.getRestartPoints() != null) { ZoneType type = zone.getType(); if ((type == ZoneType.battle_zone) || (type == ZoneType.peace_zone) || (type == ZoneType.offshore) || (type == ZoneType.dummy)) { return zone.getSpawn(); } } } } finally { zonesRead.unlock(); } return null; } /** * Method getPKRestartPoint. * @return Location */ public Location getPKRestartPoint() { zonesRead.lock(); try { Zone zone; for (int i = 0; i < _zones.size(); i++) { zone = _zones.get(i); if (zone.getRestartPoints() != null) { ZoneType type = zone.getType(); if ((type == ZoneType.battle_zone) || (type == ZoneType.peace_zone) || (type == ZoneType.offshore) || (type == ZoneType.dummy)) { return zone.getPKSpawn(); } } } } finally { zonesRead.unlock(); } return null; } /** * Method getGeoZ. * @param loc Location * @return int */ @Override public int getGeoZ(Location loc) { if (isFlying() || isInWater() || isInBoat() || isBoat() || isDoor()) { return loc.z; } return super.getGeoZ(loc); } /** * Method needStatusUpdate. * @return boolean */ protected boolean needStatusUpdate() { if (!isVisible() || !displayHpBar()) { return false; } boolean result = false; int bar; bar = (int) ((getCurrentHp() * CLIENT_BAR_SIZE) / getMaxHp()); if ((bar == 0) || (bar != _lastHpBarUpdate)) { _lastHpBarUpdate = bar; result = true; } bar = (int) ((getCurrentMp() * CLIENT_BAR_SIZE) / getMaxMp()); if ((bar == 0) || (bar != _lastMpBarUpdate)) { _lastMpBarUpdate = bar; result = true; } if (isPlayer()) { bar = (int) ((getCurrentCp() * CLIENT_BAR_SIZE) / getMaxCp()); if ((bar == 0) || (bar != _lastCpBarUpdate)) { _lastCpBarUpdate = bar; result = true; } } return result; } /** * Method onForcedAttack. * @param player Player * @param shift boolean */ @Override public void onForcedAttack(Player player, boolean shift) { if (player.getTarget() != this) { player.setTarget(this); } if (!isAttackable(player) || player.isConfused() || player.isBlocked()) { player.sendActionFailed(); return; } player.getAI().Attack(this, true, shift); } /** * Method onHitTimer. * @param target Creature * @param damage int * @param reflectableDamage int * @param crit boolean * @param miss boolean * @param soulshot boolean * @param shld boolean * @param unchargeSS boolean */ public void onHitTimer(Creature target, int damage, int reflectableDamage, boolean crit, boolean miss, boolean soulshot, boolean shld, boolean unchargeSS) { if (isAlikeDead()) { sendActionFailed(); return; } if (target.isDead() || !isInRange(target, 2000)) { sendActionFailed(); return; } if (isPlayable() && target.isPlayable() && (isInZoneBattle() != target.isInZoneBattle())) { Player player = getPlayer(); if (player != null) { player.sendPacket(Msg.INVALID_TARGET); player.sendActionFailed(); } return; } target.getListeners().onAttackHit(this); if (!miss && target.isPlayer() && (isCursedWeaponEquipped() || ((getActiveWeaponInstance() != null) && getActiveWeaponInstance().isHeroWeapon() && target.isCursedWeaponEquipped()))) { target.setCurrentCp(0); } if (target.isStunned() && Formulas.calcStunBreak(crit)) { target.getEffectList().stopEffects(EffectType.Stun); } if (target.getEffectList().getEffectByType(EffectType.DispelOnHit) != null && !miss) { target.getEffectList().getEffectByType(EffectType.DispelOnHit).onActionTime(); } displayGiveDamageMessage(target, damage, crit, miss, shld, false); ThreadPoolManager.getInstance().execute(new NotifyAITask(target, CtrlEvent.EVT_ATTACKED, this, damage)); boolean checkPvP = checkPvP(target, null); if (!miss && (damage > 0)) { target.reduceCurrentHp(damage, reflectableDamage, this, null, true, true, false, true, false, false, true); if (!target.isDead()) { if (crit) { useTriggers(target, TriggerType.CRIT, null, null, damage); } useTriggers(target, TriggerType.ATTACK, null, null, damage); if (Formulas.calcCastBreak(target, crit)) { target.abortCast(false, true); } } if (soulshot && unchargeSS) { unChargeShots(false); } } if (miss) { target.useTriggers(this, TriggerType.UNDER_MISSED_ATTACK, null, null, damage); } startAttackStanceTask(); if (checkPvP) { startPvPFlag(target); } } /** * Method onMagicUseTimer. * @param aimingTarget Creature * @param skill Skill * @param forceUse boolean */ public void onMagicUseTimer(Creature aimingTarget, Skill skill, boolean forceUse) { if (skill == null) { onCastEndTime(false); sendPacket(ActionFail.STATIC); return; } _castInterruptTime = 0; if (skill.isUsingWhileCasting()) { aimingTarget.getEffectList().stopEffect(skill.getId()); onCastEndTime(false); return; } if (!skill.isOffensive() && (getAggressionTarget() != null)) { forceUse = true; } if (!skill.checkCondition(this, aimingTarget, forceUse, false, false)) { if ((skill.getSkillType() == SkillType.PET_SUMMON) && isPlayer()) { getPlayer().setPetControlItem(null); } onCastEndTime(false); return; } if ((skill.getCastRange() < 32767) && (skill.getSkillType() != SkillType.TAKECASTLE) && (skill.getSkillType() != SkillType.TAKEFORTRESS) && !GeoEngine.canSeeTarget(this, aimingTarget, isFlying())) { sendPacket(SystemMsg.CANNOT_SEE_TARGET); broadcastPacket(new MagicSkillCanceled(getObjectId())); onCastEndTime(false); return; } List<Creature> targets = skill.getTargets(this, aimingTarget, forceUse); int hpConsume = skill.getHpConsume(); if (hpConsume > 0) { setCurrentHp(Math.max(0, _currentHp - hpConsume), false); } double mpConsume2 = skill.getMpConsume2(); if (mpConsume2 > 0) { if (skill.isMusic()) { double inc = mpConsume2 / 2; double add = 0; for (Effect e : getEffectList().getAllEffects()) { if ((e.getSkill().getId() != skill.getId()) && e.getSkill().isMusic() && (e.getTimeLeft() > 30)) { add += inc; } } mpConsume2 += add; mpConsume2 = calcStat(Stats.MP_DANCE_SKILL_CONSUME, mpConsume2, aimingTarget, skill); } else if (skill.isMagic()) { mpConsume2 = calcStat(Stats.MP_MAGIC_SKILL_CONSUME, mpConsume2, aimingTarget, skill); } else { mpConsume2 = calcStat(Stats.MP_PHYSICAL_SKILL_CONSUME, mpConsume2, aimingTarget, skill); } if ((_currentMp < mpConsume2) && isPlayable()) { sendPacket(Msg.NOT_ENOUGH_MP); onCastEndTime(false); return; } reduceCurrentMp(mpConsume2, null); } callSkill(skill, targets, true); if (skill.getNumCharges() > 0) { setIncreasedForce(getIncreasedForce() - skill.getNumCharges()); } if (skill.getMaxCharges() > 0) { setIncreasedForce(getIncreasedForce() - skill.getMaxCharges()); } if (skill.isSoulBoost()) { setConsumedSouls(getConsumedSouls() - Math.min(getConsumedSouls(), 5), null); } else if (skill.getSoulsConsume() > 0) { setConsumedSouls(getConsumedSouls() - skill.getSoulsConsume(), null); } switch (skill.getFlyType()) { // TARGETS FLYTYPE case THROW_UP: case THROW_HORIZONTAL: case PUSH_HORIZONTAL: case PUSH_DOWN_HORIZONTAL: Location flyLoc; for (Creature target : targets) { flyLoc = target.getFlyLocation(null, skill); if (flyLoc == null) _log.warn(skill.getFlyType() + " have null flyLoc."); target.setLoc(flyLoc); broadcastPacket(new FlyToLocation(target, flyLoc, skill.getFlyType(), 0)); } break; // CASTER FLYTYPE case CHARGE: Location flyLocCharge; for (Creature target : targets) { double radian = PositionUtils.convertHeadingToRadian(this.getHeading()); flyLocCharge = target.getLoc(); flyLocCharge.set(flyLocCharge.getX() + (int) (Math.sin(radian) * 40), flyLocCharge.getY() - (int) (Math.cos(radian) * 40), flyLocCharge.getZ()); setLoc(flyLocCharge); broadcastPacket(new FlyToLocation(this, flyLocCharge, skill.getFlyType(), 0)); } break; case DUMMY: case WARP_BACK: case WARP_FORWARD: flyLoc = getFlyLocation(null, skill); if (flyLoc != null) { setLoc(flyLoc); broadcastPacket(new FlyToLocation(this, flyLoc, skill.getFlyType(), 0)); } else { sendPacket(SystemMsg.CANNOT_SEE_TARGET); } break; default: break; } if (_scheduledCastCount > 0) { _scheduledCastCount--; if (!isDoubleCastingNow() && IsEnabledDoubleCast()) { _skillDoubleLaunchedTask = ThreadPoolManager.getInstance() .schedule(new MagicLaunchedTask(this, forceUse), _scheduledCastInterval); _skillDoubleTask = ThreadPoolManager.getInstance().schedule(new MagicUseTask(this, forceUse), _scheduledCastInterval); } else { _skillLaunchedTask = ThreadPoolManager.getInstance().schedule(new MagicLaunchedTask(this, forceUse), _scheduledCastInterval); _skillTask = ThreadPoolManager.getInstance().schedule(new MagicUseTask(this, forceUse), _scheduledCastInterval); } return; } int skillCoolTime = 0; int chargeAddition = 0; if (skill.getFlyType() == FlyType.CHARGE) chargeAddition = skill.getHitTime(); if (!skill.isSkillTimePermanent()) skillCoolTime = Formulas.calcMAtkSpd(this, skill, skill.getCoolTime() + chargeAddition); else skillCoolTime = skill.getCoolTime() + chargeAddition; if (skillCoolTime > 0) { ThreadPoolManager.getInstance().schedule(new CastEndTimeTask(this), skillCoolTime); } else { onCastEndTime(true); } } /** * Method onCastEndTime. * @param success boolean */ public void onCastEndTime(boolean success) { finishFly(); int skillId = 0; if (getCastingSkill() != null) { skillId = getCastingSkill().getId(); // TODO: CHAIN SKILL MINOR FIX if (getCastingSkill().isAlterSkill()) { if (getCastingTarget().isAirBinded()) { getCastingTarget().getEffectList().stopEffects(EffectType.HellBinding); } else if (getCastingTarget().isKnockedDown()) { getCastingTarget().getEffectList().stopEffects(EffectType.KnockDown); } } //---------------- } clearCastVars(); getAI().notifyEvent(CtrlEvent.EVT_FINISH_CASTING, skillId, success); } /** * Method clearCastVars. */ public void clearCastVars() { _animationEndTime = 0; _castInterruptTime = 0; _scheduledCastCount = 0; _castingSkill = null; _skillTask = null; _skillLaunchedTask = null; _skillDoubleTask = null; _skillDoubleLaunchedTask = null; _flyLoc = null; } /** * Method finishFly. */ private void finishFly() { Location flyLoc = _flyLoc; _flyLoc = null; if (flyLoc != null) { setLoc(flyLoc); validateLocation(1); } } /** * Method reduceCurrentHp. * @param damage double * @param reflectableDamage double * @param attacker Creature * @param skill Skill * @param awake boolean * @param standUp boolean * @param directHp boolean * @param canReflect boolean * @param transferDamage boolean * @param isDot boolean * @param sendMessage boolean */ public void reduceCurrentHp(double damage, double reflectableDamage, Creature attacker, Skill skill, boolean awake, boolean standUp, boolean directHp, boolean canReflect, boolean transferDamage, boolean isDot, boolean sendMessage) { if ((attacker == null) || isDead() || (attacker.isDead() && !isDot)) { return; } if (isDamageBlocked() && transferDamage) { return; } if (isDamageBlocked() && (attacker != this)) { if (sendMessage) { attacker.sendPacket(Msg.THE_ATTACK_HAS_BEEN_BLOCKED); } return; } if (isDeathImmune()) { damage = Math.min(damage, Math.floor(getCurrentHp() - 1)); } double damageLimit = calcStat(Stats.RECEIVE_DAMAGE_LIMIT, damage); if (damageLimit >= 0.) { damage = damageLimit; } if (canReflect) { if (attacker.absorbAndReflect(this, skill, reflectableDamage)) { return; } damage = absorbToEffector(attacker, damage); damage = absorbToMp(attacker, damage); damage = absorbToSummon(attacker, damage); } getListeners().onCurrentHpDamage(damage, attacker, skill); if (attacker != this) { if (sendMessage) { displayReceiveDamageMessage(attacker, (int) damage); } if (!isDot) { useTriggers(attacker, TriggerType.RECEIVE_DAMAGE, null, null, damage); } } onReduceCurrentHp(damage, attacker, skill, awake, standUp, directHp); if (attacker.isPlayer()) { WorldStatisticsManager.getInstance().updateStat(attacker.getPlayer(), CategoryType.DAMAGE_TO_MONSTERS, attacker.getPlayer().getClassId().getId(), (long) damage); WorldStatisticsManager.getInstance().updateStat(attacker.getPlayer(), CategoryType.DAMAGE_TO_MONSTERS_MAX, attacker.getPlayer().getClassId().getId(), (long) damage); } } /** * Method onReduceCurrentHp. * @param damage double * @param attacker Creature * @param skill Skill * @param awake boolean * @param standUp boolean * @param directHp boolean */ protected void onReduceCurrentHp(final double damage, Creature attacker, Skill skill, boolean awake, boolean standUp, boolean directHp) { if (getTransformation() != 0) { List<Effect> effects = getEffectList().getAllEffects(); for (Effect effect : effects) if (effect.getSkill().isDispelOnDamage()) getEffectList().stopEffect(effect.getSkill()); } if (awake && isSleeping()) { getEffectList().stopEffects(EffectType.Sleep); } if ((attacker != this) || ((skill != null) && skill.isOffensive())) { if (isMeditated()) { Effect effect = getEffectList().getEffectByType(EffectType.Meditation); if (effect != null) { getEffectList().stopEffect(effect.getSkill()); } } startAttackStanceTask(); checkAndRemoveInvisible(); if ((getCurrentHp() - damage) < 0.5) { useTriggers(attacker, TriggerType.DIE, null, null, damage); } } if (isPlayer() && getPlayer().isGM() && getPlayer().isUndying() && ((damage + 0.5) >= getCurrentHp())) { return; } setCurrentHp(Math.max(getCurrentHp() - damage, 0), false, attacker.getObjectId()); broadcastStatusUpdate(); if (getCurrentHp() < 0.5) { doDie(attacker); } } /** * Method reduceCurrentMp. * @param i double * @param attacker Creature */ public void reduceCurrentMp(double i, Creature attacker) { if ((attacker != null) && (attacker != this)) { if (isSleeping()) { getEffectList().stopEffects(EffectType.Sleep); } if (isMeditated()) { Effect effect = getEffectList().getEffectByType(EffectType.Meditation); if (effect != null) { getEffectList().stopEffect(effect.getSkill()); } } } if (isDamageBlocked() && (attacker != null) && (attacker != this)) { attacker.sendPacket(Msg.THE_ATTACK_HAS_BEEN_BLOCKED); return; } if ((attacker != null) && attacker.isPlayer() && (Math.abs(attacker.getLevel() - getLevel()) > 10)) { if ((attacker.getKarma() < 0) && (getEffectList().getEffectsBySkillId(5182) != null) && !isInZone(ZoneType.SIEGE)) { return; } if ((getKarma() < 0) && (attacker.getEffectList().getEffectsBySkillId(5182) != null) && !attacker.isInZone(ZoneType.SIEGE)) { return; } } i = _currentMp - i; if (i < 0) { i = 0; } setCurrentMp(i); if ((attacker != null) && (attacker != this)) { startAttackStanceTask(); } } /** * Method removeAllSkills. */ public void removeAllSkills() { for (Skill s : getAllSkillsArray()) { removeSkill(s); } } /** * Method removeBlockStats. * @param stats List<Stats> */ public void removeBlockStats(List<Stats> stats) { if (_blockedStats != null) { _blockedStats.removeAll(stats); if (_blockedStats.isEmpty()) { _blockedStats = null; } } } /** * Method removeSkill. * @param skill Skill * @return Skill */ public Skill removeSkill(Skill skill) { if (skill == null) { return null; } return removeSkillById(skill.getId()); } /** * Method removeSkillById. * @param id Integer * @return Skill */ public Skill removeSkillById(Integer id) { Skill oldSkill = _skills.remove(id); List<Effect> effects; if (oldSkill != null) { removeTriggers(oldSkill); removeStatsOwner(oldSkill); if (Config.ALT_DELETE_SA_BUFFS && (oldSkill.isItemSkill() || oldSkill.isHandler())) { effects = getEffectList().getEffectsBySkill(oldSkill); if (effects != null) { for (Effect effect : effects) { effect.exit(); } } if (isPlayer()) { for (Summon summon : ((Player) this).getSummonList()) { if (summon != null) { effects = summon.getEffectList().getEffectsBySkill(oldSkill); if (effects != null) { for (Effect effect : effects) { effect.exit(); } } } } } } } return oldSkill; } /** * Method addTriggers. * @param f StatTemplate */ public void addTriggers(StatTemplate f) { if (f.getTriggerList().isEmpty()) { return; } for (TriggerInfo t : f.getTriggerList()) { addTrigger(t); } } /** * Method addTrigger. * @param t TriggerInfo */ public void addTrigger(TriggerInfo t) { if (_triggers == null) { _triggers = new ConcurrentHashMap<TriggerType, Set<TriggerInfo>>(); } Set<TriggerInfo> hs = _triggers.get(t.getType()); if (hs == null) { hs = new CopyOnWriteArraySet<TriggerInfo>(); _triggers.put(t.getType(), hs); } hs.add(t); if (t.getType() == TriggerType.ADD) { useTriggerSkill(this, null, t, null, 0); } } /** * Method removeTriggers. * @param f StatTemplate */ public void removeTriggers(StatTemplate f) { if ((_triggers == null) || f.getTriggerList().isEmpty()) { return; } for (TriggerInfo t : f.getTriggerList()) { removeTrigger(t); } } /** * Method removeTrigger. * @param t TriggerInfo */ public void removeTrigger(TriggerInfo t) { if (_triggers == null) { return; } Set<TriggerInfo> hs = _triggers.get(t.getType()); if (hs == null) { return; } hs.remove(t); } /** * Method sendActionFailed. */ public void sendActionFailed() { sendPacket(ActionFail.STATIC); } /** * Method hasAI. * @return boolean */ public boolean hasAI() { return _ai != null; } /** * Method getAI. * @return CharacterAI */ public CharacterAI getAI() { if (_ai == null) { synchronized (this) { if (_ai == null) { _ai = new CharacterAI(this); } } } return _ai; } /** * Method setAI. * @param newAI CharacterAI */ public void setAI(CharacterAI newAI) { if (newAI == null) { return; } CharacterAI oldAI = _ai; synchronized (this) { _ai = newAI; } if (oldAI != null) { if (oldAI.isActive()) { oldAI.stopAITask(); newAI.startAITask(); newAI.setIntention(CtrlIntention.AI_INTENTION_ACTIVE); } } } /** * Method setCurrentHp. * @param newHp double * @param canRessurect boolean * @param sendInfo boolean * @param _attakerId int */ public final void setCurrentHp(double newHp, boolean canRessurect, boolean sendInfo, int _attakerId) { int maxHp = getMaxHp(); newHp = Math.min(maxHp, Math.max(0, newHp)); if (_currentHp == newHp) { return; } if ((newHp >= 0.5) && isDead() && !canRessurect) { return; } double hpStart = _currentHp; _currentHp = newHp; if (isDead.compareAndSet(true, false)) { onRevive(); } checkHpMessages(hpStart, _currentHp); if (sendInfo) { broadcastStatusUpdate(); sendChanges(); } if (_currentHp < maxHp) { startRegeneration(); } } /** * Method setCurrentHp. * @param newHp double * @param canRessurect boolean */ public final void setCurrentHp(double newHp, boolean canRessurect) { setCurrentHp(newHp, canRessurect, true, 0); } /** * Method setCurrentHp. * @param newHp double * @param canRessurect boolean * @param _attakerObjId int */ public final void setCurrentHp(double newHp, boolean canRessurect, int _attakerObjId) { setCurrentHp(newHp, canRessurect, true, _attakerObjId); } /** * Method setCurrentMp. * @param newMp double * @param sendInfo boolean */ public final void setCurrentMp(double newMp, boolean sendInfo) { int maxMp = getMaxMp(); newMp = Math.min(maxMp, Math.max(0, newMp)); if (_currentMp == newMp) { return; } if ((newMp >= 0.5) && isDead()) { return; } _currentMp = newMp; if (sendInfo) { broadcastStatusUpdate(); sendChanges(); } if (_currentMp < maxMp) { startRegeneration(); } } /** * Method setCurrentMp. * @param newMp double */ public final void setCurrentMp(double newMp) { setCurrentMp(newMp, true); } /** * Method setCurrentCp. * @param newCp double * @param sendInfo boolean */ public final void setCurrentCp(double newCp, boolean sendInfo) { if (!isPlayer()) { return; } int maxCp = getMaxCp(); newCp = Math.min(maxCp, Math.max(0, newCp)); if (_currentCp == newCp) { return; } if ((newCp >= 0.5) && isDead()) { return; } _currentCp = newCp; if (sendInfo) { broadcastStatusUpdate(); sendChanges(); } if (_currentCp < maxCp) { startRegeneration(); } } /** * Method setCurrentCp. * @param newCp double */ public final void setCurrentCp(double newCp) { setCurrentCp(newCp, true); } /** * Method setCurrentHpMp. * @param newHp double * @param newMp double * @param canRessurect boolean */ public void setCurrentHpMp(double newHp, double newMp, boolean canRessurect) { int maxHp = getMaxHp(); int maxMp = getMaxMp(); newHp = Math.min(maxHp, Math.max(0, newHp)); newMp = Math.min(maxMp, Math.max(0, newMp)); if ((_currentHp == newHp) && (_currentMp == newMp)) { return; } if ((newHp >= 0.5) && isDead() && !canRessurect) { return; } double hpStart = _currentHp; _currentHp = newHp; _currentMp = newMp; if (isDead.compareAndSet(true, false)) { onRevive(); } checkHpMessages(hpStart, _currentHp); broadcastStatusUpdate(); sendChanges(); if ((_currentHp < maxHp) || (_currentMp < maxMp)) { startRegeneration(); } } /** * Method setCurrentHpMp. * @param newHp double * @param newMp double */ public void setCurrentHpMp(double newHp, double newMp) { setCurrentHpMp(newHp, newMp, false); } /** * Method setFlying. * @param mode boolean */ public final void setFlying(boolean mode) { _flying = mode; } /** * Method getHeading. * @return int */ @Override public final int getHeading() { return _heading; } /** * Method setHeading. * @param heading int */ public void setHeading(int heading) { _heading = heading; } /** * Method setIsTeleporting. * @param value boolean */ public final void setIsTeleporting(boolean value) { isTeleporting.compareAndSet(!value, value); } /** * Method setName. * @param name String */ public final void setName(String name) { _name = name; } /** * Method getCastingTarget. * @return Creature */ public Creature getCastingTarget() { return castingTarget.get(); } /** * Method setCastingTarget. * @param target Creature */ public void setCastingTarget(Creature target) { if (target == null) { castingTarget = HardReferences.emptyRef(); } else { castingTarget = target.getRef(); } } /** * Method setRunning. */ public final void setRunning() { if (!_running) { _running = true; broadcastPacket(new ChangeMoveType(this)); } } /** * Method setSkillMastery. * @param skill Integer * @param mastery int */ public void setSkillMastery(Integer skill, int mastery) { if (_skillMastery == null) { _skillMastery = new HashMap<Integer, Integer>(); } _skillMastery.put(skill, mastery); } /** * Method setAggressionTarget. * @param target Creature */ public void setAggressionTarget(Creature target) { if (target == null) { _aggressionTarget = HardReferences.emptyRef(); } else { _aggressionTarget = target.getRef(); } } /** * Method getAggressionTarget. * @return Creature */ public Creature getAggressionTarget() { return _aggressionTarget.get(); } /** * Method setTarget. * @param object GameObject */ public void setTarget(GameObject object) { if ((object != null) && !object.isVisible()) { object = null; } if (object == null) { target = HardReferences.emptyRef(); } else { target = object.getRef(); } } /** * Method setTitle. * @param title String */ public void setTitle(String title) { _title = title; } /** * Method setWalking. */ public void setWalking() { if (_running) { _running = false; broadcastPacket(new ChangeMoveType(this)); } } /** * Method startAbnormalEffect. * @param ae AbnormalEffect */ public void startAbnormalEffect(AbnormalEffect ae) { if (ae == AbnormalEffect.NULL) { _abnormalEffects = AbnormalEffect.NULL.getMask(); _abnormalEffects2 = AbnormalEffect.NULL.getMask(); _abnormalEffects3 = AbnormalEffect.NULL.getMask(); _aveList.clear(); } else if (ae.isSpecial()) { _abnormalEffects2 |= ae.getMask(); addToAveList(ae.getId()); } else if (ae.isEvent()) { _abnormalEffects3 |= ae.getMask(); addToAveList(ae.getId()); } else { _abnormalEffects |= ae.getMask(); addToAveList(ae.getId()); } sendChanges(); broadcastCharInfo(); } /** * Method startAttackStanceTask. */ public void startAttackStanceTask() { startAttackStanceTask0(); } /** * Method startAttackStanceTask0. */ protected void startAttackStanceTask0() { if (isInCombat()) { _stanceEndTime = System.currentTimeMillis() + 15000L; return; } _stanceEndTime = System.currentTimeMillis() + 15000L; broadcastPacket(new AutoAttackStart(getObjectId())); final Future<?> task = _stanceTask; if (task != null) { task.cancel(false); } _stanceTask = LazyPrecisionTaskManager.getInstance().scheduleAtFixedRate( _stanceTaskRunnable == null ? _stanceTaskRunnable = new AttackStanceTask() : _stanceTaskRunnable, 1000L, 1000L); } /** * Method stopAttackStanceTask. */ public void stopAttackStanceTask() { _stanceEndTime = 0L; final Future<?> task = _stanceTask; if (task != null) { task.cancel(false); _stanceTask = null; broadcastPacket(new AutoAttackStop(getObjectId())); } } /** * @author Mobius */ private class AttackStanceTask extends RunnableImpl { /** * Constructor for AttackStanceTask. */ public AttackStanceTask() { // TODO Auto-generated constructor stub } /** * Method runImpl. */ @Override public void runImpl() { if (!isInCombat()) { stopAttackStanceTask(); } } } /** * Method stopRegeneration. */ protected void stopRegeneration() { regenLock.lock(); try { if (_isRegenerating) { _isRegenerating = false; if (_regenTask != null) { _regenTask.cancel(false); _regenTask = null; } } } finally { regenLock.unlock(); } } /** * Method startRegeneration. */ protected void startRegeneration() { if (!isVisible() || isDead() || (getRegenTick() == 0L)) { return; } if (_isRegenerating) { return; } regenLock.lock(); try { if (!_isRegenerating) { _isRegenerating = true; _regenTask = RegenTaskManager.getInstance().scheduleAtFixedRate( _regenTaskRunnable == null ? _regenTaskRunnable = new RegenTask() : _regenTaskRunnable, 0, getRegenTick()); } } finally { regenLock.unlock(); } } /** * Method getRegenTick. * @return long */ public long getRegenTick() { return 3000L; } /** * @author Mobius */ private class RegenTask implements Runnable { /** * Constructor for RegenTask. */ public RegenTask() { // TODO Auto-generated constructor stub } /** * Method run. * @see java.lang.Runnable#run() */ @Override public void run() { if (isAlikeDead() || (getRegenTick() == 0L)) { return; } double hpStart = _currentHp; int maxHp = getMaxHp(); int maxMp = getMaxMp(); int maxCp = isPlayer() ? getMaxCp() : 0; double addHp = 0.; double addMp = 0.; regenLock.lock(); try { if (_currentHp < maxHp) { addHp += Formulas.calcHpRegen(Creature.this); } if (_currentMp < maxMp) { addMp += Formulas.calcMpRegen(Creature.this); } if (isPlayer() && Config.REGEN_SIT_WAIT) { Player pl = (Player) Creature.this; if (pl.isSitting()) { pl.updateWaitSitTime(); if (pl.getWaitSitTime() > 5) { addHp += pl.getWaitSitTime(); addMp += pl.getWaitSitTime(); } } } else if (isRaid()) { addHp *= Config.RATE_RAID_REGEN; addMp *= Config.RATE_RAID_REGEN; } _currentHp += Math.max(0, Math.min(addHp, ((calcStat(Stats.HP_LIMIT, null, null) * maxHp) / 100.) - _currentHp)); _currentMp += Math.max(0, Math.min(addMp, ((calcStat(Stats.MP_LIMIT, null, null) * maxMp) / 100.) - _currentMp)); _currentHp = Math.min(maxHp, _currentHp); _currentMp = Math.min(maxMp, _currentMp); if (isPlayer()) { _currentCp += Math.max(0, Math.min(Formulas.calcCpRegen(Creature.this), ((calcStat(Stats.CP_LIMIT, null, null) * maxCp) / 100.) - _currentCp)); _currentCp = Math.min(maxCp, _currentCp); } if ((_currentHp == maxHp) && (_currentMp == maxMp) && (_currentCp == maxCp)) { stopRegeneration(); } } finally { regenLock.unlock(); } broadcastStatusUpdate(); sendChanges(); checkHpMessages(hpStart, _currentHp); } } /** * Method stopAbnormalEffect. * @param ae AbnormalEffect */ public void stopAbnormalEffect(AbnormalEffect ae) { if (ae.isSpecial()) { _abnormalEffects2 &= ~ae.getMask(); removeFromAveList(ae.getId()); } else if (ae.isEvent()) { _abnormalEffects3 &= ~ae.getMask(); removeFromAveList(ae.getId()); } else { _abnormalEffects &= ~ae.getMask(); removeFromAveList(ae.getId()); } sendChanges(); broadcastCharInfo(); } /** * Method block. */ public void block() { _blocked = true; } /** * Method unblock. */ public void unblock() { _blocked = false; } /** * Method startConfused. * @return boolean */ public boolean startConfused() { return _confused.getAndSet(true); } /** * Method stopConfused. * @return boolean */ public boolean stopConfused() { return _confused.setAndGet(false); } /** * Method startFear. * @return boolean */ public boolean startFear() { return _afraid.getAndSet(true); } /** * Method stopFear. * @return boolean */ public boolean stopFear() { return _afraid.setAndGet(false); } /** * Method startMuted. * @return boolean */ public boolean startMuted() { return _muted.getAndSet(true); } /** * Method stopMuted. * @return boolean */ public boolean stopMuted() { return _muted.setAndGet(false); } /** * Method startPMuted. * @return boolean */ public boolean startPMuted() { return _pmuted.getAndSet(true); } /** * Method stopPMuted. * @return boolean */ public boolean stopPMuted() { return _pmuted.setAndGet(false); } /** * Method startAMuted. * @return boolean */ public boolean startAMuted() { return _amuted.getAndSet(true); } /** * Method stopAMuted. * @return boolean */ public boolean stopAMuted() { return _amuted.setAndGet(false); } /** * Method startRooted. * @return boolean */ public boolean startRooted() { return _rooted.getAndSet(true); } /** * Method stopRooted. * @return boolean */ public boolean stopRooted() { return _rooted.setAndGet(false); } /** * Method startSleeping. * @return boolean */ public boolean startSleeping() { return _sleeping.getAndSet(true); } /** * Method stopSleeping. * @return boolean */ public boolean stopSleeping() { return _sleeping.setAndGet(false); } /** * Method startAirbinding. * @return boolean */ public boolean startAirbinding() { return _airbinded.getAndSet(true); } /** * Method stopAirbinding. * @return boolean */ public boolean stopAirbinding() { return _airbinded.setAndGet(false); } /** * Method startKnockingback. * @return boolean */ public boolean startKnockingback() { return _knockedback.getAndSet(true); } /** * Method stopKnockingback. * @return boolean */ public boolean stopKnockingback() { return _knockedback.setAndGet(false); } /** * Method startKnockingback. * @return boolean */ public boolean startKnockingdown() { return _knockeddown.getAndSet(true); } /** * Method stopKnockingback. * @return boolean */ public boolean stopKnockingdown() { return _knockeddown.setAndGet(false); } /** * Method startPulling For chain skills. * @return boolean */ public boolean startPulling() { return _pulled.getAndSet(true); } /** * Method stopKnockingback for chain skill. * @return boolean */ public boolean stopPulling() { return _pulled.setAndGet(false); } /** * Method startStunning. * @return boolean */ public boolean startStunning() { return _stunned.getAndSet(true); } /** * Method stopStunning. * @return boolean */ public boolean stopStunning() { return _stunned.setAndGet(false); } /** * Method startParalyzed. * @return boolean */ public boolean startParalyzed() { return _paralyzed.getAndSet(true); } /** * Method stopParalyzed. * @return boolean */ public boolean stopParalyzed() { return _paralyzed.setAndGet(false); } /** * Method startImmobilized. * @return boolean */ public boolean startImmobilized() { return _immobilized.getAndSet(true); } /** * Method stopImmobilized. * @return boolean */ public boolean stopImmobilized() { return _immobilized.setAndGet(false); } /** * Method startHealBlocked. * @return boolean */ public boolean startHealBlocked() { return _healBlocked.getAndSet(true); } /** * Method stopHealBlocked. * @return boolean */ public boolean stopHealBlocked() { return _healBlocked.setAndGet(false); } /** * Method startDamageBlocked. * @return boolean */ public boolean startDamageBlocked() { return _damageBlocked.getAndSet(true); } /** * Method stopDamageBlocked. * @return boolean */ public boolean stopDamageBlocked() { return _damageBlocked.setAndGet(false); } /** * Method startBuffImmunity. * @return boolean */ public boolean startBuffImmunity() { return _buffImmunity.getAndSet(true); } /** * Method stopBuffImmunity. * @return boolean */ public boolean stopBuffImmunity() { return _buffImmunity.setAndGet(false); } /** * Method startDebuffImmunity. * @return boolean */ public boolean startDebuffImmunity() { return _debuffImmunity.getAndSet(true); } /** * Method stopDebuffImmunity. * @return boolean */ public boolean stopDebuffImmunity() { return _debuffImmunity.setAndGet(false); } /** * Method startEffectImmunity. * @return boolean */ public boolean startEffectImmunity() { return _effectImmunity.getAndSet(true); } /** * Method stopEffectImmunity. * @return boolean */ public boolean stopEffectImmunity() { return _effectImmunity.setAndGet(false); } /** * Method startWeaponEquipBlocked. * @return boolean */ public boolean startWeaponEquipBlocked() { return _weaponEquipBlocked.getAndSet(true); } /** * Method stopWeaponEquipBlocked. * @return boolean */ public boolean stopWeaponEquipBlocked() { return _weaponEquipBlocked.getAndSet(false); } /** * Method startFrozen. * @return boolean */ public boolean startFrozen() { return _frozen.getAndSet(true); } /** * Method stopFrozen. * @return boolean */ public boolean stopFrozen() { return _frozen.setAndGet(false); } /** * Method setFakeDeath. * @param value boolean */ public void setFakeDeath(boolean value) { _fakeDeath = value; } /** * Method breakFakeDeath. */ public void breakFakeDeath() { getEffectList().stopAllSkillEffects(EffectType.FakeDeath); } /** * Method setMeditated. * @param value boolean */ public void setMeditated(boolean value) { _meditated = value; } /** * Method setIsBlessedByNoblesse. * @param value boolean */ public final void setIsBlessedByNoblesse(boolean value) { _isBlessedByNoblesse = value; } /** * Method setIsSalvation. * @param value boolean */ public final void setIsSalvation(boolean value) { _isSalvation = value; } /** * Method setIsInvul. * @param value boolean */ public void setIsInvul(boolean value) { _isInvul = value; } /** * Method setLockedTarget. * @param value boolean */ public void setLockedTarget(boolean value) { _lockedTarget = value; } /** * Method setTargetable. * @param value boolean */ public void setTargetable(boolean value) { _isTargetable = value; } /** * Method isConfused. * @return boolean */ public boolean isConfused() { return _confused.get(); } /** * Method isFakeDeath. * @return boolean */ public boolean isFakeDeath() { return _fakeDeath; } /** * Method isAfraid. * @return boolean */ public boolean isAfraid() { return _afraid.get(); } /** * Method isBlocked. * @return boolean */ public boolean isBlocked() { return _blocked; } /** * Method isMuted. * @param skill Skill * @return boolean */ public boolean isMuted(Skill skill) { if ((skill == null) || skill.isNotAffectedByMute()) { return false; } return (isMMuted() && skill.isMagic()) || (isPMuted() && !skill.isMagic()); } /** * Method isPMuted. * @return boolean */ public boolean isPMuted() { return _pmuted.get(); } /** * Method isMMuted. * @return boolean */ public boolean isMMuted() { return _muted.get(); } /** * Method isAMuted. * @return boolean */ public boolean isAMuted() { return _amuted.get(); } /** * Method isRooted. * @return boolean */ public boolean isRooted() { return _rooted.get(); } /** * Method isSleeping. * @return boolean */ public boolean isSleeping() { return _sleeping.get(); } /** * Method isStunned. * @return boolean */ public boolean isStunned() { return _stunned.get(); } /** * Method isAirBinded. * @return boolean */ public boolean isAirBinded() { return _airbinded.get(); } /** * Method isKnockedBack. * @return boolean */ public boolean isKnockedBack() { return _knockedback.get(); } /** * Method isKnockedDown. * @return boolean */ public boolean isKnockedDown() { return _knockeddown.get(); } /** * Method isPulledNow. * @return boolean */ public boolean isPulledNow() { return _pulled.get(); } /** * Method isMeditated. * @return boolean */ public boolean isMeditated() { return _meditated; } /** * Method isWeaponEquipBlocked. * @return boolean */ public boolean isWeaponEquipBlocked() { return _weaponEquipBlocked.get(); } /** * Method isParalyzed. * @return boolean */ public boolean isParalyzed() { return _paralyzed.get(); } /** * Method isFrozen. * @return boolean */ public boolean isFrozen() { return _frozen.get(); } /** * Method isImmobilized. * @return boolean */ public boolean isImmobilized() { return _immobilized.get() || (getRunSpeed() < 1); } /** * Method isHealBlocked. * @return boolean */ public boolean isHealBlocked() { return isAlikeDead() || _healBlocked.get(); } /** * Method isDamageBlocked. * @return boolean */ public boolean isDamageBlocked() { return isInvul() || _damageBlocked.get(); } /** * Method isCastingNow. * @return boolean */ public boolean isCastingNow() { return _skillTask != null; } /** * Method isDoubleCastingNow. * @return boolean */ public boolean isDoubleCastingNow() { return _skillDoubleTask != null; } /** * Method isLockedTarget. * @return boolean */ public boolean isLockedTarget() { return _lockedTarget; } /** * Method isTargetable. * @return boolean */ public boolean isTargetable() { return _isTargetable; } /** * Method isMovementDisabled. * @return boolean */ public boolean isMovementDisabled() { return isBlocked() || isRooted() || isImmobilized() || isAlikeDead() || isStunned() || isSleeping() || isParalyzed() || isAttackingNow() || isCastingNow() || isFrozen() || isAirBinded() || isKnockedBack() || isKnockedDown() || isPulledNow(); } /** * Method isActionsDisabled. * @return boolean */ public boolean isActionsDisabled() { return isBlocked() || isAlikeDead() || isStunned() || isSleeping() || isParalyzed() || isAttackingNow() || isCastingNow() || isFrozen() || isAirBinded() || isKnockedBack() || isKnockedDown() || isPulledNow(); } /** * Method isAttackingDisabled. * @return boolean */ public final boolean isAttackingDisabled() { return _attackReuseEndTime > System.currentTimeMillis(); } /** * Method isOutOfControl. * @return boolean */ public boolean isOutOfControl() { return isBlocked() || isConfused() || isAfraid(); } /** * Method teleToLocation. * @param loc Location */ public void teleToLocation(Location loc) { teleToLocation(loc.x, loc.y, loc.z, getReflection()); } /** * Method teleToLocation. * @param loc Location * @param refId int */ public void teleToLocation(Location loc, int refId) { teleToLocation(loc.x, loc.y, loc.z, refId); } /** * Method teleToLocation. * @param loc Location * @param r Reflection */ public void teleToLocation(Location loc, Reflection r) { teleToLocation(loc.x, loc.y, loc.z, r); } /** * Method teleToLocation. * @param x int * @param y int * @param z int */ public void teleToLocation(int x, int y, int z) { teleToLocation(x, y, z, getReflection()); } /** * Method checkAndRemoveInvisible. */ public void checkAndRemoveInvisible() { InvisibleType invisibleType = getInvisibleType(); if (invisibleType == InvisibleType.EFFECT) { getEffectList().stopEffects(EffectType.Invisible); } } /** * Method teleToLocation. * @param x int * @param y int * @param z int * @param refId int */ public void teleToLocation(int x, int y, int z, int refId) { Reflection r = ReflectionManager.getInstance().get(refId); if (r == null) { return; } teleToLocation(x, y, z, r); } /** * Method teleToLocation. * @param x int * @param y int * @param z int * @param r Reflection */ public void teleToLocation(int x, int y, int z, Reflection r) { if (!isTeleporting.compareAndSet(false, true)) { return; } if (isFakeDeath()) { breakFakeDeath(); } abortCast(true, false); if (!isLockedTarget()) { setTarget(null); } stopMove(); if (!isBoat() && !isFlying() && !World.isWater(new Location(x, y, z), r)) { z = GeoEngine.getHeight(x, y, z, r.getGeoIndex()); } if (isPlayer()) { Player player = (Player) this; player.getListeners().onTeleport(x, y, z, r); decayMe(); setXYZ(x, y, z); setReflection(r); player.setLastClientPosition(null); player.setLastServerPosition(null); player.sendPacket(new TeleportToLocation(player, x, y, z)); player.sendPacket(new ExTeleportToLocationActivate(player, x, y, z)); } else { setXYZ(x, y, z); setReflection(r); broadcastPacket(new TeleportToLocation(this, x, y, z)); onTeleported(); } } /** * Method onTeleported. * @return boolean */ public boolean onTeleported() { return isTeleporting.compareAndSet(true, false); } /** * Method sendMessage. * @param message CustomMessage */ public void sendMessage(CustomMessage message) { } /** * Method toString. * @return String */ @Override public String toString() { return getClass().getSimpleName() + "[" + getObjectId() + "]"; } /** * Method getEffectList. * @return EffectList */ public EffectList getEffectList() { if (_effectList == null) { synchronized (this) { if (_effectList == null) { _effectList = new EffectList(this); } } } return _effectList; } /** * Method paralizeOnAttack. * @param attacker Creature * @return boolean */ public boolean paralizeOnAttack(Creature attacker) { int max_attacker_level = 0xFFFF; MonsterInstance leader; if (isRaid() || (isMinion() && ((leader = ((MinionInstance) this).getLeader()) != null) && leader.isRaid())) { max_attacker_level = getLevel() + Config.RAID_MAX_LEVEL_DIFF; } else if (isNpc()) { int max_level_diff = ((NpcInstance) this).getParameter("ParalizeOnAttack", -1000); if (max_level_diff != -1000) { max_attacker_level = getLevel() + max_level_diff; } } if (attacker.getLevel() > max_attacker_level) { return true; } return false; } /** * Method onDelete. */ @Override protected void onDelete() { GameObjectsStorage.remove(_storedId); getEffectList().stopAllEffects(); super.onDelete(); } /** * Method addExpAndSp. * @param exp long * @param sp long */ public void addExpAndSp(long exp, long sp) { } /** * Method broadcastCharInfo. */ public void broadcastCharInfo() { } /** * Method checkHpMessages. * @param currentHp double * @param newHp double */ public void checkHpMessages(double currentHp, double newHp) { } /** * Method checkPvP. * @param target Creature * @param skill Skill * @return boolean */ public boolean checkPvP(Creature target, Skill skill) { return false; } /** * Method consumeItem. * @param itemConsumeId int * @param itemCount long * @return boolean */ public boolean consumeItem(int itemConsumeId, long itemCount) { return true; } /** * Method consumeItemMp. * @param itemId int * @param mp int * @return boolean */ public boolean consumeItemMp(int itemId, int mp) { return true; } /** * Method isFearImmune. * @return boolean */ public boolean isFearImmune() { return false; } /** * Method isLethalImmune. * @return boolean */ public boolean isLethalImmune() { return getMaxHp() >= 50000; } /** * Method getChargedSoulShot. * @return boolean */ public boolean getChargedSoulShot() { return false; } /** * Method getChargedSpiritShot. * @return int */ public int getChargedSpiritShot() { return 0; } /** * Method getIncreasedForce. * @return int */ public int getIncreasedForce() { return 0; } /** * Method getConsumedSouls. * @return int */ public int getConsumedSouls() { return 0; } /** * Method getAgathionEnergy. * @return int */ public int getAgathionEnergy() { return 0; } /** * Method setAgathionEnergy. * @param val int */ public void setAgathionEnergy(int val) { } /** * Method getKarma. * @return int */ public int getKarma() { return 0; } /** * Method getLevelMod. * @return double */ public double getLevelMod() { return 1; } /** * Method getNpcId. * @return int */ public int getNpcId() { return 0; } /** * Method getPvpFlag. * @return int */ public int getPvpFlag() { return 0; } /** * Method setTeam. * @param t TeamType */ public void setTeam(TeamType t) { _team = t; sendChanges(); } /** * Method getTeam. * @return TeamType */ public TeamType getTeam() { return _team; } /** * Method isUndead. * @return boolean */ public boolean isUndead() { return false; } /** * Method isParalyzeImmune. * @return boolean */ public boolean isParalyzeImmune() { return false; } /** * Method reduceArrowCount. */ public void reduceArrowCount() { } /** * Method sendChanges. */ public void sendChanges() { getStatsRecorder().sendChanges(); } /** * Method sendMessage. * @param message String */ public void sendMessage(String message) { } /** * Method sendPacket. * @param mov IStaticPacket */ public void sendPacket(IStaticPacket mov) { } /** * Method sendPacket. * @param mov IStaticPacket[] */ public void sendPacket(IStaticPacket... mov) { } /** * Method sendPacket. * @param mov List<? extends IStaticPacket> */ public void sendPacket(List<? extends IStaticPacket> mov) { } /** * Method setIncreasedForce. * @param i int */ public void setIncreasedForce(int i) { } /** * Method setConsumedSouls. * @param i int * @param monster NpcInstance */ public void setConsumedSouls(int i, NpcInstance monster) { } /** * Method startPvPFlag. * @param target Creature */ public void startPvPFlag(Creature target) { } /** * Method unChargeShots. * @param spirit boolean * @return boolean */ public boolean unChargeShots(boolean spirit) { return false; } /** * Method updateEffectIcons. */ public void updateEffectIcons() { } /** * Method refreshHpMpCp. */ protected void refreshHpMpCp() { final int maxHp = getMaxHp(); final int maxMp = getMaxMp(); final int maxCp = isPlayer() ? getMaxCp() : 0; if (_currentHp > maxHp) { setCurrentHp(maxHp, false); } if (_currentMp > maxMp) { setCurrentMp(maxMp, false); } if (_currentCp > maxCp) { setCurrentCp(maxCp, false); } if ((_currentHp < maxHp) || (_currentMp < maxMp) || (_currentCp < maxCp)) { startRegeneration(); } } /** * Method updateStats. */ public void updateStats() { refreshHpMpCp(); sendChanges(); } /** * Method setOverhitAttacker. * @param attacker Creature */ public void setOverhitAttacker(Creature attacker) { } /** * Method setOverhitDamage. * @param damage double */ public void setOverhitDamage(double damage) { } /** * Method isCursedWeaponEquipped. * @return boolean */ public boolean isCursedWeaponEquipped() { return false; } /** * Method isHero. * @return boolean */ public boolean isHero() { return false; } /** * Method getAccessLevel. * @return int */ public int getAccessLevel() { return 0; } /** * Method getClan. * @return Clan */ public Clan getClan() { return null; } /** * Method getRateAdena. * @return double */ public double getRateAdena() { return 1.; } /** * Method getRateItems. * @return double */ public double getRateItems() { return 1.; } /** * Method getRateExp. * @return double */ public double getRateExp() { return 1.; } /** * Method getRateSp. * @return double */ public double getRateSp() { return 1.; } /** * Method getRateSpoil. * @return double */ public double getRateSpoil() { return 1.; } /** * Method getFormId. * @return int */ public int getFormId() { return 0; } /** * Method isNameAbove. * @return boolean */ public boolean isNameAbove() { return true; } /** * Method setLoc. * @param loc Location */ @Override public void setLoc(Location loc) { setXYZ(loc.x, loc.y, loc.z); } /** * Method setLoc. * @param loc Location * @param MoveTask boolean */ public void setLoc(Location loc, boolean MoveTask) { setXYZ(loc.x, loc.y, loc.z, MoveTask); } /** * Method setXYZ. * @param x int * @param y int * @param z int */ @Override public void setXYZ(int x, int y, int z) { setXYZ(x, y, z, false); } /** * Method setXYZ. * @param x int * @param y int * @param z int * @param MoveTask boolean */ public void setXYZ(int x, int y, int z, boolean MoveTask) { if (!MoveTask) { stopMove(); } moveLock.lock(); try { super.setXYZ(x, y, z); } finally { moveLock.unlock(); } updateZones(); } /** * Method onSpawn. */ @Override protected void onSpawn() { super.onSpawn(); updateStats(); updateZones(); } /** * Method spawnMe. * @param loc Location */ @Override public void spawnMe(Location loc) { if (loc.h > 0) { setHeading(loc.h); } super.spawnMe(loc); } /** * Method onDespawn. */ @Override protected void onDespawn() { if (!isLockedTarget()) { setTarget(null); } stopMove(); stopAttackStanceTask(); stopRegeneration(); updateZones(); clearStatusListeners(); super.onDespawn(); } /** * Method doDecay. */ public final void doDecay() { if (!isDead()) { return; } onDecay(); } /** * Method onDecay. */ protected void onDecay() { decayMe(); } /** * Method validateLocation. * @param broadcast int */ public void validateLocation(int broadcast) { L2GameServerPacket sp = new ValidateLocation(this); if (broadcast == 0) { sendPacket(sp); } else if (broadcast == 1) { broadcastPacket(sp); } else { broadcastPacketToOthers(sp); } } /** * Field _unActiveSkills. */ private final TIntHashSet _unActiveSkills = new TIntHashSet(); /** * Method addUnActiveSkill. * @param skill Skill */ public void addUnActiveSkill(Skill skill) { if ((skill == null) || isUnActiveSkill(skill.getId())) { return; } removeStatsOwner(skill); removeTriggers(skill); _unActiveSkills.add(skill.getId()); } /** * Method removeUnActiveSkill. * @param skill Skill */ public void removeUnActiveSkill(Skill skill) { if ((skill == null) || !isUnActiveSkill(skill.getId())) { return; } addStatFuncs(skill.getStatFuncs()); addTriggers(skill); _unActiveSkills.remove(skill.getId()); } /** * Method isUnActiveSkill. * @param id int * @return boolean */ public boolean isUnActiveSkill(int id) { return _unActiveSkills.contains(id); } /** * Method getLevel. * @return int */ public abstract int getLevel(); /** * Method getActiveWeaponInstance. * @return ItemInstance */ public abstract ItemInstance getActiveWeaponInstance(); /** * Method getActiveWeaponItem. * @return WeaponTemplate */ public abstract WeaponTemplate getActiveWeaponItem(); /** * Method getSecondaryWeaponInstance. * @return ItemInstance */ public abstract ItemInstance getSecondaryWeaponInstance(); /** * Method getSecondaryWeaponItem. * @return WeaponTemplate */ public abstract WeaponTemplate getSecondaryWeaponItem(); /** * Method getListeners. * @return CharListenerList */ public CharListenerList getListeners() { if (listeners == null) { synchronized (this) { if (listeners == null) { listeners = new CharListenerList(this); } } } return listeners; } /** * Method addListener. * @param listener T * @return boolean */ public <T extends Listener<Creature>> boolean addListener(T listener) { return getListeners().add(listener); } /** * Method removeListener. * @param listener T * @return boolean */ public <T extends Listener<Creature>> boolean removeListener(T listener) { return getListeners().remove(listener); } /** * Method getStatsRecorder. * @return CharStatsChangeRecorder<? extends Creature> */ public CharStatsChangeRecorder<? extends Creature> getStatsRecorder() { if (_statsRecorder == null) { synchronized (this) { if (_statsRecorder == null) { _statsRecorder = new CharStatsChangeRecorder<>(this); } } } return _statsRecorder; } /** * Method isCreature. * @return boolean */ @Override public boolean isCreature() { return true; } /** * Method displayGiveDamageMessage. * @param target Creature * @param damage int * @param crit boolean * @param miss boolean * @param shld boolean * @param magic boolean */ public void displayGiveDamageMessage(Creature target, int damage, boolean crit, boolean miss, boolean shld, boolean magic) { if (miss && target.isPlayer() && !target.isDamageBlocked()) { target.sendPacket( new SystemMessage(SystemMessage.C1_HAS_EVADED_C2S_ATTACK).addName(target).addName(this)); } } /** * Method displayReceiveDamageMessage. * @param attacker Creature * @param damage int */ public void displayReceiveDamageMessage(Creature attacker, int damage) { } /** * Method getSkillReuses. * @return Collection<TimeStamp> */ public Collection<TimeStamp> getSkillReuses() { return _skillReuses.values(); } /** * Method getSkillReuse. * @param skill Skill * @return TimeStamp */ public TimeStamp getSkillReuse(Skill skill) { return _skillReuses.get(skill.hashCode()); } /** * Method isInFlyingTransform. * @return boolean */ public boolean isInFlyingTransform() { return (_transformationId == 8) || (_transformationId == 9) || (_transformationId == 260); } /** * Method isInMountTransform. * @return boolean */ public boolean isInMountTransform() { return (_transformationId == 106) || (_transformationId == 109) || (_transformationId == 110) || (_transformationId == 20001); } /** * Method setTransformation. * @param id int */ public void setTransformation(int id) { _transformationId = id; } /** * Method getTransformation. * @return int */ public int getTransformation() { return _transformationId; } /** * Method getTransformationName. * @return String */ public String getTransformationName() { return _transformationName; } /** * Method setTransformationName. * @param name String */ public void setTransformationName(String name) { _transformationName = name; } /** * Method setTransformationTemplate. * @param template int */ public void setTransformationTemplate(int template) { _transformationTemplate = template; } /** * Method getTransformationTemplate. * @return int */ public int getTransformationTemplate() { return _transformationTemplate; } /** * Method getHpRegen. * @return double */ public double getHpRegen() { return calcStat(Stats.REGENERATE_HP_RATE, getTemplate().getBaseHpReg()); } /** * Method getMpRegen. * @return double */ public double getMpRegen() { return calcStat(Stats.REGENERATE_MP_RATE, getTemplate().getBaseMpReg()); } /** * Method getCpRegen. * @return double */ public double getCpRegen() { return 0.0D; } /** * Method getColRadius. * @return double */ @Override public double getColRadius() { return getTemplate().getCollisionRadius(); } /** * Method getColHeight. * @return double */ @Override public double getColHeight() { return getTemplate().getCollisionHeight(); } /** * Method addDeathImmunity. */ public void addDeathImmunity() { _deathImmune = true; } /** * Method removeDeathImmunity. */ public void removeDeathImmunity() { _deathImmune = false; } /** * Method isDeathImmune. * @return boolean */ public boolean isDeathImmune() { return _deathImmune; } /** * Method setWalkerRouteTemplate. * @param template WalkerRouteTemplate */ public void setWalkerRouteTemplate(WalkerRouteTemplate template) { _walkerRoutesTemplate = template; } /** * Method getWalkerRouteTemplate. * @return WalkerRouteTemplate */ public WalkerRouteTemplate getWalkerRouteTemplate() { return _walkerRoutesTemplate; } /** * Method setIsEnabledDoubleCast. * @param doubleCast boolean */ public void setIsEnabledDoubleCast(boolean doubleCast) { _isEnabledDoubleCast = doubleCast; } /** * Method IsEnabledDoubleCast. * @return boolean */ public boolean IsEnabledDoubleCast() { return _isEnabledDoubleCast; } /** * Method getDefaultMaxHp. * @return double */ public double getDefaultMaxHp() { return 0; } /** * Method getDefaultMaxMp. * @return double */ public double getDefaultMaxMp() { return 0; } public Collection<Summon> getPets() { return new ArrayList<Summon>(0); } public void broadcastEffectsStatusToListeners() { if (!isVehicle() && !isDoor()) { final ExAbnormalStatusUpdateFromTarget exb = new ExAbnormalStatusUpdateFromTarget(this); if (isPlayer() && (getTarget() == this)) { sendPacket(exb); } broadcastToStatusListeners(exb); } } @Override public void onActionTarget(final Player player, boolean forced) { super.onActionTarget(player, forced); if ((player != this) && !isDoor()) { validateLocation(0); } } @Override public void onActionTargeted(final Player player, boolean forced) { if (player == this) { return; } if (isAutoAttackable(player)) { player.getAI().Attack(this, false, forced); return; } super.onActionTargeted(player, forced); } }