Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * l2jlegacy Project - www.l2jlegacy.com
- *
- * 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 2, 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * http://www.gnu.org/copyleft/gpl.html
- */
- package com.l2jlegacy.gameserver.model;
- import static com.l2jlegacy.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
- import static com.l2jlegacy.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.Future;
- import javolution.util.FastList;
- import javolution.util.FastMap;
- import javolution.util.FastTable;
- import org.apache.log4j.Logger;
- import com.l2jlegacy.Config;
- import com.l2jlegacy.gameserver.ai.CtrlEvent;
- import com.l2jlegacy.gameserver.ai.CtrlIntention;
- import com.l2jlegacy.gameserver.ai.L2AttackableAI;
- import com.l2jlegacy.gameserver.ai.L2CharacterAI;
- import com.l2jlegacy.gameserver.controllers.GameTimeController;
- import com.l2jlegacy.gameserver.datatables.HeroSkillTable;
- import com.l2jlegacy.gameserver.datatables.SkillTable;
- import com.l2jlegacy.gameserver.datatables.csv.DoorTable;
- import com.l2jlegacy.gameserver.datatables.csv.MapRegionTable;
- import com.l2jlegacy.gameserver.datatables.csv.MapRegionTable.TeleportWhereType;
- import com.l2jlegacy.gameserver.datatables.sql.NpcTable;
- import com.l2jlegacy.gameserver.geo.GeoData;
- import com.l2jlegacy.gameserver.geo.pathfinding.Node;
- import com.l2jlegacy.gameserver.geo.pathfinding.PathFinding;
- import com.l2jlegacy.gameserver.handler.ISkillHandler;
- import com.l2jlegacy.gameserver.handler.SkillHandler;
- import com.l2jlegacy.gameserver.handler.itemhandlers.Potions;
- import com.l2jlegacy.gameserver.managers.DimensionalRiftManager;
- import com.l2jlegacy.gameserver.managers.DuelManager;
- import com.l2jlegacy.gameserver.managers.GrandBossManager;
- import com.l2jlegacy.gameserver.managers.RaidBossSpawnManager;
- import com.l2jlegacy.gameserver.managers.TownManager;
- import com.l2jlegacy.gameserver.model.L2Skill.SkillTargetType;
- import com.l2jlegacy.gameserver.model.L2Skill.SkillType;
- import com.l2jlegacy.gameserver.model.actor.instance.L2BoatInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2ControlTowerInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2DoorInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2EffectPointInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2GrandBossInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2GuardInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2ItemInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2MinionInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2MonsterInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2NpcInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2NpcWalkerInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2PcInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2PetInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2PlayableInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2RaidBossInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2RiftInvaderInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2SiegeFlagInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2SummonInstance;
- import com.l2jlegacy.gameserver.model.actor.instance.L2PcInstance.SkillDat;
- import com.l2jlegacy.gameserver.model.actor.knownlist.CharKnownList;
- import com.l2jlegacy.gameserver.model.actor.knownlist.ObjectKnownList.KnownListAsynchronousUpdateTask;
- import com.l2jlegacy.gameserver.model.actor.position.L2CharPosition;
- import com.l2jlegacy.gameserver.model.actor.position.ObjectPosition;
- import com.l2jlegacy.gameserver.model.actor.stat.CharStat;
- import com.l2jlegacy.gameserver.model.actor.status.CharStatus;
- import com.l2jlegacy.gameserver.model.entity.Duel;
- import com.l2jlegacy.gameserver.model.entity.event.CTF;
- import com.l2jlegacy.gameserver.model.entity.event.DM;
- import com.l2jlegacy.gameserver.model.entity.event.L2Event;
- import com.l2jlegacy.gameserver.model.entity.event.TvT;
- import com.l2jlegacy.gameserver.model.entity.event.VIP;
- import com.l2jlegacy.gameserver.model.entity.olympiad.Olympiad;
- import com.l2jlegacy.gameserver.model.extender.BaseExtender.EventType;
- import com.l2jlegacy.gameserver.model.quest.Quest;
- import com.l2jlegacy.gameserver.model.quest.QuestState;
- import com.l2jlegacy.gameserver.model.zone.type.L2BossZone;
- import com.l2jlegacy.gameserver.model.zone.type.L2TownZone;
- import com.l2jlegacy.gameserver.network.SystemMessageId;
- import com.l2jlegacy.gameserver.network.serverpackets.ActionFailed;
- import com.l2jlegacy.gameserver.network.serverpackets.Attack;
- import com.l2jlegacy.gameserver.network.serverpackets.BeginRotation;
- import com.l2jlegacy.gameserver.network.serverpackets.ChangeMoveType;
- import com.l2jlegacy.gameserver.network.serverpackets.ChangeWaitType;
- import com.l2jlegacy.gameserver.network.serverpackets.CharInfo;
- import com.l2jlegacy.gameserver.network.serverpackets.CharMoveToLocation;
- import com.l2jlegacy.gameserver.network.serverpackets.ExOlympiadSpelledInfo;
- import com.l2jlegacy.gameserver.network.serverpackets.L2GameServerPacket;
- import com.l2jlegacy.gameserver.network.serverpackets.MagicEffectIcons;
- import com.l2jlegacy.gameserver.network.serverpackets.MagicSkillCanceld;
- import com.l2jlegacy.gameserver.network.serverpackets.MagicSkillLaunched;
- import com.l2jlegacy.gameserver.network.serverpackets.MagicSkillUser;
- import com.l2jlegacy.gameserver.network.serverpackets.MyTargetSelected;
- import com.l2jlegacy.gameserver.network.serverpackets.NpcInfo;
- import com.l2jlegacy.gameserver.network.serverpackets.PartySpelled;
- import com.l2jlegacy.gameserver.network.serverpackets.PetInfo;
- import com.l2jlegacy.gameserver.network.serverpackets.RelationChanged;
- import com.l2jlegacy.gameserver.network.serverpackets.Revive;
- import com.l2jlegacy.gameserver.network.serverpackets.SetupGauge;
- import com.l2jlegacy.gameserver.network.serverpackets.StatusUpdate;
- import com.l2jlegacy.gameserver.network.serverpackets.StopMove;
- import com.l2jlegacy.gameserver.network.serverpackets.SystemMessage;
- import com.l2jlegacy.gameserver.network.serverpackets.TargetUnselected;
- import com.l2jlegacy.gameserver.network.serverpackets.TeleportToLocation;
- import com.l2jlegacy.gameserver.network.serverpackets.ValidateLocation;
- import com.l2jlegacy.gameserver.network.serverpackets.ValidateLocationInVehicle;
- import com.l2jlegacy.gameserver.skills.Calculator;
- import com.l2jlegacy.gameserver.skills.Formulas;
- import com.l2jlegacy.gameserver.skills.Stats;
- import com.l2jlegacy.gameserver.skills.effects.EffectCharge;
- import com.l2jlegacy.gameserver.skills.funcs.Func;
- import com.l2jlegacy.gameserver.skills.holders.ISkillsHolder;
- import com.l2jlegacy.gameserver.templates.L2CharTemplate;
- import com.l2jlegacy.gameserver.templates.L2NpcTemplate;
- import com.l2jlegacy.gameserver.templates.L2Weapon;
- import com.l2jlegacy.gameserver.templates.L2WeaponType;
- import com.l2jlegacy.gameserver.templates.StatsSet;
- import com.l2jlegacy.gameserver.thread.ThreadPoolManager;
- import com.l2jlegacy.gameserver.util.Util;
- import com.l2jlegacy.util.Point3D;
- import com.l2jlegacy.util.random.Rnd;
- /**
- * Mother class of all character objects of the world (PC, NPC...)<BR>
- * <BR>
- * L2Character :<BR>
- * <BR>
- * <li>L2CastleGuardInstance</li> <li>L2DoorInstance</li> <li>L2NpcInstance</li> <li>L2PlayableInstance</li><BR>
- * <BR>
- * <B><U> Concept of L2CharTemplate</U> :</B><BR>
- * <BR>
- * Each L2Character owns generic and static properties (ex : all Keltir have the same number of HP...). All of those properties are stored in a different template for each type of L2Character. Each template is loaded once in the server cache memory (reduce memory use). When a new instance of
- * L2Character is spawned, server just create a link between the instance and the template. This link is stored in <B>_template</B><BR>
- * <BR>
- * @version $Revision: 1.5.5 $ $Date: 2009/05/12 19:45:27 $
- * @authors eX1steam, programmos, L2Scoria dev&sword dev
- */
- public abstract class L2Character extends L2Object implements ISkillsHolder
- {
- /** The Constant LOGGER. */
- protected static final Logger LOGGER = Logger.getLogger(L2Character.class);
- // =========================================================
- // Data Field
- /** The attack stance. */
- private long attackStance;
- /** The _attack by list. */
- private List<L2Character> _attackByList;
- // private L2Character _attackingChar;
- /** The _last skill cast. */
- private L2Skill _lastSkillCast;
- /** The _last potion cast. */
- private L2Skill _lastPotionCast;
- /** The _is buff protected. */
- private boolean _isBuffProtected = false; // Protect From Debuffs
- /** The _is afraid. */
- private boolean _isAfraid = false; // Flee in a random direction
- /** The _is confused. */
- private boolean _isConfused = false; // Attack anyone randomly
- /** The _is fake death. */
- private boolean _isFakeDeath = false; // Fake death
- /** The _is flying. */
- private boolean _isFlying = false; // Is flying Wyvern?
- /** The _is fallsdown. */
- private boolean _isFallsdown = false; // Falls down
- /** The _is muted. */
- private boolean _isMuted = false; // Cannot use magic
- /** The _is psychical muted. */
- private boolean _isPsychicalMuted = false; // Cannot use psychical skills
- /** The _is killed already. */
- private boolean _isKilledAlready = false;
- /** The _is imobilised. */
- private int _isImmobilized = 0;
- /** The _is overloaded. */
- private boolean _isOverloaded = false; // the char is carrying too much
- /** The _is paralyzed. */
- private boolean _isParalyzed = false;
- /** The _is riding. */
- private boolean _isRiding = false; // Is Riding strider?
- /** The _is pending revive. */
- private boolean _isPendingRevive = false;
- /** The _is rooted. */
- private boolean _isRooted = false; // Cannot move until root timed out
- /** The _is running. */
- private boolean _isRunning = false;
- /** The _is immobile until attacked. */
- private boolean _isImmobileUntilAttacked = false; // Is in immobile until attacked.
- /** The _is sleeping. */
- private boolean _isSleeping = false; // Cannot move/attack until sleep timed out or monster is attacked
- /** The _is stunned. */
- private boolean _isStunned = false; // Cannot move/attack until stun timed out
- /** The _is betrayed. */
- private boolean _isBetrayed = false; // Betrayed by own summon
- /** The _is block buff. */
- private boolean _isBlockBuff = false; // Got blocked buff bar
- /** The _is block debuff. */
- private boolean _isBlockDebuff = false; // Got blocked debuff bar
- /** The _is teleporting. */
- protected boolean _isTeleporting = false;
- /** The _is invul. */
- protected boolean _isInvul = false;
- /** The _is killable */
- protected boolean _isUnkillable = false;
- /** The attackDisabled */
- protected boolean _isAttackDisabled = false;
- /** The _last heal amount. */
- private int _lastHealAmount = 0;
- /** The _stat. */
- private CharStat _stat;
- /** The _status. */
- private CharStatus _status;
- /** The _template. */
- private L2CharTemplate _template; // The link on the L2CharTemplate object containing generic and static properties of this L2Character type (ex : Max HP, Speed...)
- /** The _title. */
- private String _title;
- /** The _ai class. */
- private String _aiClass = "default";
- /** The _hp update inc check. */
- private double _hpUpdateIncCheck = .0;
- /** The _hp update dec check. */
- private double _hpUpdateDecCheck = .0;
- /** The _hp update interval. */
- private double _hpUpdateInterval = .0;
- /** The _champion. */
- private boolean _champion = false;
- /** Table of Calculators containing all used calculator. */
- private Calculator[] _calculators;
- /** FastMap(Integer, L2Skill) containing all skills of the L2Character. */
- protected final Map<Integer, L2Skill> _skills;
- /** FastMap(Integer, L2Skill) containing all triggered skills of the L2PcInstance. */
- protected final Map<Integer, L2Skill> _triggeredSkills;
- /** FastMap containing the active chance skills on this character. */
- protected ChanceSkillList _chanceSkills;
- /** Current force buff this caster is casting to a target. */
- protected ForceBuff _forceBuff;
- /** The _blocked. */
- private boolean _blocked;
- /** The _meditated. */
- private boolean _meditated;
- /**
- * Zone system<br>
- * x^2 or x*x.
- */
- public static final int ZONE_PVP = 1;
- /** The Constant ZONE_PEACE. */
- public static final int ZONE_PEACE = 2;
- /** The Constant ZONE_SIEGE. */
- public static final int ZONE_SIEGE = 4;
- /** The Constant ZONE_MOTHERTREE. */
- public static final int ZONE_MOTHERTREE = 8;
- /** The Constant ZONE_CLANHALL. */
- public static final int ZONE_CLANHALL = 16;
- /** The Constant ZONE_UNUSED. */
- public static final int ZONE_UNUSED = 32;
- /** The Constant ZONE_NOLANDING. */
- public static final int ZONE_NOLANDING = 64;
- /** The Constant ZONE_WATER. */
- public static final int ZONE_WATER = 128;
- /** The Constant ZONE_JAIL. */
- public static final int ZONE_JAIL = 256;
- /** The Constant ZONE_MONSTERTRACK. */
- public static final int ZONE_MONSTERTRACK = 512;
- /** The Constant ZONE_SWAMP. */
- public static final int ZONE_SWAMP = 1024;
- /** The Constant ZONE_NOSUMMONFRIEND. */
- public static final int ZONE_NOSUMMONFRIEND = 2048;
- /** The Constant ZONE_OLY. */
- public static final int ZONE_OLY = 4096;
- /** The Constant ZONE_NOHQ. */
- public static final int ZONE_NOHQ = 8192;
- /** The Constant ZONE_DANGERAREA. */
- public static final int ZONE_DANGERAREA = 16384;
- /** The Constant ZONE_NOSTORE. */
- public static final int ZONE_NOSTORE = 32768;
- /** The _current zones. */
- private int _currentZones = 0;
- /** Advance Headquarters */
- private boolean _advanceFlag = false;
- private int _advanceMultiplier = 1;
- /**
- * Checks if is inside zone.
- * @param zone the zone
- * @return true, if is inside zone
- */
- public boolean isInsideZone(final int zone)
- {
- return (_currentZones & zone) != 0;
- }
- /**
- * Sets the inside zone.
- * @param zone the zone
- * @param state the state
- */
- public void setInsideZone(final int zone, final boolean state)
- {
- if (state)
- {
- _currentZones |= zone;
- }
- else if (isInsideZone(zone))
- {
- _currentZones ^= zone;
- }
- }
- /**
- * This will return true if the player is GM,<br>
- * but if the player is not GM it will return false.
- * @return GM status
- */
- public boolean charIsGM()
- {
- if (this instanceof L2PcInstance)
- {
- if (((L2PcInstance) this).isGM())
- {
- return true;
- }
- }
- return false;
- }
- // =========================================================
- // Constructor
- /**
- * Constructor of L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * Each L2Character owns generic and static properties (ex : all Keltir have the same number of HP...). All of those properties are stored in a different template for each type of L2Character. Each template is loaded once in the server cache memory (reduce memory use). When a new instance of
- * L2Character is spawned, server just create a link between the instance and the template This link is stored in <B>_template</B><BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Set the _template of the L2Character</li> <li>Set _overloaded to false (the charcater can take more items)</li> <BR>
- * <BR>
- * <li>If L2Character is a L2NPCInstance, copy skills from template to object</li> <li>If L2Character is a L2NPCInstance, link _calculators to NPC_STD_CALCULATOR</li><BR>
- * <BR>
- * <li>If L2Character is NOT a L2NPCInstance, create an empty _skills slot</li> <li>If L2Character is a L2PcInstance or L2Summon, copy basic Calculator set to object</li><BR>
- * <BR>
- * @param objectId Identifier of the object to initialized
- * @param template The L2CharTemplate to apply to the object
- */
- // MAKE TO US From DREAM
- // int attackcountmax = (int) Math.round(calcStat(Stats.POLE_TARGERT_COUNT, 3, null, null));
- public L2Character(final int objectId, final L2CharTemplate template)
- {
- super(objectId);
- getKnownList();
- // Set its template to the new L2Character
- _template = template;
- _triggeredSkills = new FastMap<>();
- if (template != null && this instanceof L2NpcInstance)
- {
- // Copy the Standard Calcultors of the L2NPCInstance in _calculators
- _calculators = NPC_STD_CALCULATOR;
- // Copy the skills of the L2NPCInstance from its template to the L2Character Instance
- // The skills list can be affected by spell effects so it's necessary to make a copy
- // to avoid that a spell affecting a L2NPCInstance, affects others L2NPCInstance of the same type too.
- _skills = ((L2NpcTemplate) template).getSkills();
- for (final Map.Entry<Integer, L2Skill> skill : _skills.entrySet())
- {
- addStatFuncs(skill.getValue().getStatFuncs(null, this));
- }
- if (!Config.NPC_ATTACKABLE || !(this instanceof L2Attackable) && !(this instanceof L2ControlTowerInstance) && !(this instanceof L2SiegeFlagInstance) && !(this instanceof L2EffectPointInstance))
- {
- setIsInvul(true);
- }
- }
- else
- // not L2NpcInstance
- {
- // Initialize the FastMap _skills to null
- _skills = new FastMap<Integer, L2Skill>().shared();
- // If L2Character is a L2PcInstance or a L2Summon, create the basic calculator set
- _calculators = new Calculator[Stats.NUM_STATS];
- Formulas.getInstance().addFuncsToNewCharacter(this);
- if (!(this instanceof L2Attackable) && !this.isAttackable() && !(this instanceof L2DoorInstance))
- setIsInvul(true);
- }
- /*
- * if(!(this instanceof L2PcInstance) && !(this instanceof L2MonsterInstance) && !(this instanceof L2GuardInstance) && !(this instanceof L2SiegeGuardInstance) && !(this instanceof L2ControlTowerInstance) && !(this instanceof L2DoorInstance) && !(this instanceof L2FriendlyMobInstance) &&
- * !(this instanceof L2SiegeSummonInstance) && !(this instanceof L2PetInstance) && !(this instanceof L2SummonInstance) && !(this instanceof L2SiegeFlagInstance) && !(this instanceof L2EffectPointInstance) && !(this instanceof L2CommanderInstance) && !(this instanceof
- * L2FortSiegeGuardInstance)) { ///////////////////////////////////////////////////////////////////////////////////////////// setIsInvul(true); }
- */
- }
- /**
- * Inits the char status update values.
- */
- protected void initCharStatusUpdateValues()
- {
- _hpUpdateInterval = getMaxHp() / 352.0; // MAX_HP div MAX_HP_BAR_PX
- _hpUpdateIncCheck = getMaxHp();
- _hpUpdateDecCheck = getMaxHp() - _hpUpdateInterval;
- }
- // =========================================================
- // Event - Public
- /**
- * Remove the L2Character from the world when the decay task is launched.<BR>
- * <BR>
- * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T REMOVE the object from _allObjects of L2World </B></FONT><BR>
- * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packets to players</B></FONT><BR>
- * <BR>
- */
- public void onDecay()
- {
- L2WorldRegion reg = getWorldRegion();
- if (reg != null)
- {
- reg.removeFromZones(this);
- }
- decayMe();
- reg = null;
- }
- /*
- * (non-Javadoc)
- * @see com.l2jlegacy.gameserver.model.L2Object#onSpawn()
- */
- @Override
- public void onSpawn()
- {
- super.onSpawn();
- revalidateZone();
- }
- /**
- * On teleported.
- */
- public void onTeleported()
- {
- if (!isTeleporting())
- return;
- final ObjectPosition pos = getPosition();
- if (pos != null)
- spawnMe(getPosition().getX(), getPosition().getY(), getPosition().getZ());
- setIsTeleporting(false);
- if (_isPendingRevive)
- {
- doRevive();
- }
- final L2Summon pet = getPet();
- // Modify the position of the pet if necessary
- if (pet != null && pos != null)
- {
- pet.setFollowStatus(false);
- pet.teleToLocation(pos.getX() + Rnd.get(-100, 100), pos.getY() + Rnd.get(-100, 100), pos.getZ(), false);
- pet.setFollowStatus(true);
- }
- }
- // =========================================================
- // Method - Public
- /**
- * Add L2Character instance that is attacking to the attacker list.<BR>
- * <BR>
- * @param player The L2Character that attcks this one
- */
- public void addAttackerToAttackByList(final L2Character player)
- {
- if (player == null || player == this || getAttackByList() == null || getAttackByList().contains(player))
- return;
- getAttackByList().add(player);
- }
- /**
- * Send a packet to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>. In order to inform other players of state modification on the L2Character, server just need to go through _knownPlayers to send Server->Client Packet<BR>
- * <BR>
- */
- protected byte _startingRotationCounter = 4;
- /**
- * Checks if is starting rotation allowed.
- * @return true, if is starting rotation allowed
- */
- public synchronized boolean isStartingRotationAllowed()
- {
- // This function is called too often from movement arrow
- _startingRotationCounter--;
- if (_startingRotationCounter < 0)
- _startingRotationCounter = 4;
- if (_startingRotationCounter == 4)
- {
- return true;
- }
- return false;
- }
- /**
- * Broadcast packet.
- * @param mov the mov
- */
- public final void broadcastPacket(final L2GameServerPacket mov)
- {
- if (!(mov instanceof CharInfo))
- {
- sendPacket(mov);
- }
- // don't broadcast anytime the rotating packet
- if (mov instanceof BeginRotation && !isStartingRotationAllowed())
- {
- return;
- }
- // if (Config.DEBUG) LOGGER.fine("players to notify:" + knownPlayers.size() + " packet:"+mov.getType());
- for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
- {
- if (player != null)
- {
- /*
- * TEMP FIX: If player is not visible don't send packets broadcast to all his KnowList. This will avoid GM detection with l2net and olympiad's crash. We can now find old problems with invisible mode.
- */
- if (this instanceof L2PcInstance && !player.isGM() && (((L2PcInstance) this).getAppearance().getInvisible() || ((L2PcInstance) this).inObserverMode()))
- return;
- try
- {
- player.sendPacket(mov);
- if (mov instanceof CharInfo && this instanceof L2PcInstance)
- {
- final int relation = ((L2PcInstance) this).getRelation(player);
- if (getKnownList().getKnownRelations().get(player.getObjectId()) != null && getKnownList().getKnownRelations().get(player.getObjectId()) != relation)
- {
- player.sendPacket(new RelationChanged((L2PcInstance) this, relation, player.isAutoAttackable(this)));
- }
- }
- // if(Config.DEVELOPER && !isInsideRadius(player, 3500, false, false)) LOGGER.warn("broadcastPacket: Too far player see event!");
- }
- catch (final NullPointerException e)
- {
- e.printStackTrace();
- }
- }
- }
- }
- /**
- * Send a packet to the L2Character AND to all L2PcInstance in the radius (max knownlist radius) from the L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>. In order to inform other players of state modification on the L2Character, server just need to go through _knownPlayers to send Server->Client Packet<BR>
- * <BR>
- * @param mov the mov
- * @param radiusInKnownlist the radius in knownlist
- */
- public final void broadcastPacket(final L2GameServerPacket mov, final int radiusInKnownlist)
- {
- if (!(mov instanceof CharInfo))
- {
- sendPacket(mov);
- }
- // if (Config.DEBUG) LOGGER.fine("players to notify:" + knownPlayers.size() + " packet:"+mov.getType());
- for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
- {
- try
- {
- if (!isInsideRadius(player, radiusInKnownlist, false, false))
- {
- continue;
- }
- player.sendPacket(mov);
- if (mov instanceof CharInfo && this instanceof L2PcInstance)
- {
- final int relation = ((L2PcInstance) this).getRelation(player);
- if (getKnownList().getKnownRelations().get(player.getObjectId()) != null && getKnownList().getKnownRelations().get(player.getObjectId()) != relation)
- {
- player.sendPacket(new RelationChanged((L2PcInstance) this, relation, player.isAutoAttackable(this)));
- }
- }
- }
- catch (final NullPointerException e)
- {
- e.printStackTrace();
- }
- }
- }
- /**
- * Need hp update.
- * @param barPixels the bar pixels
- * @return true if hp update should be done, false if not
- */
- protected boolean needHpUpdate(final int barPixels)
- {
- final double currentHp = getCurrentHp();
- if (currentHp <= 1.0 || getMaxHp() < barPixels)
- return true;
- if (currentHp <= _hpUpdateDecCheck || currentHp >= _hpUpdateIncCheck)
- {
- if (currentHp == getMaxHp())
- {
- _hpUpdateIncCheck = currentHp + 1;
- _hpUpdateDecCheck = currentHp - _hpUpdateInterval;
- }
- else
- {
- final double doubleMulti = currentHp / _hpUpdateInterval;
- int intMulti = (int) doubleMulti;
- _hpUpdateDecCheck = _hpUpdateInterval * (doubleMulti < intMulti ? intMulti-- : intMulti);
- _hpUpdateIncCheck = _hpUpdateDecCheck + _hpUpdateInterval;
- }
- return true;
- }
- return false;
- }
- /**
- * Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Create the Server->Client packet StatusUpdate with current HP and MP</li> <li>Send the Server->Client packet StatusUpdate with current HP and MP to all L2Character called _statusListener that must be informed of HP/MP updates of this L2Character</li><BR>
- * <BR>
- * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND CP information</B></FONT><BR>
- * <BR>
- * <B><U> Overriden in </U> :</B><BR>
- * <BR>
- * <li>L2PcInstance : Send current HP,MP and CP to the L2PcInstance and only current HP, MP and Level to all other L2PcInstance of the Party</li><BR>
- * <BR>
- */
- public void broadcastStatusUpdate()
- {
- if (getStatus().getStatusListener().isEmpty())
- return;
- if (!needHpUpdate(352))
- return;
- if (Config.DEBUG)
- {
- LOGGER.debug("Broadcast Status Update for " + getObjectId() + "(" + getName() + "). HP: " + getCurrentHp());
- }
- // Create the Server->Client packet StatusUpdate with current HP and MP
- StatusUpdate su = null;
- if (Config.FORCE_COMPLETE_STATUS_UPDATE && this instanceof L2PcInstance)
- {
- su = new StatusUpdate((L2PcInstance) this);
- }
- else
- {
- su = new StatusUpdate(getObjectId());
- su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
- su.addAttribute(StatusUpdate.CUR_MP, (int) getCurrentMp());
- }
- // Go through the StatusListener
- // Send the Server->Client packet StatusUpdate with current HP and MP
- for (final L2Character temp : getStatus().getStatusListener())
- {
- if (temp != null)
- temp.sendPacket(su);
- }
- /*
- * synchronized (getStatus().getStatusListener()) { for(L2Character temp : getStatus().getStatusListener()) { try { temp.sendPacket(su); } catch(NullPointerException e) { e.printStackTrace(); } } }
- */
- }
- /**
- * Not Implemented.<BR>
- * <BR>
- * <B><U> Overridden in </U> :</B><BR>
- * <BR>
- * <li>L2PcInstance</li><BR>
- * <BR>
- * @param mov the mov
- */
- public void sendPacket(final L2GameServerPacket mov)
- {
- // default implementation
- }
- /** The _in town war. */
- private boolean _inTownWar;
- /**
- * Checks if is in town war.
- * @return true, if is in town war
- */
- public final boolean isinTownWar()
- {
- return _inTownWar;
- }
- /**
- * Sets the in town war.
- * @param value the new in town war
- */
- public final void setInTownWar(final boolean value)
- {
- _inTownWar = value;
- }
- /*
- * public void teleToLocation(int x, int y, int z, boolean allowRandomOffset) { if(Config.TW_DISABLE_GK) { int x1,y1,z1; x1 = getX(); y1 = getY(); z1 = getZ(); L2TownZone Town; Town = TownManager.getInstance().getTown(x1,y1,z1); if(Town != null && isinTownWar() ) { if(Town.getTownId() ==
- * Config.TW_TOWN_ID && !Config.TW_ALL_TOWNS) { return; } else if(Config.TW_ALL_TOWNS) { return; } } } // Stop movement stopMove(null, false); abortAttack(); abortCast(); setIsTeleporting(true); setTarget(null); // Remove from world regions zones if(getWorldRegion() != null) {
- * getWorldRegion().removeFromZones(this); } getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE); if(Config.RESPAWN_RANDOM_ENABLED && allowRandomOffset) { x += Rnd.get(-Config.RESPAWN_RANDOM_MAX_OFFSET, Config.RESPAWN_RANDOM_MAX_OFFSET); y += Rnd.get(-Config.RESPAWN_RANDOM_MAX_OFFSET,
- * Config.RESPAWN_RANDOM_MAX_OFFSET); } //z = GeoData.getInstance().getHeight(x, y, z); z += 5; if(Config.DEBUG) { LOGGER.fine("Teleporting to: " + x + ", " + y + ", " + z); } // Send a Server->Client packet TeleportToLocationt to the L2Character AND to all L2PcInstance in the _KnownPlayers of
- * the L2Character broadcastPacket(new TeleportToLocation(this, x, y, z)); // Set the x,y,z position of the L2Object and if necessary modify its _worldRegion getPosition().setXYZ(x, y, z); decayMe(); // Set the x, y, z coords of the object, but do not update it's world region yet -
- * onTeleported() will do it getPosition().setWorldPosition(x, y, z); if(!(this instanceof L2PcInstance)) { onTeleported(); } }
- */
- /**
- * Teleport a L2Character and its pet if necessary.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Stop the movement of the L2Character</li> <li>Set the x,y,z position of the L2Object and if necessary modify its _worldRegion</li> <li>Send a Server->Client packet TeleportToLocationt to the L2Character AND to all L2PcInstance in its _KnownPlayers</li> <li>Modify the position of the pet
- * if necessary</li><BR>
- * <BR>
- * @param x the x
- * @param y the y
- * @param z the z
- * @param allowRandomOffset the allow random offset
- */
- public void teleToLocation(int x, int y, int z, final boolean allowRandomOffset)
- {
- if (Config.TW_DISABLE_GK)
- {
- int x1, y1, z1;
- x1 = getX();
- y1 = getY();
- z1 = getZ();
- L2TownZone Town;
- Town = TownManager.getInstance().getTown(x1, y1, z1);
- if (Town != null && isinTownWar())
- {
- if (Town.getTownId() == Config.TW_TOWN_ID && !Config.TW_ALL_TOWNS)
- {
- return;
- }
- else if (Config.TW_ALL_TOWNS)
- {
- return;
- }
- }
- }
- // Stop movement
- stopMove(null, false);
- abortAttack();
- abortCast();
- setIsTeleporting(true);
- setTarget(null);
- // Remove from world regions zones
- final L2WorldRegion region = getWorldRegion();
- if (region != null)
- region.removeFromZones(this);
- getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
- if (Config.RESPAWN_RANDOM_ENABLED && allowRandomOffset)
- {
- x += Rnd.get(-Config.RESPAWN_RANDOM_MAX_OFFSET, Config.RESPAWN_RANDOM_MAX_OFFSET);
- y += Rnd.get(-Config.RESPAWN_RANDOM_MAX_OFFSET, Config.RESPAWN_RANDOM_MAX_OFFSET);
- }
- z += 5;
- if (Config.DEBUG)
- LOGGER.debug("Teleporting to: " + x + ", " + y + ", " + z);
- // Send a Server->Client packet TeleportToLocationt to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character
- broadcastPacket(new TeleportToLocation(this, x, y, z));
- // remove the object from its old location
- decayMe();
- // Set the x,y,z position of the L2Object and if necessary modify its _worldRegion
- getPosition().setXYZ(x, y, z);
- // if (!(this instanceof L2PcInstance) || (((L2PcInstance)this).isOffline()))/*.getClient() != null && ((L2PcInstance)this).getClient().isDetached()))*/
- if (!(this instanceof L2PcInstance))
- onTeleported();
- revalidateZone(true);
- }
- /** The _zone validate counter. */
- protected byte _zoneValidateCounter = 4;
- /**
- * Revalidate zone.
- * @param force the force
- */
- public void revalidateZone(final boolean force)
- {
- final L2WorldRegion region = getWorldRegion();
- if (region == null)
- return;
- // This function is called too often from movement code
- if (force)
- _zoneValidateCounter = 4;
- else
- {
- _zoneValidateCounter--;
- if (_zoneValidateCounter < 0)
- _zoneValidateCounter = 4;
- else
- return;
- }
- region.revalidateZones(this);
- }
- /**
- * Tele to location.
- * @param x the x
- * @param y the y
- * @param z the z
- */
- public void teleToLocation(final int x, final int y, final int z)
- {
- teleToLocation(x, y, z, false);
- }
- /**
- * Tele to location.
- * @param loc the loc
- * @param allowRandomOffset the allow random offset
- */
- public void teleToLocation(final Location loc, final boolean allowRandomOffset)
- {
- int x = loc.getX();
- int y = loc.getY();
- int z = loc.getZ();
- if (this instanceof L2PcInstance && DimensionalRiftManager.getInstance().checkIfInRiftZone(getX(), getY(), getZ(), true))
- { // true -> ignore waiting room :)
- L2PcInstance player = (L2PcInstance) this;
- player.sendMessage("You have been sent to the waiting room.");
- if (player.isInParty() && player.getParty().isInDimensionalRift())
- {
- player.getParty().getDimensionalRift().usedTeleport(player);
- }
- final int[] newCoords = DimensionalRiftManager.getInstance().getRoom((byte) 0, (byte) 0).getTeleportCoords();
- x = newCoords[0];
- y = newCoords[1];
- z = newCoords[2];
- player = null;
- }
- teleToLocation(x, y, z, allowRandomOffset);
- }
- /**
- * Tele to location.
- * @param teleportWhere the teleport where
- */
- public void teleToLocation(final TeleportWhereType teleportWhere)
- {
- teleToLocation(MapRegionTable.getInstance().getTeleToLocation(this, teleportWhere), true);
- }
- /*
- * // Fall Damage public void Falling(int fallHeight) { if(isDead() || isFlying() || isInvul() || (this instanceof L2PcInstance && isInFunEvent())) return; final int maxHp = getMaxHp(); final int curHp = (int) getCurrentHp(); final int damage = (int) calcStat(Stats.FALL, maxHp / 1000 *
- * fallHeight, null, null); if(curHp - damage < 1) setCurrentHp(1); else setCurrentHp(curHp - damage); sendPacket(new SystemMessage(SystemMessageId.FALL_DAMAGE_S1).addNumber(damage)); //YOU_RECEIVED_S1_DAMAGE_FROM_TAKING_A_HIGH_FALL }
- */
- // =========================================================
- // Method - Private
- /**
- * Launch a physical attack against a target (Simple, Bow, Pole or Dual).<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Get the active weapon (always equiped in the right hand)</li><BR>
- * <BR>
- * <li>If weapon is a bow, check for arrows, MP and bow re-use delay (if necessary, equip the L2PcInstance with arrows in left hand)</li> <li>If weapon is a bow, consume MP and set the new period of bow non re-use</li><BR>
- * <BR>
- * <li>Get the Attack Speed of the L2Character (delay (in milliseconds) before next attack)</li> <li>Select the type of attack to start (Simple, Bow, Pole or Dual) and verify if SoulShot are charged then start calculation</li> <li>If the Server->Client packet Attack contains at least 1 hit, send
- * the Server->Client packet Attack to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character</li> <li>Notify AI with EVT_READY_TO_ACT</li><BR>
- * <BR>
- * @param target The L2Character targeted
- */
- protected void doAttack(final L2Character target)
- {
- if (Config.DEBUG)
- {
- LOGGER.debug(getName() + " doAttack: target=" + target);
- }
- if (target == null)
- return;
- // Like L2OFF wait that the hit task finish and then player can move
- if (this instanceof L2PcInstance && ((L2PcInstance) this).isMovingTaskDefined() && !((L2PcInstance) this).isAttackingNow())
- {
- final L2ItemInstance rhand = ((L2PcInstance) this).getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
- if ((rhand != null && rhand.getItemType() != L2WeaponType.BOW) || (rhand == null))
- {
- ((L2PcInstance) this).startMovingTask();
- return;
- }
- }
- if (isAlikeDead())
- {
- // If L2PcInstance is dead or the target is dead, the action is stoped
- getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (this instanceof L2NpcInstance && target.isAlikeDead())
- {
- // If L2PcInstance is dead or the target is dead, the action is stoped
- getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (this instanceof L2PcInstance && target.isDead() && !target.isFakeDeath())
- {
- // If L2PcInstance is dead or the target is dead, the action is stoped
- getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (!getKnownList().knowsObject(target))
- {
- // If L2PcInstance is dead or the target is dead, the action is stoped
- getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (this instanceof L2PcInstance && isDead())
- {
- // If L2PcInstance is dead or the target is dead, the action is stoped
- getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (target instanceof L2PcInstance && ((L2PcInstance) target).getDuelState() == Duel.DUELSTATE_DEAD)
- {
- // If L2PcInstance is dead or the target is dead, the action is stoped
- getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (target instanceof L2DoorInstance && !((L2DoorInstance) target).isAttackable(this))
- return;
- if (isAttackingDisabled())
- return;
- if (this instanceof L2PcInstance)
- {
- if (((L2PcInstance) this).inObserverMode())
- {
- sendPacket(new SystemMessage(SystemMessageId.OBSERVERS_CANNOT_PARTICIPATE));
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (target instanceof L2PcInstance)
- {
- if (((L2PcInstance) target).isCursedWeaponEquiped() && ((L2PcInstance) this).getLevel() <= Config.MAX_LEVEL_NEWBIE)
- {
- ((L2PcInstance) this).sendMessage("Can't attack a cursed player when under level 21.");
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (((L2PcInstance) this).isCursedWeaponEquiped() && ((L2PcInstance) target).getLevel() <= Config.MAX_LEVEL_NEWBIE)
- {
- ((L2PcInstance) this).sendMessage("Can't attack a newbie player using a cursed weapon.");
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- }
- // thank l2dot
- if (getObjectId() == target.getObjectId())
- {
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (target instanceof L2NpcInstance && Config.DISABLE_ATTACK_NPC_TYPE)
- {
- final String mobtype = ((L2NpcInstance) target).getTemplate().type;
- if (!Config.LIST_ALLOWED_NPC_TYPES.contains(mobtype))
- {
- final SystemMessage sm = new SystemMessage(SystemMessageId.S1_S2);
- sm.addString("Npc Type " + mobtype + " has Protection - No Attack Allowed!");
- ((L2PcInstance) this).sendPacket(sm);
- ((L2PcInstance) this).sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- }
- }
- // Get the active weapon instance (always equiped in the right hand)
- L2ItemInstance weaponInst = getActiveWeaponInstance();
- // Get the active weapon item corresponding to the active weapon instance (always equiped in the right hand)
- L2Weapon weaponItem = getActiveWeaponItem();
- if (weaponItem != null && weaponItem.getItemType() == L2WeaponType.ROD)
- {
- // You can't make an attack with a fishing pole.
- ((L2PcInstance) this).sendPacket(new SystemMessage(SystemMessageId.CANNOT_ATTACK_WITH_FISHING_POLE));
- getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- /*
- * TEMPFIX: Check client Z coordinate instead of server z to avoid exploit killing Zaken from others floor
- */
- if ((target instanceof L2GrandBossInstance) && ((L2GrandBossInstance) target).getNpcId() == 29022)
- {
- if (Math.abs(this.getClientZ() - target.getZ()) > 200)
- {
- sendPacket(new SystemMessage(SystemMessageId.CANT_SEE_TARGET));
- getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- }
- // GeoData Los Check here (or dz > 1000)
- if (!GeoData.getInstance().canSeeTarget(this, target))
- {
- sendPacket(new SystemMessage(SystemMessageId.CANT_SEE_TARGET));
- getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- // Check for a bow
- if (weaponItem != null && weaponItem.getItemType() == L2WeaponType.BOW)
- {
- // Equip arrows needed in left hand and send a Server->Client packet ItemList to the L2PcINstance then return True
- if (!checkAndEquipArrows())
- {
- // Cancel the action because the L2PcInstance have no arrow
- getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
- sendPacket(ActionFailed.STATIC_PACKET);
- sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ARROWS));
- return;
- }
- // Check for arrows and MP
- if (this instanceof L2PcInstance)
- {
- // Checking if target has moved to peace zone - only for player-bow attacks at the moment
- // Other melee is checked in movement code and for offensive spells a check is done every time
- if (target.isInsidePeaceZone((L2PcInstance) this))
- {
- getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- // Verify if the bow can be use
- if (_disableBowAttackEndTime <= GameTimeController.getGameTicks())
- {
- // Verify if L2PcInstance owns enough MP
- final int saMpConsume = (int) getStat().calcStat(Stats.MP_CONSUME, 0, null, null);
- final int mpConsume = saMpConsume == 0 ? weaponItem.getMpConsume() : saMpConsume;
- if (getCurrentMp() < mpConsume)
- {
- // If L2PcInstance doesn't have enough MP, stop the attack
- ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(CtrlEvent.EVT_READY_TO_ACT), 1000);
- sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_MP));
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- // If L2PcInstance have enough MP, the bow consummes it
- getStatus().reduceMp(mpConsume);
- // Set the period of bow non re-use
- _disableBowAttackEndTime = 5 * GameTimeController.TICKS_PER_SECOND + GameTimeController.getGameTicks();
- }
- else
- {
- // Cancel the action because the bow can't be re-use at this moment
- ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(CtrlEvent.EVT_READY_TO_ACT), 1000);
- sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- }
- else if (this instanceof L2NpcInstance)
- {
- if (_disableBowAttackEndTime > GameTimeController.getGameTicks())
- return;
- }
- }
- // Add the L2PcInstance to _knownObjects and _knownPlayer of the target
- target.getKnownList().addKnownObject(this);
- // Reduce the current CP if TIREDNESS configuration is activated
- if (Config.ALT_GAME_TIREDNESS)
- {
- setCurrentCp(getCurrentCp() - 10);
- }
- final int timeAtk = calculateTimeBetweenAttacks(target, weaponItem);
- // Recharge any active auto soulshot tasks for player (or player's summon if one exists).
- if (this instanceof L2PcInstance)
- {
- ((L2PcInstance) this).rechargeAutoSoulShot(true, false, false, timeAtk);
- }
- else if (this instanceof L2Summon)
- {
- ((L2Summon) this).getOwner().rechargeAutoSoulShot(true, false, true, timeAtk);
- }
- // Verify if soulshots are charged.
- boolean wasSSCharged;
- if (this instanceof L2Summon && !(this instanceof L2PetInstance))
- {
- wasSSCharged = ((L2Summon) this).getChargedSoulShot() != L2ItemInstance.CHARGED_NONE;
- }
- else
- {
- wasSSCharged = weaponInst != null && weaponInst.getChargedSoulshot() != L2ItemInstance.CHARGED_NONE;
- }
- // Get the Attack Speed of the L2Character (delay (in milliseconds) before next attack)
- // the hit is calculated to happen halfway to the animation - might need further tuning e.g. in bow case
- final int timeToHit = timeAtk / 2;
- _attackEndTime = GameTimeController.getGameTicks();
- _attackEndTime += (timeAtk / GameTimeController.MILLIS_IN_TICK);
- _attackEndTime -= 1;
- int ssGrade = 0;
- if (weaponItem != null)
- {
- ssGrade = weaponItem.getCrystalType();
- }
- // Create a Server->Client packet Attack
- Attack attack = new Attack(this, wasSSCharged, ssGrade);
- boolean hitted;
- // Set the Attacking Body part to CHEST
- setAttackingBodypart();
- // Heading calculation on every attack
- this.setHeading(Util.calculateHeadingFrom(this.getX(), this.getY(), target.getX(), target.getY()));
- // Get the Attack Reuse Delay of the L2Weapon
- final int reuse = calculateReuseTime(target, weaponItem);
- // Select the type of attack to start
- if (weaponItem == null)
- {
- hitted = doAttackHitSimple(attack, target, timeToHit);
- }
- else if (weaponItem.getItemType() == L2WeaponType.BOW)
- {
- hitted = doAttackHitByBow(attack, target, timeAtk, reuse);
- }
- else if (weaponItem.getItemType() == L2WeaponType.POLE)
- {
- hitted = doAttackHitByPole(attack, timeToHit);
- }
- else if (isUsingDualWeapon())
- {
- hitted = doAttackHitByDual(attack, target, timeToHit);
- }
- else
- {
- hitted = doAttackHitSimple(attack, target, timeToHit);
- }
- // Flag the attacker if it's a L2PcInstance outside a PvP area
- L2PcInstance player = null;
- if (this instanceof L2PcInstance)
- {
- player = (L2PcInstance) this;
- }
- else if (this instanceof L2Summon)
- {
- player = ((L2Summon) this).getOwner();
- }
- if (player != null)
- {
- player.updatePvPStatus(target);
- }
- // Check if hit isn't missed
- if (!hitted)
- {
- // MAJAX fix
- sendPacket(new SystemMessage(SystemMessageId.MISSED_TARGET));
- // Abort the attack of the L2Character and send Server->Client ActionFailed packet
- abortAttack();
- }
- else
- {
- /*
- * ADDED BY nexus - 2006-08-17 As soon as we know that our hit landed, we must discharge any active soulshots. This must be done so to avoid unwanted soulshot consumption.
- */
- // If we didn't miss the hit, discharge the shoulshots, if any
- if (this instanceof L2Summon && !(this instanceof L2PetInstance))
- {
- ((L2Summon) this).setChargedSoulShot(L2ItemInstance.CHARGED_NONE);
- }
- else if (weaponInst != null)
- {
- weaponInst.setChargedSoulshot(L2ItemInstance.CHARGED_NONE);
- }
- if (player != null)
- {
- if (player.isCursedWeaponEquiped())
- {
- // If hitted by a cursed weapon, Cp is reduced to 0
- if (!target.isInvul())
- {
- target.setCurrentCp(0);
- }
- }
- else if (player.isHero())
- {
- if (target instanceof L2PcInstance && ((L2PcInstance) target).isCursedWeaponEquiped())
- {
- // If a cursed weapon is hitted by a Hero, Cp is reduced to 0
- target.setCurrentCp(0);
- }
- }
- }
- weaponInst = null;
- weaponItem = null;
- }
- // If the Server->Client packet Attack contains at least 1 hit, send the Server->Client packet Attack
- // to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character
- if (attack.hasHits())
- {
- broadcastPacket(attack);
- fireEvent(EventType.ATTACK.name, new Object[]
- {
- getTarget()
- });
- }
- // Like L2OFF mobs id 27181 can teleport players near cabrio
- if (this instanceof L2MonsterInstance && ((L2MonsterInstance) this).getNpcId() == 27181)
- {
- final int rndNum = Rnd.get(100);
- final L2PcInstance gettarget = (L2PcInstance) this.getTarget();
- if (rndNum < 5 && gettarget != null)
- gettarget.teleToLocation(179768, 6364, -2734);
- }
- // Like L2OFF if target is not auto attackable you give only one hit
- if (this instanceof L2PcInstance && target instanceof L2PcInstance && !target.isAutoAttackable(this))
- {
- ((L2PcInstance) this).getAI().clientStopAutoAttack();
- ((L2PcInstance) this).getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, this);
- }
- // Notify AI with EVT_READY_TO_ACT
- ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(CtrlEvent.EVT_READY_TO_ACT), timeAtk + reuse);
- attack = null;
- player = null;
- }
- /**
- * Launch a Bow attack.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Calculate if hit is missed or not</li> <li>Consumme arrows</li> <li>If hit isn't missed, calculate if shield defense is efficient</li> <li>If hit isn't missed, calculate if hit is critical</li> <li>If hit isn't missed, calculate physical damages</li> <li>If the L2Character is a
- * L2PcInstance, Send a Server->Client packet SetupGauge</li> <li>Create a new hit task with Medium priority</li> <li>Calculate and set the disable delay of the bow in function of the Attack Speed</li> <li>Add this hit to the Server-Client packet Attack</li><BR>
- * <BR>
- * @param attack Server->Client packet Attack in which the hit will be added
- * @param target The L2Character targeted
- * @param sAtk The Attack Speed of the attacker
- * @param reuse the reuse
- * @return True if the hit isn't missed
- */
- private boolean doAttackHitByBow(final Attack attack, final L2Character target, final int sAtk, final int reuse)
- {
- int damage1 = 0;
- boolean shld1 = false;
- boolean crit1 = false;
- // Calculate if hit is missed or not
- final boolean miss1 = Formulas.calcHitMiss(this, target);
- // Consumme arrows
- reduceArrowCount();
- _move = null;
- // Check if hit isn't missed
- if (!miss1)
- {
- // Calculate if shield defense is efficient
- shld1 = Formulas.calcShldUse(this, target);
- // Calculate if hit is critical
- crit1 = Formulas.calcCrit(getStat().getCriticalHit(target, null));
- // Calculate physical damages
- damage1 = (int) Formulas.calcPhysDam(this, target, null, shld1, crit1, false, attack.soulshot);
- }
- // Check if the L2Character is a L2PcInstance
- if (this instanceof L2PcInstance)
- {
- // Send a system message
- sendPacket(new SystemMessage(SystemMessageId.GETTING_READY_TO_SHOOT_AN_ARROW));
- // Send a Server->Client packet SetupGauge
- SetupGauge sg = new SetupGauge(SetupGauge.RED, sAtk + reuse);
- sendPacket(sg);
- sg = null;
- }
- // Create a new hit task with Medium priority
- ThreadPoolManager.getInstance().scheduleAi(new HitTask(target, damage1, crit1, miss1, attack.soulshot, shld1), sAtk);
- // Calculate and set the disable delay of the bow in function of the Attack Speed
- _disableBowAttackEndTime = (sAtk + reuse) / GameTimeController.MILLIS_IN_TICK + GameTimeController.getGameTicks();
- // Add this hit to the Server-Client packet Attack
- attack.addHit(target, damage1, miss1, crit1, shld1);
- // Return true if hit isn't missed
- return !miss1;
- }
- /**
- * Launch a Dual attack.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Calculate if hits are missed or not</li> <li>If hits aren't missed, calculate if shield defense is efficient</li> <li>If hits aren't missed, calculate if hit is critical</li> <li>If hits aren't missed, calculate physical damages</li> <li>Create 2 new hit tasks with Medium priority</li>
- * <li>Add those hits to the Server-Client packet Attack</li><BR>
- * <BR>
- * @param attack Server->Client packet Attack in which the hit will be added
- * @param target The L2Character targeted
- * @param sAtk the s atk
- * @return True if hit 1 or hit 2 isn't missed
- */
- private boolean doAttackHitByDual(final Attack attack, final L2Character target, final int sAtk)
- {
- int damage1 = 0;
- int damage2 = 0;
- boolean shld1 = false;
- boolean shld2 = false;
- boolean crit1 = false;
- boolean crit2 = false;
- // Calculate if hits are missed or not
- final boolean miss1 = Formulas.calcHitMiss(this, target);
- final boolean miss2 = Formulas.calcHitMiss(this, target);
- // Check if hit 1 isn't missed
- if (!miss1)
- {
- // Calculate if shield defense is efficient against hit 1
- shld1 = Formulas.calcShldUse(this, target);
- // Calculate if hit 1 is critical
- crit1 = Formulas.calcCrit(getStat().getCriticalHit(target, null));
- // Calculate physical damages of hit 1
- damage1 = (int) Formulas.calcPhysDam(this, target, null, shld1, crit1, true, attack.soulshot);
- damage1 /= 2;
- }
- // Check if hit 2 isn't missed
- if (!miss2)
- {
- // Calculate if shield defense is efficient against hit 2
- shld2 = Formulas.calcShldUse(this, target);
- // Calculate if hit 2 is critical
- crit2 = Formulas.calcCrit(getStat().getCriticalHit(target, null));
- // Calculate physical damages of hit 2
- damage2 = (int) Formulas.calcPhysDam(this, target, null, shld2, crit2, true, attack.soulshot);
- damage2 /= 2;
- }
- // Create a new hit task with Medium priority for hit 1
- ThreadPoolManager.getInstance().scheduleAi(new HitTask(target, damage1, crit1, miss1, attack.soulshot, shld1), sAtk / 2);
- // Create a new hit task with Medium priority for hit 2 with a higher delay
- ThreadPoolManager.getInstance().scheduleAi(new HitTask(target, damage2, crit2, miss2, attack.soulshot, shld2), sAtk);
- // Add those hits to the Server-Client packet Attack
- attack.addHit(target, damage1, miss1, crit1, shld1);
- attack.addHit(target, damage2, miss2, crit2, shld2);
- // Return true if hit 1 or hit 2 isn't missed
- return !miss1 || !miss2;
- }
- /**
- * Launch a Pole attack.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Get all visible objects in a spheric area near the L2Character to obtain possible targets</li> <li>If possible target is the L2Character targeted, launch a simple attack against it</li> <li>If possible target isn't the L2Character targeted but is attakable, launch a simple attack against
- * it</li><BR>
- * <BR>
- * @param attack Server->Client packet Attack in which the hit will be added
- * @param sAtk the s atk
- * @return True if one hit isn't missed
- */
- private boolean doAttackHitByPole(final Attack attack, final int sAtk)
- {
- boolean hitted = false;
- double angleChar, angleTarget;
- final int maxRadius = (int) getStat().calcStat(Stats.POWER_ATTACK_RANGE, 66, null, null);
- final int maxAngleDiff = (int) getStat().calcStat(Stats.POWER_ATTACK_ANGLE, 120, null, null);
- if (getTarget() == null)
- return false;
- angleTarget = Util.calculateAngleFrom(this, getTarget());
- setHeading((int) (angleTarget / 9.0 * 1610.0));
- angleChar = Util.convertHeadingToDegree(getHeading());
- double attackpercent = 85;
- final int attackcountmax = (int) getStat().calcStat(Stats.ATTACK_COUNT_MAX, 3, null, null);
- int attackcount = 0;
- if (angleChar <= 0)
- angleChar += 360;
- L2Character target;
- for (final L2Object obj : getKnownList().getKnownObjects().values())
- {
- if (obj instanceof L2Character)
- {
- if (obj instanceof L2PetInstance && this instanceof L2PcInstance && ((L2PetInstance) obj).getOwner() == (L2PcInstance) this)
- {
- continue;
- }
- if (!Util.checkIfInRange(maxRadius, this, obj, false))
- {
- continue;
- }
- if (Math.abs(obj.getZ() - getZ()) > Config.DIFFERENT_Z_CHANGE_OBJECT)
- {
- continue;
- }
- angleTarget = Util.calculateAngleFrom(this, obj);
- if (Math.abs(angleChar - angleTarget) > maxAngleDiff && Math.abs(angleChar + 360 - angleTarget) > maxAngleDiff && Math.abs(angleChar - (angleTarget + 360)) > maxAngleDiff)
- {
- continue;
- }
- target = (L2Character) obj;
- if (!target.isAlikeDead())
- {
- attackcount += 1;
- if (attackcount <= attackcountmax)
- {
- if (target == getAI().getAttackTarget() || target.isAutoAttackable(this))
- {
- hitted |= doAttackHitSimple(attack, target, attackpercent, sAtk);
- attackpercent /= 1.15;
- // Flag player if the target is another player
- if (this instanceof L2PcInstance && obj instanceof L2PcInstance)
- ((L2PcInstance) this).updatePvPStatus(target);
- }
- }
- }
- }
- }
- target = null;
- // Return true if one hit isn't missed
- return hitted;
- }
- /**
- * Launch a simple attack.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Calculate if hit is missed or not</li> <li>If hit isn't missed, calculate if shield defense is efficient</li> <li>If hit isn't missed, calculate if hit is critical</li> <li>If hit isn't missed, calculate physical damages</li> <li>Create a new hit task with Medium priority</li> <li>Add
- * this hit to the Server-Client packet Attack</li><BR>
- * <BR>
- * @param attack Server->Client packet Attack in which the hit will be added
- * @param target The L2Character targeted
- * @param sAtk the s atk
- * @return True if the hit isn't missed
- */
- private boolean doAttackHitSimple(final Attack attack, final L2Character target, final int sAtk)
- {
- return doAttackHitSimple(attack, target, 100, sAtk);
- }
- /**
- * Do attack hit simple.
- * @param attack the attack
- * @param target the target
- * @param attackpercent the attackpercent
- * @param sAtk the s atk
- * @return true, if successful
- */
- private boolean doAttackHitSimple(final Attack attack, final L2Character target, final double attackpercent, final int sAtk)
- {
- int damage1 = 0;
- boolean shld1 = false;
- boolean crit1 = false;
- // Calculate if hit is missed or not
- final boolean miss1 = Formulas.calcHitMiss(this, target);
- // Check if hit isn't missed
- if (!miss1)
- {
- // Calculate if shield defense is efficient
- shld1 = Formulas.calcShldUse(this, target);
- // Calculate if hit is critical
- crit1 = Formulas.calcCrit(getStat().getCriticalHit(target, null));
- // Calculate physical damages
- damage1 = (int) Formulas.calcPhysDam(this, target, null, shld1, crit1, false, attack.soulshot);
- if (attackpercent != 100)
- {
- damage1 = (int) (damage1 * attackpercent / 100);
- }
- }
- // Create a new hit task with Medium priority
- ThreadPoolManager.getInstance().scheduleAi(new HitTask(target, damage1, crit1, miss1, attack.soulshot, shld1), sAtk);
- // Add this hit to the Server-Client packet Attack
- attack.addHit(target, damage1, miss1, crit1, shld1);
- // Return true if hit isn't missed
- return !miss1;
- }
- /**
- * Manage the casting task (casting and interrupt time, re-use delay...) and display the casting bar and animation on client.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Verify the possibilty of the the cast : skill is a spell, caster isn't muted...</li> <li>Get the list of all targets (ex : area effects) and define the L2Charcater targeted (its stats will be used in calculation)</li> <li>Calculate the casting time (base + modifier of MAtkSpd), interrupt
- * time and re-use delay</li> <li>Send a Server->Client packet MagicSkillUser (to diplay casting animation), a packet SetupGauge (to display casting bar) and a system message</li> <li>Disable all skills during the casting time (create a task EnableAllSkills)</li> <li>Disable the skill during the
- * re-use delay (create a task EnableSkill)</li> <li>Create a task MagicUseTask (that will call method onMagicUseTimer) to launch the Magic Skill at the end of the casting time</li><BR>
- * <BR>
- * @param skill The L2Skill to use
- */
- public void doCast(final L2Skill skill)
- {
- final L2Character activeChar = this;
- if (skill == null)
- {
- getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
- return;
- }
- // Check if the skill is a magic spell and if the L2Character is not muted
- if (skill.isMagic() && isMuted() && !skill.isPotion())
- {
- getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
- return;
- }
- if (this instanceof L2PcInstance)
- {
- L2PcInstance player = (L2PcInstance) this;
- if (player.getTarget() != null && player.getTarget() == player)
- if (skill.getSkillType() == SkillType.CHARGEDAM)
- {
- player.sendMessage("修理:");
- return;
- }
- }
- // Check if the skill is psychical and if the L2Character is not psychical_muted
- if (!skill.isMagic() && isPsychicalMuted() && !skill.isPotion())
- {
- getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
- return;
- }
- // Can't use Hero and resurrect skills during Olympiad
- if (activeChar instanceof L2PcInstance && ((L2PcInstance) activeChar).isInOlympiadMode() && (skill.isHeroSkill() || skill.getSkillType() == SkillType.RESURRECT))
- {
- SystemMessage sm = new SystemMessage(SystemMessageId.THIS_SKILL_IS_NOT_AVAILABLE_FOR_THE_OLYMPIAD_EVENT);
- sendPacket(sm);
- sm = null;
- return;
- }
- // Like L2OFF you can't use skills when you are attacking now
- if (activeChar instanceof L2PcInstance && !skill.isPotion())
- {
- final L2ItemInstance rhand = ((L2PcInstance) this).getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
- if ((rhand != null && rhand.getItemType() == L2WeaponType.BOW))
- {
- if (isAttackingNow())
- return;
- }
- }
- // prevent casting signets to peace zone
- if (skill.getSkillType() == SkillType.SIGNET || skill.getSkillType() == SkillType.SIGNET_CASTTIME)
- {
- /*
- * for (L2Effect effect : getAllEffects()) { if (effect.getEffectType() == L2Effect.EffectType.SIGNET_EFFECT || effect.getEffectType() == L2Effect.EffectType.SIGNET_GROUND) { SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED); sm.addSkillName(skill.getId());
- * sendPacket(sm); return; } }
- */
- final L2WorldRegion region = getWorldRegion();
- if (region == null)
- return;
- boolean canCast = true;
- if (skill.getTargetType() == SkillTargetType.TARGET_GROUND && this instanceof L2PcInstance)
- {
- final Point3D wp = ((L2PcInstance) this).getCurrentSkillWorldPosition();
- if (!region.checkEffectRangeInsidePeaceZone(skill, wp.getX(), wp.getY(), wp.getZ()))
- canCast = false;
- }
- else if (!region.checkEffectRangeInsidePeaceZone(skill, getX(), getY(), getZ()))
- canCast = false;
- if (!canCast)
- {
- final SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
- sm.addSkillName(skill.getId());
- sendPacket(sm);
- return;
- }
- }
- // Recharge AutoSoulShot
- final int atkTime = Formulas.getInstance().calcMAtkSpd(activeChar, skill, skill.getHitTime());
- if (skill.useSoulShot())
- {
- if (activeChar instanceof L2PcInstance)
- {
- ((L2PcInstance) activeChar).rechargeAutoSoulShot(true, false, false, atkTime);
- }
- else if (this instanceof L2Summon)
- {
- ((L2Summon) activeChar).getOwner().rechargeAutoSoulShot(true, false, true, atkTime);
- }
- }
- // else if (skill.useFishShot())
- // {
- // if (this instanceof L2PcInstance)
- // ((L2PcInstance)this).rechargeAutoSoulShot(true, false, false);
- // }
- // Get all possible targets of the skill in a table in function of the skill target type
- final L2Object[] targets = skill.getTargetList(activeChar);
- // Set the target of the skill in function of Skill Type and Target Type
- L2Character target = null;
- if (skill.getTargetType() == SkillTargetType.TARGET_AURA || skill.getTargetType() == SkillTargetType.TARGET_GROUND || skill.isPotion())
- {
- target = this;
- }
- else if (targets == null || targets.length == 0)
- {
- getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
- return;
- }
- else if ((skill.getSkillType() == SkillType.BUFF || skill.getSkillType() == SkillType.HEAL || skill.getSkillType() == SkillType.COMBATPOINTHEAL || skill.getSkillType() == SkillType.COMBATPOINTPERCENTHEAL || skill.getSkillType() == SkillType.MANAHEAL || skill.getSkillType() == SkillType.REFLECT || skill.getSkillType() == SkillType.SEED || skill.getTargetType() == L2Skill.SkillTargetType.TARGET_SELF || skill.getTargetType() == L2Skill.SkillTargetType.TARGET_PET || skill.getTargetType() == L2Skill.SkillTargetType.TARGET_PARTY || skill.getTargetType() == L2Skill.SkillTargetType.TARGET_CLAN || skill.getTargetType() == L2Skill.SkillTargetType.TARGET_ALLY) && !skill.isPotion())
- {
- target = (L2Character) targets[0];
- /*
- * if (this instanceof L2PcInstance && target instanceof L2PcInstance && target.getAI().getIntention() == CtrlIntention.AI_INTENTION_ATTACK) { if(skill.getSkillType() == SkillType.BUFF || skill.getSkillType() == SkillType.HOT || skill.getSkillType() == SkillType.HEAL ||
- * skill.getSkillType() == SkillType.HEAL_PERCENT || skill.getSkillType() == SkillType.MANAHEAL || skill.getSkillType() == SkillType.MANAHEAL_PERCENT || skill.getSkillType() == SkillType.BALANCE_LIFE) target.setLastBuffer(this); if (((L2PcInstance)this).isInParty() &&
- * skill.getTargetType() == L2Skill.SkillTargetType.TARGET_PARTY) { for (L2PcInstance member : ((L2PcInstance)this).getParty().getPartyMembers()) member.setLastBuffer(this); } }
- */
- }
- else
- {
- target = (L2Character) getTarget();
- }
- if (target == null)
- {
- getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
- return;
- }
- // Player can't heal rb config
- if (!Config.PLAYERS_CAN_HEAL_RB && activeChar instanceof L2PcInstance && !((L2PcInstance) activeChar).isGM() && (target instanceof L2RaidBossInstance || target instanceof L2GrandBossInstance) && (skill.getSkillType() == SkillType.HEAL || skill.getSkillType() == SkillType.HEAL_PERCENT))
- {
- this.sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- if (activeChar instanceof L2PcInstance && target instanceof L2NpcInstance && Config.DISABLE_ATTACK_NPC_TYPE)
- {
- final String mobtype = ((L2NpcInstance) target).getTemplate().type;
- if (!Config.LIST_ALLOWED_NPC_TYPES.contains(mobtype))
- {
- final SystemMessage sm = new SystemMessage(SystemMessageId.S1_S2);
- sm.addString("Npc Type " + mobtype + " has Protection - No Attack Allowed!");
- ((L2PcInstance) activeChar).sendPacket(sm);
- ((L2PcInstance) activeChar).sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- }
- if (skill.isPotion())
- setLastPotionCast(skill);
- else
- setLastSkillCast(skill);
- // Get the Identifier of the skill
- final int magicId = skill.getId();
- // Get the Display Identifier for a skill that client can't display
- final int displayId = skill.getDisplayId();
- // Get the level of the skill
- int level = skill.getLevel();
- if (level < 1)
- {
- level = 1;
- }
- // Get the casting time of the skill (base)
- int hitTime = skill.getHitTime();
- int coolTime = skill.getCoolTime();
- final boolean effectWhileCasting = skill.hasEffectWhileCasting();
- final boolean forceBuff = skill.getSkillType() == SkillType.FORCE_BUFF && target instanceof L2PcInstance;
- // Calculate the casting time of the skill (base + modifier of MAtkSpd)
- // Don't modify the skill time for FORCE_BUFF skills. The skill time for those skills represent the buff time.
- if (!effectWhileCasting && !forceBuff && !skill.isStaticHitTime())
- {
- hitTime = Formulas.getInstance().calcMAtkSpd(activeChar, skill, hitTime);
- if (coolTime > 0)
- {
- coolTime = Formulas.getInstance().calcMAtkSpd(activeChar, skill, coolTime);
- }
- }
- // Calculate altered Cast Speed due to BSpS/SpS only for Magic skills
- if ((checkBss() || checkSps()) && !skill.isStaticHitTime() && !skill.isPotion() && skill.isMagic())
- {
- // Only takes 70% of the time to cast a BSpS/SpS cast
- hitTime = (int) (0.70 * hitTime);
- coolTime = (int) (0.70 * coolTime);
- // Because the following are magic skills that do not actively 'eat' BSpS/SpS,
- // I must 'eat' them here so players don't take advantage of infinite speed increase
- /* MANAHEAL, MANARECHARGE, RESURRECT, RECALL */
- // if (skill.getSkillType() == SkillType.MANAHEAL || skill.getSkillType() == SkillType.MANARECHARGE || skill.getSkillType() == SkillType.RESURRECT || skill.getSkillType() == SkillType.RECALL)
- // {
- // if (checkBss())
- // removeBss();
- // else
- // removeSps();
- // }
- }
- /*
- * // Calculate altered Cast Speed due to BSpS/SpS L2ItemInstance weaponInst = getActiveWeaponInstance(); if(weaponInst != null && skill.isMagic() && !forceBuff && skill.getTargetType() != SkillTargetType.TARGET_SELF && !skill.isStaticHitTime() && !skill.isPotion()) {
- * if(weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_BLESSED_SPIRITSHOT || weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_SPIRITSHOT) { //Only takes 70% of the time to cast a BSpS/SpS cast hitTime = (int) (0.70 * hitTime); coolTime = (int) (0.70 * coolTime);
- * //Because the following are magic skills that do not actively 'eat' BSpS/SpS, //I must 'eat' them here so players don't take advantage of infinite speed increase if(skill.getSkillType() == SkillType.BUFF || skill.getSkillType() == SkillType.MANAHEAL || skill.getSkillType() ==
- * SkillType.RESURRECT || skill.getSkillType() == SkillType.RECALL || skill.getSkillType() == SkillType.DOT) { weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE); } } } weaponInst = null;
- */
- if (skill.isPotion())
- {
- // Set the _castEndTime and _castInterruptTim. +10 ticks for lag situations, will be reseted in onMagicFinalizer
- _castPotionEndTime = 10 + GameTimeController.getGameTicks() + (coolTime + hitTime) / GameTimeController.MILLIS_IN_TICK;
- _castPotionInterruptTime = -2 + GameTimeController.getGameTicks() + hitTime / GameTimeController.MILLIS_IN_TICK;
- }
- else
- {
- // Set the _castEndTime and _castInterruptTim. +10 ticks for lag situations, will be reseted in onMagicFinalizer
- _castEndTime = 10 + GameTimeController.getGameTicks() + (coolTime + hitTime) / GameTimeController.MILLIS_IN_TICK;
- _castInterruptTime = -2 + GameTimeController.getGameTicks() + hitTime / GameTimeController.MILLIS_IN_TICK;
- }
- // Init the reuse time of the skill
- // int reuseDelay = (int)(skill.getReuseDelay() * getStat().getMReuseRate(skill));
- // reuseDelay *= 333.0 / (skill.isMagic() ? getMAtkSpd() : getPAtkSpd());
- int reuseDelay = skill.getReuseDelay();
- if (activeChar instanceof L2PcInstance && Formulas.getInstance().calcSkillMastery(activeChar))
- {
- reuseDelay = 0;
- }
- else if (!skill.isStaticReuse() && !skill.isPotion())
- {
- if (skill.isMagic())
- {
- reuseDelay *= getStat().getMReuseRate(skill);
- }
- else
- {
- reuseDelay *= getStat().getPReuseRate(skill);
- }
- reuseDelay *= 333.0 / (skill.isMagic() ? getMAtkSpd() : getPAtkSpd());
- }
- // To turn local player in target direction
- setHeading(Util.calculateHeadingFrom(getX(), getY(), target.getX(), target.getY()));
- /*
- * if(skill.isOffensive() && skill.getTargetType() != SkillTargetType.TARGET_AURA && target.isBehind(this)) { moveToLocation(target.getX(), target.getY(), target.getZ(), 0); stopMove(null); }
- */
- // Like L2OFF after a skill the player must stop the movement, also with toggle
- if (!skill.isPotion() && this instanceof L2PcInstance)
- ((L2PcInstance) this).stopMove(null);
- // Start the effect as long as the player is casting.
- if (effectWhileCasting)
- {
- callSkill(skill, targets);
- }
- // Send a Server->Client packet MagicSkillUser with target, displayId, level, skillTime, reuseDelay
- // to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character
- broadcastPacket(new MagicSkillUser(this, target, displayId, level, hitTime, reuseDelay));
- // Send a system message USE_S1 to the L2Character
- if (activeChar instanceof L2PcInstance && magicId != 1312)
- {
- if (skill.isPotion())
- {
- SystemMessage sm = new SystemMessage(SystemMessageId.USE_S1_);
- if (magicId == 2005)
- sm.addItemName(728);
- else if (magicId == 2003)
- sm.addItemName(726);
- // Message greater cp potions like retail
- else if (magicId == 2166 && skill.getLevel() == 2)
- sm.addItemName(5592);
- // Message cp potions like retail
- else if (magicId == 2166 && skill.getLevel() == 1)
- sm.addItemName(5591);
- else
- sm.addSkillName(magicId, skill.getLevel());
- sendPacket(sm);
- sm = null;
- }
- else
- {
- SystemMessage sm = new SystemMessage(SystemMessageId.USE_S1);
- if (magicId == 2005)
- sm.addItemName(728);
- else if (magicId == 2003)
- sm.addItemName(726);
- // Message greater cp potions like retail
- else if (magicId == 2166 && skill.getLevel() == 2)
- sm.addItemName(5592);
- // Message cp potions like retail
- else if (magicId == 2166 && skill.getLevel() == 1)
- sm.addItemName(5591);
- else
- sm.addSkillName(magicId, skill.getLevel());
- // Skill 2046 is used only for animation on pets
- if (magicId != 2046)
- sendPacket(sm);
- sm = null;
- }
- }
- // Skill reuse check
- if (reuseDelay > 30000)
- {
- addTimeStamp(skill, reuseDelay);
- }
- // Check if this skill consume mp on start casting
- final int initmpcons = getStat().getMpInitialConsume(skill);
- if (initmpcons > 0)
- {
- StatusUpdate su = new StatusUpdate(getObjectId());
- if (skill.isDance())
- {
- getStatus().reduceMp(calcStat(Stats.DANCE_MP_CONSUME_RATE, initmpcons, null, null));
- }
- else if (skill.isMagic())
- {
- getStatus().reduceMp(calcStat(Stats.MAGICAL_MP_CONSUME_RATE, initmpcons, null, null));
- }
- else
- {
- getStatus().reduceMp(calcStat(Stats.PHYSICAL_MP_CONSUME_RATE, initmpcons, null, null));
- }
- su.addAttribute(StatusUpdate.CUR_MP, (int) getCurrentMp());
- sendPacket(su);
- su = null;
- }
- // Disable the skill during the re-use delay and create a task EnableSkill with Medium priority to enable it at the end of the re-use delay
- if (reuseDelay > 10)
- {
- disableSkill(skill, reuseDelay);
- }
- // For force buff skills, start the effect as long as the player is casting.
- if (forceBuff)
- {
- startForceBuff(target, skill);
- }
- // launch the magic in hitTime milliseconds
- if (hitTime > 210)
- {
- // Send a Server->Client packet SetupGauge with the color of the gauge and the casting time
- if (activeChar instanceof L2PcInstance && !forceBuff)
- {
- SetupGauge sg = new SetupGauge(SetupGauge.BLUE, hitTime);
- sendPacket(sg);
- sg = null;
- }
- // Disable all skills during the casting
- if (!skill.isPotion())
- { // for particular potion is the timestamp to disable particular skill
- disableAllSkills();
- if (_skillCast != null) // delete previous skill cast
- {
- _skillCast.cancel(true);
- _skillCast = null;
- }
- }
- // Create a task MagicUseTask to launch the MagicSkill at the end of the casting time (hitTime)
- // For client animation reasons (party buffs especially) 200 ms before!
- if (getForceBuff() != null || effectWhileCasting)
- {
- if (skill.isPotion())
- _potionCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 2), hitTime);
- else
- _skillCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 2), hitTime);
- }
- else
- {
- if (skill.isPotion())
- _potionCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 1), hitTime - 200);
- else
- _skillCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 1), hitTime - 200);
- }
- }
- else
- {
- onMagicLaunchedTimer(targets, skill, coolTime, true);
- }
- fireEvent(EventType.CAST.name, new Object[]
- {
- skill,
- target,
- targets
- });
- }
- /**
- * Index according to skill id the current timestamp of use.<br>
- * @param skill the s
- * @param r the r
- */
- public void addTimeStamp(final L2Skill skill, final int r)
- {
- }
- /**
- * Index according to skill id the current timestamp of use.<br>
- * @param _skill the s
- */
- public void removeTimeStamp(final L2Skill _skill)
- {
- }
- /**
- * Starts a force buff on target.<br>
- * @param target the target
- * @param skill the skill
- */
- public void startForceBuff(final L2Character target, final L2Skill skill)
- {
- if (skill.getSkillType() != SkillType.FORCE_BUFF)
- return;
- if (_forceBuff == null)
- {
- _forceBuff = new ForceBuff(this, target, skill);
- }
- }
- /**
- * Kill the L2Character.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Set target to null and cancel Attack or Cast</li> <li>Stop movement</li> <li>Stop HP/MP/CP Regeneration task</li> <li>Stop all active skills effects in progress on the L2Character</li> <li>Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to
- * inform</li> <li>Notify L2Character AI</li><BR>
- * <BR>
- * <B><U> Overriden in </U> :</B><BR>
- * <BR>
- * <li>L2NpcInstance : Create a DecayTask to remove the corpse of the L2NpcInstance after 7 seconds</li> <li>L2Attackable : Distribute rewards (EXP, SP, Drops...) and notify Quest Engine</li> <li>L2PcInstance : Apply Death Penalty, Manage gain/loss Karma and Item Drop</li><BR>
- * <BR>
- * @param killer The L2Character who killed it
- * @return true, if successful
- */
- public boolean doDie(final L2Character killer)
- {
- // killing is only possible one time
- synchronized (this)
- {
- if (isKilledAlready())
- return false;
- setIsKilledAlready(true);
- }
- // Set target to null and cancel Attack or Cast
- setTarget(null);
- // Stop fear to avoid possible bug with char position after death
- if (isAfraid())
- stopFear(null);
- // Stop movement
- stopMove(null);
- // Stop HP/MP/CP Regeneration task
- getStatus().stopHpMpRegeneration();
- // Stop all active skills effects in progress on the L2Character,
- // if the Character isn't affected by Soul of The Phoenix or Salvation
- if (this instanceof L2PlayableInstance && ((L2PlayableInstance) this).isPhoenixBlessed())
- {
- if (((L2PlayableInstance) this).isNoblesseBlessed())
- {
- ((L2PlayableInstance) this).stopNoblesseBlessing(null);
- }
- if (((L2PlayableInstance) this).getCharmOfLuck())
- {
- ((L2PlayableInstance) this).stopCharmOfLuck(null);
- }
- }
- // Same thing if the Character isn't a Noblesse Blessed L2PlayableInstance
- else if (this instanceof L2PlayableInstance && ((L2PlayableInstance) this).isNoblesseBlessed())
- {
- ((L2PlayableInstance) this).stopNoblesseBlessing(null);
- if (((L2PlayableInstance) this).getCharmOfLuck())
- {
- ((L2PlayableInstance) this).stopCharmOfLuck(null);
- }
- }
- else
- {
- if (this instanceof L2PcInstance)
- {
- final L2PcInstance player = (L2PcInstance) this;
- // to avoid Event Remove buffs on die
- if (player._inEventDM && DM.is_started())
- {
- if (Config.DM_REMOVE_BUFFS_ON_DIE)
- stopAllEffects();
- }
- else if (player._inEventTvT && TvT.is_started())
- {
- if (Config.TVT_REMOVE_BUFFS_ON_DIE)
- stopAllEffects();
- }
- else if (player._inEventCTF && CTF.is_started())
- {
- if (Config.CTF_REMOVE_BUFFS_ON_DIE)
- stopAllEffects();
- }
- else if (Config.LEAVE_BUFFS_ON_DIE) // this means that the player is not in event
- {
- stopAllEffects();
- }
- }
- else
- // this means all other characters, including Summons
- {
- stopAllEffects();
- }
- }
- // if killer is the same then the most damager/hated
- L2Character mostHated = null;
- if (this instanceof L2Attackable)
- {
- mostHated = ((L2Attackable) this)._mostHated;
- }
- if (mostHated != null && isInsideRadius(mostHated, 200, false, false))
- {
- calculateRewards(mostHated);
- }
- else
- {
- calculateRewards(killer);
- }
- // Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform
- broadcastStatusUpdate();
- // Notify L2Character AI
- getAI().notifyEvent(CtrlEvent.EVT_DEAD, null);
- if (getWorldRegion() != null)
- {
- getWorldRegion().onDeath(this);
- }
- // Notify Quest of character's death
- for (final QuestState qs : getNotifyQuestOfDeath())
- {
- qs.getQuest().notifyDeath((killer == null ? this : killer), this, qs);
- }
- getNotifyQuestOfDeath().clear();
- getAttackByList().clear();
- // If character is PhoenixBlessed a resurrection popup will show up
- if (this instanceof L2PlayableInstance && ((L2PlayableInstance) this).isPhoenixBlessed())
- {
- ((L2PcInstance) this).reviveRequest(((L2PcInstance) this), null, false);
- }
- fireEvent(EventType.DIE.name, new Object[]
- {
- killer
- });
- // Update active skills in progress (In Use and Not In Use because stacked) icones on client
- updateEffectIcons();
- // After dead mob check if the killer got a moving task actived
- if (killer instanceof L2PcInstance)
- {
- if (((L2PcInstance) killer).isMovingTaskDefined())
- {
- ((L2PcInstance) killer).startMovingTask();
- }
- }
- return true;
- }
- /**
- * Calculate rewards.
- * @param killer the killer
- */
- protected void calculateRewards(final L2Character killer)
- {
- }
- /** Sets HP, MP and CP and revives the L2Character. */
- public void doRevive()
- {
- if (!isTeleporting())
- {
- setIsPendingRevive(false);
- if (this instanceof L2PlayableInstance && ((L2PlayableInstance) this).isPhoenixBlessed())
- {
- ((L2PlayableInstance) this).stopPhoenixBlessing(null);
- // Like L2OFF Soul of The Phoenix and Salvation restore all hp,cp,mp.
- _status.setCurrentCp(getMaxCp());
- _status.setCurrentHp(getMaxHp());
- _status.setCurrentMp(getMaxMp());
- }
- else
- {
- _status.setCurrentCp(getMaxCp() * Config.RESPAWN_RESTORE_CP);
- _status.setCurrentHp(getMaxHp() * Config.RESPAWN_RESTORE_HP);
- }
- }
- // Start broadcast status
- broadcastPacket(new Revive(this));
- if (getWorldRegion() != null)
- {
- getWorldRegion().onRevive(this);
- }
- else
- {
- setIsPendingRevive(true);
- }
- fireEvent(EventType.REVIVE.name, (Object[]) null);
- }
- /**
- * Revives the L2Character using skill.
- * @param revivePower the revive power
- */
- public void doRevive(final double revivePower)
- {
- doRevive();
- }
- /**
- * Check if the active L2Skill can be casted.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Check if the L2Character can cast (ex : not sleeping...)</li> <li>Check if the target is correct</li> <li>Notify the AI with AI_INTENTION_CAST and target</li><BR>
- * <BR>
- * @param skill The L2Skill to use
- */
- protected void useMagic(final L2Skill skill)
- {
- if (skill == null || isDead())
- return;
- // Check if the L2Character can cast
- if (!skill.isPotion() && isAllSkillsDisabled())
- // must be checked by caller
- return;
- // Ignore the passive skill request. why does the client send it anyway ??
- if (skill.isPassive() || skill.isChance())
- return;
- // Get the target for the skill
- L2Object target = null;
- switch (skill.getTargetType())
- {
- case TARGET_AURA: // AURA, SELF should be cast even if no target has been found
- case TARGET_SELF:
- target = this;
- break;
- default:
- // Get the first target of the list
- target = skill.getFirstOfTargetList(this);
- break;
- }
- // Notify the AI with AI_INTENTION_CAST and target
- getAI().setIntention(CtrlIntention.AI_INTENTION_CAST, skill, target);
- target = null;
- }
- // =========================================================
- // Property - Public
- /**
- * Return the L2CharacterAI of the L2Character and if its null create a new one.
- * @return the aI
- */
- public L2CharacterAI getAI()
- {
- if (_ai == null)
- {
- synchronized (this)
- {
- if (_ai == null)
- {
- _ai = new L2CharacterAI(new AIAccessor());
- }
- }
- }
- return _ai;
- }
- /**
- * Sets the aI.
- * @param newAI the new aI
- */
- public void setAI(final L2CharacterAI newAI)
- {
- L2CharacterAI oldAI = getAI();
- if (oldAI != null && oldAI != newAI && oldAI instanceof L2AttackableAI)
- {
- ((L2AttackableAI) oldAI).stopAITask();
- }
- _ai = newAI;
- oldAI = null;
- }
- /**
- * Return True if the L2Character has a L2CharacterAI.
- * @return true, if successful
- */
- public boolean hasAI()
- {
- return _ai != null;
- }
- /**
- * Return True if the L2Character is RaidBoss or his minion.
- * @return true, if is raid
- */
- @Override
- public boolean isRaid()
- {
- return false;
- }
- /**
- * Return True if the L2Character is an Npc.
- * @return true, if is npc
- */
- @Override
- public boolean isNpc()
- {
- return false;
- }
- /**
- * Return a list of L2Character that attacked.
- * @return the attack by list
- */
- public final List<L2Character> getAttackByList()
- {
- if (_attackByList == null)
- {
- _attackByList = new FastList<>();
- }
- return _attackByList;
- }
- /**
- * Gets the last skill cast.
- * @return the last skill cast
- */
- public final L2Skill getLastSkillCast()
- {
- return _lastSkillCast;
- }
- /**
- * Sets the last skill cast.
- * @param skill the new last skill cast
- */
- public void setLastSkillCast(final L2Skill skill)
- {
- _lastSkillCast = skill;
- }
- /**
- * Gets the last potion cast.
- * @return the last potion cast
- */
- public final L2Skill getLastPotionCast()
- {
- return _lastPotionCast;
- }
- /**
- * Sets the last potion cast.
- * @param skill the new last potion cast
- */
- public void setLastPotionCast(final L2Skill skill)
- {
- _lastPotionCast = skill;
- }
- /**
- * Checks if is afraid.
- * @return true, if is afraid
- */
- public final boolean isAfraid()
- {
- return _isAfraid;
- }
- /**
- * Sets the checks if is afraid.
- * @param value the new checks if is afraid
- */
- public final void setIsAfraid(final boolean value)
- {
- _isAfraid = value;
- }
- /**
- * Return True if the L2Character is dead or use fake death.
- * @return true, if is alike dead
- */
- public final boolean isAlikeDead()
- {
- return isFakeDeath() || !(getCurrentHp() > 0.01);
- }
- /**
- * Return True if the L2Character can't use its skills (ex : stun, sleep...).
- * @return true, if is all skills disabled
- */
- public final boolean isAllSkillsDisabled()
- {
- return _allSkillsDisabled || isImmobileUntilAttacked() || isStunned() || isSleeping() || isParalyzed();
- }
- /**
- * Return True if the L2Character can't attack (stun, sleep, attackEndTime, fakeDeath, paralyse).
- * @return true, if is attacking disabled
- */
- public boolean isAttackingDisabled()
- {
- return isImmobileUntilAttacked() || isStunned() || isSleeping() || isFallsdown() || _attackEndTime > GameTimeController.getGameTicks() || isFakeDeath() || isParalyzed() || isAttackDisabled();
- }
- /**
- * Gets the calculators.
- * @return the calculators
- */
- public final Calculator[] getCalculators()
- {
- return _calculators;
- }
- /**
- * Checks if is confused.
- * @return true, if is confused
- */
- public final boolean isConfused()
- {
- return _isConfused;
- }
- /**
- * Sets the checks if is confused.
- * @param value the new checks if is confused
- */
- public final void setIsConfused(final boolean value)
- {
- _isConfused = value;
- }
- /**
- * Return True if the L2Character is dead.
- * @return true, if is dead
- */
- public final boolean isDead()
- {
- return !isFakeDeath() && (getCurrentHp() < 0.5);
- }
- /**
- * Checks if is fake death.
- * @return true, if is fake death
- */
- public final boolean isFakeDeath()
- {
- return _isFakeDeath;
- }
- /**
- * Sets the checks if is fake death.
- * @param value the new checks if is fake death
- */
- public final void setIsFakeDeath(final boolean value)
- {
- _isFakeDeath = value;
- }
- /**
- * Return True if the L2Character is flying.
- * @return true, if is flying
- */
- public final boolean isFlying()
- {
- return _isFlying;
- }
- /**
- * Set the L2Character flying mode to True.
- * @param mode the new checks if is flying
- */
- public final void setIsFlying(final boolean mode)
- {
- _isFlying = mode;
- }
- /**
- * Checks if is fallsdown.
- * @return true, if is fallsdown
- */
- public final boolean isFallsdown()
- {
- return _isFallsdown;
- }
- /**
- * Sets the checks if is fallsdown.
- * @param value the new checks if is fallsdown
- */
- public final void setIsFallsdown(final boolean value)
- {
- _isFallsdown = value;
- }
- /**
- * Checks if is imobilised.
- * @return true, if is imobilised
- */
- public boolean isImobilised()
- {
- return _isImmobilized > 0;
- }
- /**
- * Sets the checks if is imobilised.
- * @param value the new checks if is imobilised
- */
- public void setIsImobilised(final boolean value)
- {
- // Stop this if he is moving
- this.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
- if (value)
- {
- _isImmobilized++;
- }
- else
- {
- _isImmobilized--;
- }
- }
- /**
- * Checks if is block buff.
- * @return the _isBlockBuff
- */
- public boolean isBlockBuff()
- {
- return _isBlockBuff;
- }
- /**
- * Sets the block buff.
- * @param blockBuff the _isBlockBuff to set
- */
- public void setBlockBuff(final boolean blockBuff)
- {
- _isBlockBuff = blockBuff;
- }
- /**
- * Checks if is block debuff.
- * @return the _isBlockDebuff
- */
- public boolean isBlockDebuff()
- {
- return _isBlockDebuff;
- }
- /**
- * Sets the block debuff.
- * @param blockDebuff the _isBlockDebuff to set
- */
- public void setBlockDebuff(final boolean blockDebuff)
- {
- _isBlockDebuff = blockDebuff;
- }
- /**
- * Checks if is killed already.
- * @return true, if is killed already
- */
- public final boolean isKilledAlready()
- {
- return _isKilledAlready;
- }
- /**
- * Sets the checks if is killed already.
- * @param value the new checks if is killed already
- */
- public final void setIsKilledAlready(final boolean value)
- {
- _isKilledAlready = value;
- }
- /**
- * Checks if is muted.
- * @return true, if is muted
- */
- public final boolean isMuted()
- {
- return _isMuted;
- }
- /**
- * Sets the checks if is muted.
- * @param value the new checks if is muted
- */
- public final void setIsMuted(final boolean value)
- {
- _isMuted = value;
- }
- /**
- * Checks if is psychical muted.
- * @return true, if is psychical muted
- */
- public final boolean isPsychicalMuted()
- {
- return _isPsychicalMuted;
- }
- /**
- * Sets the checks if is psychical muted.
- * @param value the new checks if is psychical muted
- */
- public final void setIsPsychicalMuted(final boolean value)
- {
- _isPsychicalMuted = value;
- }
- /**
- * Return True if the L2Character can't move (stun, root, sleep, overload, paralyzed).
- * @return true, if is movement disabled
- */
- public boolean isMovementDisabled()
- {
- return isImmobileUntilAttacked() || isStunned() || isRooted() || isSleeping() || isOverloaded() || isParalyzed() || isImobilised() || isFakeDeath() || isFallsdown();
- }
- /**
- * Return True if the L2Character can be controlled by the player (confused, afraid).
- * @return true, if is out of control
- */
- public final boolean isOutOfControl()
- {
- return isConfused() || isAfraid() || isBlocked();
- }
- /**
- * Checks if is overloaded.
- * @return true, if is overloaded
- */
- public final boolean isOverloaded()
- {
- return _isOverloaded;
- }
- /**
- * Set the overloaded status of the L2Character is overloaded (if True, the L2PcInstance can't take more item).
- * @param value the new checks if is overloaded
- */
- public final void setIsOverloaded(final boolean value)
- {
- _isOverloaded = value;
- }
- /**
- * Checks if is paralyzed.
- * @return true, if is paralyzed
- */
- public final boolean isParalyzed()
- {
- return _isParalyzed;
- }
- /**
- * Sets the checks if is paralyzed.
- * @param value the new checks if is paralyzed
- */
- public final void setIsParalyzed(final boolean value)
- {
- if (_petrified)
- return;
- _isParalyzed = value;
- }
- /**
- * Checks if is pending revive.
- * @return true, if is pending revive
- */
- public final boolean isPendingRevive()
- {
- return isDead() && _isPendingRevive;
- }
- /**
- * Sets the checks if is pending revive.
- * @param value the new checks if is pending revive
- */
- public final void setIsPendingRevive(final boolean value)
- {
- _isPendingRevive = value;
- }
- /**
- * Return the L2Summon of the L2Character.<BR>
- * <BR>
- * <B><U> Overriden in </U> :</B><BR>
- * <BR>
- * <li>L2PcInstance</li><BR>
- * <BR>
- * @return the pet
- */
- public L2Summon getPet()
- {
- return null;
- }
- /**
- * Return True if the L2Character is ridding.
- * @return true, if is riding
- */
- public final boolean isRiding()
- {
- return _isRiding;
- }
- /**
- * Set the L2Character riding mode to True.
- * @param mode the new checks if is riding
- */
- public final void setIsRiding(final boolean mode)
- {
- _isRiding = mode;
- }
- /**
- * Checks if is rooted.
- * @return true, if is rooted
- */
- public final boolean isRooted()
- {
- return _isRooted;
- }
- /**
- * Sets the checks if is rooted.
- * @param value the new checks if is rooted
- */
- public final void setIsRooted(final boolean value)
- {
- _isRooted = value;
- }
- /**
- * Return True if the L2Character is running.
- * @return true, if is running
- */
- public final boolean isRunning()
- {
- return _isRunning;
- }
- /**
- * Sets the checks if is running.
- * @param value the new checks if is running
- */
- public final void setIsRunning(final boolean value)
- {
- _isRunning = value;
- broadcastPacket(new ChangeMoveType(this));
- }
- /**
- * Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance.
- */
- public final void setRunning()
- {
- if (!isRunning())
- {
- setIsRunning(true);
- }
- }
- /**
- * Checks if is immobile until attacked.
- * @return true, if is immobile until attacked
- */
- public final boolean isImmobileUntilAttacked()
- {
- return _isImmobileUntilAttacked;
- }
- /**
- * Sets the checks if is immobile until attacked.
- * @param value the new checks if is immobile until attacked
- */
- public final void setIsImmobileUntilAttacked(final boolean value)
- {
- _isImmobileUntilAttacked = value;
- }
- /**
- * Checks if is sleeping.
- * @return true, if is sleeping
- */
- public final boolean isSleeping()
- {
- return _isSleeping;
- }
- /**
- * Sets the checks if is sleeping.
- * @param value the new checks if is sleeping
- */
- public final void setIsSleeping(final boolean value)
- {
- _isSleeping = value;
- }
- /**
- * Checks if is stunned.
- * @return true, if is stunned
- */
- public final boolean isStunned()
- {
- return _isStunned;
- }
- /**
- * Sets the checks if is stunned.
- * @param value the new checks if is stunned
- */
- public final void setIsStunned(final boolean value)
- {
- _isStunned = value;
- }
- /**
- * Checks if is betrayed.
- * @return true, if is betrayed
- */
- public final boolean isBetrayed()
- {
- return _isBetrayed;
- }
- /**
- * Sets the checks if is betrayed.
- * @param value the new checks if is betrayed
- */
- public final void setIsBetrayed(final boolean value)
- {
- _isBetrayed = value;
- }
- /**
- * Checks if is teleporting.
- * @return true, if is teleporting
- */
- public final boolean isTeleporting()
- {
- return _isTeleporting;
- }
- /**
- * Sets the checks if is teleporting.
- * @param value the new checks if is teleporting
- */
- public void setIsTeleporting(final boolean value)
- {
- _isTeleporting = value;
- }
- /**
- * Sets the checks if is invul.
- * @param b the new checks if is invul
- */
- public void setIsInvul(final boolean b)
- {
- if (_petrified)
- return;
- _isInvul = b;
- }
- /**
- * Checks if is invul.
- * @return true, if is invul
- */
- public boolean isInvul()
- {
- return _isInvul || _isTeleporting;
- }
- /**
- * Checks if is undead.
- * @return true, if is undead
- */
- public boolean isUndead()
- {
- return _template.isUndead;
- }
- /*
- * (non-Javadoc)
- * @see com.l2jlegacy.gameserver.model.L2Object#getKnownList()
- */
- @Override
- public CharKnownList getKnownList()
- {
- if (super.getKnownList() == null || !(super.getKnownList() instanceof CharKnownList))
- {
- setKnownList(new CharKnownList(this));
- }
- return (CharKnownList) super.getKnownList();
- }
- /**
- * Gets the stat.
- * @return the stat
- */
- public CharStat getStat()
- {
- if (_stat == null)
- {
- _stat = new CharStat(this);
- }
- return _stat;
- }
- /**
- * Sets the stat.
- * @param value the new stat
- */
- public final void setStat(final CharStat value)
- {
- _stat = value;
- }
- /**
- * Gets the status.
- * @return the status
- */
- public CharStatus getStatus()
- {
- if (_status == null)
- {
- _status = new CharStatus(this);
- }
- return _status;
- }
- /**
- * Sets the status.
- * @param value the new status
- */
- public final void setStatus(final CharStatus value)
- {
- _status = value;
- }
- /**
- * Gets the template.
- * @return the template
- */
- public L2CharTemplate getTemplate()
- {
- return _template;
- }
- /**
- * Set the template of the L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * Each L2Character owns generic and static properties (ex : all Keltir have the same number of HP...). All of those properties are stored in a different template for each type of L2Character. Each template is loaded once in the server cache memory (reduce memory use). When a new instance of
- * L2Character is spawned, server just create a link between the instance and the template This link is stored in <B>_template</B><BR>
- * <BR>
- * <B><U> Assert </U> :</B><BR>
- * <BR>
- * <li>this instanceof L2Character</li><BR>
- * <BR
- * @param template the new template
- */
- protected synchronized final void setTemplate(final L2CharTemplate template)
- {
- _template = template;
- }
- /**
- * Return the Title of the L2Character.
- * @return the title
- */
- public final String getTitle()
- {
- if (_title == null)
- return "";
- return _title;
- }
- /**
- * Set the Title of the L2Character.
- * @param value the new title
- */
- public final void setTitle(String value)
- {
- if (value == null)
- value = "";
- if (this instanceof L2PcInstance && value.length() > 16)
- {
- value = value.substring(0, 15);
- }
- _title = value; // public final void setTitle(String value) { _title = value; }
- }
- /**
- * Set the L2Character movement type to walk and send Server->Client packet ChangeMoveType to all others L2PcInstance.
- */
- public final void setWalking()
- {
- if (isRunning())
- {
- setIsRunning(false);
- }
- }
- /**
- * Task lauching the function enableSkill().
- */
- class EnableSkill implements Runnable
- {
- /** The _skill id. */
- L2Skill _skillId;
- /**
- * Instantiates a new enable skill.
- * @param skill the skill
- */
- public EnableSkill(final L2Skill skill)
- {
- _skillId = skill;
- }
- /*
- * (non-Javadoc)
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run()
- {
- try
- {
- enableSkill(_skillId);
- }
- catch (final Throwable e)
- {
- LOGGER.error("", e);
- }
- }
- }
- /**
- * Task lauching the function onHitTimer().<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>If the attacker/target is dead or use fake death, notify the AI with EVT_CANCEL and send a Server->Client packet ActionFailed (if attacker is a L2PcInstance)</li> <li>If attack isn't aborted, send a message system (critical hit, missed...) to attacker/target if they are L2PcInstance</li>
- * <li>If attack isn't aborted and hit isn't missed, reduce HP of the target and calculate reflection damage to reduce HP of attacker if necessary</li> <li>if attack isn't aborted and hit isn't missed, manage attack or cast break of the target (calculating rate, sending message...)</li><BR>
- * <BR>
- */
- class HitTask implements Runnable
- {
- /** The _hit target. */
- L2Character _hitTarget;
- /** The _damage. */
- int _damage;
- /** The _crit. */
- boolean _crit;
- /** The _miss. */
- boolean _miss;
- /** The _shld. */
- boolean _shld;
- /** The _soulshot. */
- boolean _soulshot;
- /**
- * Instantiates a new hit task.
- * @param target the target
- * @param damage the damage
- * @param crit the crit
- * @param miss the miss
- * @param soulshot the soulshot
- * @param shld the shld
- */
- public HitTask(final L2Character target, final int damage, final boolean crit, final boolean miss, final boolean soulshot, final boolean shld)
- {
- _hitTarget = target;
- _damage = damage;
- _crit = crit;
- _shld = shld;
- _miss = miss;
- _soulshot = soulshot;
- }
- /*
- * (non-Javadoc)
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run()
- {
- try
- {
- onHitTimer(_hitTarget, _damage, _crit, _miss, _soulshot, _shld);
- }
- catch (final Throwable e)
- {
- LOGGER.error("fixme:hit task unhandled exception", e);
- }
- }
- }
- /**
- * Task lauching the magic skill phases.
- */
- class MagicUseTask implements Runnable
- {
- /** The _targets. */
- L2Object[] _targets;
- /** The _skill. */
- L2Skill _skill;
- /** The _cool time. */
- int _coolTime;
- /** The _phase. */
- int _phase;
- /**
- * Instantiates a new magic use task.
- * @param targets the targets
- * @param skill the skill
- * @param coolTime the cool time
- * @param phase the phase
- */
- public MagicUseTask(final L2Object[] targets, final L2Skill skill, final int coolTime, final int phase)
- {
- _targets = targets;
- _skill = skill;
- _coolTime = coolTime;
- _phase = phase;
- }
- /*
- * (non-Javadoc)
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run()
- {
- try
- {
- switch (_phase)
- {
- case 1:
- onMagicLaunchedTimer(_targets, _skill, _coolTime, false);
- break;
- case 2:
- onMagicHitTimer(_targets, _skill, _coolTime, false);
- break;
- case 3:
- onMagicFinalizer(_targets, _skill);
- break;
- default:
- break;
- }
- }
- catch (final Throwable e)
- {
- LOGGER.error("", e);
- e.printStackTrace();
- enableAllSkills();
- }
- }
- }
- /**
- * Task lauching the function useMagic().
- */
- class QueuedMagicUseTask implements Runnable
- {
- /** The _curr player. */
- L2PcInstance _currPlayer;
- /** The _queued skill. */
- L2Skill _queuedSkill;
- /** The _is ctrl pressed. */
- boolean _isCtrlPressed;
- /** The _is shift pressed. */
- boolean _isShiftPressed;
- /**
- * Instantiates a new queued magic use task.
- * @param currPlayer the curr player
- * @param queuedSkill the queued skill
- * @param isCtrlPressed the is ctrl pressed
- * @param isShiftPressed the is shift pressed
- */
- public QueuedMagicUseTask(final L2PcInstance currPlayer, final L2Skill queuedSkill, final boolean isCtrlPressed, final boolean isShiftPressed)
- {
- _currPlayer = currPlayer;
- _queuedSkill = queuedSkill;
- _isCtrlPressed = isCtrlPressed;
- _isShiftPressed = isShiftPressed;
- }
- /*
- * (non-Javadoc)
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run()
- {
- try
- {
- _currPlayer.useMagic(_queuedSkill, _isCtrlPressed, _isShiftPressed);
- }
- catch (final Throwable e)
- {
- LOGGER.error("", e);
- }
- }
- }
- /**
- * Task of AI notification.
- */
- public class NotifyAITask implements Runnable
- {
- /** The _evt. */
- private final CtrlEvent _evt;
- /**
- * Instantiates a new notify ai task.
- * @param evt the evt
- */
- NotifyAITask(final CtrlEvent evt)
- {
- _evt = evt;
- }
- /*
- * (non-Javadoc)
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run()
- {
- try
- {
- getAI().notifyEvent(_evt, null);
- }
- catch (final Throwable t)
- {
- LOGGER.warn("", t);
- }
- }
- }
- /**
- * Task lauching the function stopPvPFlag().
- */
- class PvPFlag implements Runnable
- {
- /**
- * Instantiates a new pvp flag.
- */
- public PvPFlag()
- {
- // null
- }
- /*
- * (non-Javadoc)
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run()
- {
- try
- {
- // LOGGER.fine("Checking pvp time: " + getlastPvpAttack());
- // "lastattack: " _lastAttackTime "currenttime: "
- // System.currentTimeMillis());
- if (System.currentTimeMillis() > getPvpFlagLasts())
- {
- // LOGGER.fine("Stopping PvP");
- stopPvPFlag();
- }
- else if (System.currentTimeMillis() > getPvpFlagLasts() - 5000)
- {
- updatePvPFlag(2);
- }
- else
- {
- updatePvPFlag(1);
- // Start a new PvP timer check
- // checkPvPFlag();
- }
- }
- catch (final Exception e)
- {
- LOGGER.warn("error in pvp flag task:", e);
- }
- }
- }
- // =========================================================
- // =========================================================
- // Abnormal Effect - NEED TO REMOVE ONCE L2CHARABNORMALEFFECT IS COMPLETE
- // Data Field
- /** Map 32 bits (0x0000) containing all abnormal effect in progress. */
- private int _AbnormalEffects;
- /**
- * FastTable containing all active skills effects in progress of a L2Character.
- */
- private final FastTable<L2Effect> _effects = new FastTable<>();
- /** The table containing the List of all stacked effect in progress for each Stack group Identifier. */
- protected Map<String, List<L2Effect>> _stackedEffects = new FastMap<>();
- /** The Constant ABNORMAL_EFFECT_BLEEDING. */
- public static final int ABNORMAL_EFFECT_BLEEDING = 0x000001;
- /** The Constant ABNORMAL_EFFECT_POISON. */
- public static final int ABNORMAL_EFFECT_POISON = 0x000002;
- /** The Constant ABNORMAL_EFFECT_REDCIRCLE. */
- public static final int ABNORMAL_EFFECT_REDCIRCLE = 0x000004;
- /** The Constant ABNORMAL_EFFECT_ICE. */
- public static final int ABNORMAL_EFFECT_ICE = 0x000008;
- /** The Constant ABNORMAL_EFFECT_WIND. */
- public static final int ABNORMAL_EFFECT_WIND = 0x0000010;
- /** The Constant ABNORMAL_EFFECT_FEAR. */
- public static final int ABNORMAL_EFFECT_FEAR = 0x0000020;
- /** The Constant ABNORMAL_EFFECT_STUN. */
- public static final int ABNORMAL_EFFECT_STUN = 0x000040;
- /** The Constant ABNORMAL_EFFECT_SLEEP. */
- public static final int ABNORMAL_EFFECT_SLEEP = 0x000080;
- /** The Constant ABNORMAL_EFFECT_MUTED. */
- public static final int ABNORMAL_EFFECT_MUTED = 0x000100;
- /** The Constant ABNORMAL_EFFECT_ROOT. */
- public static final int ABNORMAL_EFFECT_ROOT = 0x000200;
- /** The Constant ABNORMAL_EFFECT_HOLD_1. */
- public static final int ABNORMAL_EFFECT_HOLD_1 = 0x000400;
- /** The Constant ABNORMAL_EFFECT_HOLD_2. */
- public static final int ABNORMAL_EFFECT_HOLD_2 = 0x000800;
- /** The Constant ABNORMAL_EFFECT_UNKNOWN_13. */
- public static final int ABNORMAL_EFFECT_UNKNOWN_13 = 0x001000;
- /** The Constant ABNORMAL_EFFECT_BIG_HEAD. */
- public static final int ABNORMAL_EFFECT_BIG_HEAD = 0x002000;
- /** The Constant ABNORMAL_EFFECT_FLAME. */
- public static final int ABNORMAL_EFFECT_FLAME = 0x004000;
- /** The Constant ABNORMAL_EFFECT_UNKNOWN_16. */
- public static final int ABNORMAL_EFFECT_UNKNOWN_16 = 0x008000;
- /** The Constant ABNORMAL_EFFECT_GROW. */
- public static final int ABNORMAL_EFFECT_GROW = 0x010000;
- /** The Constant ABNORMAL_EFFECT_FLOATING_ROOT. */
- public static final int ABNORMAL_EFFECT_FLOATING_ROOT = 0x020000;
- /** The Constant ABNORMAL_EFFECT_DANCE_STUNNED. */
- public static final int ABNORMAL_EFFECT_DANCE_STUNNED = 0x040000;
- /** The Constant ABNORMAL_EFFECT_PARALYZE. */
- public static final int ABNORMAL_EFFECT_PARALYZE = 0x0400;
- /** The Constant ABNORMAL_EFFECT_FIREROOT_STUN. */
- public static final int ABNORMAL_EFFECT_FIREROOT_STUN = 0x080000;
- /** The Constant ABNORMAL_EFFECT_STEALTH. */
- public static final int ABNORMAL_EFFECT_STEALTH = 0x100000;
- /** The Constant ABNORMAL_EFFECT_IMPRISIONING_1. */
- public static final int ABNORMAL_EFFECT_IMPRISIONING_1 = 0x200000;
- /** The Constant ABNORMAL_EFFECT_IMPRISIONING_2. */
- public static final int ABNORMAL_EFFECT_IMPRISIONING_2 = 0x400000;
- /** The Constant ABNORMAL_EFFECT_MAGIC_CIRCLE. */
- public static final int ABNORMAL_EFFECT_MAGIC_CIRCLE = 0x800000;
- /** The Constant ABNORMAL_EFFECT_CONFUSED. */
- public static final int ABNORMAL_EFFECT_CONFUSED = 0x0020;
- /** The Constant ABNORMAL_EFFECT_AFRAID. */
- public static final int ABNORMAL_EFFECT_AFRAID = 0x0010;
- // Method - Public
- /**
- * Launch and add L2Effect (including Stack Group management) to L2Character and update client magic icone.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress on the L2Character are identified in ConcurrentHashMap(Integer,L2Effect) <B>_effects</B>. The Integer key of _effects is the L2Skill Identifier that has created the L2Effect.<BR>
- * <BR>
- * Several same effect can't be used on a L2Character at the same time. Indeed, effects are not stackable and the last cast will replace the previous in progress. More, some effects belong to the same Stack Group (ex WindWald and Haste Potion). If 2 effects of a same group are used at the same
- * time on a L2Character, only the more efficient (identified by its priority order) will be preserve.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Add the L2Effect to the L2Character _effects</li> <li>If this effect doesn't belong to a Stack Group, add its Funcs to the Calculator set of the L2Character (remove the old one if necessary)</li> <li>If this effect has higher priority in its Stack Group, add its Funcs to the Calculator
- * set of the L2Character (remove previous stacked effect Funcs if necessary)</li> <li>If this effect has NOT higher priority in its Stack Group, set the effect to Not In Use</li> <li>Update active skills in progress icones on player client</li><BR>
- * @param newEffect the new effect
- */
- public synchronized void addEffect(final L2Effect newEffect)
- {
- if (newEffect == null)
- return;
- final L2Effect[] effects = getAllEffects();
- // Make sure there's no same effect previously
- for (final L2Effect effect : effects)
- {
- if (effect == null)
- {
- synchronized (_effects)
- {
- _effects.remove(effect);
- }
- continue;
- }
- if (effect.getSkill().getId() == newEffect.getSkill().getId() && effect.getEffectType() == newEffect.getEffectType() && effect.getStackType() == newEffect.getStackType())
- {
- if (this instanceof L2PcInstance)
- {
- final L2PcInstance player = (L2PcInstance) this;
- if (player.isInDuel())
- {
- DuelManager.getInstance().getDuel(player.getDuelId()).onBuffStop(player, effect);
- }
- }
- if ((newEffect.getSkill().getSkillType() == SkillType.BUFF || newEffect.getEffectType() == L2Effect.EffectType.BUFF || newEffect.getEffectType() == L2Effect.EffectType.HEAL_OVER_TIME) && newEffect.getStackOrder() >= effect.getStackOrder())
- {
- effect.exit(false);
- }
- else
- {
- // newEffect.exit(false);
- newEffect.stopEffectTask();
- return;
- }
- }
- }
- final L2Skill tempskill = newEffect.getSkill();
- // Remove first Buff if number of buffs > BUFFS_MAX_AMOUNT
- if (getBuffCount() >= getMaxBuffCount() && !doesStack(tempskill) && (tempskill.getSkillType() == L2Skill.SkillType.BUFF || tempskill.getSkillType() == L2Skill.SkillType.REFLECT || tempskill.getSkillType() == L2Skill.SkillType.HEAL_PERCENT || tempskill.getSkillType() == L2Skill.SkillType.MANAHEAL_PERCENT) && !(tempskill.getId() > 4360 && tempskill.getId() < 4367) && !(tempskill.getId() > 4550 && tempskill.getId() < 4555))
- {
- if (newEffect.isHerbEffect())
- {
- newEffect.exit(false);
- return;
- }
- removeFirstBuff(tempskill.getId());
- }
- // Remove first DeBuff if number of debuffs > DEBUFFS_MAX_AMOUNT
- if (getDeBuffCount() >= Config.DEBUFFS_MAX_AMOUNT && !doesStack(tempskill) && tempskill.is_Debuff())
- {
- removeFirstDeBuff(tempskill.getId());
- }
- synchronized (_effects)
- {
- // Add the L2Effect to all effect in progress on the L2Character
- if (!newEffect.getSkill().isToggle())
- {
- int pos = 0;
- for (int i = 0; i < _effects.size(); i++)
- {
- if (_effects.get(i) == null)
- {
- _effects.remove(i);
- i--;
- continue;
- }
- if (_effects.get(i) != null)
- {
- final int skillid = _effects.get(i).getSkill().getId();
- if (!_effects.get(i).getSkill().isToggle() && !(skillid > 4360 && skillid < 4367))
- {
- pos++;
- }
- }
- else
- {
- break;
- }
- }
- _effects.add(pos, newEffect);
- }
- else
- {
- _effects.addLast(newEffect);
- }
- }
- // Check if a stack group is defined for this effect
- if (newEffect.getStackType().equals("none"))
- {
- // Set this L2Effect to In Use
- newEffect.setInUse(true);
- // Add Funcs of this effect to the Calculator set of the L2Character
- addStatFuncs(newEffect.getStatFuncs());
- // Update active skills in progress icones on player client
- updateEffectIcons();
- return;
- }
- // Get the list of all stacked effects corresponding to the stack type of the L2Effect to add
- List<L2Effect> stackQueue = _stackedEffects.get(newEffect.getStackType());
- if (stackQueue == null)
- {
- stackQueue = new FastList<>();
- }
- // L2Effect tempEffect = null;
- if (stackQueue.size() > 0)
- {
- // Get the first stacked effect of the Stack group selected
- if (_effects.contains(stackQueue.get(0)))
- {
- // Remove all Func objects corresponding to this stacked effect from the Calculator set of the L2Character
- removeStatsOwner(stackQueue.get(0));
- // Set the L2Effect to Not In Use
- stackQueue.get(0).setInUse(false);
- }
- }
- // Add the new effect to the stack group selected at its position
- stackQueue = effectQueueInsert(newEffect, stackQueue);
- if (stackQueue == null)
- return;
- // Update the Stack Group table _stackedEffects of the L2Character
- _stackedEffects.put(newEffect.getStackType(), stackQueue);
- // Get the first stacked effect of the Stack group selected
- if (_effects.contains(stackQueue.get(0)))
- {
- // Set this L2Effect to In Use
- stackQueue.get(0).setInUse(true);
- // Add all Func objects corresponding to this stacked effect to the Calculator set of the L2Character
- addStatFuncs(stackQueue.get(0).getStatFuncs());
- }
- // Update active skills in progress (In Use and Not In Use because stacked) icones on client
- updateEffectIcons();
- }
- /**
- * Insert an effect at the specified position in a Stack Group.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * Several same effect can't be used on a L2Character at the same time. Indeed, effects are not stackable and the last cast will replace the previous in progress. More, some effects belong to the same Stack Group (ex WindWald and Haste Potion). If 2 effects of a same group are used at the same
- * time on a L2Character, only the more efficient (identified by its priority order) will be preserve.<BR>
- * <BR>
- * @param newStackedEffect the new stacked effect
- * @param stackQueue The Stack Group in wich the effect must be added
- * @return the list
- */
- private List<L2Effect> effectQueueInsert(final L2Effect newStackedEffect, final List<L2Effect> stackQueue)
- {
- // Create an Iterator to go through the list of stacked effects in progress on the L2Character
- Iterator<L2Effect> queueIterator = stackQueue.iterator();
- int i = 0;
- while (queueIterator.hasNext())
- {
- final L2Effect cur = queueIterator.next();
- if (newStackedEffect.getStackOrder() < cur.getStackOrder())
- {
- i++;
- }
- else
- {
- break;
- }
- }
- // Add the new effect to the Stack list in function of its position in the Stack group
- stackQueue.add(i, newStackedEffect);
- // skill.exit() could be used, if the users don't wish to see "effect
- // removed" always when a timer goes off, even if the buff isn't active
- // any more (has been replaced). but then check e.g. npc hold and raid petrify.
- if (Config.EFFECT_CANCELING && !newStackedEffect.isHerbEffect() && stackQueue.size() > 1)
- {
- synchronized (_effects)
- {
- _effects.remove(stackQueue.get(1));
- }
- stackQueue.remove(1);
- }
- queueIterator = null;
- return stackQueue;
- }
- /**
- * Stop and remove L2Effect (including Stack Group management) from L2Character and update client magic icone.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress on the L2Character are identified in ConcurrentHashMap(Integer,L2Effect) <B>_effects</B>. The Integer key of _effects is the L2Skill Identifier that has created the L2Effect.<BR>
- * <BR>
- * Several same effect can't be used on a L2Character at the same time. Indeed, effects are not stackable and the last cast will replace the previous in progress. More, some effects belong to the same Stack Group (ex WindWald and Haste Potion). If 2 effects of a same group are used at the same
- * time on a L2Character, only the more efficient (identified by its priority order) will be preserve.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Remove Func added by this effect from the L2Character Calculator (Stop L2Effect)</li> <li>If the L2Effect belongs to a not empty Stack Group, replace theses Funcs by next stacked effect Funcs</li> <li>Remove the L2Effect from _effects of the L2Character</li> <li>Update active skills in
- * progress icones on player client</li><BR>
- * @param effect the effect
- */
- public final void removeEffect(final L2Effect effect)
- {
- if (effect == null/* || _effects == null */)
- return;
- if (effect.getStackType() == "none")
- {
- // Remove Func added by this effect from the L2Character Calculator
- removeStatsOwner(effect);
- }
- else
- {
- if (_stackedEffects == null)
- return;
- // Get the list of all stacked effects corresponding to the stack type of the L2Effect to add
- final List<L2Effect> stackQueue = _stackedEffects.get(effect.getStackType());
- if (stackQueue == null || stackQueue.size() < 1)
- return;
- // Get the Identifier of the first stacked effect of the Stack group selected
- final L2Effect frontEffect = stackQueue.get(0);
- // Remove the effect from the Stack Group
- final boolean removed = stackQueue.remove(effect);
- if (removed)
- {
- // Check if the first stacked effect was the effect to remove
- if (frontEffect == effect)
- {
- // Remove all its Func objects from the L2Character calculator set
- removeStatsOwner(effect);
- // Check if there's another effect in the Stack Group
- if (stackQueue.size() > 0)
- {
- // Add its list of Funcs to the Calculator set of the L2Character
- if (_effects.contains(stackQueue.get(0)))
- {
- // Add its list of Funcs to the Calculator set of the L2Character
- addStatFuncs(stackQueue.get(0).getStatFuncs());
- // Set the effect to In Use
- stackQueue.get(0).setInUse(true);
- }
- }
- }
- if (stackQueue.isEmpty())
- {
- _stackedEffects.remove(effect.getStackType());
- }
- else
- {
- // Update the Stack Group table _stackedEffects of the L2Character
- _stackedEffects.put(effect.getStackType(), stackQueue);
- }
- }
- }
- synchronized (_effects)
- {
- // Remove the active skill L2effect from _effects of the L2Character
- _effects.remove(effect);
- }
- // Update active skills in progress (In Use and Not In Use because stacked) icones on client
- updateEffectIcons();
- }
- /**
- * Active abnormal effects flags in the binary mask and send Server->Client UserInfo/CharInfo packet.<BR>
- * <BR>
- * @param mask the mask
- */
- public final void startAbnormalEffect(final int mask)
- {
- _AbnormalEffects |= mask;
- updateAbnormalEffect();
- }
- /**
- * immobile start.
- */
- public final void startImmobileUntilAttacked()
- {
- setIsImmobileUntilAttacked(true);
- abortAttack();
- abortCast();
- getAI().notifyEvent(CtrlEvent.EVT_SLEEPING);
- updateAbnormalEffect();
- }
- /**
- * Active the abnormal effect Confused flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
- * <BR>
- */
- public final void startConfused()
- {
- setIsConfused(true);
- getAI().notifyEvent(CtrlEvent.EVT_CONFUSED);
- updateAbnormalEffect();
- }
- /**
- * Active the abnormal effect Fake Death flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
- * <BR>
- */
- public final void startFakeDeath()
- {
- setIsFallsdown(true);
- setIsFakeDeath(true);
- /* Aborts any attacks/casts if fake dead */
- abortAttack();
- abortCast();
- stopMove(null);
- getAI().notifyEvent(CtrlEvent.EVT_FAKE_DEATH, null);
- broadcastPacket(new ChangeWaitType(this, ChangeWaitType.WT_START_FAKEDEATH));
- }
- /**
- * Active the abnormal effect Fear flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
- * <BR>
- */
- public final void startFear()
- {
- setIsAfraid(true);
- getAI().notifyEvent(CtrlEvent.EVT_AFFRAID);
- updateAbnormalEffect();
- }
- /**
- * Active the abnormal effect Muted flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
- * <BR>
- */
- public final void startMuted()
- {
- setIsMuted(true);
- /* Aborts any casts if muted */
- abortCast();
- getAI().notifyEvent(CtrlEvent.EVT_MUTED);
- updateAbnormalEffect();
- }
- /**
- * Active the abnormal effect Psychical_Muted flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
- * <BR>
- */
- public final void startPsychicalMuted()
- {
- setIsPsychicalMuted(true);
- getAI().notifyEvent(CtrlEvent.EVT_MUTED);
- updateAbnormalEffect();
- }
- /**
- * Active the abnormal effect Root flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
- * <BR>
- */
- public final void startRooted()
- {
- setIsRooted(true);
- stopMove(null);
- getAI().notifyEvent(CtrlEvent.EVT_ROOTED, null);
- updateAbnormalEffect();
- }
- /**
- * Active the abnormal effect Sleep flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
- * <BR>
- */
- public final void startSleeping()
- {
- setIsSleeping(true);
- /* Aborts any attacks/casts if sleeped */
- abortAttack();
- abortCast();
- stopMove(null);
- getAI().notifyEvent(CtrlEvent.EVT_SLEEPING, null);
- updateAbnormalEffect();
- }
- /**
- * Launch a Stun Abnormal Effect on the L2Character.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Calculate the success rate of the Stun Abnormal Effect on this L2Character</li> <li>If Stun succeed, active the abnormal effect Stun flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet</li> <li>If Stun NOT succeed, send a system message Failed to the
- * L2PcInstance attacker</li><BR>
- * <BR>
- */
- public final void startStunning()
- {
- if (isStunned())
- return;
- setIsStunned(true);
- /* Aborts any attacks/casts if stunned */
- abortAttack();
- abortCast();
- getAI().stopFollow(); // Like L2OFF char stop to follow if sticked to another one
- stopMove(null);
- getAI().notifyEvent(CtrlEvent.EVT_STUNNED, null);
- updateAbnormalEffect();
- }
- /**
- * Start betray.
- */
- public final void startBetray()
- {
- setIsBetrayed(true);
- getAI().notifyEvent(CtrlEvent.EVT_BETRAYED, null);
- updateAbnormalEffect();
- }
- /**
- * Stop betray.
- */
- public final void stopBetray()
- {
- stopEffects(L2Effect.EffectType.BETRAY);
- setIsBetrayed(false);
- updateAbnormalEffect();
- }
- /**
- * Modify the abnormal effect map according to the mask.<BR>
- * <BR>
- * @param mask the mask
- */
- public final void stopAbnormalEffect(final int mask)
- {
- _AbnormalEffects &= ~mask;
- updateAbnormalEffect();
- }
- /**
- * Stop all active skills effects in progress on the L2Character.<BR>
- * <BR>
- */
- public final void stopAllEffects()
- {
- final L2Effect[] effects = getAllEffects();
- for (final L2Effect effect : effects)
- {
- if (effect != null)
- {
- effect.exit(true);
- }
- else
- {
- synchronized (_effects)
- {
- _effects.remove(effect);
- }
- }
- }
- if (this instanceof L2PcInstance)
- {
- ((L2PcInstance) this).updateAndBroadcastStatus(2);
- }
- }
- /**
- * Stop immobilization until attacked abnormal L2Effect.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Delete a specified/all (if effect=null) immobilization until attacked abnormal L2Effect from L2Character and update client magic icon</li> <li>Set the abnormal effect flag _muted to False</li> <li>Notify the L2Character AI</li> <li>Send Server->Client UserInfo/CharInfo packet</li><BR>
- * <BR>
- * @param effect the effect
- */
- public final void stopImmobileUntilAttacked(final L2Effect effect)
- {
- if (effect == null)
- {
- stopEffects(L2Effect.EffectType.IMMOBILEUNTILATTACKED);
- }
- else
- {
- removeEffect(effect);
- stopSkillEffects(effect.getSkill().getNegateId());
- }
- setIsImmobileUntilAttacked(false);
- getAI().notifyEvent(CtrlEvent.EVT_THINK);
- updateAbnormalEffect();
- }
- /**
- * Stop a specified/all Confused abnormal L2Effect.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Delete a specified/all (if effect=null) Confused abnormal L2Effect from L2Character and update client magic icone</li> <li>Set the abnormal effect flag _confused to False</li> <li>Notify the L2Character AI</li> <li>Send Server->Client UserInfo/CharInfo packet</li><BR>
- * <BR>
- * @param effect the effect
- */
- public final void stopConfused(final L2Effect effect)
- {
- if (effect == null)
- {
- stopEffects(L2Effect.EffectType.CONFUSION);
- }
- else
- {
- removeEffect(effect);
- }
- setIsConfused(false);
- getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
- updateAbnormalEffect();
- }
- /**
- * Stop and remove the L2Effects corresponding to the L2Skill Identifier and update client magic icone.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress on the L2Character are identified in ConcurrentHashMap(Integer,L2Effect) <B>_effects</B>. The Integer key of _effects is the L2Skill Identifier that has created the L2Effect.<BR>
- * <BR>
- * @param skillId the skill id
- */
- public final void stopSkillEffects(final int skillId)
- {
- final L2Effect[] effects = getAllEffects();
- for (final L2Effect effect : effects)
- {
- if (effect == null || effect.getSkill() == null)
- {
- synchronized (_effects)
- {
- _effects.remove(effect);
- }
- continue;
- }
- if (effect.getSkill().getId() == skillId)
- {
- effect.exit(true);
- }
- }
- }
- /**
- * Stop and remove all L2Effect of the selected type (ex : BUFF, DMG_OVER_TIME...) from the L2Character and update client magic icone.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress on the L2Character are identified in ConcurrentHashMap(Integer,L2Effect) <B>_effects</B>. The Integer key of _effects is the L2Skill Identifier that has created the L2Effect.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Remove Func added by this effect from the L2Character Calculator (Stop L2Effect)</li> <li>Remove the L2Effect from _effects of the L2Character</li> <li>Update active skills in progress icones on player client</li><BR>
- * <BR>
- * @param type The type of effect to stop ((ex : BUFF, DMG_OVER_TIME...)
- */
- public final void stopEffects(final L2Effect.EffectType type)
- {
- final L2Effect[] effects = getAllEffects();
- for (final L2Effect effect : effects)
- {
- if (effect == null)
- {
- synchronized (_effects)
- {
- _effects.remove(effect);
- }
- continue;
- }
- // LOGGER.info("Character Effect Type: "+effects[i].getEffectType());
- if (effect.getEffectType() == type)
- {
- effect.exit(true);
- }
- }
- }
- /**
- * Stop and remove the L2Effects corresponding to the L2SkillType and update client magic icon.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress on the L2Character are identified in ConcurrentHashMap(Integer,L2Effect) <B>_effects</B>. The Integer key of _effects is the L2Skill Identifier that has created the L2Effect.<BR>
- * <BR>
- * @param skillType The L2SkillType of the L2Effect to remove from _effects
- * @param power the power
- */
- public final void stopSkillEffects(final SkillType skillType, final double power)
- {
- final L2Effect[] effects = getAllEffects();
- for (final L2Effect effect : effects)
- {
- if (effect == null || effect.getSkill() == null)
- {
- synchronized (_effects)
- {
- _effects.remove(effect);
- }
- continue;
- }
- if (effect.getSkill().getSkillType() == skillType && (power == 0 || effect.getSkill().getPower() <= power))
- {
- effect.exit(true);
- }
- }
- }
- /**
- * Stop skill effects.
- * @param skillType the skill type
- */
- public final void stopSkillEffects(final SkillType skillType)
- {
- stopSkillEffects(skillType, -1);
- }
- /**
- * Stop a specified/all Fake Death abnormal L2Effect.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Delete a specified/all (if effect=null) Fake Death abnormal L2Effect from L2Character and update client magic icone</li> <li>Set the abnormal effect flag _fake_death to False</li> <li>Notify the L2Character AI</li><BR>
- * <BR>
- * @param effect the effect
- */
- public final void stopFakeDeath(final L2Effect effect)
- {
- if (effect == null)
- {
- stopEffects(L2Effect.EffectType.FAKE_DEATH);
- }
- else
- {
- removeEffect(effect);
- }
- setIsFakeDeath(false);
- setIsFallsdown(false);
- // if this is a player instance, start the grace period for this character (grace from mobs only)!
- if (this instanceof L2PcInstance)
- {
- ((L2PcInstance) this).setRecentFakeDeath(true);
- }
- ChangeWaitType revive = new ChangeWaitType(this, ChangeWaitType.WT_STOP_FAKEDEATH);
- broadcastPacket(revive);
- broadcastPacket(new Revive(this));
- getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
- revive = null;
- }
- /**
- * Stop a specified/all Fear abnormal L2Effect.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Delete a specified/all (if effect=null) Fear abnormal L2Effect from L2Character and update client magic icone</li> <li>Set the abnormal effect flag _affraid to False</li> <li>Notify the L2Character AI</li> <li>Send Server->Client UserInfo/CharInfo packet</li><BR>
- * <BR>
- * @param effect the effect
- */
- public final void stopFear(final L2Effect effect)
- {
- if (effect == null)
- {
- stopEffects(L2Effect.EffectType.FEAR);
- }
- else
- {
- removeEffect(effect);
- }
- setIsAfraid(false);
- updateAbnormalEffect();
- }
- /**
- * Stop a specified/all Muted abnormal L2Effect.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Delete a specified/all (if effect=null) Muted abnormal L2Effect from L2Character and update client magic icone</li> <li>Set the abnormal effect flag _muted to False</li> <li>Notify the L2Character AI</li> <li>Send Server->Client UserInfo/CharInfo packet</li><BR>
- * <BR>
- * @param effect the effect
- */
- public final void stopMuted(final L2Effect effect)
- {
- if (effect == null)
- {
- stopEffects(L2Effect.EffectType.MUTE);
- }
- else
- {
- removeEffect(effect);
- }
- setIsMuted(false);
- updateAbnormalEffect();
- }
- /**
- * Stop psychical muted.
- * @param effect the effect
- */
- public final void stopPsychicalMuted(final L2Effect effect)
- {
- if (effect == null)
- {
- stopEffects(L2Effect.EffectType.PSYCHICAL_MUTE);
- }
- else
- {
- removeEffect(effect);
- }
- setIsPsychicalMuted(false);
- updateAbnormalEffect();
- }
- /**
- * Stop a specified/all Root abnormal L2Effect.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Delete a specified/all (if effect=null) Root abnormal L2Effect from L2Character and update client magic icone</li> <li>Set the abnormal effect flag _rooted to False</li> <li>Notify the L2Character AI</li> <li>Send Server->Client UserInfo/CharInfo packet</li><BR>
- * <BR>
- * @param effect the effect
- */
- public final void stopRooting(final L2Effect effect)
- {
- if (effect == null)
- {
- stopEffects(L2Effect.EffectType.ROOT);
- }
- else
- {
- removeEffect(effect);
- }
- setIsRooted(false);
- getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
- updateAbnormalEffect();
- }
- /**
- * Stop a specified/all Sleep abnormal L2Effect.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Delete a specified/all (if effect=null) Sleep abnormal L2Effect from L2Character and update client magic icone</li> <li>Set the abnormal effect flag _sleeping to False</li> <li>Notify the L2Character AI</li> <li>Send Server->Client UserInfo/CharInfo packet</li><BR>
- * <BR>
- * @param effect the effect
- */
- public final void stopSleeping(final L2Effect effect)
- {
- if (effect == null)
- {
- stopEffects(L2Effect.EffectType.SLEEP);
- }
- else
- {
- removeEffect(effect);
- }
- setIsSleeping(false);
- getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
- updateAbnormalEffect();
- }
- /**
- * Stop a specified/all Stun abnormal L2Effect.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Delete a specified/all (if effect=null) Stun abnormal L2Effect from L2Character and update client magic icone</li> <li>Set the abnormal effect flag _stuned to False</li> <li>Notify the L2Character AI</li> <li>Send Server->Client UserInfo/CharInfo packet</li><BR>
- * <BR>
- * @param effect the effect
- */
- public final void stopStunning(final L2Effect effect)
- {
- if (!isStunned())
- return;
- if (effect == null)
- {
- stopEffects(L2Effect.EffectType.STUN);
- }
- else
- {
- removeEffect(effect);
- }
- setIsStunned(false);
- getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
- updateAbnormalEffect();
- }
- /**
- * Not Implemented.<BR>
- * <BR>
- * <B><U> Overridden in</U> :</B><BR>
- * <BR>
- * <li>L2NPCInstance</li> <li>L2PcInstance</li> <li>L2Summon</li> <li>L2DoorInstance</li><BR>
- * <BR>
- */
- public abstract void updateAbnormalEffect();
- /**
- * Update active skills in progress (In Use and Not In Use because stacked) icones on client.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress (In Use and Not In Use because stacked) are represented by an icone on the client.<BR>
- * <BR>
- * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method ONLY UPDATE the client of the player and not clients of all players in the party.</B></FONT><BR>
- * <BR>
- */
- public final void updateEffectIcons()
- {
- updateEffectIcons(false);
- }
- /**
- * Update effect icons.
- * @param partyOnly the party only
- */
- public final void updateEffectIcons(final boolean partyOnly)
- {
- // Create a L2PcInstance of this if needed
- L2PcInstance player = null;
- if (this instanceof L2PcInstance)
- {
- player = (L2PcInstance) this;
- }
- // Create a L2Summon of this if needed
- L2Summon summon = null;
- if (this instanceof L2Summon)
- {
- summon = (L2Summon) this;
- player = summon.getOwner();
- summon.getOwner().sendPacket(new PetInfo(summon));
- }
- // Create the main packet if needed
- MagicEffectIcons mi = null;
- if (!partyOnly)
- {
- mi = new MagicEffectIcons();
- }
- // Create the party packet if needed
- PartySpelled ps = null;
- if (summon != null)
- {
- ps = new PartySpelled(summon);
- }
- else if (player != null && player.isInParty())
- {
- ps = new PartySpelled(player);
- }
- // Create the olympiad spectator packet if needed
- ExOlympiadSpelledInfo os = null;
- if (player != null && player.isInOlympiadMode())
- {
- os = new ExOlympiadSpelledInfo(player);
- }
- if (mi == null && ps == null && os == null)
- return; // nothing to do (should not happen)
- // Add special effects
- // Note: Now handled by EtcStatusUpdate packet
- // NOTE: CHECK IF THEY WERE EVEN VISIBLE TO OTHERS...
- /*
- * if (player != null && mi != null) { if (player.getWeightPenalty() > 0) mi.addEffect(4270, player.getWeightPenalty(), -1); if (player.getExpertisePenalty() > 0) mi.addEffect(4267, 1, -1); if (player.getMessageRefusal()) mi.addEffect(4269, 1, -1); }
- */
- // Go through all effects if any
- synchronized (_effects)
- {
- for (int i = 0; i < _effects.size(); i++)
- {
- if (_effects.get(i) == null || _effects.get(i).getSkill() == null)
- {
- _effects.remove(i);
- i--;
- continue;
- }
- if (_effects.get(i).getEffectType() == L2Effect.EffectType.CHARGE && player != null)
- {
- // handled by EtcStatusUpdate
- continue;
- }
- if (_effects.get(i).getInUse())
- {
- if (mi != null)
- {
- _effects.get(i).addIcon(mi);
- }
- // Like L2OFF toggle and healing potions must not be showed on party buff list
- if (ps != null && !_effects.get(i).getSkill().isToggle() && !(_effects.get(i).getSkill().getId() == 2031) && !(_effects.get(i).getSkill().getId() == 2037) && !(_effects.get(i).getSkill().getId() == 2032))
- {
- _effects.get(i).addPartySpelledIcon(ps);
- }
- if (os != null)
- {
- _effects.get(i).addOlympiadSpelledIcon(os);
- }
- }
- }
- }
- // Send the packets if needed
- if (mi != null)
- {
- sendPacket(mi);
- }
- if (ps != null && player != null)
- {
- // summon info only needs to go to the owner, not to the whole party
- // player info: if in party, send to all party members except one's self.
- // if not in party, send to self.
- if (player.isInParty() && summon == null)
- {
- player.getParty().broadcastToPartyMembers(player, ps);
- }
- else
- {
- player.sendPacket(ps);
- }
- }
- if (os != null)
- {
- if ((player != null) && Olympiad.getInstance().getSpectators(player.getOlympiadGameId()) != null)
- {
- for (final L2PcInstance spectator : Olympiad.getInstance().getSpectators(player.getOlympiadGameId()))
- {
- if (spectator == null)
- {
- continue;
- }
- spectator.sendPacket(os);
- }
- }
- }
- }
- // Property - Public
- /**
- * Return a map of 16 bits (0x0000) containing all abnormal effect in progress for this L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * In Server->Client packet, each effect is represented by 1 bit of the map (ex : BLEEDING = 0x0001 (bit 1), SLEEP = 0x0080 (bit 8)...). The map is calculated by applying a BINARY OR operation on each effect.<BR>
- * <BR>
- * <B><U> Example of use </U> :</B><BR>
- * <BR>
- * <li>Server Packet : CharInfo, NpcInfo, NpcInfoPoly, UserInfo...</li><BR>
- * <BR>
- * @return the abnormal effect
- */
- public int getAbnormalEffect()
- {
- int ae = _AbnormalEffects;
- if (isStunned())
- {
- ae |= ABNORMAL_EFFECT_STUN;
- }
- if (isRooted())
- {
- ae |= ABNORMAL_EFFECT_ROOT;
- }
- if (isSleeping())
- {
- ae |= ABNORMAL_EFFECT_SLEEP;
- }
- if (isConfused())
- {
- ae |= ABNORMAL_EFFECT_CONFUSED;
- }
- if (isMuted())
- {
- ae |= ABNORMAL_EFFECT_MUTED;
- }
- if (isAfraid())
- {
- ae |= ABNORMAL_EFFECT_AFRAID;
- }
- if (isPsychicalMuted())
- {
- ae |= ABNORMAL_EFFECT_MUTED;
- }
- return ae;
- }
- /**
- * Return all active skills effects in progress on the L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress on the L2Character are identified in <B>_effects</B>. The Integer key of _effects is the L2Skill Identifier that has created the effect.<BR>
- * <BR>
- * @return A table containing all active skills effect in progress on the L2Character
- */
- public final L2Effect[] getAllEffects()
- {
- synchronized (_effects)
- {
- final L2Effect[] output = _effects.toArray(new L2Effect[_effects.size()]);
- return output;
- }
- }
- /**
- * Return L2Effect in progress on the L2Character corresponding to the L2Skill Identifier.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress on the L2Character are identified in <B>_effects</B>.
- * @param index The L2Skill Identifier of the L2Effect to return from the _effects
- * @return The L2Effect corresponding to the L2Skill Identifier
- */
- public final L2Effect getFirstEffect(final int index)
- {
- final L2Effect[] effects = getAllEffects();
- L2Effect effNotInUse = null;
- for (final L2Effect effect : effects)
- {
- if (effect == null)
- {
- synchronized (_effects)
- {
- _effects.remove(effect);
- }
- continue;
- }
- if (effect.getSkill().getId() == index)
- {
- if (effect.getInUse())
- return effect;
- if (effNotInUse == null)
- effNotInUse = effect;
- }
- }
- return effNotInUse;
- }
- /**
- * Gets the first effect.
- * @param type the type
- * @return the first effect
- */
- public final L2Effect getFirstEffect(final SkillType type)
- {
- final L2Effect[] effects = getAllEffects();
- L2Effect effNotInUse = null;
- for (final L2Effect effect : effects)
- {
- if (effect == null)
- {
- synchronized (_effects)
- {
- _effects.remove(effect);
- }
- continue;
- }
- if (effect.getSkill().getSkillType() == type)
- {
- if (effect.getInUse())
- return effect;
- if (effNotInUse == null)
- effNotInUse = effect;
- }
- }
- return effNotInUse;
- }
- /**
- * Return the first L2Effect in progress on the L2Character created by the L2Skill.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress on the L2Character are identified in <B>_effects</B>.
- * @param skill The L2Skill whose effect must be returned
- * @return The first L2Effect created by the L2Skill
- */
- public final L2Effect getFirstEffect(final L2Skill skill)
- {
- final L2Effect[] effects = getAllEffects();
- L2Effect effNotInUse = null;
- for (final L2Effect effect : effects)
- {
- if (effect == null)
- {
- synchronized (_effects)
- {
- _effects.remove(effect);
- }
- continue;
- }
- if (effect.getSkill() == skill)
- {
- if (effect.getInUse())
- return effect;
- if (effNotInUse == null)
- effNotInUse = effect;
- }
- }
- return effNotInUse;
- }
- /**
- * Return the first L2Effect in progress on the L2Character corresponding to the Effect Type (ex : BUFF, STUN, ROOT...).<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * All active skills effects in progress on the L2Character are identified in ConcurrentHashMap(Integer,L2Effect) <B>_effects</B>. The Integer key of _effects is the L2Skill Identifier that has created the L2Effect.<BR>
- * <BR>
- * @param tp The Effect Type of skills whose effect must be returned
- * @return The first L2Effect corresponding to the Effect Type
- */
- public final L2Effect getFirstEffect(final L2Effect.EffectType tp)
- {
- final L2Effect[] effects = getAllEffects();
- L2Effect effNotInUse = null;
- for (final L2Effect effect : effects)
- {
- if (effect == null)
- {
- synchronized (_effects)
- {
- _effects.remove(effect);
- }
- continue;
- }
- if (effect.getEffectType() == tp)
- {
- if (effect.getInUse())
- return effect;
- if (effNotInUse == null)
- effNotInUse = effect;
- }
- }
- return effNotInUse;
- }
- /**
- * Gets the charge effect.
- * @return the charge effect
- */
- public EffectCharge getChargeEffect()
- {
- final L2Effect effect = getFirstEffect(SkillType.CHARGE);
- if (effect != null)
- return (EffectCharge) effect;
- return null;
- }
- // =========================================================
- // NEED TO ORGANIZE AND MOVE TO PROPER PLACE
- /**
- * This class permit to the L2Character AI to obtain informations and uses L2Character method.
- */
- public class AIAccessor
- {
- /**
- * Instantiates a new aI accessor.
- */
- public AIAccessor()
- {
- // null
- }
- /**
- * Return the L2Character managed by this Accessor AI.<BR>
- * <BR>
- * @return the actor
- */
- public L2Character getActor()
- {
- return L2Character.this;
- }
- /**
- * Accessor to L2Character moveToLocation() method with an interaction area.<BR>
- * <BR>
- * @param x the x
- * @param y the y
- * @param z the z
- * @param offset the offset
- */
- public void moveTo(final int x, final int y, final int z, final int offset)
- {
- moveToLocation(x, y, z, offset);
- }
- /**
- * Accessor to L2Character moveToLocation() method without interaction area.<BR>
- * <BR>
- * @param x the x
- * @param y the y
- * @param z the z
- */
- public void moveTo(final int x, final int y, final int z)
- {
- moveToLocation(x, y, z, 0);
- }
- /**
- * Accessor to L2Character stopMove() method.<BR>
- * <BR>
- * @param pos the pos
- */
- public void stopMove(final L2CharPosition pos)
- {
- L2Character.this.stopMove(pos);
- }
- /**
- * Accessor to L2Character doAttack() method.<BR>
- * <BR>
- * @param target the target
- */
- public void doAttack(final L2Character target)
- {
- L2Character.this.doAttack(target);
- }
- /**
- * Accessor to L2Character doCast() method.<BR>
- * <BR>
- * @param skill the skill
- */
- public void doCast(final L2Skill skill)
- {
- L2Character.this.doCast(skill);
- }
- /**
- * Create a NotifyAITask.<BR>
- * <BR>
- * @param evt the evt
- * @return the notify ai task
- */
- public NotifyAITask newNotifyTask(final CtrlEvent evt)
- {
- return new NotifyAITask(evt);
- }
- /**
- * Cancel the AI.<BR>
- * <BR>
- */
- public void detachAI()
- {
- _ai = null;
- }
- }
- /**
- * This class group all mouvement data.<BR>
- * <BR>
- * <B><U> Data</U> :</B><BR>
- * <BR>
- * <li>_moveTimestamp : Last time position update</li> <li>_xDestination, _yDestination, _zDestination : Position of the destination</li> <li>_xMoveFrom, _yMoveFrom, _zMoveFrom : Position of the origin</li> <li>_moveStartTime : Start time of the movement</li> <li>_ticksToMove : Nb of ticks
- * between the start and the destination</li> <li>_xSpeedTicks, _ySpeedTicks : Speed in unit/ticks</li><BR>
- * <BR>
- */
- public static class MoveData
- {
- // when we retrieve x/y/z we use GameTimeControl.getGameTicks()
- // if we are moving, but move timestamp==gameticks, we don't need
- // to recalculate position
- /** The _move start time. */
- public int _moveStartTime;
- /** The _move timestamp. */
- public int _moveTimestamp;
- /** The _x destination. */
- public int _xDestination;
- /** The _y destination. */
- public int _yDestination;
- /** The _z destination. */
- public int _zDestination;
- /** The _x accurate. */
- public double _xAccurate;
- /** The _y accurate. */
- public double _yAccurate;
- /** The _z accurate. */
- public double _zAccurate;
- /** The _heading. */
- public int _heading;
- /** The disregarding geodata. */
- public boolean disregardingGeodata;
- /** The on geodata path index. */
- public int onGeodataPathIndex;
- /** The geo path. */
- public Node[] geoPath;
- /** The geo path accurate tx. */
- public int geoPathAccurateTx;
- /** The geo path accurate ty. */
- public int geoPathAccurateTy;
- /** The geo path gtx. */
- public int geoPathGtx;
- /** The geo path gty. */
- public int geoPathGty;
- }
- /** Table containing all skillId that are disabled. */
- protected List<Integer> _disabledSkills;
- /** The _all skills disabled. */
- private boolean _allSkillsDisabled;
- // private int _flyingRunSpeed;
- // private int _floatingWalkSpeed;
- // private int _flyingWalkSpeed;
- // private int _floatingRunSpeed;
- /** Movement data of this L2Character. */
- protected MoveData _move;
- /** Orientation of the L2Character. */
- private int _heading;
- /** L2Charcater targeted by the L2Character. */
- private L2Object _target;
- // set by the start of casting, in game ticks
- /** The _cast end time. */
- private int _castEndTime;
- /** The _cast interrupt time. */
- private int _castInterruptTime;
- // set by the start of casting, in game ticks
- /** The _cast potion end time. */
- private int _castPotionEndTime;
- /** The _cast potion interrupt time. */
- @SuppressWarnings("unused")
- private int _castPotionInterruptTime;
- // set by the start of attack, in game ticks
- /** The _attack end time. */
- int _attackEndTime;
- /** The _attacking. */
- private int _attacking;
- /** The _disable bow attack end time. */
- private int _disableBowAttackEndTime;
- /** Table of calculators containing all standard NPC calculator (ex : ACCURACY_COMBAT, EVASION_RATE. */
- private static final Calculator[] NPC_STD_CALCULATOR;
- static
- {
- NPC_STD_CALCULATOR = Formulas.getInstance().getStdNPCCalculators();
- }
- /** The _ai. */
- protected L2CharacterAI _ai;
- /** Future Skill Cast. */
- protected Future<?> _skillCast;
- /** Future Potion Cast. */
- protected Future<?> _potionCast;
- /** Char Coords from Client. */
- private int _clientX;
- /** The _client y. */
- private int _clientY;
- /** The _client z. */
- private int _clientZ;
- /** The _client heading. */
- private int _clientHeading;
- /** List of all QuestState instance that needs to be notified of this character's death. */
- private List<QuestState> _NotifyQuestOfDeathList = new FastList<>();
- /**
- * Add QuestState instance that is to be notified of character's death.<BR>
- * <BR>
- * @param qs The QuestState that subscribe to this event
- */
- public void addNotifyQuestOfDeath(final QuestState qs)
- {
- if (qs == null || _NotifyQuestOfDeathList.contains(qs))
- return;
- _NotifyQuestOfDeathList.add(qs);
- }
- /**
- * Return a list of L2Character that attacked.<BR>
- * <BR>
- * @return the notify quest of death
- */
- public final List<QuestState> getNotifyQuestOfDeath()
- {
- if (_NotifyQuestOfDeathList == null)
- {
- _NotifyQuestOfDeathList = new FastList<>();
- }
- return _NotifyQuestOfDeathList;
- }
- /**
- * Add a Func to the Calculator set of the L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * A L2Character owns a table of Calculators called <B>_calculators</B>. Each Calculator (a calculator per state) own a table of Func object. A Func object is a mathematic function that permit to calculate the modifier of a state (ex : REGENERATE_HP_RATE...). To reduce cache memory use,
- * L2NPCInstances who don't have skills share the same Calculator set called <B>NPC_STD_CALCULATOR</B>.<BR>
- * <BR>
- * That's why, if a L2NPCInstance is under a skill/spell effect that modify one of its state, a copy of the NPC_STD_CALCULATOR must be create in its _calculators before addind new Func object.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>If _calculators is linked to NPC_STD_CALCULATOR, create a copy of NPC_STD_CALCULATOR in _calculators</li> <li>Add the Func object to _calculators</li><BR>
- * <BR>
- * @param f The Func object to add to the Calculator corresponding to the state affected
- */
- public final synchronized void addStatFunc(final Func f)
- {
- if (f == null)
- return;
- // Check if Calculator set is linked to the standard Calculator set of NPC
- if (_calculators == NPC_STD_CALCULATOR)
- {
- // Create a copy of the standard NPC Calculator set
- _calculators = new Calculator[Stats.NUM_STATS];
- for (int i = 0; i < Stats.NUM_STATS; i++)
- {
- if (NPC_STD_CALCULATOR[i] != null)
- {
- _calculators[i] = new Calculator(NPC_STD_CALCULATOR[i]);
- }
- }
- }
- // Select the Calculator of the affected state in the Calculator set
- final int stat = f.stat.ordinal();
- if (_calculators[stat] == null)
- {
- _calculators[stat] = new Calculator();
- }
- // Add the Func to the calculator corresponding to the state
- _calculators[stat].addFunc(f);
- }
- /**
- * Add a list of Funcs to the Calculator set of the L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * A L2Character owns a table of Calculators called <B>_calculators</B>. Each Calculator (a calculator per state) own a table of Func object. A Func object is a mathematic function that permit to calculate the modifier of a state (ex : REGENERATE_HP_RATE...). <BR>
- * <BR>
- * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method is ONLY for L2PcInstance</B></FONT><BR>
- * <BR>
- * <B><U> Example of use </U> :</B><BR>
- * <BR>
- * <li>Equip an item from inventory</li> <li>Learn a new passive skill</li> <li>Use an active skill</li><BR>
- * <BR>
- * @param funcs The list of Func objects to add to the Calculator corresponding to the state affected
- */
- public final synchronized void addStatFuncs(final Func[] funcs)
- {
- FastList<Stats> modifiedStats = new FastList<>();
- for (final Func f : funcs)
- {
- modifiedStats.add(f.stat);
- addStatFunc(f);
- }
- broadcastModifiedStats(modifiedStats);
- modifiedStats = null;
- }
- /**
- * Remove a Func from the Calculator set of the L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * A L2Character owns a table of Calculators called <B>_calculators</B>. Each Calculator (a calculator per state) own a table of Func object. A Func object is a mathematic function that permit to calculate the modifier of a state (ex : REGENERATE_HP_RATE...). To reduce cache memory use,
- * L2NPCInstances who don't have skills share the same Calculator set called <B>NPC_STD_CALCULATOR</B>.<BR>
- * <BR>
- * That's why, if a L2NPCInstance is under a skill/spell effect that modify one of its state, a copy of the NPC_STD_CALCULATOR must be create in its _calculators before addind new Func object.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Remove the Func object from _calculators</li><BR>
- * <BR>
- * <li>If L2Character is a L2NPCInstance and _calculators is equal to NPC_STD_CALCULATOR, free cache memory and just create a link on NPC_STD_CALCULATOR in _calculators</li><BR>
- * <BR>
- * @param f The Func object to remove from the Calculator corresponding to the state affected
- */
- public final synchronized void removeStatFunc(final Func f)
- {
- if (f == null)
- return;
- // Select the Calculator of the affected state in the Calculator set
- final int stat = f.stat.ordinal();
- if (_calculators[stat] == null)
- return;
- // Remove the Func object from the Calculator
- _calculators[stat].removeFunc(f);
- if (_calculators[stat].size() == 0)
- {
- _calculators[stat] = null;
- }
- // If possible, free the memory and just create a link on NPC_STD_CALCULATOR
- if (this instanceof L2NpcInstance)
- {
- int i = 0;
- for (; i < Stats.NUM_STATS; i++)
- {
- if (!Calculator.equalsCals(_calculators[i], NPC_STD_CALCULATOR[i]))
- {
- break;
- }
- }
- if (i >= Stats.NUM_STATS)
- {
- _calculators = NPC_STD_CALCULATOR;
- }
- }
- }
- /**
- * Remove a list of Funcs from the Calculator set of the L2PcInstance.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * A L2Character owns a table of Calculators called <B>_calculators</B>. Each Calculator (a calculator per state) own a table of Func object. A Func object is a mathematic function that permit to calculate the modifier of a state (ex : REGENERATE_HP_RATE...). <BR>
- * <BR>
- * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method is ONLY for L2PcInstance</B></FONT><BR>
- * <BR>
- * <B><U> Example of use </U> :</B><BR>
- * <BR>
- * <li>Unequip an item from inventory</li> <li>Stop an active skill</li><BR>
- * <BR>
- * @param funcs The list of Func objects to add to the Calculator corresponding to the state affected
- */
- public final synchronized void removeStatFuncs(final Func[] funcs)
- {
- FastList<Stats> modifiedStats = new FastList<>();
- for (final Func f : funcs)
- {
- modifiedStats.add(f.stat);
- removeStatFunc(f);
- }
- broadcastModifiedStats(modifiedStats);
- modifiedStats = null;
- }
- /**
- * Remove all Func objects with the selected owner from the Calculator set of the L2Character.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * A L2Character owns a table of Calculators called <B>_calculators</B>. Each Calculator (a calculator per state) own a table of Func object. A Func object is a mathematic function that permit to calculate the modifier of a state (ex : REGENERATE_HP_RATE...). To reduce cache memory use,
- * L2NPCInstances who don't have skills share the same Calculator set called <B>NPC_STD_CALCULATOR</B>.<BR>
- * <BR>
- * That's why, if a L2NPCInstance is under a skill/spell effect that modify one of its state, a copy of the NPC_STD_CALCULATOR must be create in its _calculators before addind new Func object.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Remove all Func objects of the selected owner from _calculators</li><BR>
- * <BR>
- * <li>If L2Character is a L2NPCInstance and _calculators is equal to NPC_STD_CALCULATOR, free cache memory and just create a link on NPC_STD_CALCULATOR in _calculators</li><BR>
- * <BR>
- * <B><U> Example of use </U> :</B><BR>
- * <BR>
- * <li>Unequip an item from inventory</li> <li>Stop an active skill</li><BR>
- * <BR>
- * @param owner The Object(Skill, Item...) that has created the effect
- */
- public final void removeStatsOwner(final Object owner)
- {
- FastList<Stats> modifiedStats = null;
- int i = 0;
- // Go through the Calculator set
- synchronized (_calculators)
- {
- for (final Calculator calc : _calculators)
- {
- if (calc != null)
- {
- // Delete all Func objects of the selected owner
- if (modifiedStats != null)
- {
- modifiedStats.addAll(calc.removeOwner(owner));
- }
- else
- {
- modifiedStats = calc.removeOwner(owner);
- }
- if (calc.size() == 0)
- {
- _calculators[i] = null;
- }
- }
- i++;
- }
- // If possible, free the memory and just create a link on NPC_STD_CALCULATOR
- if (this instanceof L2NpcInstance)
- {
- i = 0;
- for (; i < Stats.NUM_STATS; i++)
- {
- if (!Calculator.equalsCals(_calculators[i], NPC_STD_CALCULATOR[i]))
- {
- break;
- }
- }
- if (i >= Stats.NUM_STATS)
- {
- _calculators = NPC_STD_CALCULATOR;
- }
- }
- if (owner instanceof L2Effect && !((L2Effect) owner).preventExitUpdate)
- {
- broadcastModifiedStats(modifiedStats);
- }
- }
- modifiedStats = null;
- }
- /**
- * Broadcast modified stats.
- * @param stats the stats
- */
- public void broadcastModifiedStats(final FastList<Stats> stats)
- {
- if (stats == null || stats.isEmpty())
- return;
- boolean broadcastFull = false;
- boolean otherStats = false;
- StatusUpdate su = null;
- for (final Stats stat : stats)
- {
- if (stat == Stats.POWER_ATTACK_SPEED)
- {
- if (su == null)
- {
- su = new StatusUpdate(getObjectId());
- }
- su.addAttribute(StatusUpdate.ATK_SPD, getPAtkSpd());
- }
- else if (stat == Stats.MAGIC_ATTACK_SPEED)
- {
- if (su == null)
- {
- su = new StatusUpdate(getObjectId());
- }
- su.addAttribute(StatusUpdate.CAST_SPD, getMAtkSpd());
- }
- // else if (stat==Stats.MAX_HP) //
- // {
- // if (su == null) su = new StatusUpdate(getObjectId());
- // su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
- // }
- else if (stat == Stats.MAX_CP)
- {
- if (this instanceof L2PcInstance)
- {
- if (su == null)
- {
- su = new StatusUpdate(getObjectId());
- }
- su.addAttribute(StatusUpdate.MAX_CP, getMaxCp());
- }
- }
- // else if (stat==Stats.MAX_MP)
- // {
- // if (su == null) su = new StatusUpdate(getObjectId());
- // su.addAttribute(StatusUpdate.MAX_MP, getMaxMp());
- // }
- else if (stat == Stats.RUN_SPEED)
- {
- broadcastFull = true;
- }
- else
- {
- otherStats = true;
- }
- }
- if (this instanceof L2PcInstance)
- {
- if (broadcastFull)
- {
- ((L2PcInstance) this).updateAndBroadcastStatus(2);
- }
- else
- {
- if (otherStats)
- {
- ((L2PcInstance) this).updateAndBroadcastStatus(1);
- if (su != null)
- {
- for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
- {
- try
- {
- player.sendPacket(su);
- }
- catch (final NullPointerException e)
- {
- e.printStackTrace();
- }
- }
- }
- }
- else if (su != null)
- {
- broadcastPacket(su);
- }
- }
- }
- else if (this instanceof L2NpcInstance)
- {
- if (broadcastFull && getKnownList() != null && getKnownList().getKnownPlayers() != null)
- {
- for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
- if (player != null)
- {
- player.sendPacket(new NpcInfo((L2NpcInstance) this, player));
- }
- }
- else if (su != null)
- {
- broadcastPacket(su);
- }
- }
- else if (this instanceof L2Summon)
- {
- if (broadcastFull)
- {
- for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
- if (player != null)
- {
- player.sendPacket(new NpcInfo((L2Summon) this, player));
- }
- }
- else if (su != null)
- {
- broadcastPacket(su);
- }
- }
- else if (su != null)
- {
- broadcastPacket(su);
- }
- su = null;
- }
- /**
- * Return the orientation of the L2Character.<BR>
- * <BR>
- * @return the heading
- */
- public final int getHeading()
- {
- return _heading;
- }
- /**
- * Set the orientation of the L2Character.<BR>
- * <BR>
- * @param heading the new heading
- */
- public final void setHeading(final int heading)
- {
- _heading = heading;
- }
- /**
- * Return the X destination of the L2Character or the X position if not in movement.<BR>
- * <BR>
- * @return the client x
- */
- public final int getClientX()
- {
- return _clientX;
- }
- /**
- * Gets the client y.
- * @return the client y
- */
- public final int getClientY()
- {
- return _clientY;
- }
- /**
- * Gets the client z.
- * @return the client z
- */
- public final int getClientZ()
- {
- return _clientZ;
- }
- /**
- * Gets the client heading.
- * @return the client heading
- */
- public final int getClientHeading()
- {
- return _clientHeading;
- }
- /**
- * Sets the client x.
- * @param val the new client x
- */
- public final void setClientX(final int val)
- {
- _clientX = val;
- }
- /**
- * Sets the client y.
- * @param val the new client y
- */
- public final void setClientY(final int val)
- {
- _clientY = val;
- }
- /**
- * Sets the client z.
- * @param val the new client z
- */
- public final void setClientZ(final int val)
- {
- _clientZ = val;
- }
- /**
- * Sets the client heading.
- * @param val the new client heading
- */
- public final void setClientHeading(final int val)
- {
- _clientHeading = val;
- }
- /**
- * Gets the xdestination.
- * @return the xdestination
- */
- public final int getXdestination()
- {
- final MoveData m = _move;
- if (m != null)
- return m._xDestination;
- return getX();
- }
- /**
- * Return the Y destination of the L2Character or the Y position if not in movement.<BR>
- * <BR>
- * @return the ydestination
- */
- public final int getYdestination()
- {
- final MoveData m = _move;
- if (m != null)
- return m._yDestination;
- return getY();
- }
- /**
- * Return the Z destination of the L2Character or the Z position if not in movement.<BR>
- * <BR>
- * @return the zdestination
- */
- public final int getZdestination()
- {
- final MoveData m = _move;
- if (m != null)
- return m._zDestination;
- return getZ();
- }
- /**
- * Return True if the L2Character is in combat.<BR>
- * <BR>
- * @return true, if is in combat
- */
- public boolean isInCombat()
- {
- return (getAI().getAttackTarget() != null || getAI().isAutoAttacking());
- }
- /**
- * Return True if the L2Character is moving.<BR>
- * <BR>
- * @return true, if is moving
- */
- public final boolean isMoving()
- {
- return _move != null;
- }
- /**
- * Return True if the L2Character is travelling a calculated path.<BR>
- * <BR>
- * @return true, if is on geodata path
- */
- public final boolean isOnGeodataPath()
- {
- final MoveData move = _move;
- if (move == null)
- return false;
- try
- {
- if (move.onGeodataPathIndex == -1)
- return false;
- if (move.onGeodataPathIndex == move.geoPath.length - 1)
- return false;
- }
- catch (final NullPointerException e)
- {
- e.printStackTrace();
- return false;
- }
- return true;
- }
- /**
- * Return True if the L2Character is casting.<BR>
- * <BR>
- * @return true, if is casting now
- */
- public final boolean isCastingNow()
- {
- final L2Effect mog = getFirstEffect(L2Effect.EffectType.SIGNET_GROUND);
- if (mog != null)
- {
- return true;
- }
- return _castEndTime > GameTimeController.getGameTicks();
- }
- /**
- * Return True if the L2Character is casting.<BR>
- * <BR>
- * @return true, if is casting potion now
- */
- public final boolean isCastingPotionNow()
- {
- return _castPotionEndTime > GameTimeController.getGameTicks();
- }
- /**
- * Return True if the cast of the L2Character can be aborted.<BR>
- * <BR>
- * @return true, if successful
- */
- public final boolean canAbortCast()
- {
- return _castInterruptTime > GameTimeController.getGameTicks();
- }
- /**
- * Return True if the L2Character is attacking.<BR>
- * <BR>
- * @return true, if is attacking now
- */
- public final boolean isAttackingNow()
- {
- return _attackEndTime > GameTimeController.getGameTicks();
- }
- /**
- * Return True if the L2Character has aborted its attack.<BR>
- * <BR>
- * @return true, if is attack aborted
- */
- public final boolean isAttackAborted()
- {
- return _attacking <= 0;
- }
- /**
- * Abort the attack of the L2Character and send Server->Client ActionFailed packet.<BR>
- * <BR>
- * see com.l2jlegacy.gameserver.model.L2Character
- */
- public final void abortAttack()
- {
- if (isAttackingNow())
- {
- _attacking = 0;
- sendPacket(ActionFailed.STATIC_PACKET);
- }
- }
- /**
- * Returns body part (paperdoll slot) we are targeting right now.
- * @return the attacking body part
- */
- public final int getAttackingBodyPart()
- {
- return _attacking;
- }
- /**
- * Abort the cast of the L2Character and send Server->Client MagicSkillCanceld/ActionFailed packet.<BR>
- * <BR>
- */
- public final void abortCast()
- {
- abortCast(false);
- }
- /**
- * Abort the cast of the L2Character and send Server->Client MagicSkillCanceld/ActionFailed packet.<BR>
- * <BR>
- * @param force the force
- */
- public final void abortCast(final boolean force)
- {
- if (isCastingNow() || force)
- {
- _castEndTime = 0;
- _castInterruptTime = 0;
- if (_skillCast != null)
- {
- _skillCast.cancel(true);
- _skillCast = null;
- }
- if (getForceBuff() != null)
- {
- getForceBuff().onCastAbort();
- }
- final L2Effect mog = getFirstEffect(L2Effect.EffectType.SIGNET_GROUND);
- if (mog != null)
- {
- mog.exit(true);
- }
- // cancels the skill hit scheduled task
- enableAllSkills(); // re-enables the skills
- if (this instanceof L2PcInstance)
- {
- getAI().notifyEvent(CtrlEvent.EVT_FINISH_CASTING); // setting back previous intention
- }
- broadcastPacket(new MagicSkillCanceld(getObjectId())); // broadcast packet to stop animations client-side
- sendPacket(ActionFailed.STATIC_PACKET); // send an "action failed" packet to the caster
- }
- /*
- * can't abort potion cast if(isCastingPotionNow()){ _castPotionEndTime = 0; _castPotionInterruptTime = 0; if(_potionCast != null) { _potionCast.cancel(true); _potionCast = null; } }
- */
- }
- /**
- * Update the position of the L2Character during a movement and return True if the movement is finished.<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * At the beginning of the move action, all properties of the movement are stored in the MoveData object called <B>_move</B> of the L2Character. The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.<BR>
- * <BR>
- * When the movement is started (ex : by MovetoLocation), this method will be called each 0.1 sec to estimate and update the L2Character position on the server. Note, that the current server position can differe from the current client position even if each movement is straight foward. That's
- * why, client send regularly a Client->Server ValidatePosition packet to eventually correct the gap on the server. But, it's always the server position that is used in range calculation.<BR>
- * <BR>
- * At the end of the estimated movement time, the L2Character position is automatically set to the destination position even if the movement is not finished.<BR>
- * <BR>
- * <FONT COLOR=#FF0000><B> <U>Caution</U> : The current Z position is obtained FROM THE CLIENT by the Client->Server ValidatePosition Packet. But x and y positions must be calculated to avoid that players try to modify their movement speed.</B></FONT><BR>
- * <BR>
- * @param gameTicks Nb of ticks since the server start
- * @return True if the movement is finished
- */
- public boolean updatePosition(final int gameTicks)
- {
- // Get movement data
- final MoveData m = _move;
- if (m == null)
- return true;
- if (!isVisible())
- {
- _move = null;
- return true;
- }
- if (m._moveTimestamp == 0)
- {
- m._moveTimestamp = m._moveStartTime;
- m._xAccurate = getX();
- m._yAccurate = getY();
- }
- // Check if the position has alreday be calculated
- if (m._moveTimestamp == gameTicks)
- return false;
- final int xPrev = getX();
- final int yPrev = getY();
- int zPrev = getZ();
- double dx, dy, dz, distFraction;
- if (Config.COORD_SYNCHRONIZE == 1)
- // the only method that can modify x,y while moving (otherwise _move would/should be set null)
- {
- dx = m._xDestination - xPrev;
- dy = m._yDestination - yPrev;
- }
- else
- // otherwise we need saved temporary values to avoid rounding errors
- {
- dx = m._xDestination - m._xAccurate;
- dy = m._yDestination - m._yAccurate;
- }
- // Z coordinate will follow geodata or client values
- if (Config.GEODATA > 0 && Config.COORD_SYNCHRONIZE == 2 && !isFlying() && !isInsideZone(L2Character.ZONE_WATER) && !m.disregardingGeodata && GameTimeController.getGameTicks() % 10 == 0 // once a second to reduce possible cpu load
- && !(this instanceof L2BoatInstance))
- {
- final short geoHeight = GeoData.getInstance().getSpawnHeight(xPrev, yPrev, zPrev - 30, zPrev + 30, getObjectId());
- dz = m._zDestination - geoHeight;
- // quite a big difference, compare to validatePosition packet
- if (this instanceof L2PcInstance && Math.abs(((L2PcInstance) this).getClientZ() - geoHeight) > 200 && Math.abs(((L2PcInstance) this).getClientZ() - geoHeight) < 1500)
- {
- dz = m._zDestination - zPrev; // allow diff
- }
- else if (isInCombat() && Math.abs(dz) > 200 && dx * dx + dy * dy < 40000) // allow mob to climb up to pcinstance
- {
- dz = m._zDestination - zPrev; // climbing
- }
- else
- {
- zPrev = geoHeight;
- }
- }
- else
- {
- dz = m._zDestination - zPrev;
- }
- float speed;
- if (this instanceof L2BoatInstance)
- {
- speed = ((L2BoatInstance) this).boatSpeed;
- }
- else
- {
- speed = getStat().getMoveSpeed();
- }
- final double distPassed = speed * (gameTicks - m._moveTimestamp) / GameTimeController.TICKS_PER_SECOND;
- if (dx * dx + dy * dy < 10000 && dz * dz > 2500) // close enough, allows error between client and server geodata if it cannot be avoided
- {
- distFraction = distPassed / Math.sqrt(dx * dx + dy * dy);
- }
- else
- {
- distFraction = distPassed / Math.sqrt(dx * dx + dy * dy + dz * dz);
- }
- // if (Config.DEVELOPER) LOGGER.warn("Move Ticks:" + (gameTicks - m._moveTimestamp) + ", distPassed:" + distPassed + ", distFraction:" + distFraction);
- if (distFraction > 1) // already there
- {
- // Set the position of the L2Character to the destination
- super.getPosition().setXYZ(m._xDestination, m._yDestination, m._zDestination);
- if (this instanceof L2BoatInstance)
- {
- ((L2BoatInstance) this).updatePeopleInTheBoat(m._xDestination, m._yDestination, m._zDestination);
- }
- else
- {
- revalidateZone();
- }
- }
- else
- {
- m._xAccurate += dx * distFraction;
- m._yAccurate += dy * distFraction;
- // Set the position of the L2Character to estimated after parcial move
- super.getPosition().setXYZ((int) m._xAccurate, (int) m._yAccurate, zPrev + (int) (dz * distFraction + 0.5));
- if (this instanceof L2BoatInstance)
- {
- ((L2BoatInstance) this).updatePeopleInTheBoat((int) m._xAccurate, (int) m._yAccurate, zPrev + (int) (dz * distFraction + 0.5));
- }
- else
- {
- revalidateZone();
- }
- }
- // Set the timer of last position update to now
- m._moveTimestamp = gameTicks;
- return distFraction > 1;
- }
- /**
- * Revalidate zone.
- */
- public void revalidateZone()
- {
- if (getWorldRegion() == null)
- return;
- getWorldRegion().revalidateZones(this);
- }
- /**
- * Stop movement of the L2Character (Called by AI Accessor only).<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Delete movement data of the L2Character</li> <li>Set the current position (x,y,z), its current L2WorldRegion if necessary and its heading</li> <li>Remove the L2Object object from _gmList** of GmListTable</li> <li>Remove object from _knownObjects and _knownPlayer* of all surrounding
- * L2WorldRegion L2Characters</li><BR>
- * <BR>
- * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T send Server->Client packet StopMove/StopRotation </B></FONT><BR>
- * <BR>
- * @param pos the pos
- */
- public void stopMove(final L2CharPosition pos)
- {
- stopMove(pos, true);
- }
- /**
- * TODO: test broadcast head packets ffro !in boat.
- * @param pos the pos
- * @param updateKnownObjects the update known objects
- */
- public void stopMove(final L2CharPosition pos, final boolean updateKnownObjects)
- {
- // Delete movement data of the L2Character
- _move = null;
- // Set AI_INTENTION_IDLE
- if (this instanceof L2PcInstance && getAI() != null)
- ((L2PcInstance) this).getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
- // Set the current position (x,y,z), its current L2WorldRegion if necessary and its heading
- // All data are contained in a L2CharPosition object
- if (pos != null)
- {
- getPosition().setXYZ(pos.x, pos.y, GeoData.getInstance().getHeight(pos.x, pos.y, pos.z));
- setHeading(pos.heading);
- if (this instanceof L2PcInstance)
- {
- ((L2PcInstance) this).revalidateZone(true);
- if (((L2PcInstance) this).isInBoat())
- broadcastPacket(new ValidateLocationInVehicle(this));
- }
- }
- broadcastPacket(new StopMove(this));
- if (updateKnownObjects)
- ThreadPoolManager.getInstance().executeTask(new KnownListAsynchronousUpdateTask(this));
- }
- /**
- * Target a L2Object (add the target to the L2Character _target, _knownObject and L2Character to _KnownObject of the L2Object).<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * The L2Object (including L2Character) targeted is identified in <B>_target</B> of the L2Character<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Set the _target of L2Character to L2Object</li> <li>If necessary, add L2Object to _knownObject of the L2Character</li> <li>If necessary, add L2Character to _KnownObject of the L2Object</li> <li>If object==null, cancel Attak or Cast</li><BR>
- * <BR>
- * <B><U> Overriden in </U> :</B><BR>
- * <BR>
- * <li>L2PcInstance : Remove the L2PcInstance from the old target _statusListener and add it to the new target if it was a L2Character</li><BR>
- * <BR>
- * @param object L2object to target
- */
- public void setTarget(L2Object object)
- {
- if (object != null && !object.isVisible())
- {
- object = null;
- }
- if (object != null && object != _target)
- {
- getKnownList().addKnownObject(object);
- object.getKnownList().addKnownObject(this);
- }
- // If object==null, Cancel Attak or Cast
- if (object == null)
- {
- if (_target != null)
- {
- final TargetUnselected my = new TargetUnselected(this);
- // No need to broadcast the packet to all players
- if (this instanceof L2PcInstance)
- {
- // Send packet just to me and to party, not to any other that does not use the information
- if (!this.isInParty())
- {
- this.sendPacket(my);
- }
- else
- {
- this.getParty().broadcastToPartyMembers(my);
- }
- }
- else
- {
- sendPacket(new TargetUnselected(this));
- }
- }
- }
- _target = object;
- }
- /**
- * Return the identifier of the L2Object targeted or -1.<BR>
- * <BR>
- * @return the target id
- */
- public final int getTargetId()
- {
- if (_target != null)
- return _target.getObjectId();
- return -1;
- }
- /**
- * Return the L2Object targeted or null.<BR>
- * <BR>
- * @return the target
- */
- public final L2Object getTarget()
- {
- return _target;
- }
- // called from AIAccessor only
- /**
- * Calculate movement data for a move to location action and add the L2Character to movingObjects of GameTimeController (only called by AI Accessor).<BR>
- * <BR>
- * <B><U> Concept</U> :</B><BR>
- * <BR>
- * At the beginning of the move action, all properties of the movement are stored in the MoveData object called <B>_move</B> of the L2Character. The position of the start point and of the destination permit to estimated in function of the movement speed the time to achieve the destination.<BR>
- * <BR>
- * All L2Character in movement are identified in <B>movingObjects</B> of GameTimeController that will call the updatePosition method of those L2Character each 0.1s.<BR>
- * <BR>
- * <B><U> Actions</U> :</B><BR>
- * <BR>
- * <li>Get current position of the L2Character</li> <li>Calculate distance (dx,dy) between current position and destination including offset</li> <li>Create and Init a MoveData object</li> <li>Set the L2Character _move object to MoveData object</li> <li>Add the L2Character to movingObjects of
- * the GameTimeController</li> <li>Create a task to notify the AI that L2Character arrives at a check point of the movement</li><BR>
- * <BR>
- * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T send Server->Client packet MoveToPawn/CharMoveToLocation </B></FONT><BR>
- * <BR>
- * <B><U> Example of use </U> :</B><BR>
- * <BR>
- * <li>AI : onIntentionMoveTo(L2CharPosition), onIntentionPickUp(L2Object), onIntentionInteract(L2Object)</li> <li>FollowTask</li><BR>
- * <BR>
- * @param x The X position of the destination
- * @param y The Y position of the destination
- * @param z The Y position of the destination
- * @param offset The size of the interaction area of the L2Character targeted
- */
- protected void moveToLocation(int x, int y, int z, int offset)
- {
- // Block movment during Event start
- if (this instanceof L2PcInstance)
- {
- if (L2Event.active && ((L2PcInstance) this).eventSitForced)
- {
- ((L2PcInstance) this).sendMessage("A dark force beyond your mortal understanding makes your knees to shake when you try to stand up...");
- ((L2PcInstance) this).getClient().sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- else if ((TvT.is_sitForced() && ((L2PcInstance) this)._inEventTvT) || (CTF.is_sitForced() && ((L2PcInstance) this)._inEventCTF) || (DM.is_sitForced() && ((L2PcInstance) this)._inEventDM))
- {
- ((L2PcInstance) this).sendMessage("A dark force beyond your mortal understanding makes your knees to shake when you try to stand up...");
- ((L2PcInstance) this).getClient().sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- else if (VIP._sitForced && ((L2PcInstance) this)._inEventVIP)
- {
- ((L2PcInstance) this).sendMessage("A dark force beyond your mortal understanding makes your knees to shake when you try to stand up...");
- ((L2PcInstance) this).sendPacket(ActionFailed.STATIC_PACKET);
- return;
- }
- }
- // when start to move again, it has to stop sitdown task
- if (this instanceof L2PcInstance)
- ((L2PcInstance) this).setPosticipateSit(false);
- // Fix archer bug with movment/hittask
- if (this instanceof L2PcInstance && this.isAttackingNow())
- {
- final L2ItemInstance rhand = ((L2PcInstance) this).getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
- if ((rhand != null && rhand.getItemType() == L2WeaponType.BOW))
- return;
- }
- // Get the Move Speed of the L2Charcater
- final float speed = getStat().getMoveSpeed();
- if (speed <= 0 || isMovementDisabled())
- return;
- // Get current position of the L2Character
- final int curX = super.getX();
- final int curY = super.getY();
- final int curZ = super.getZ();
- // Calculate distance (dx,dy) between current position and destination
- //
- double dx = x - curX;
- double dy = y - curY;
- double dz = z - curZ;
- double distance = Math.sqrt(dx * dx + dy * dy);
- if (Config.GEODATA > 0 && isInsideZone(ZONE_WATER) && distance > 700)
- {
- final double divider = 700 / distance;
- x = curX + (int) (divider * dx);
- y = curY + (int) (divider * dy);
- z = curZ + (int) (divider * dz);
- dx = x - curX;
- dy = y - curY;
- dz = z - curZ;
- distance = Math.sqrt(dx * dx + dy * dy);
- }
- /*
- * if(Config.DEBUG) { LOGGER.fine("distance to target:" + distance); }
- &nbs