· 7 years ago · Jan 19, 2019, 11:48 AM
1/*
2 * L2jFrozen Project - www.l2jfrozen.com
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
18 *
19 * http://www.gnu.org/copyleft/gpl.html
20 */
21package com.l2jfrozen.gameserver.model;
22
23import static com.l2jfrozen.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
24import static com.l2jfrozen.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
25
26import java.util.Collections;
27import java.util.Iterator;
28import java.util.List;
29import java.util.Map;
30import java.util.concurrent.Future;
31
32import javolution.util.FastList;
33import javolution.util.FastMap;
34import javolution.util.FastTable;
35
36import org.apache.log4j.Logger;
37
38import com.l2jfrozen.Config;
39import com.l2jfrozen.gameserver.ai.CtrlEvent;
40import com.l2jfrozen.gameserver.ai.CtrlIntention;
41import com.l2jfrozen.gameserver.ai.L2AttackableAI;
42import com.l2jfrozen.gameserver.ai.L2CharacterAI;
43import com.l2jfrozen.gameserver.controllers.GameTimeController;
44import com.l2jfrozen.gameserver.datatables.HeroSkillTable;
45import com.l2jfrozen.gameserver.datatables.SkillTable;
46import com.l2jfrozen.gameserver.datatables.csv.DoorTable;
47import com.l2jfrozen.gameserver.datatables.csv.MapRegionTable;
48import com.l2jfrozen.gameserver.datatables.csv.MapRegionTable.TeleportWhereType;
49import com.l2jfrozen.gameserver.datatables.sql.NpcTable;
50import com.l2jfrozen.gameserver.geo.GeoData;
51import com.l2jfrozen.gameserver.geo.pathfinding.Node;
52import com.l2jfrozen.gameserver.geo.pathfinding.PathFinding;
53import com.l2jfrozen.gameserver.handler.ISkillHandler;
54import com.l2jfrozen.gameserver.handler.SkillHandler;
55import com.l2jfrozen.gameserver.handler.itemhandlers.Potions;
56import com.l2jfrozen.gameserver.managers.DimensionalRiftManager;
57import com.l2jfrozen.gameserver.managers.DuelManager;
58import com.l2jfrozen.gameserver.managers.GrandBossManager;
59import com.l2jfrozen.gameserver.managers.RaidBossSpawnManager;
60import com.l2jfrozen.gameserver.managers.TownManager;
61import com.l2jfrozen.gameserver.model.L2Skill.SkillTargetType;
62import com.l2jfrozen.gameserver.model.L2Skill.SkillType;
63import com.l2jfrozen.gameserver.model.actor.instance.L2BoatInstance;
64import com.l2jfrozen.gameserver.model.actor.instance.L2ControlTowerInstance;
65import com.l2jfrozen.gameserver.model.actor.instance.L2DoorInstance;
66import com.l2jfrozen.gameserver.model.actor.instance.L2EffectPointInstance;
67import com.l2jfrozen.gameserver.model.actor.instance.L2GrandBossInstance;
68import com.l2jfrozen.gameserver.model.actor.instance.L2GuardInstance;
69import com.l2jfrozen.gameserver.model.actor.instance.L2ItemInstance;
70import com.l2jfrozen.gameserver.model.actor.instance.L2MinionInstance;
71import com.l2jfrozen.gameserver.model.actor.instance.L2MonsterInstance;
72import com.l2jfrozen.gameserver.model.actor.instance.L2NpcInstance;
73import com.l2jfrozen.gameserver.model.actor.instance.L2NpcWalkerInstance;
74import com.l2jfrozen.gameserver.model.actor.instance.L2PcInstance;
75import com.l2jfrozen.gameserver.model.actor.instance.L2PcInstance.SkillDat;
76import com.l2jfrozen.gameserver.model.actor.instance.L2PetInstance;
77import com.l2jfrozen.gameserver.model.actor.instance.L2PlayableInstance;
78import com.l2jfrozen.gameserver.model.actor.instance.L2RaidBossInstance;
79import com.l2jfrozen.gameserver.model.actor.instance.L2RiftInvaderInstance;
80import com.l2jfrozen.gameserver.model.actor.instance.L2SiegeFlagInstance;
81import com.l2jfrozen.gameserver.model.actor.instance.L2SummonInstance;
82import com.l2jfrozen.gameserver.model.actor.knownlist.CharKnownList;
83import com.l2jfrozen.gameserver.model.actor.knownlist.ObjectKnownList.KnownListAsynchronousUpdateTask;
84import com.l2jfrozen.gameserver.model.actor.position.L2CharPosition;
85import com.l2jfrozen.gameserver.model.actor.position.ObjectPosition;
86import com.l2jfrozen.gameserver.model.actor.stat.CharStat;
87import com.l2jfrozen.gameserver.model.actor.status.CharStatus;
88import com.l2jfrozen.gameserver.model.entity.Duel;
89import com.l2jfrozen.gameserver.model.entity.event.CTF;
90import com.l2jfrozen.gameserver.model.entity.event.DM;
91import com.l2jfrozen.gameserver.model.entity.event.L2Event;
92import com.l2jfrozen.gameserver.model.entity.event.TvT;
93import com.l2jfrozen.gameserver.model.entity.event.VIP;
94import com.l2jfrozen.gameserver.model.entity.olympiad.Olympiad;
95import com.l2jfrozen.gameserver.model.extender.BaseExtender.EventType;
96import com.l2jfrozen.gameserver.model.quest.Quest;
97import com.l2jfrozen.gameserver.model.quest.QuestState;
98import com.l2jfrozen.gameserver.model.zone.type.L2BossZone;
99import com.l2jfrozen.gameserver.model.zone.type.L2TownZone;
100import com.l2jfrozen.gameserver.network.SystemMessageId;
101import com.l2jfrozen.gameserver.network.serverpackets.ActionFailed;
102import com.l2jfrozen.gameserver.network.serverpackets.Attack;
103import com.l2jfrozen.gameserver.network.serverpackets.BeginRotation;
104import com.l2jfrozen.gameserver.network.serverpackets.ChangeMoveType;
105import com.l2jfrozen.gameserver.network.serverpackets.ChangeWaitType;
106import com.l2jfrozen.gameserver.network.serverpackets.CharInfo;
107import com.l2jfrozen.gameserver.network.serverpackets.CharMoveToLocation;
108import com.l2jfrozen.gameserver.network.serverpackets.ExOlympiadSpelledInfo;
109import com.l2jfrozen.gameserver.network.serverpackets.L2GameServerPacket;
110import com.l2jfrozen.gameserver.network.serverpackets.MagicEffectIcons;
111import com.l2jfrozen.gameserver.network.serverpackets.MagicSkillCanceld;
112import com.l2jfrozen.gameserver.network.serverpackets.MagicSkillLaunched;
113import com.l2jfrozen.gameserver.network.serverpackets.MagicSkillUser;
114import com.l2jfrozen.gameserver.network.serverpackets.MyTargetSelected;
115import com.l2jfrozen.gameserver.network.serverpackets.NpcInfo;
116import com.l2jfrozen.gameserver.network.serverpackets.PartySpelled;
117import com.l2jfrozen.gameserver.network.serverpackets.PetInfo;
118import com.l2jfrozen.gameserver.network.serverpackets.RelationChanged;
119import com.l2jfrozen.gameserver.network.serverpackets.Revive;
120import com.l2jfrozen.gameserver.network.serverpackets.SetupGauge;
121import com.l2jfrozen.gameserver.network.serverpackets.StatusUpdate;
122import com.l2jfrozen.gameserver.network.serverpackets.StopMove;
123import com.l2jfrozen.gameserver.network.serverpackets.SystemMessage;
124import com.l2jfrozen.gameserver.network.serverpackets.TargetUnselected;
125import com.l2jfrozen.gameserver.network.serverpackets.TeleportToLocation;
126import com.l2jfrozen.gameserver.network.serverpackets.ValidateLocation;
127import com.l2jfrozen.gameserver.network.serverpackets.ValidateLocationInVehicle;
128import com.l2jfrozen.gameserver.skills.Calculator;
129import com.l2jfrozen.gameserver.skills.Formulas;
130import com.l2jfrozen.gameserver.skills.Stats;
131import com.l2jfrozen.gameserver.skills.effects.EffectCharge;
132import com.l2jfrozen.gameserver.skills.funcs.Func;
133import com.l2jfrozen.gameserver.skills.holders.ISkillsHolder;
134import com.l2jfrozen.gameserver.templates.L2CharTemplate;
135import com.l2jfrozen.gameserver.templates.L2NpcTemplate;
136import com.l2jfrozen.gameserver.templates.L2Weapon;
137import com.l2jfrozen.gameserver.templates.L2WeaponType;
138import com.l2jfrozen.gameserver.templates.StatsSet;
139import com.l2jfrozen.gameserver.thread.ThreadPoolManager;
140import com.l2jfrozen.gameserver.util.Util;
141import com.l2jfrozen.util.Point3D;
142import com.l2jfrozen.util.random.Rnd;
143
144/**
145 * Mother class of all character objects of the world (PC, NPC...)<BR>
146 * <BR>
147 * L2Character :<BR>
148 * <BR>
149 * <li>L2CastleGuardInstance</li> <li>L2DoorInstance</li> <li>L2NpcInstance</li> <li>L2PlayableInstance</li><BR>
150 * <BR>
151 * <B><U> Concept of L2CharTemplate</U> :</B><BR>
152 * <BR>
153 * 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
154 * L2Character is spawned, server just create a link between the instance and the template. This link is stored in <B>_template</B><BR>
155 * <BR>
156 * @version $Revision: 1.5.5 $ $Date: 2009/05/12 19:45:27 $
157 * @authors eX1steam, programmos, L2Scoria dev&sword dev
158 */
159public abstract class L2Character extends L2Object implements ISkillsHolder
160{
161 /** The Constant LOGGER. */
162 protected static final Logger LOGGER = Logger.getLogger(L2Character.class);
163
164 // =========================================================
165 // Data Field
166 /** The attack stance. */
167 private long attackStance;
168
169 /** The _attack by list. */
170 private List<L2Character> _attackByList;
171 // private L2Character _attackingChar;
172 /** The _last skill cast. */
173 private L2Skill _lastSkillCast;
174
175 /** The _last potion cast. */
176 private L2Skill _lastPotionCast;
177
178 /** The _is buff protected. */
179 private boolean _isBuffProtected = false; // Protect From Debuffs
180
181 /** The _is afraid. */
182 private boolean _isAfraid = false; // Flee in a random direction
183
184 /** The _is confused. */
185 private boolean _isConfused = false; // Attack anyone randomly
186
187 /** The _is fake death. */
188 private boolean _isFakeDeath = false; // Fake death
189
190 /** The _is flying. */
191 private boolean _isFlying = false; // Is flying Wyvern?
192
193 /** The _is fallsdown. */
194 private boolean _isFallsdown = false; // Falls down
195
196 /** The _is muted. */
197 private boolean _isMuted = false; // Cannot use magic
198
199 /** The _is psychical muted. */
200 private boolean _isPsychicalMuted = false; // Cannot use psychical skills
201
202 /** The _is killed already. */
203 private boolean _isKilledAlready = false;
204
205 /** The _is imobilised. */
206 private int _isImobilised = 0;
207
208 /** The _is overloaded. */
209 private boolean _isOverloaded = false; // the char is carrying too much
210
211 /** The _is paralyzed. */
212 private boolean _isParalyzed = false;
213
214 /** The _is riding. */
215 private boolean _isRiding = false; // Is Riding strider?
216
217 /** The _is pending revive. */
218 private boolean _isPendingRevive = false;
219
220 /** The _is rooted. */
221 private boolean _isRooted = false; // Cannot move until root timed out
222
223 /** The _is running. */
224 private boolean _isRunning = false;
225
226 /** The _is immobile until attacked. */
227 private boolean _isImmobileUntilAttacked = false; // Is in immobile until attacked.
228
229 /** The _is sleeping. */
230 private boolean _isSleeping = false; // Cannot move/attack until sleep timed out or monster is attacked
231
232 /** The _is stunned. */
233 private boolean _isStunned = false; // Cannot move/attack until stun timed out
234
235 /** The _is betrayed. */
236 private boolean _isBetrayed = false; // Betrayed by own summon
237
238 /** The _is block buff. */
239 private boolean _isBlockBuff = false; // Got blocked buff bar
240
241 /** The _is block debuff. */
242 private boolean _isBlockDebuff = false; // Got blocked debuff bar
243
244 /** The _is teleporting. */
245 protected boolean _isTeleporting = false;
246
247 /** The _is invul. */
248 protected boolean _isInvul = false;
249
250 /** The _is killable */
251 protected boolean _isUnkillable = false;
252
253 /** The attackDisabled */
254 protected boolean _isAttackDisabled = false;
255
256 /** The _last heal amount. */
257 private int _lastHealAmount = 0;
258
259 /** The _stat. */
260 private CharStat _stat;
261
262 /** The _status. */
263 private CharStatus _status;
264
265 /** The _template. */
266 private L2CharTemplate _template; // The link on the L2CharTemplate object containing generic and static properties of this L2Character type (ex : Max HP, Speed...)
267
268 /** The _title. */
269 private String _title;
270
271 /** The _ai class. */
272 private String _aiClass = "default";
273
274 /** The _hp update inc check. */
275 private double _hpUpdateIncCheck = .0;
276
277 /** The _hp update dec check. */
278 private double _hpUpdateDecCheck = .0;
279
280 /** The _hp update interval. */
281 private double _hpUpdateInterval = .0;
282
283 /** The _champion. */
284 private boolean _champion = false;
285
286 /** Table of Calculators containing all used calculator. */
287 private Calculator[] _calculators;
288
289 /** FastMap(Integer, L2Skill) containing all skills of the L2Character. */
290 protected final Map<Integer, L2Skill> _skills;
291
292 /** FastMap(Integer, L2Skill) containing all triggered skills of the L2PcInstance. */
293 protected final Map<Integer, L2Skill> _triggeredSkills;
294
295 /** FastMap containing the active chance skills on this character. */
296 protected ChanceSkillList _chanceSkills;
297
298 /** Current force buff this caster is casting to a target. */
299 protected ForceBuff _forceBuff;
300
301 /** The _blocked. */
302 private boolean _blocked;
303
304 /** The _meditated. */
305 private boolean _meditated;
306
307 /**
308 * Zone system<br>
309 * x^2 or x*x.
310 */
311 public static final int ZONE_PVP = 1;
312
313 /** The Constant ZONE_PEACE. */
314 public static final int ZONE_PEACE = 2;
315
316 /** The Constant ZONE_SIEGE. */
317 public static final int ZONE_SIEGE = 4;
318
319 /** The Constant ZONE_MOTHERTREE. */
320 public static final int ZONE_MOTHERTREE = 8;
321
322 /** The Constant ZONE_CLANHALL. */
323 public static final int ZONE_CLANHALL = 16;
324
325 /** The Constant ZONE_UNUSED. */
326 public static final int ZONE_UNUSED = 32;
327
328 /** The Constant ZONE_NOLANDING. */
329 public static final int ZONE_NOLANDING = 64;
330
331 /** The Constant ZONE_WATER. */
332 public static final int ZONE_WATER = 128;
333
334 /** The Constant ZONE_JAIL. */
335 public static final int ZONE_JAIL = 256;
336
337 /** The Constant ZONE_MONSTERTRACK. */
338 public static final int ZONE_MONSTERTRACK = 512;
339
340 /** The Constant ZONE_SWAMP. */
341 public static final int ZONE_SWAMP = 1024;
342
343 /** The Constant ZONE_NOSUMMONFRIEND. */
344 public static final int ZONE_NOSUMMONFRIEND = 2048;
345
346 /** The Constant ZONE_OLY. */
347 public static final int ZONE_OLY = 4096;
348
349 /** The Constant ZONE_NOHQ. */
350 public static final int ZONE_NOHQ = 8192;
351
352 /** The Constant ZONE_DANGERAREA. */
353 public static final int ZONE_DANGERAREA = 16384;
354
355 /** The Constant ZONE_NOSTORE. */
356 public static final int ZONE_NOSTORE = 32768;
357
358 /** The Constant ZONE_MULTIFUNCTION. */
359 public static final int ZONE_MULTIFUNCTION= 32;
360
361 /** The _current zones. */
362 private int _currentZones = 0;
363
364 /** Advance Headquarters */
365 private boolean _advanceFlag = false;
366 private int _advanceMultiplier = 1;
367
368 /**
369 * Checks if is inside zone.
370 * @param zone the zone
371 * @return true, if is inside zone
372 */
373 public boolean isInsideZone(final int zone)
374 {
375 return (_currentZones & zone) != 0;
376 }
377
378 /**
379 * Sets the inside zone.
380 * @param zone the zone
381 * @param state the state
382 */
383 public void setInsideZone(final int zone, final boolean state)
384 {
385 if (state)
386 {
387 _currentZones |= zone;
388 }
389 else if (isInsideZone(zone))
390 {
391 _currentZones ^= zone;
392 }
393 }
394
395 /**
396 * This will return true if the player is GM,<br>
397 * but if the player is not GM it will return false.
398 * @return GM status
399 */
400 public boolean charIsGM()
401 {
402 if (this instanceof L2PcInstance)
403 {
404 if (((L2PcInstance) this).isGM())
405 {
406 return true;
407 }
408 }
409 return false;
410 }
411
412 // =========================================================
413 // Constructor
414 /**
415 * Constructor of L2Character.<BR>
416 * <BR>
417 * <B><U> Concept</U> :</B><BR>
418 * <BR>
419 * 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
420 * L2Character is spawned, server just create a link between the instance and the template This link is stored in <B>_template</B><BR>
421 * <BR>
422 * <B><U> Actions</U> :</B><BR>
423 * <BR>
424 * <li>Set the _template of the L2Character</li> <li>Set _overloaded to false (the charcater can take more items)</li> <BR>
425 * <BR>
426 * <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>
427 * <BR>
428 * <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>
429 * <BR>
430 * @param objectId Identifier of the object to initialized
431 * @param template The L2CharTemplate to apply to the object
432 */
433 // MAKE TO US From DREAM
434 // int attackcountmax = (int) Math.round(calcStat(Stats.POLE_TARGERT_COUNT, 3, null, null));
435 public L2Character(final int objectId, final L2CharTemplate template)
436 {
437 super(objectId);
438 getKnownList();
439
440 // Set its template to the new L2Character
441 _template = template;
442
443 _triggeredSkills = new FastMap<>();
444
445 if (template != null && this instanceof L2NpcInstance)
446 {
447 // Copy the Standard Calcultors of the L2NPCInstance in _calculators
448 _calculators = NPC_STD_CALCULATOR;
449
450 // Copy the skills of the L2NPCInstance from its template to the L2Character Instance
451 // The skills list can be affected by spell effects so it's necessary to make a copy
452 // to avoid that a spell affecting a L2NPCInstance, affects others L2NPCInstance of the same type too.
453 _skills = ((L2NpcTemplate) template).getSkills();
454
455 for (final Map.Entry<Integer, L2Skill> skill : _skills.entrySet())
456 {
457 addStatFuncs(skill.getValue().getStatFuncs(null, this));
458 }
459
460 if (!Config.NPC_ATTACKABLE || !(this instanceof L2Attackable) && !(this instanceof L2ControlTowerInstance) && !(this instanceof L2SiegeFlagInstance) && !(this instanceof L2EffectPointInstance))
461 {
462 setIsInvul(true);
463 }
464 }
465 else
466 // not L2NpcInstance
467 {
468 // Initialize the FastMap _skills to null
469 _skills = new FastMap<Integer, L2Skill>().shared();
470
471 // If L2Character is a L2PcInstance or a L2Summon, create the basic calculator set
472 _calculators = new Calculator[Stats.NUM_STATS];
473 Formulas.getInstance().addFuncsToNewCharacter(this);
474
475 if (!(this instanceof L2Attackable) && !this.isAttackable() && !(this instanceof L2DoorInstance))
476 setIsInvul(true);
477 }
478
479 /*
480 * if(!(this instanceof L2PcInstance) && !(this instanceof L2MonsterInstance) && !(this instanceof L2GuardInstance) && !(this instanceof L2SiegeGuardInstance) && !(this instanceof L2ControlTowerInstance) && !(this instanceof L2DoorInstance) && !(this instanceof L2FriendlyMobInstance) &&
481 * !(this instanceof L2SiegeSummonInstance) && !(this instanceof L2PetInstance) && !(this instanceof L2SummonInstance) && !(this instanceof L2SiegeFlagInstance) && !(this instanceof L2EffectPointInstance) && !(this instanceof L2CommanderInstance) && !(this instanceof
482 * L2FortSiegeGuardInstance)) { ///////////////////////////////////////////////////////////////////////////////////////////// setIsInvul(true); }
483 */
484 }
485
486 /**
487 * Inits the char status update values.
488 */
489 protected void initCharStatusUpdateValues()
490 {
491 _hpUpdateInterval = getMaxHp() / 352.0; // MAX_HP div MAX_HP_BAR_PX
492 _hpUpdateIncCheck = getMaxHp();
493 _hpUpdateDecCheck = getMaxHp() - _hpUpdateInterval;
494 }
495
496 // =========================================================
497 // Event - Public
498 /**
499 * Remove the L2Character from the world when the decay task is launched.<BR>
500 * <BR>
501 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T REMOVE the object from _allObjects of L2World </B></FONT><BR>
502 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packets to players</B></FONT><BR>
503 * <BR>
504 */
505 public void onDecay()
506 {
507 L2WorldRegion reg = getWorldRegion();
508
509 if (reg != null)
510 {
511 reg.removeFromZones(this);
512 }
513
514 decayMe();
515
516 reg = null;
517 }
518
519 /*
520 * (non-Javadoc)
521 * @see com.l2jfrozen.gameserver.model.L2Object#onSpawn()
522 */
523 @Override
524 public void onSpawn()
525 {
526 super.onSpawn();
527 revalidateZone();
528 }
529
530 /**
531 * On teleported.
532 */
533 public void onTeleported()
534 {
535 if (!isTeleporting())
536 return;
537
538 final ObjectPosition pos = getPosition();
539
540 if (pos != null)
541 spawnMe(getPosition().getX(), getPosition().getY(), getPosition().getZ());
542
543 setIsTeleporting(false);
544
545 if (_isPendingRevive)
546 {
547 doRevive();
548 }
549
550 final L2Summon pet = getPet();
551
552 // Modify the position of the pet if necessary
553 if (pet != null && pos != null)
554 {
555 pet.setFollowStatus(false);
556 pet.teleToLocation(pos.getX() + Rnd.get(-100, 100), pos.getY() + Rnd.get(-100, 100), pos.getZ(), false);
557 pet.setFollowStatus(true);
558 }
559
560 }
561
562 // =========================================================
563 // Method - Public
564 /**
565 * Add L2Character instance that is attacking to the attacker list.<BR>
566 * <BR>
567 * @param player The L2Character that attcks this one
568 */
569 public void addAttackerToAttackByList(final L2Character player)
570 {
571 if (player == null || player == this || getAttackByList() == null || getAttackByList().contains(player))
572 return;
573
574 getAttackByList().add(player);
575 }
576
577 /**
578 * Send a packet to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character.<BR>
579 * <BR>
580 * <B><U> Concept</U> :</B><BR>
581 * <BR>
582 * 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>
583 * <BR>
584 */
585
586 protected byte _startingRotationCounter = 4;
587
588 /**
589 * Checks if is starting rotation allowed.
590 * @return true, if is starting rotation allowed
591 */
592 public synchronized boolean isStartingRotationAllowed()
593 {
594 // This function is called too often from movement arrow
595 _startingRotationCounter--;
596 if (_startingRotationCounter < 0)
597 _startingRotationCounter = 4;
598
599 if (_startingRotationCounter == 4)
600 {
601 return true;
602 }
603 return false;
604 }
605
606 /**
607 * Broadcast packet.
608 * @param mov the mov
609 */
610 public final void broadcastPacket(final L2GameServerPacket mov)
611 {
612 if (!(mov instanceof CharInfo))
613 {
614 sendPacket(mov);
615 }
616
617 // don't broadcast anytime the rotating packet
618 if (mov instanceof BeginRotation && !isStartingRotationAllowed())
619 {
620 return;
621 }
622
623 // if (Config.DEBUG) LOGGER.fine("players to notify:" + knownPlayers.size() + " packet:"+mov.getType());
624
625 for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
626 {
627 if (player != null)
628 {
629 /*
630 * 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.
631 */
632 if (this instanceof L2PcInstance && !player.isGM() && (((L2PcInstance) this).getAppearance().getInvisible() || ((L2PcInstance) this).inObserverMode()))
633 return;
634
635 try
636 {
637 player.sendPacket(mov);
638
639 if (mov instanceof CharInfo && this instanceof L2PcInstance)
640 {
641 final int relation = ((L2PcInstance) this).getRelation(player);
642 if (getKnownList().getKnownRelations().get(player.getObjectId()) != null && getKnownList().getKnownRelations().get(player.getObjectId()) != relation)
643 {
644 player.sendPacket(new RelationChanged((L2PcInstance) this, relation, player.isAutoAttackable(this)));
645 }
646 }
647 // if(Config.DEVELOPER && !isInsideRadius(player, 3500, false, false)) LOGGER.warn("broadcastPacket: Too far player see event!");
648 }
649 catch (final NullPointerException e)
650 {
651 e.printStackTrace();
652 }
653 }
654 }
655 }
656
657 /**
658 * Send a packet to the L2Character AND to all L2PcInstance in the radius (max knownlist radius) from the L2Character.<BR>
659 * <BR>
660 * <B><U> Concept</U> :</B><BR>
661 * <BR>
662 * 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>
663 * <BR>
664 * @param mov the mov
665 * @param radiusInKnownlist the radius in knownlist
666 */
667 public final void broadcastPacket(final L2GameServerPacket mov, final int radiusInKnownlist)
668 {
669 if (!(mov instanceof CharInfo))
670 {
671 sendPacket(mov);
672 }
673
674 // if (Config.DEBUG) LOGGER.fine("players to notify:" + knownPlayers.size() + " packet:"+mov.getType());
675
676 for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
677 {
678 try
679 {
680 if (!isInsideRadius(player, radiusInKnownlist, false, false))
681 {
682 continue;
683 }
684
685 player.sendPacket(mov);
686
687 if (mov instanceof CharInfo && this instanceof L2PcInstance)
688 {
689 final int relation = ((L2PcInstance) this).getRelation(player);
690 if (getKnownList().getKnownRelations().get(player.getObjectId()) != null && getKnownList().getKnownRelations().get(player.getObjectId()) != relation)
691 {
692 player.sendPacket(new RelationChanged((L2PcInstance) this, relation, player.isAutoAttackable(this)));
693 }
694 }
695 }
696 catch (final NullPointerException e)
697 {
698 e.printStackTrace();
699 }
700 }
701 }
702
703 /**
704 * Need hp update.
705 * @param barPixels the bar pixels
706 * @return true if hp update should be done, false if not
707 */
708 protected boolean needHpUpdate(final int barPixels)
709 {
710 final double currentHp = getCurrentHp();
711
712 if (currentHp <= 1.0 || getMaxHp() < barPixels)
713 return true;
714
715 if (currentHp <= _hpUpdateDecCheck || currentHp >= _hpUpdateIncCheck)
716 {
717 if (currentHp == getMaxHp())
718 {
719 _hpUpdateIncCheck = currentHp + 1;
720 _hpUpdateDecCheck = currentHp - _hpUpdateInterval;
721 }
722 else
723 {
724 final double doubleMulti = currentHp / _hpUpdateInterval;
725 int intMulti = (int) doubleMulti;
726
727 _hpUpdateDecCheck = _hpUpdateInterval * (doubleMulti < intMulti ? intMulti-- : intMulti);
728 _hpUpdateIncCheck = _hpUpdateDecCheck + _hpUpdateInterval;
729 }
730 return true;
731 }
732
733 return false;
734 }
735
736 /**
737 * Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform.<BR>
738 * <BR>
739 * <B><U> Actions</U> :</B><BR>
740 * <BR>
741 * <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>
742 * <BR>
743 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND CP information</B></FONT><BR>
744 * <BR>
745 * <B><U> Overriden in </U> :</B><BR>
746 * <BR>
747 * <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>
748 * <BR>
749 */
750 public void broadcastStatusUpdate()
751 {
752 if (getStatus().getStatusListener().isEmpty())
753 return;
754
755 if (!needHpUpdate(352))
756 return;
757
758 if (Config.DEBUG)
759 {
760 LOGGER.debug("Broadcast Status Update for " + getObjectId() + "(" + getName() + "). HP: " + getCurrentHp());
761 }
762
763 // Create the Server->Client packet StatusUpdate with current HP and MP
764 StatusUpdate su = null;
765 if (Config.FORCE_COMPLETE_STATUS_UPDATE && this instanceof L2PcInstance)
766 {
767 su = new StatusUpdate((L2PcInstance) this);
768 }
769 else
770 {
771 su = new StatusUpdate(getObjectId());
772 su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
773 su.addAttribute(StatusUpdate.CUR_MP, (int) getCurrentMp());
774 }
775
776 // Go through the StatusListener
777 // Send the Server->Client packet StatusUpdate with current HP and MP
778 for (final L2Character temp : getStatus().getStatusListener())
779 {
780 if (temp != null)
781 temp.sendPacket(su);
782 }
783 /*
784 * synchronized (getStatus().getStatusListener()) { for(L2Character temp : getStatus().getStatusListener()) { try { temp.sendPacket(su); } catch(NullPointerException e) { e.printStackTrace(); } } }
785 */
786 }
787
788 /**
789 * Not Implemented.<BR>
790 * <BR>
791 * <B><U> Overridden in </U> :</B><BR>
792 * <BR>
793 * <li>L2PcInstance</li><BR>
794 * <BR>
795 * @param mov the mov
796 */
797 public void sendPacket(final L2GameServerPacket mov)
798 {
799 // default implementation
800 }
801
802 /** The _in town war. */
803 private boolean _inTownWar;
804
805 /**
806 * Checks if is in town war.
807 * @return true, if is in town war
808 */
809 public final boolean isinTownWar()
810 {
811 return _inTownWar;
812 }
813
814 /**
815 * Sets the in town war.
816 * @param value the new in town war
817 */
818 public final void setInTownWar(final boolean value)
819 {
820 _inTownWar = value;
821 }
822
823 /*
824 * 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() ==
825 * 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) {
826 * 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,
827 * 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
828 * 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 -
829 * onTeleported() will do it getPosition().setWorldPosition(x, y, z); if(!(this instanceof L2PcInstance)) { onTeleported(); } }
830 */
831
832 /**
833 * Teleport a L2Character and its pet if necessary.<BR>
834 * <BR>
835 * <B><U> Actions</U> :</B><BR>
836 * <BR>
837 * <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
838 * if necessary</li><BR>
839 * <BR>
840 * @param x the x
841 * @param y the y
842 * @param z the z
843 * @param allowRandomOffset the allow random offset
844 */
845 public void teleToLocation(int x, int y, int z, final boolean allowRandomOffset)
846 {
847 if (Config.TW_DISABLE_GK)
848 {
849 int x1, y1, z1;
850 x1 = getX();
851 y1 = getY();
852 z1 = getZ();
853 L2TownZone Town;
854 Town = TownManager.getInstance().getTown(x1, y1, z1);
855 if (Town != null && isinTownWar())
856 {
857 if (Town.getTownId() == Config.TW_TOWN_ID && !Config.TW_ALL_TOWNS)
858 {
859 return;
860 }
861 else if (Config.TW_ALL_TOWNS)
862 {
863 return;
864 }
865 }
866 }
867
868 // Stop movement
869 stopMove(null, false);
870 abortAttack();
871 abortCast();
872
873 setIsTeleporting(true);
874 setTarget(null);
875
876 // Remove from world regions zones
877 final L2WorldRegion region = getWorldRegion();
878 if (region != null)
879 region.removeFromZones(this);
880
881 getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
882
883 if (Config.RESPAWN_RANDOM_ENABLED && allowRandomOffset)
884 {
885 x += Rnd.get(-Config.RESPAWN_RANDOM_MAX_OFFSET, Config.RESPAWN_RANDOM_MAX_OFFSET);
886 y += Rnd.get(-Config.RESPAWN_RANDOM_MAX_OFFSET, Config.RESPAWN_RANDOM_MAX_OFFSET);
887 }
888
889 z += 5;
890
891 if (Config.DEBUG)
892 LOGGER.debug("Teleporting to: " + x + ", " + y + ", " + z);
893
894 // Send a Server->Client packet TeleportToLocationt to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character
895 broadcastPacket(new TeleportToLocation(this, x, y, z));
896
897 // remove the object from its old location
898 decayMe();
899
900 // Set the x,y,z position of the L2Object and if necessary modify its _worldRegion
901 getPosition().setXYZ(x, y, z);
902
903 // if (!(this instanceof L2PcInstance) || (((L2PcInstance)this).isOffline()))/*.getClient() != null && ((L2PcInstance)this).getClient().isDetached()))*/
904 if (!(this instanceof L2PcInstance))
905 onTeleported();
906
907 revalidateZone(true);
908 }
909
910 /** The _zone validate counter. */
911 protected byte _zoneValidateCounter = 4;
912
913 /**
914 * Revalidate zone.
915 * @param force the force
916 */
917 public void revalidateZone(final boolean force)
918 {
919 final L2WorldRegion region = getWorldRegion();
920 if (region == null)
921 return;
922
923 // This function is called too often from movement code
924 if (force)
925 _zoneValidateCounter = 4;
926 else
927 {
928 _zoneValidateCounter--;
929 if (_zoneValidateCounter < 0)
930 _zoneValidateCounter = 4;
931 else
932 return;
933 }
934 region.revalidateZones(this);
935 }
936
937 /**
938 * Tele to location.
939 * @param x the x
940 * @param y the y
941 * @param z the z
942 */
943 public void teleToLocation(final int x, final int y, final int z)
944 {
945 teleToLocation(x, y, z, false);
946 }
947
948 /**
949 * Tele to location.
950 * @param loc the loc
951 * @param allowRandomOffset the allow random offset
952 */
953 public void teleToLocation(final Location loc, final boolean allowRandomOffset)
954 {
955 int x = loc.getX();
956 int y = loc.getY();
957 int z = loc.getZ();
958
959 if (this instanceof L2PcInstance && DimensionalRiftManager.getInstance().checkIfInRiftZone(getX(), getY(), getZ(), true))
960 { // true -> ignore waiting room :)
961 L2PcInstance player = (L2PcInstance) this;
962 player.sendMessage("You have been sent to the waiting room.");
963
964 if (player.isInParty() && player.getParty().isInDimensionalRift())
965 {
966 player.getParty().getDimensionalRift().usedTeleport(player);
967 }
968
969 final int[] newCoords = DimensionalRiftManager.getInstance().getRoom((byte) 0, (byte) 0).getTeleportCoords();
970
971 x = newCoords[0];
972 y = newCoords[1];
973 z = newCoords[2];
974
975 player = null;
976 }
977 teleToLocation(x, y, z, allowRandomOffset);
978 }
979
980 /**
981 * Tele to location.
982 * @param teleportWhere the teleport where
983 */
984 public void teleToLocation(final TeleportWhereType teleportWhere)
985 {
986 teleToLocation(MapRegionTable.getInstance().getTeleToLocation(this, teleportWhere), true);
987 }
988
989 /*
990 * // 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 *
991 * 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 }
992 */
993
994 // =========================================================
995 // Method - Private
996 /**
997 * Launch a physical attack against a target (Simple, Bow, Pole or Dual).<BR>
998 * <BR>
999 * <B><U> Actions</U> :</B><BR>
1000 * <BR>
1001 * <li>Get the active weapon (always equiped in the right hand)</li><BR>
1002 * <BR>
1003 * <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>
1004 * <BR>
1005 * <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
1006 * 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>
1007 * <BR>
1008 * @param target The L2Character targeted
1009 */
1010 protected void doAttack(final L2Character target)
1011 {
1012 if (Config.DEBUG)
1013 {
1014 LOGGER.debug(getName() + " doAttack: target=" + target);
1015 }
1016
1017 if (target == null)
1018 return;
1019
1020 // Like L2OFF wait that the hit task finish and then player can move
1021 if (this instanceof L2PcInstance && ((L2PcInstance) this).isMovingTaskDefined() && !((L2PcInstance) this).isAttackingNow())
1022 {
1023 final L2ItemInstance rhand = ((L2PcInstance) this).getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
1024 if ((rhand != null && rhand.getItemType() != L2WeaponType.BOW) || (rhand == null))
1025 {
1026 ((L2PcInstance) this).startMovingTask();
1027 return;
1028 }
1029 }
1030
1031 if (isAlikeDead())
1032 {
1033 // If L2PcInstance is dead or the target is dead, the action is stoped
1034 getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
1035
1036 sendPacket(ActionFailed.STATIC_PACKET);
1037 return;
1038 }
1039
1040 if (this instanceof L2NpcInstance && target.isAlikeDead())
1041 {
1042 // If L2PcInstance is dead or the target is dead, the action is stoped
1043 getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
1044
1045 sendPacket(ActionFailed.STATIC_PACKET);
1046 return;
1047 }
1048
1049 if (this instanceof L2PcInstance && target.isDead() && !target.isFakeDeath())
1050 {
1051 // If L2PcInstance is dead or the target is dead, the action is stoped
1052 getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
1053
1054 sendPacket(ActionFailed.STATIC_PACKET);
1055 return;
1056 }
1057
1058 if (!getKnownList().knowsObject(target))
1059 {
1060 // If L2PcInstance is dead or the target is dead, the action is stoped
1061 getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
1062
1063 sendPacket(ActionFailed.STATIC_PACKET);
1064 return;
1065 }
1066
1067 if (this instanceof L2PcInstance && isDead())
1068 {
1069 // If L2PcInstance is dead or the target is dead, the action is stoped
1070 getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
1071
1072 sendPacket(ActionFailed.STATIC_PACKET);
1073 return;
1074 }
1075
1076 if (target instanceof L2PcInstance && ((L2PcInstance) target).getDuelState() == Duel.DUELSTATE_DEAD)
1077 {
1078 // If L2PcInstance is dead or the target is dead, the action is stoped
1079 getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
1080
1081 sendPacket(ActionFailed.STATIC_PACKET);
1082 return;
1083 }
1084
1085 if (target instanceof L2DoorInstance && !((L2DoorInstance) target).isAttackable(this))
1086 return;
1087
1088 if (isAttackingDisabled())
1089 return;
1090
1091 if (this instanceof L2PcInstance)
1092 {
1093 if (((L2PcInstance) this).inObserverMode())
1094 {
1095 sendPacket(new SystemMessage(SystemMessageId.OBSERVERS_CANNOT_PARTICIPATE));
1096 sendPacket(ActionFailed.STATIC_PACKET);
1097 return;
1098 }
1099
1100 if (target instanceof L2PcInstance)
1101 {
1102 if (((L2PcInstance) target).isCursedWeaponEquiped() && ((L2PcInstance) this).getLevel() <= Config.MAX_LEVEL_NEWBIE)
1103 {
1104 ((L2PcInstance) this).sendMessage("Can't attack a cursed player when under level 21.");
1105 sendPacket(ActionFailed.STATIC_PACKET);
1106 return;
1107 }
1108
1109 if (((L2PcInstance) this).isCursedWeaponEquiped() && ((L2PcInstance) target).getLevel() <= Config.MAX_LEVEL_NEWBIE)
1110 {
1111 ((L2PcInstance) this).sendMessage("Can't attack a newbie player using a cursed weapon.");
1112 sendPacket(ActionFailed.STATIC_PACKET);
1113 return;
1114 }
1115 }
1116
1117 // thank l2dot
1118 if (getObjectId() == target.getObjectId())
1119 {
1120 sendPacket(ActionFailed.STATIC_PACKET);
1121 return;
1122 }
1123 /**
1124 * by gevorakoC
1125 */
1126 if (target instanceof L2NpcInstance && Config.DISABLE_ATTACK_NPC_TYPE)
1127 {
1128 final String mobtype = ((L2NpcInstance) target).getTemplate().type;
1129 if (!Config.LIST_ALLOWED_NPC_TYPES.contains(mobtype))
1130 {
1131 final SystemMessage sm = new SystemMessage(SystemMessageId.S1_S2);
1132 sm.addString("Npc Type " + mobtype + " has Protection - No Attack Allowed!");
1133 ((L2PcInstance) this).sendPacket(sm);
1134 ((L2PcInstance) this).sendPacket(ActionFailed.STATIC_PACKET);
1135 return;
1136 }
1137 }
1138 }
1139
1140 // Get the active weapon instance (always equiped in the right hand)
1141 L2ItemInstance weaponInst = getActiveWeaponInstance();
1142
1143 // Get the active weapon item corresponding to the active weapon instance (always equiped in the right hand)
1144 L2Weapon weaponItem = getActiveWeaponItem();
1145
1146 if (weaponItem != null && weaponItem.getItemType() == L2WeaponType.ROD)
1147 {
1148 // You can't make an attack with a fishing pole.
1149 ((L2PcInstance) this).sendPacket(new SystemMessage(SystemMessageId.CANNOT_ATTACK_WITH_FISHING_POLE));
1150 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
1151
1152 sendPacket(ActionFailed.STATIC_PACKET);
1153 return;
1154 }
1155
1156 /*
1157 * TEMPFIX: Check client Z coordinate instead of server z to avoid exploit killing Zaken from others floor
1158 */
1159 if ((target instanceof L2GrandBossInstance) && ((L2GrandBossInstance) target).getNpcId() == 29022)
1160 {
1161 if (Math.abs(this.getClientZ() - target.getZ()) > 200)
1162 {
1163 sendPacket(new SystemMessage(SystemMessageId.CANT_SEE_TARGET));
1164 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
1165 sendPacket(ActionFailed.STATIC_PACKET);
1166 return;
1167 }
1168 }
1169
1170 // GeoData Los Check here (or dz > 1000)
1171 if (!GeoData.getInstance().canSeeTarget(this, target))
1172 {
1173 sendPacket(new SystemMessage(SystemMessageId.CANT_SEE_TARGET));
1174 getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
1175 sendPacket(ActionFailed.STATIC_PACKET);
1176 return;
1177 }
1178
1179 // Check for a bow
1180 if (weaponItem != null && weaponItem.getItemType() == L2WeaponType.BOW)
1181 {
1182 // Equip arrows needed in left hand and send a Server->Client packet ItemList to the L2PcINstance then return True
1183 if (!checkAndEquipArrows())
1184 {
1185 // Cancel the action because the L2PcInstance have no arrow
1186 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
1187
1188 sendPacket(ActionFailed.STATIC_PACKET);
1189 sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ARROWS));
1190 return;
1191 }
1192
1193 // Check for arrows and MP
1194 if (this instanceof L2PcInstance)
1195 {
1196 // Checking if target has moved to peace zone - only for player-bow attacks at the moment
1197 // Other melee is checked in movement code and for offensive spells a check is done every time
1198 if (target.isInsidePeaceZone((L2PcInstance) this))
1199 {
1200 getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
1201 sendPacket(ActionFailed.STATIC_PACKET);
1202 return;
1203 }
1204
1205 // Verify if the bow can be use
1206 if (_disableBowAttackEndTime <= GameTimeController.getGameTicks())
1207 {
1208 // Verify if L2PcInstance owns enough MP
1209 final int saMpConsume = (int) getStat().calcStat(Stats.MP_CONSUME, 0, null, null);
1210 final int mpConsume = saMpConsume == 0 ? weaponItem.getMpConsume() : saMpConsume;
1211
1212 if (getCurrentMp() < mpConsume)
1213 {
1214 // If L2PcInstance doesn't have enough MP, stop the attack
1215 ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(CtrlEvent.EVT_READY_TO_ACT), 1000);
1216
1217 sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_MP));
1218 sendPacket(ActionFailed.STATIC_PACKET);
1219 return;
1220 }
1221 // If L2PcInstance have enough MP, the bow consummes it
1222 getStatus().reduceMp(mpConsume);
1223
1224 // Set the period of bow non re-use
1225 _disableBowAttackEndTime = 5 * GameTimeController.TICKS_PER_SECOND + GameTimeController.getGameTicks();
1226 }
1227 else
1228 {
1229 // Cancel the action because the bow can't be re-use at this moment
1230 ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(CtrlEvent.EVT_READY_TO_ACT), 1000);
1231
1232 sendPacket(ActionFailed.STATIC_PACKET);
1233 return;
1234 }
1235
1236 }
1237 else if (this instanceof L2NpcInstance)
1238 {
1239 if (_disableBowAttackEndTime > GameTimeController.getGameTicks())
1240 return;
1241 }
1242 }
1243
1244 // Add the L2PcInstance to _knownObjects and _knownPlayer of the target
1245 target.getKnownList().addKnownObject(this);
1246
1247 // Reduce the current CP if TIREDNESS configuration is activated
1248 if (Config.ALT_GAME_TIREDNESS)
1249 {
1250 setCurrentCp(getCurrentCp() - 10);
1251 }
1252
1253 final int timeAtk = calculateTimeBetweenAttacks(target, weaponItem);
1254
1255 // Recharge any active auto soulshot tasks for player (or player's summon if one exists).
1256 if (this instanceof L2PcInstance)
1257 {
1258 ((L2PcInstance) this).rechargeAutoSoulShot(true, false, false, timeAtk);
1259 }
1260 else if (this instanceof L2Summon)
1261 {
1262 ((L2Summon) this).getOwner().rechargeAutoSoulShot(true, false, true, timeAtk);
1263 }
1264
1265 // Verify if soulshots are charged.
1266 boolean wasSSCharged;
1267
1268 if (this instanceof L2Summon && !(this instanceof L2PetInstance))
1269 {
1270 wasSSCharged = ((L2Summon) this).getChargedSoulShot() != L2ItemInstance.CHARGED_NONE;
1271 }
1272 else
1273 {
1274 wasSSCharged = weaponInst != null && weaponInst.getChargedSoulshot() != L2ItemInstance.CHARGED_NONE;
1275 }
1276
1277 // Get the Attack Speed of the L2Character (delay (in milliseconds) before next attack)
1278 // the hit is calculated to happen halfway to the animation - might need further tuning e.g. in bow case
1279 final int timeToHit = timeAtk / 2;
1280 _attackEndTime = GameTimeController.getGameTicks();
1281 _attackEndTime += (timeAtk / GameTimeController.MILLIS_IN_TICK);
1282 _attackEndTime -= 1;
1283
1284 int ssGrade = 0;
1285
1286 if (weaponItem != null)
1287 {
1288 ssGrade = weaponItem.getCrystalType();
1289 }
1290
1291 // Create a Server->Client packet Attack
1292 Attack attack = new Attack(this, wasSSCharged, ssGrade);
1293
1294 boolean hitted;
1295
1296 // Set the Attacking Body part to CHEST
1297 setAttackingBodypart();
1298
1299 // Heading calculation on every attack
1300 this.setHeading(Util.calculateHeadingFrom(this.getX(), this.getY(), target.getX(), target.getY()));
1301
1302 // Get the Attack Reuse Delay of the L2Weapon
1303 final int reuse = calculateReuseTime(target, weaponItem);
1304
1305 // Select the type of attack to start
1306 if (weaponItem == null)
1307 {
1308 hitted = doAttackHitSimple(attack, target, timeToHit);
1309 }
1310 else if (weaponItem.getItemType() == L2WeaponType.BOW)
1311 {
1312 hitted = doAttackHitByBow(attack, target, timeAtk, reuse);
1313 }
1314 else if (weaponItem.getItemType() == L2WeaponType.POLE)
1315 {
1316 hitted = doAttackHitByPole(attack, timeToHit);
1317 }
1318 else if (isUsingDualWeapon())
1319 {
1320 hitted = doAttackHitByDual(attack, target, timeToHit);
1321 }
1322 else
1323 {
1324 hitted = doAttackHitSimple(attack, target, timeToHit);
1325 }
1326
1327 // Flag the attacker if it's a L2PcInstance outside a PvP area
1328 L2PcInstance player = null;
1329
1330 if (this instanceof L2PcInstance)
1331 {
1332 player = (L2PcInstance) this;
1333 }
1334 else if (this instanceof L2Summon)
1335 {
1336 player = ((L2Summon) this).getOwner();
1337 }
1338
1339 if (player != null)
1340 {
1341 player.updatePvPStatus(target);
1342 }
1343
1344 // Check if hit isn't missed
1345 if (!hitted)
1346 {
1347 // MAJAX fix
1348 sendPacket(new SystemMessage(SystemMessageId.MISSED_TARGET));
1349 // Abort the attack of the L2Character and send Server->Client ActionFailed packet
1350 abortAttack();
1351 }
1352 else
1353 {
1354 /*
1355 * 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.
1356 */
1357
1358 // If we didn't miss the hit, discharge the shoulshots, if any
1359 if (this instanceof L2Summon && !(this instanceof L2PetInstance))
1360 {
1361 ((L2Summon) this).setChargedSoulShot(L2ItemInstance.CHARGED_NONE);
1362 }
1363 else if (weaponInst != null)
1364 {
1365 weaponInst.setChargedSoulshot(L2ItemInstance.CHARGED_NONE);
1366 }
1367
1368 if (player != null)
1369 {
1370 if (player.isCursedWeaponEquiped())
1371 {
1372 // If hitted by a cursed weapon, Cp is reduced to 0
1373 if (!target.isInvul())
1374 {
1375 target.setCurrentCp(0);
1376 }
1377 }
1378 else if (player.isHero())
1379 {
1380 if (target instanceof L2PcInstance && ((L2PcInstance) target).isCursedWeaponEquiped())
1381 {
1382 // If a cursed weapon is hitted by a Hero, Cp is reduced to 0
1383 target.setCurrentCp(0);
1384 }
1385 }
1386 }
1387
1388 weaponInst = null;
1389 weaponItem = null;
1390 }
1391
1392 // If the Server->Client packet Attack contains at least 1 hit, send the Server->Client packet Attack
1393 // to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character
1394 if (attack.hasHits())
1395 {
1396 broadcastPacket(attack);
1397 fireEvent(EventType.ATTACK.name, new Object[]
1398 {
1399 getTarget()
1400 });
1401 }
1402
1403 // Like L2OFF mobs id 27181 can teleport players near cabrio
1404 if (this instanceof L2MonsterInstance && ((L2MonsterInstance) this).getNpcId() == 27181)
1405 {
1406 final int rndNum = Rnd.get(100);
1407 final L2PcInstance gettarget = (L2PcInstance) this.getTarget();
1408
1409 if (rndNum < 5 && gettarget != null)
1410 gettarget.teleToLocation(179768, 6364, -2734);
1411 }
1412
1413 // Like L2OFF if target is not auto attackable you give only one hit
1414 if (this instanceof L2PcInstance && target instanceof L2PcInstance && !target.isAutoAttackable(this))
1415 {
1416 ((L2PcInstance) this).getAI().clientStopAutoAttack();
1417 ((L2PcInstance) this).getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, this);
1418 }
1419
1420 // Notify AI with EVT_READY_TO_ACT
1421 ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(CtrlEvent.EVT_READY_TO_ACT), timeAtk + reuse);
1422
1423 attack = null;
1424 player = null;
1425 }
1426
1427 /**
1428 * Launch a Bow attack.<BR>
1429 * <BR>
1430 * <B><U> Actions</U> :</B><BR>
1431 * <BR>
1432 * <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
1433 * 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>
1434 * <BR>
1435 * @param attack Server->Client packet Attack in which the hit will be added
1436 * @param target The L2Character targeted
1437 * @param sAtk The Attack Speed of the attacker
1438 * @param reuse the reuse
1439 * @return True if the hit isn't missed
1440 */
1441 private boolean doAttackHitByBow(final Attack attack, final L2Character target, final int sAtk, final int reuse)
1442 {
1443 int damage1 = 0;
1444 boolean shld1 = false;
1445 boolean crit1 = false;
1446
1447 // Calculate if hit is missed or not
1448 final boolean miss1 = Formulas.calcHitMiss(this, target);
1449
1450 // Consumme arrows
1451 reduceArrowCount();
1452
1453 _move = null;
1454
1455 // Check if hit isn't missed
1456 if (!miss1)
1457 {
1458 // Calculate if shield defense is efficient
1459 shld1 = Formulas.calcShldUse(this, target);
1460
1461 // Calculate if hit is critical
1462 crit1 = Formulas.calcCrit(this, target);
1463
1464 // Calculate physical damages
1465 damage1 = (int) Formulas.calcPhysDam(this, target, null, shld1, crit1, false, attack.soulshot);
1466 }
1467
1468 // Check if the L2Character is a L2PcInstance
1469 if (this instanceof L2PcInstance)
1470 {
1471 // Send a system message
1472 sendPacket(new SystemMessage(SystemMessageId.GETTING_READY_TO_SHOOT_AN_ARROW));
1473
1474 // Send a Server->Client packet SetupGauge
1475 SetupGauge sg = new SetupGauge(SetupGauge.RED, sAtk + reuse);
1476 sendPacket(sg);
1477 sg = null;
1478 }
1479
1480 // Create a new hit task with Medium priority
1481 ThreadPoolManager.getInstance().scheduleAi(new HitTask(target, damage1, crit1, miss1, attack.soulshot, shld1), sAtk);
1482
1483 // Calculate and set the disable delay of the bow in function of the Attack Speed
1484 _disableBowAttackEndTime = (sAtk + reuse) / GameTimeController.MILLIS_IN_TICK + GameTimeController.getGameTicks();
1485
1486 // Add this hit to the Server-Client packet Attack
1487 attack.addHit(target, damage1, miss1, crit1, shld1);
1488
1489 // Return true if hit isn't missed
1490 return !miss1;
1491 }
1492
1493 /**
1494 * Launch a Dual attack.<BR>
1495 * <BR>
1496 * <B><U> Actions</U> :</B><BR>
1497 * <BR>
1498 * <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>
1499 * <li>Add those hits to the Server-Client packet Attack</li><BR>
1500 * <BR>
1501 * @param attack Server->Client packet Attack in which the hit will be added
1502 * @param target The L2Character targeted
1503 * @param sAtk the s atk
1504 * @return True if hit 1 or hit 2 isn't missed
1505 */
1506 private boolean doAttackHitByDual(final Attack attack, final L2Character target, final int sAtk)
1507 {
1508 int damage1 = 0;
1509 int damage2 = 0;
1510 boolean shld1 = false;
1511 boolean shld2 = false;
1512 boolean crit1 = false;
1513 boolean crit2 = false;
1514
1515 // Calculate if hits are missed or not
1516 final boolean miss1 = Formulas.calcHitMiss(this, target);
1517 final boolean miss2 = Formulas.calcHitMiss(this, target);
1518
1519 // Check if hit 1 isn't missed
1520 if (!miss1)
1521 {
1522 // Calculate if shield defense is efficient against hit 1
1523 shld1 = Formulas.calcShldUse(this, target);
1524
1525 // Calculate if hit 1 is critical
1526 crit1 = Formulas.calcCrit(this, target);
1527
1528 // Calculate physical damages of hit 1
1529 damage1 = (int) Formulas.calcPhysDam(this, target, null, shld1, crit1, true, attack.soulshot);
1530 damage1 /= 2;
1531 }
1532
1533 // Check if hit 2 isn't missed
1534 if (!miss2)
1535 {
1536 // Calculate if shield defense is efficient against hit 2
1537 shld2 = Formulas.calcShldUse(this, target);
1538
1539 // Calculate if hit 2 is critical
1540 crit2 = Formulas.calcCrit(this, target);
1541
1542 // Calculate physical damages of hit 2
1543 damage2 = (int) Formulas.calcPhysDam(this, target, null, shld2, crit2, true, attack.soulshot);
1544 damage2 /= 2;
1545 }
1546
1547 // Create a new hit task with Medium priority for hit 1
1548 ThreadPoolManager.getInstance().scheduleAi(new HitTask(target, damage1, crit1, miss1, attack.soulshot, shld1), sAtk / 2);
1549
1550 // Create a new hit task with Medium priority for hit 2 with a higher delay
1551 ThreadPoolManager.getInstance().scheduleAi(new HitTask(target, damage2, crit2, miss2, attack.soulshot, shld2), sAtk);
1552
1553 // Add those hits to the Server-Client packet Attack
1554 attack.addHit(target, damage1, miss1, crit1, shld1);
1555 attack.addHit(target, damage2, miss2, crit2, shld2);
1556
1557 // Return true if hit 1 or hit 2 isn't missed
1558 return !miss1 || !miss2;
1559 }
1560
1561 /**
1562 * Launch a Pole attack.<BR>
1563 * <BR>
1564 * <B><U> Actions</U> :</B><BR>
1565 * <BR>
1566 * <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
1567 * it</li><BR>
1568 * <BR>
1569 * @param attack Server->Client packet Attack in which the hit will be added
1570 * @param sAtk the s atk
1571 * @return True if one hit isn't missed
1572 */
1573 private boolean doAttackHitByPole(final Attack attack, final int sAtk)
1574 {
1575 boolean hitted = false;
1576
1577 double angleChar, angleTarget;
1578 final int maxRadius = (int) getStat().calcStat(Stats.POWER_ATTACK_RANGE, 66, null, null);
1579 final int maxAngleDiff = (int) getStat().calcStat(Stats.POWER_ATTACK_ANGLE, 120, null, null);
1580
1581 if (getTarget() == null)
1582 return false;
1583
1584 angleTarget = Util.calculateAngleFrom(this, getTarget());
1585 setHeading((int) (angleTarget / 9.0 * 1610.0));
1586
1587 angleChar = Util.convertHeadingToDegree(getHeading());
1588 double attackpercent = 85;
1589 final int attackcountmax = (int) getStat().calcStat(Stats.ATTACK_COUNT_MAX, 3, null, null);
1590 int attackcount = 0;
1591
1592 if (angleChar <= 0)
1593 angleChar += 360;
1594
1595 L2Character target;
1596 for (final L2Object obj : getKnownList().getKnownObjects().values())
1597 {
1598 if (obj instanceof L2Character)
1599 {
1600 if (obj instanceof L2PetInstance && this instanceof L2PcInstance && ((L2PetInstance) obj).getOwner() == (L2PcInstance) this)
1601 {
1602 continue;
1603 }
1604
1605 if (!Util.checkIfInRange(maxRadius, this, obj, false))
1606 {
1607 continue;
1608 }
1609
1610 if (Math.abs(obj.getZ() - getZ()) > Config.DIFFERENT_Z_CHANGE_OBJECT)
1611 {
1612 continue;
1613 }
1614
1615 angleTarget = Util.calculateAngleFrom(this, obj);
1616
1617 if (Math.abs(angleChar - angleTarget) > maxAngleDiff && Math.abs(angleChar + 360 - angleTarget) > maxAngleDiff && Math.abs(angleChar - (angleTarget + 360)) > maxAngleDiff)
1618 {
1619 continue;
1620 }
1621
1622 target = (L2Character) obj;
1623
1624 if (!target.isAlikeDead())
1625 {
1626 attackcount += 1;
1627
1628 if (attackcount <= attackcountmax)
1629 {
1630 if (target == getAI().getAttackTarget() || target.isAutoAttackable(this))
1631 {
1632 hitted |= doAttackHitSimple(attack, target, attackpercent, sAtk);
1633 attackpercent /= 1.15;
1634
1635 // Flag player if the target is another player
1636 if (this instanceof L2PcInstance && obj instanceof L2PcInstance)
1637 ((L2PcInstance) this).updatePvPStatus(target);
1638 }
1639 }
1640 }
1641 }
1642 }
1643 target = null;
1644 // Return true if one hit isn't missed
1645 return hitted;
1646 }
1647
1648 /**
1649 * Launch a simple attack.<BR>
1650 * <BR>
1651 * <B><U> Actions</U> :</B><BR>
1652 * <BR>
1653 * <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
1654 * this hit to the Server-Client packet Attack</li><BR>
1655 * <BR>
1656 * @param attack Server->Client packet Attack in which the hit will be added
1657 * @param target The L2Character targeted
1658 * @param sAtk the s atk
1659 * @return True if the hit isn't missed
1660 */
1661 private boolean doAttackHitSimple(final Attack attack, final L2Character target, final int sAtk)
1662 {
1663 return doAttackHitSimple(attack, target, 100, sAtk);
1664 }
1665
1666 /**
1667 * Do attack hit simple.
1668 * @param attack the attack
1669 * @param target the target
1670 * @param attackpercent the attackpercent
1671 * @param sAtk the s atk
1672 * @return true, if successful
1673 */
1674 private boolean doAttackHitSimple(final Attack attack, final L2Character target, final double attackpercent, final int sAtk)
1675 {
1676 int damage1 = 0;
1677 boolean shld1 = false;
1678 boolean crit1 = false;
1679
1680 // Calculate if hit is missed or not
1681 final boolean miss1 = Formulas.calcHitMiss(this, target);
1682
1683 // Check if hit isn't missed
1684 if (!miss1)
1685 {
1686 // Calculate if shield defense is efficient
1687 shld1 = Formulas.calcShldUse(this, target);
1688
1689 // Calculate if hit is critical
1690 crit1 = Formulas.calcCrit(this, target);
1691
1692 // Calculate physical damages
1693 damage1 = (int) Formulas.calcPhysDam(this, target, null, shld1, crit1, false, attack.soulshot);
1694
1695 if (attackpercent != 100)
1696 {
1697 damage1 = (int) (damage1 * attackpercent / 100);
1698 }
1699 }
1700
1701 // Create a new hit task with Medium priority
1702 ThreadPoolManager.getInstance().scheduleAi(new HitTask(target, damage1, crit1, miss1, attack.soulshot, shld1), sAtk);
1703
1704 // Add this hit to the Server-Client packet Attack
1705 attack.addHit(target, damage1, miss1, crit1, shld1);
1706
1707 // Return true if hit isn't missed
1708 return !miss1;
1709 }
1710
1711 /**
1712 * Manage the casting task (casting and interrupt time, re-use delay...) and display the casting bar and animation on client.<BR>
1713 * <BR>
1714 * <B><U> Actions</U> :</B><BR>
1715 * <BR>
1716 * <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
1717 * 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
1718 * 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>
1719 * <BR>
1720 * @param skill The L2Skill to use
1721 */
1722 public void doCast(final L2Skill skill)
1723 {
1724 final L2Character activeChar = this;
1725
1726 if (skill == null)
1727 {
1728 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
1729 return;
1730 }
1731
1732 // Check if the skill is a magic spell and if the L2Character is not muted
1733 if (skill.isMagic() && isMuted() && !skill.isPotion())
1734 {
1735 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
1736 return;
1737 }
1738
1739 // Check if the skill is psychical and if the L2Character is not psychical_muted
1740 if (!skill.isMagic() && isPsychicalMuted() && !skill.isPotion())
1741 {
1742 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
1743 return;
1744 }
1745
1746 // Can't use Hero and resurrect skills during Olympiad
1747 if (activeChar instanceof L2PcInstance && ((L2PcInstance) activeChar).isInOlympiadMode() && (skill.isHeroSkill() || skill.getSkillType() == SkillType.RESURRECT))
1748 {
1749 SystemMessage sm = new SystemMessage(SystemMessageId.THIS_SKILL_IS_NOT_AVAILABLE_FOR_THE_OLYMPIAD_EVENT);
1750 sendPacket(sm);
1751 sm = null;
1752 return;
1753 }
1754
1755 // Like L2OFF you can't use skills when you are attacking now
1756 if (activeChar instanceof L2PcInstance && !skill.isPotion())
1757 {
1758 final L2ItemInstance rhand = ((L2PcInstance) this).getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
1759 if ((rhand != null && rhand.getItemType() == L2WeaponType.BOW))
1760 {
1761 if (isAttackingNow())
1762 return;
1763 }
1764 }
1765
1766 // prevent casting signets to peace zone
1767 if (skill.getSkillType() == SkillType.SIGNET || skill.getSkillType() == SkillType.SIGNET_CASTTIME)
1768 {
1769 /*
1770 * 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());
1771 * sendPacket(sm); return; } }
1772 */
1773
1774 final L2WorldRegion region = getWorldRegion();
1775 if (region == null)
1776 return;
1777 boolean canCast = true;
1778 if (skill.getTargetType() == SkillTargetType.TARGET_GROUND && this instanceof L2PcInstance)
1779 {
1780 final Point3D wp = ((L2PcInstance) this).getCurrentSkillWorldPosition();
1781 if (!region.checkEffectRangeInsidePeaceZone(skill, wp.getX(), wp.getY(), wp.getZ()))
1782 canCast = false;
1783 }
1784 else if (!region.checkEffectRangeInsidePeaceZone(skill, getX(), getY(), getZ()))
1785 canCast = false;
1786 if (!canCast)
1787 {
1788 final SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
1789 sm.addSkillName(skill.getId());
1790 sendPacket(sm);
1791 return;
1792 }
1793 }
1794
1795 // Recharge AutoSoulShot
1796
1797 final int atkTime = Formulas.getInstance().calcMAtkSpd(activeChar, skill, skill.getHitTime());
1798 if (skill.useSoulShot())
1799 {
1800 if (activeChar instanceof L2PcInstance)
1801 {
1802 ((L2PcInstance) activeChar).rechargeAutoSoulShot(true, false, false, atkTime);
1803 }
1804 else if (this instanceof L2Summon)
1805 {
1806 ((L2Summon) activeChar).getOwner().rechargeAutoSoulShot(true, false, true, atkTime);
1807 }
1808 }
1809
1810 // else if (skill.useFishShot())
1811 // {
1812 // if (this instanceof L2PcInstance)
1813 // ((L2PcInstance)this).rechargeAutoSoulShot(true, false, false);
1814 // }
1815
1816 // Get all possible targets of the skill in a table in function of the skill target type
1817 final L2Object[] targets = skill.getTargetList(activeChar);
1818 // Set the target of the skill in function of Skill Type and Target Type
1819 L2Character target = null;
1820
1821 if (skill.getTargetType() == SkillTargetType.TARGET_AURA || skill.getTargetType() == SkillTargetType.TARGET_GROUND || skill.isPotion())
1822 {
1823 target = this;
1824 }
1825 else if (targets == null || targets.length == 0)
1826 {
1827 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
1828 return;
1829 }
1830 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())
1831 {
1832 target = (L2Character) targets[0];
1833
1834 /*
1835 * 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 ||
1836 * 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() &&
1837 * skill.getTargetType() == L2Skill.SkillTargetType.TARGET_PARTY) { for (L2PcInstance member : ((L2PcInstance)this).getParty().getPartyMembers()) member.setLastBuffer(this); } }
1838 */
1839 }
1840 else
1841 {
1842 target = (L2Character) getTarget();
1843 }
1844
1845 if (target == null)
1846 {
1847 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
1848 return;
1849 }
1850
1851 // Player can't heal rb config
1852 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))
1853 {
1854 this.sendPacket(ActionFailed.STATIC_PACKET);
1855 return;
1856 }
1857
1858 if (activeChar instanceof L2PcInstance && target instanceof L2NpcInstance && Config.DISABLE_ATTACK_NPC_TYPE)
1859 {
1860 final String mobtype = ((L2NpcInstance) target).getTemplate().type;
1861 if (!Config.LIST_ALLOWED_NPC_TYPES.contains(mobtype))
1862 {
1863 final SystemMessage sm = new SystemMessage(SystemMessageId.S1_S2);
1864 sm.addString("Npc Type " + mobtype + " has Protection - No Attack Allowed!");
1865 ((L2PcInstance) activeChar).sendPacket(sm);
1866 ((L2PcInstance) activeChar).sendPacket(ActionFailed.STATIC_PACKET);
1867 return;
1868 }
1869 }
1870
1871 if (skill.isPotion())
1872 setLastPotionCast(skill);
1873 else
1874 setLastSkillCast(skill);
1875
1876 // Get the Identifier of the skill
1877 final int magicId = skill.getId();
1878
1879 // Get the Display Identifier for a skill that client can't display
1880 final int displayId = skill.getDisplayId();
1881
1882 // Get the level of the skill
1883 int level = skill.getLevel();
1884
1885 if (level < 1)
1886 {
1887 level = 1;
1888 }
1889
1890 // Get the casting time of the skill (base)
1891 int hitTime = skill.getHitTime();
1892 int coolTime = skill.getCoolTime();
1893 final boolean effectWhileCasting = skill.hasEffectWhileCasting();
1894
1895 final boolean forceBuff = skill.getSkillType() == SkillType.FORCE_BUFF && target instanceof L2PcInstance;
1896
1897 // Calculate the casting time of the skill (base + modifier of MAtkSpd)
1898 // Don't modify the skill time for FORCE_BUFF skills. The skill time for those skills represent the buff time.
1899 if (!effectWhileCasting && !forceBuff && !skill.isStaticHitTime())
1900 {
1901 hitTime = Formulas.getInstance().calcMAtkSpd(activeChar, skill, hitTime);
1902
1903 if (coolTime > 0)
1904 {
1905 coolTime = Formulas.getInstance().calcMAtkSpd(activeChar, skill, coolTime);
1906 }
1907 }
1908
1909 // Calculate altered Cast Speed due to BSpS/SpS only for Magic skills
1910 if ((checkBss() || checkSps()) && !skill.isStaticHitTime() && !skill.isPotion() && skill.isMagic())
1911 {
1912
1913 // Only takes 70% of the time to cast a BSpS/SpS cast
1914 hitTime = (int) (0.70 * hitTime);
1915 coolTime = (int) (0.70 * coolTime);
1916
1917 // Because the following are magic skills that do not actively 'eat' BSpS/SpS,
1918 // I must 'eat' them here so players don't take advantage of infinite speed increase
1919 /* MANAHEAL, MANARECHARGE, RESURRECT, RECALL */
1920 // if (skill.getSkillType() == SkillType.MANAHEAL || skill.getSkillType() == SkillType.MANARECHARGE || skill.getSkillType() == SkillType.RESURRECT || skill.getSkillType() == SkillType.RECALL)
1921 // {
1922 // if (checkBss())
1923 // removeBss();
1924 // else
1925 // removeSps();
1926 // }
1927
1928 }
1929
1930 /*
1931 * // 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()) {
1932 * 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);
1933 * //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() ==
1934 * SkillType.RESURRECT || skill.getSkillType() == SkillType.RECALL || skill.getSkillType() == SkillType.DOT) { weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE); } } } weaponInst = null;
1935 */
1936
1937 if (skill.isPotion())
1938 {
1939 // Set the _castEndTime and _castInterruptTim. +10 ticks for lag situations, will be reseted in onMagicFinalizer
1940 _castPotionEndTime = 10 + GameTimeController.getGameTicks() + (coolTime + hitTime) / GameTimeController.MILLIS_IN_TICK;
1941 _castPotionInterruptTime = -2 + GameTimeController.getGameTicks() + hitTime / GameTimeController.MILLIS_IN_TICK;
1942
1943 }
1944 else
1945 {
1946 // Set the _castEndTime and _castInterruptTim. +10 ticks for lag situations, will be reseted in onMagicFinalizer
1947 _castEndTime = 10 + GameTimeController.getGameTicks() + (coolTime + hitTime) / GameTimeController.MILLIS_IN_TICK;
1948 _castInterruptTime = -2 + GameTimeController.getGameTicks() + hitTime / GameTimeController.MILLIS_IN_TICK;
1949
1950 }
1951
1952 // Init the reuse time of the skill
1953 // int reuseDelay = (int)(skill.getReuseDelay() * getStat().getMReuseRate(skill));
1954 // reuseDelay *= 333.0 / (skill.isMagic() ? getMAtkSpd() : getPAtkSpd());
1955 int reuseDelay = skill.getReuseDelay();
1956
1957 if (activeChar instanceof L2PcInstance && Formulas.getInstance().calcSkillMastery(activeChar))
1958 {
1959 reuseDelay = 0;
1960 }
1961 else if (!skill.isStaticReuse() && !skill.isPotion())
1962 {
1963 if (skill.isMagic())
1964 {
1965 reuseDelay *= getStat().getMReuseRate(skill);
1966 }
1967 else
1968 {
1969 reuseDelay *= getStat().getPReuseRate(skill);
1970 }
1971
1972 reuseDelay *= 333.0 / (skill.isMagic() ? getMAtkSpd() : getPAtkSpd());
1973 }
1974
1975 // To turn local player in target direction
1976 setHeading(Util.calculateHeadingFrom(getX(), getY(), target.getX(), target.getY()));
1977
1978 /*
1979 * if(skill.isOffensive() && skill.getTargetType() != SkillTargetType.TARGET_AURA && target.isBehind(this)) { moveToLocation(target.getX(), target.getY(), target.getZ(), 0); stopMove(null); }
1980 */
1981
1982 // Like L2OFF after a skill the player must stop the movement, also with toggle
1983 if (!skill.isPotion() && this instanceof L2PcInstance)
1984 ((L2PcInstance) this).stopMove(null);
1985
1986 // Start the effect as long as the player is casting.
1987 if (effectWhileCasting)
1988 {
1989 callSkill(skill, targets);
1990 }
1991
1992 // Send a Server->Client packet MagicSkillUser with target, displayId, level, skillTime, reuseDelay
1993 // to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character
1994 broadcastPacket(new MagicSkillUser(this, target, displayId, level, hitTime, reuseDelay));
1995
1996 // Send a system message USE_S1 to the L2Character
1997 if (activeChar instanceof L2PcInstance && magicId != 1312)
1998 {
1999 if (skill.isPotion())
2000 {
2001 SystemMessage sm = new SystemMessage(SystemMessageId.USE_S1_);
2002 if (magicId == 2005)
2003 sm.addItemName(728);
2004 else if (magicId == 2003)
2005 sm.addItemName(726);
2006 // Message greater cp potions like retail
2007 else if (magicId == 2166 && skill.getLevel() == 2)
2008 sm.addItemName(5592);
2009 // Message cp potions like retail
2010 else if (magicId == 2166 && skill.getLevel() == 1)
2011 sm.addItemName(5591);
2012 else
2013 sm.addSkillName(magicId, skill.getLevel());
2014 sendPacket(sm);
2015 sm = null;
2016 }
2017 else
2018 {
2019 SystemMessage sm = new SystemMessage(SystemMessageId.USE_S1);
2020 if (magicId == 2005)
2021 sm.addItemName(728);
2022 else if (magicId == 2003)
2023 sm.addItemName(726);
2024 // Message greater cp potions like retail
2025 else if (magicId == 2166 && skill.getLevel() == 2)
2026 sm.addItemName(5592);
2027 // Message cp potions like retail
2028 else if (magicId == 2166 && skill.getLevel() == 1)
2029 sm.addItemName(5591);
2030 else
2031 sm.addSkillName(magicId, skill.getLevel());
2032
2033 // Skill 2046 is used only for animation on pets
2034 if (magicId != 2046)
2035 sendPacket(sm);
2036 sm = null;
2037 }
2038 }
2039
2040 // Skill reuse check
2041 if (reuseDelay > 30000)
2042 {
2043 addTimeStamp(skill, reuseDelay);
2044 }
2045
2046 // Check if this skill consume mp on start casting
2047 final int initmpcons = getStat().getMpInitialConsume(skill);
2048
2049 if (initmpcons > 0)
2050 {
2051 StatusUpdate su = new StatusUpdate(getObjectId());
2052
2053 if (skill.isDance())
2054 {
2055 getStatus().reduceMp(calcStat(Stats.DANCE_MP_CONSUME_RATE, initmpcons, null, null));
2056 }
2057 else if (skill.isMagic())
2058 {
2059 getStatus().reduceMp(calcStat(Stats.MAGICAL_MP_CONSUME_RATE, initmpcons, null, null));
2060 }
2061 else
2062 {
2063 getStatus().reduceMp(calcStat(Stats.PHYSICAL_MP_CONSUME_RATE, initmpcons, null, null));
2064 }
2065
2066 su.addAttribute(StatusUpdate.CUR_MP, (int) getCurrentMp());
2067 sendPacket(su);
2068 su = null;
2069 }
2070
2071 // 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
2072 if (reuseDelay > 10)
2073 {
2074 disableSkill(skill, reuseDelay);
2075 }
2076
2077 // For force buff skills, start the effect as long as the player is casting.
2078 if (forceBuff)
2079 {
2080 startForceBuff(target, skill);
2081 }
2082
2083 // launch the magic in hitTime milliseconds
2084 if (hitTime > 210)
2085 {
2086 // Send a Server->Client packet SetupGauge with the color of the gauge and the casting time
2087 if (activeChar instanceof L2PcInstance && !forceBuff)
2088 {
2089 SetupGauge sg = new SetupGauge(SetupGauge.BLUE, hitTime);
2090 sendPacket(sg);
2091 sg = null;
2092 }
2093
2094 // Disable all skills during the casting
2095 if (!skill.isPotion())
2096 { // for particular potion is the timestamp to disable particular skill
2097
2098 disableAllSkills();
2099
2100 if (_skillCast != null) // delete previous skill cast
2101 {
2102 _skillCast.cancel(true);
2103 _skillCast = null;
2104 }
2105
2106 }
2107
2108 // Create a task MagicUseTask to launch the MagicSkill at the end of the casting time (hitTime)
2109 // For client animation reasons (party buffs especially) 200 ms before!
2110 if (getForceBuff() != null || effectWhileCasting)
2111 {
2112 if (skill.isPotion())
2113 _potionCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 2), hitTime);
2114
2115 else
2116 _skillCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 2), hitTime);
2117 }
2118 else
2119 {
2120 if (skill.isPotion())
2121 _potionCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 1), hitTime - 200);
2122
2123 else
2124 _skillCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 1), hitTime - 200);
2125 }
2126 }
2127 else
2128 {
2129 onMagicLaunchedTimer(targets, skill, coolTime, true);
2130 }
2131 fireEvent(EventType.CAST.name, new Object[]
2132 {
2133 skill,
2134 target,
2135 targets
2136 });
2137
2138 }
2139
2140 /**
2141 * Index according to skill id the current timestamp of use.<br>
2142 * @param skill the s
2143 * @param r the r
2144 */
2145 public void addTimeStamp(final L2Skill skill, final int r)
2146 {
2147
2148 }
2149
2150 /**
2151 * Index according to skill id the current timestamp of use.<br>
2152 * @param _skill the s
2153 */
2154 public void removeTimeStamp(final L2Skill _skill)
2155 {
2156
2157 }
2158
2159 /**
2160 * Starts a force buff on target.<br>
2161 * @param target the target
2162 * @param skill the skill
2163 */
2164 public void startForceBuff(final L2Character target, final L2Skill skill)
2165 {
2166 if (skill.getSkillType() != SkillType.FORCE_BUFF)
2167 return;
2168
2169 if (_forceBuff == null)
2170 {
2171 _forceBuff = new ForceBuff(this, target, skill);
2172 }
2173 }
2174
2175 /**
2176 * Kill the L2Character.<BR>
2177 * <BR>
2178 * <B><U> Actions</U> :</B><BR>
2179 * <BR>
2180 * <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
2181 * inform</li> <li>Notify L2Character AI</li><BR>
2182 * <BR>
2183 * <B><U> Overriden in </U> :</B><BR>
2184 * <BR>
2185 * <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>
2186 * <BR>
2187 * @param killer The L2Character who killed it
2188 * @return true, if successful
2189 */
2190 public boolean doDie(final L2Character killer)
2191 {
2192 // killing is only possible one time
2193 synchronized (this)
2194 {
2195 if (isKilledAlready())
2196 return false;
2197
2198 setIsKilledAlready(true);
2199 }
2200 // Set target to null and cancel Attack or Cast
2201 setTarget(null);
2202
2203 // Stop fear to avoid possible bug with char position after death
2204 if (isAfraid())
2205 stopFear(null);
2206
2207 // Stop movement
2208 stopMove(null);
2209
2210 // Stop HP/MP/CP Regeneration task
2211 getStatus().stopHpMpRegeneration();
2212
2213 // Stop all active skills effects in progress on the L2Character,
2214 // if the Character isn't affected by Soul of The Phoenix or Salvation
2215 if (this instanceof L2PlayableInstance && ((L2PlayableInstance) this).isPhoenixBlessed())
2216 {
2217 if (((L2PlayableInstance) this).isNoblesseBlessed())
2218 {
2219 ((L2PlayableInstance) this).stopNoblesseBlessing(null);
2220 }
2221 if (((L2PlayableInstance) this).getCharmOfLuck())
2222 {
2223 ((L2PlayableInstance) this).stopCharmOfLuck(null);
2224 }
2225 }
2226 // Same thing if the Character isn't a Noblesse Blessed L2PlayableInstance
2227 else if (this instanceof L2PlayableInstance && ((L2PlayableInstance) this).isNoblesseBlessed())
2228 {
2229 ((L2PlayableInstance) this).stopNoblesseBlessing(null);
2230
2231 if (((L2PlayableInstance) this).getCharmOfLuck())
2232 {
2233 ((L2PlayableInstance) this).stopCharmOfLuck(null);
2234 }
2235 }
2236 else
2237 {
2238 if (this instanceof L2PcInstance)
2239 {
2240
2241 final L2PcInstance player = (L2PcInstance) this;
2242
2243 // to avoid Event Remove buffs on die
2244 if (player._inEventDM && DM.is_started())
2245 {
2246 if (Config.DM_REMOVE_BUFFS_ON_DIE)
2247 stopAllEffects();
2248 }
2249 else if (player._inEventTvT && TvT.is_started())
2250 {
2251 if (Config.TVT_REMOVE_BUFFS_ON_DIE)
2252 stopAllEffects();
2253 }
2254 else if (player._inEventCTF && CTF.is_started())
2255 {
2256 if (Config.CTF_REMOVE_BUFFS_ON_DIE)
2257 stopAllEffects();
2258 }
2259 else if (Config.LEAVE_BUFFS_ON_DIE) // this means that the player is not in event
2260 {
2261 stopAllEffects();
2262 }
2263 }
2264 else
2265 // this means all other characters, including Summons
2266 {
2267 stopAllEffects();
2268 }
2269 }
2270
2271 // if killer is the same then the most damager/hated
2272 L2Character mostHated = null;
2273 if (this instanceof L2Attackable)
2274 {
2275 mostHated = ((L2Attackable) this)._mostHated;
2276 }
2277
2278 if (mostHated != null && isInsideRadius(mostHated, 200, false, false))
2279 {
2280 calculateRewards(mostHated);
2281 }
2282 else
2283 {
2284 calculateRewards(killer);
2285 }
2286
2287 // Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform
2288 broadcastStatusUpdate();
2289
2290 // Notify L2Character AI
2291 getAI().notifyEvent(CtrlEvent.EVT_DEAD, null);
2292
2293 if (getWorldRegion() != null)
2294 {
2295 getWorldRegion().onDeath(this);
2296 }
2297
2298 // Notify Quest of character's death
2299 for (final QuestState qs : getNotifyQuestOfDeath())
2300 {
2301 qs.getQuest().notifyDeath((killer == null ? this : killer), this, qs);
2302 }
2303
2304 getNotifyQuestOfDeath().clear();
2305
2306 getAttackByList().clear();
2307
2308 // If character is PhoenixBlessed a resurrection popup will show up
2309 if (this instanceof L2PlayableInstance && ((L2PlayableInstance) this).isPhoenixBlessed())
2310 {
2311 ((L2PcInstance) this).reviveRequest(((L2PcInstance) this), null, false);
2312 }
2313 fireEvent(EventType.DIE.name, new Object[]
2314 {
2315 killer
2316 });
2317
2318 // Update active skills in progress (In Use and Not In Use because stacked) icones on client
2319 updateEffectIcons();
2320
2321 // After dead mob check if the killer got a moving task actived
2322 if (killer instanceof L2PcInstance)
2323 {
2324 if (((L2PcInstance) killer).isMovingTaskDefined())
2325 {
2326 ((L2PcInstance) killer).startMovingTask();
2327 }
2328 }
2329
2330 return true;
2331 }
2332
2333 /**
2334 * Calculate rewards.
2335 * @param killer the killer
2336 */
2337 protected void calculateRewards(final L2Character killer)
2338 {
2339 }
2340
2341 /** Sets HP, MP and CP and revives the L2Character. */
2342 public void doRevive()
2343 {
2344 if (!isTeleporting())
2345 {
2346 setIsPendingRevive(false);
2347
2348 if (this instanceof L2PlayableInstance && ((L2PlayableInstance) this).isPhoenixBlessed())
2349 {
2350 ((L2PlayableInstance) this).stopPhoenixBlessing(null);
2351
2352 // Like L2OFF Soul of The Phoenix and Salvation restore all hp,cp,mp.
2353 _status.setCurrentCp(getMaxCp());
2354 _status.setCurrentHp(getMaxHp());
2355 _status.setCurrentMp(getMaxMp());
2356 }
2357 else
2358 {
2359 _status.setCurrentCp(getMaxCp() * Config.RESPAWN_RESTORE_CP);
2360 _status.setCurrentHp(getMaxHp() * Config.RESPAWN_RESTORE_HP);
2361 }
2362 }
2363 // Start broadcast status
2364 broadcastPacket(new Revive(this));
2365
2366 if (getWorldRegion() != null)
2367 {
2368 getWorldRegion().onRevive(this);
2369 }
2370 else
2371 {
2372 setIsPendingRevive(true);
2373 }
2374 fireEvent(EventType.REVIVE.name, (Object[]) null);
2375 }
2376
2377 /**
2378 * Revives the L2Character using skill.
2379 * @param revivePower the revive power
2380 */
2381 public void doRevive(final double revivePower)
2382 {
2383 doRevive();
2384 }
2385
2386 /**
2387 * Check if the active L2Skill can be casted.<BR>
2388 * <BR>
2389 * <B><U> Actions</U> :</B><BR>
2390 * <BR>
2391 * <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>
2392 * <BR>
2393 * @param skill The L2Skill to use
2394 */
2395 protected void useMagic(final L2Skill skill)
2396 {
2397 if (skill == null || isDead())
2398 return;
2399
2400 // Check if the L2Character can cast
2401 if (!skill.isPotion() && isAllSkillsDisabled())
2402 // must be checked by caller
2403 return;
2404
2405 // Ignore the passive skill request. why does the client send it anyway ??
2406 if (skill.isPassive() || skill.isChance())
2407 return;
2408
2409 // Get the target for the skill
2410 L2Object target = null;
2411
2412 switch (skill.getTargetType())
2413 {
2414 case TARGET_AURA: // AURA, SELF should be cast even if no target has been found
2415 case TARGET_SELF:
2416 target = this;
2417 break;
2418 default:
2419 // Get the first target of the list
2420 target = skill.getFirstOfTargetList(this);
2421 break;
2422 }
2423
2424 // Notify the AI with AI_INTENTION_CAST and target
2425 getAI().setIntention(CtrlIntention.AI_INTENTION_CAST, skill, target);
2426 target = null;
2427 }
2428
2429 // =========================================================
2430 // Property - Public
2431 /**
2432 * Return the L2CharacterAI of the L2Character and if its null create a new one.
2433 * @return the aI
2434 */
2435 public L2CharacterAI getAI()
2436 {
2437 if (_ai == null)
2438 {
2439 synchronized (this)
2440 {
2441 if (_ai == null)
2442 {
2443 _ai = new L2CharacterAI(new AIAccessor());
2444 }
2445 }
2446 }
2447
2448 return _ai;
2449 }
2450
2451 /**
2452 * Sets the aI.
2453 * @param newAI the new aI
2454 */
2455 public void setAI(final L2CharacterAI newAI)
2456 {
2457 L2CharacterAI oldAI = getAI();
2458
2459 if (oldAI != null && oldAI != newAI && oldAI instanceof L2AttackableAI)
2460 {
2461 ((L2AttackableAI) oldAI).stopAITask();
2462 }
2463 _ai = newAI;
2464
2465 oldAI = null;
2466 }
2467
2468 /**
2469 * Return True if the L2Character has a L2CharacterAI.
2470 * @return true, if successful
2471 */
2472 public boolean hasAI()
2473 {
2474 return _ai != null;
2475 }
2476
2477 /**
2478 * Return True if the L2Character is RaidBoss or his minion.
2479 * @return true, if is raid
2480 */
2481 @Override
2482 public boolean isRaid()
2483 {
2484 return false;
2485 }
2486
2487 /**
2488 * Return True if the L2Character is an Npc.
2489 * @return true, if is npc
2490 */
2491 @Override
2492 public boolean isNpc()
2493 {
2494 return false;
2495 }
2496
2497 /**
2498 * Return a list of L2Character that attacked.
2499 * @return the attack by list
2500 */
2501 public final List<L2Character> getAttackByList()
2502 {
2503 if (_attackByList == null)
2504 {
2505 _attackByList = new FastList<>();
2506 }
2507
2508 return _attackByList;
2509 }
2510
2511 /**
2512 * Gets the last skill cast.
2513 * @return the last skill cast
2514 */
2515 public final L2Skill getLastSkillCast()
2516 {
2517 return _lastSkillCast;
2518 }
2519
2520 /**
2521 * Sets the last skill cast.
2522 * @param skill the new last skill cast
2523 */
2524 public void setLastSkillCast(final L2Skill skill)
2525 {
2526 _lastSkillCast = skill;
2527 }
2528
2529 /**
2530 * Gets the last potion cast.
2531 * @return the last potion cast
2532 */
2533 public final L2Skill getLastPotionCast()
2534 {
2535 return _lastPotionCast;
2536 }
2537
2538 /**
2539 * Sets the last potion cast.
2540 * @param skill the new last potion cast
2541 */
2542 public void setLastPotionCast(final L2Skill skill)
2543 {
2544 _lastPotionCast = skill;
2545 }
2546
2547 /**
2548 * Checks if is afraid.
2549 * @return true, if is afraid
2550 */
2551 public final boolean isAfraid()
2552 {
2553 return _isAfraid;
2554 }
2555
2556 /**
2557 * Sets the checks if is afraid.
2558 * @param value the new checks if is afraid
2559 */
2560 public final void setIsAfraid(final boolean value)
2561 {
2562 _isAfraid = value;
2563 }
2564
2565 /**
2566 * Return True if the L2Character is dead or use fake death.
2567 * @return true, if is alike dead
2568 */
2569 public final boolean isAlikeDead()
2570 {
2571 return isFakeDeath() || !(getCurrentHp() > 0.01);
2572 }
2573
2574 /**
2575 * Return True if the L2Character can't use its skills (ex : stun, sleep...).
2576 * @return true, if is all skills disabled
2577 */
2578 public final boolean isAllSkillsDisabled()
2579 {
2580 return _allSkillsDisabled || isImmobileUntilAttacked() || isStunned() || isSleeping() || isParalyzed();
2581 }
2582
2583 /**
2584 * Return True if the L2Character can't attack (stun, sleep, attackEndTime, fakeDeath, paralyse).
2585 * @return true, if is attacking disabled
2586 */
2587 public boolean isAttackingDisabled()
2588 {
2589 return isImmobileUntilAttacked() || isStunned() || isSleeping() || isFallsdown() || _attackEndTime > GameTimeController.getGameTicks() || isFakeDeath() || isParalyzed() || isAttackDisabled();
2590 }
2591
2592 /**
2593 * Gets the calculators.
2594 * @return the calculators
2595 */
2596 public final Calculator[] getCalculators()
2597 {
2598 return _calculators;
2599 }
2600
2601 /**
2602 * Checks if is confused.
2603 * @return true, if is confused
2604 */
2605 public final boolean isConfused()
2606 {
2607 return _isConfused;
2608 }
2609
2610 /**
2611 * Sets the checks if is confused.
2612 * @param value the new checks if is confused
2613 */
2614 public final void setIsConfused(final boolean value)
2615 {
2616 _isConfused = value;
2617 }
2618
2619 /**
2620 * Return True if the L2Character is dead.
2621 * @return true, if is dead
2622 */
2623 public final boolean isDead()
2624 {
2625 return !isFakeDeath() && (getCurrentHp() < 0.5);
2626 }
2627
2628 /**
2629 * Checks if is fake death.
2630 * @return true, if is fake death
2631 */
2632 public final boolean isFakeDeath()
2633 {
2634 return _isFakeDeath;
2635 }
2636
2637 /**
2638 * Sets the checks if is fake death.
2639 * @param value the new checks if is fake death
2640 */
2641 public final void setIsFakeDeath(final boolean value)
2642 {
2643 _isFakeDeath = value;
2644 }
2645
2646 /**
2647 * Return True if the L2Character is flying.
2648 * @return true, if is flying
2649 */
2650 public final boolean isFlying()
2651 {
2652 return _isFlying;
2653 }
2654
2655 /**
2656 * Set the L2Character flying mode to True.
2657 * @param mode the new checks if is flying
2658 */
2659 public final void setIsFlying(final boolean mode)
2660 {
2661 _isFlying = mode;
2662 }
2663
2664 /**
2665 * Checks if is fallsdown.
2666 * @return true, if is fallsdown
2667 */
2668 public final boolean isFallsdown()
2669 {
2670 return _isFallsdown;
2671 }
2672
2673 /**
2674 * Sets the checks if is fallsdown.
2675 * @param value the new checks if is fallsdown
2676 */
2677 public final void setIsFallsdown(final boolean value)
2678 {
2679 _isFallsdown = value;
2680 }
2681
2682 /**
2683 * Checks if is imobilised.
2684 * @return true, if is imobilised
2685 */
2686 public boolean isImobilised()
2687 {
2688 return _isImobilised > 0;
2689 }
2690
2691 /**
2692 * Sets the checks if is imobilised.
2693 * @param value the new checks if is imobilised
2694 */
2695 public void setIsImobilised(final boolean value)
2696 {
2697 // Stop this if he is moving
2698 this.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
2699
2700 if (value)
2701 {
2702 _isImobilised++;
2703 }
2704 else
2705 {
2706 _isImobilised--;
2707 }
2708 }
2709
2710 /**
2711 * Checks if is block buff.
2712 * @return the _isBlockBuff
2713 */
2714 public boolean isBlockBuff()
2715 {
2716 return _isBlockBuff;
2717 }
2718
2719 /**
2720 * Sets the block buff.
2721 * @param blockBuff the _isBlockBuff to set
2722 */
2723 public void setBlockBuff(final boolean blockBuff)
2724 {
2725 _isBlockBuff = blockBuff;
2726 }
2727
2728 /**
2729 * Checks if is block debuff.
2730 * @return the _isBlockDebuff
2731 */
2732 public boolean isBlockDebuff()
2733 {
2734 return _isBlockDebuff;
2735 }
2736
2737 /**
2738 * Sets the block debuff.
2739 * @param blockDebuff the _isBlockDebuff to set
2740 */
2741 public void setBlockDebuff(final boolean blockDebuff)
2742 {
2743 _isBlockDebuff = blockDebuff;
2744 }
2745
2746 /**
2747 * Checks if is killed already.
2748 * @return true, if is killed already
2749 */
2750 public final boolean isKilledAlready()
2751 {
2752 return _isKilledAlready;
2753 }
2754
2755 /**
2756 * Sets the checks if is killed already.
2757 * @param value the new checks if is killed already
2758 */
2759 public final void setIsKilledAlready(final boolean value)
2760 {
2761 _isKilledAlready = value;
2762 }
2763
2764 /**
2765 * Checks if is muted.
2766 * @return true, if is muted
2767 */
2768 public final boolean isMuted()
2769 {
2770 return _isMuted;
2771 }
2772
2773 /**
2774 * Sets the checks if is muted.
2775 * @param value the new checks if is muted
2776 */
2777 public final void setIsMuted(final boolean value)
2778 {
2779 _isMuted = value;
2780 }
2781
2782 /**
2783 * Checks if is psychical muted.
2784 * @return true, if is psychical muted
2785 */
2786 public final boolean isPsychicalMuted()
2787 {
2788 return _isPsychicalMuted;
2789 }
2790
2791 /**
2792 * Sets the checks if is psychical muted.
2793 * @param value the new checks if is psychical muted
2794 */
2795 public final void setIsPsychicalMuted(final boolean value)
2796 {
2797 _isPsychicalMuted = value;
2798 }
2799
2800 /**
2801 * Return True if the L2Character can't move (stun, root, sleep, overload, paralyzed).
2802 * @return true, if is movement disabled
2803 */
2804 public boolean isMovementDisabled()
2805 {
2806 return isImmobileUntilAttacked() || isStunned() || isRooted() || isSleeping() || isOverloaded() || isParalyzed() || isImobilised() || isFakeDeath() || isFallsdown();
2807 }
2808
2809 /**
2810 * Return True if the L2Character can be controlled by the player (confused, afraid).
2811 * @return true, if is out of control
2812 */
2813 public final boolean isOutOfControl()
2814 {
2815 return isConfused() || isAfraid() || isBlocked();
2816 }
2817
2818 /**
2819 * Checks if is overloaded.
2820 * @return true, if is overloaded
2821 */
2822 public final boolean isOverloaded()
2823 {
2824 return _isOverloaded;
2825 }
2826
2827 /**
2828 * Set the overloaded status of the L2Character is overloaded (if True, the L2PcInstance can't take more item).
2829 * @param value the new checks if is overloaded
2830 */
2831 public final void setIsOverloaded(final boolean value)
2832 {
2833 _isOverloaded = value;
2834 }
2835
2836 /**
2837 * Checks if is paralyzed.
2838 * @return true, if is paralyzed
2839 */
2840 public final boolean isParalyzed()
2841 {
2842 return _isParalyzed;
2843 }
2844
2845 /**
2846 * Sets the checks if is paralyzed.
2847 * @param value the new checks if is paralyzed
2848 */
2849 public final void setIsParalyzed(final boolean value)
2850 {
2851 if (_petrified)
2852 return;
2853 _isParalyzed = value;
2854 }
2855
2856 /**
2857 * Checks if is pending revive.
2858 * @return true, if is pending revive
2859 */
2860 public final boolean isPendingRevive()
2861 {
2862 return isDead() && _isPendingRevive;
2863 }
2864
2865 /**
2866 * Sets the checks if is pending revive.
2867 * @param value the new checks if is pending revive
2868 */
2869 public final void setIsPendingRevive(final boolean value)
2870 {
2871 _isPendingRevive = value;
2872 }
2873
2874 /**
2875 * Return the L2Summon of the L2Character.<BR>
2876 * <BR>
2877 * <B><U> Overriden in </U> :</B><BR>
2878 * <BR>
2879 * <li>L2PcInstance</li><BR>
2880 * <BR>
2881 * @return the pet
2882 */
2883 public L2Summon getPet()
2884 {
2885 return null;
2886 }
2887
2888 /**
2889 * Return True if the L2Character is ridding.
2890 * @return true, if is riding
2891 */
2892 public final boolean isRiding()
2893 {
2894 return _isRiding;
2895 }
2896
2897 /**
2898 * Set the L2Character riding mode to True.
2899 * @param mode the new checks if is riding
2900 */
2901 public final void setIsRiding(final boolean mode)
2902 {
2903 _isRiding = mode;
2904 }
2905
2906 /**
2907 * Checks if is rooted.
2908 * @return true, if is rooted
2909 */
2910 public final boolean isRooted()
2911 {
2912 return _isRooted;
2913 }
2914
2915 /**
2916 * Sets the checks if is rooted.
2917 * @param value the new checks if is rooted
2918 */
2919 public final void setIsRooted(final boolean value)
2920 {
2921 _isRooted = value;
2922 }
2923
2924 /**
2925 * Return True if the L2Character is running.
2926 * @return true, if is running
2927 */
2928 public final boolean isRunning()
2929 {
2930 return _isRunning;
2931 }
2932
2933 /**
2934 * Sets the checks if is running.
2935 * @param value the new checks if is running
2936 */
2937 public final void setIsRunning(final boolean value)
2938 {
2939 _isRunning = value;
2940 broadcastPacket(new ChangeMoveType(this));
2941 }
2942
2943 /**
2944 * Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance.
2945 */
2946 public final void setRunning()
2947 {
2948 if (!isRunning())
2949 {
2950 setIsRunning(true);
2951 }
2952 }
2953
2954 /**
2955 * Checks if is immobile until attacked.
2956 * @return true, if is immobile until attacked
2957 */
2958 public final boolean isImmobileUntilAttacked()
2959 {
2960 return _isImmobileUntilAttacked;
2961 }
2962
2963 /**
2964 * Sets the checks if is immobile until attacked.
2965 * @param value the new checks if is immobile until attacked
2966 */
2967 public final void setIsImmobileUntilAttacked(final boolean value)
2968 {
2969 _isImmobileUntilAttacked = value;
2970 }
2971
2972 /**
2973 * Checks if is sleeping.
2974 * @return true, if is sleeping
2975 */
2976 public final boolean isSleeping()
2977 {
2978 return _isSleeping;
2979 }
2980
2981 /**
2982 * Sets the checks if is sleeping.
2983 * @param value the new checks if is sleeping
2984 */
2985 public final void setIsSleeping(final boolean value)
2986 {
2987 _isSleeping = value;
2988 }
2989
2990 /**
2991 * Checks if is stunned.
2992 * @return true, if is stunned
2993 */
2994 public final boolean isStunned()
2995 {
2996 return _isStunned;
2997 }
2998
2999 /**
3000 * Sets the checks if is stunned.
3001 * @param value the new checks if is stunned
3002 */
3003 public final void setIsStunned(final boolean value)
3004 {
3005 _isStunned = value;
3006 }
3007
3008 /**
3009 * Checks if is betrayed.
3010 * @return true, if is betrayed
3011 */
3012 public final boolean isBetrayed()
3013 {
3014 return _isBetrayed;
3015 }
3016
3017 /**
3018 * Sets the checks if is betrayed.
3019 * @param value the new checks if is betrayed
3020 */
3021 public final void setIsBetrayed(final boolean value)
3022 {
3023 _isBetrayed = value;
3024 }
3025
3026 /**
3027 * Checks if is teleporting.
3028 * @return true, if is teleporting
3029 */
3030 public final boolean isTeleporting()
3031 {
3032 return _isTeleporting;
3033 }
3034
3035 /**
3036 * Sets the checks if is teleporting.
3037 * @param value the new checks if is teleporting
3038 */
3039 public void setIsTeleporting(final boolean value)
3040 {
3041 _isTeleporting = value;
3042 }
3043
3044 /**
3045 * Sets the checks if is invul.
3046 * @param b the new checks if is invul
3047 */
3048 public void setIsInvul(final boolean b)
3049 {
3050 if (_petrified)
3051 return;
3052
3053 _isInvul = b;
3054 }
3055
3056 /**
3057 * Checks if is invul.
3058 * @return true, if is invul
3059 */
3060 public boolean isInvul()
3061 {
3062 return _isInvul || _isTeleporting;
3063 }
3064
3065 /**
3066 * Checks if is undead.
3067 * @return true, if is undead
3068 */
3069 public boolean isUndead()
3070 {
3071 return _template.isUndead;
3072 }
3073
3074 /*
3075 * (non-Javadoc)
3076 * @see com.l2jfrozen.gameserver.model.L2Object#getKnownList()
3077 */
3078 @Override
3079 public CharKnownList getKnownList()
3080 {
3081 if (super.getKnownList() == null || !(super.getKnownList() instanceof CharKnownList))
3082 {
3083 setKnownList(new CharKnownList(this));
3084 }
3085
3086 return (CharKnownList) super.getKnownList();
3087 }
3088
3089 /**
3090 * Gets the stat.
3091 * @return the stat
3092 */
3093 public CharStat getStat()
3094 {
3095 if (_stat == null)
3096 {
3097 _stat = new CharStat(this);
3098 }
3099
3100 return _stat;
3101 }
3102
3103 /**
3104 * Sets the stat.
3105 * @param value the new stat
3106 */
3107 public final void setStat(final CharStat value)
3108 {
3109 _stat = value;
3110 }
3111
3112 /**
3113 * Gets the status.
3114 * @return the status
3115 */
3116 public CharStatus getStatus()
3117 {
3118 if (_status == null)
3119 {
3120 _status = new CharStatus(this);
3121 }
3122
3123 return _status;
3124 }
3125
3126 /**
3127 * Sets the status.
3128 * @param value the new status
3129 */
3130 public final void setStatus(final CharStatus value)
3131 {
3132 _status = value;
3133 }
3134
3135 /**
3136 * Gets the template.
3137 * @return the template
3138 */
3139 public L2CharTemplate getTemplate()
3140 {
3141 return _template;
3142 }
3143
3144 /**
3145 * Set the template of the L2Character.<BR>
3146 * <BR>
3147 * <B><U> Concept</U> :</B><BR>
3148 * <BR>
3149 * 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
3150 * L2Character is spawned, server just create a link between the instance and the template This link is stored in <B>_template</B><BR>
3151 * <BR>
3152 * <B><U> Assert </U> :</B><BR>
3153 * <BR>
3154 * <li>this instanceof L2Character</li><BR>
3155 * <BR
3156 * @param template the new template
3157 */
3158 protected synchronized final void setTemplate(final L2CharTemplate template)
3159 {
3160 _template = template;
3161 }
3162
3163 /**
3164 * Return the Title of the L2Character.
3165 * @return the title
3166 */
3167 public final String getTitle()
3168 {
3169 if (_title == null)
3170 return "";
3171
3172 return _title;
3173 }
3174
3175 /**
3176 * Set the Title of the L2Character.
3177 * @param value the new title
3178 */
3179 public final void setTitle(String value)
3180 {
3181 if (value == null)
3182 value = "";
3183
3184 if (this instanceof L2PcInstance && value.length() > 16)
3185 {
3186 value = value.substring(0, 15);
3187 }
3188
3189 _title = value; // public final void setTitle(String value) { _title = value; }
3190 }
3191
3192 /**
3193 * Set the L2Character movement type to walk and send Server->Client packet ChangeMoveType to all others L2PcInstance.
3194 */
3195 public final void setWalking()
3196 {
3197 if (isRunning())
3198 {
3199 setIsRunning(false);
3200 }
3201 }
3202
3203 /**
3204 * Task lauching the function enableSkill().
3205 */
3206 class EnableSkill implements Runnable
3207 {
3208
3209 /** The _skill id. */
3210 L2Skill _skillId;
3211
3212 /**
3213 * Instantiates a new enable skill.
3214 * @param skill the skill
3215 */
3216 public EnableSkill(final L2Skill skill)
3217 {
3218 _skillId = skill;
3219 }
3220
3221 /*
3222 * (non-Javadoc)
3223 * @see java.lang.Runnable#run()
3224 */
3225 @Override
3226 public void run()
3227 {
3228 try
3229 {
3230 enableSkill(_skillId);
3231 }
3232 catch (final Throwable e)
3233 {
3234 LOGGER.error("", e);
3235 }
3236 }
3237 }
3238
3239 /**
3240 * Task lauching the function onHitTimer().<BR>
3241 * <BR>
3242 * <B><U> Actions</U> :</B><BR>
3243 * <BR>
3244 * <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>
3245 * <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>
3246 * <BR>
3247 */
3248 class HitTask implements Runnable
3249 {
3250
3251 /** The _hit target. */
3252 L2Character _hitTarget;
3253
3254 /** The _damage. */
3255 int _damage;
3256
3257 /** The _crit. */
3258 boolean _crit;
3259
3260 /** The _miss. */
3261 boolean _miss;
3262
3263 /** The _shld. */
3264 boolean _shld;
3265
3266 /** The _soulshot. */
3267 boolean _soulshot;
3268
3269 /**
3270 * Instantiates a new hit task.
3271 * @param target the target
3272 * @param damage the damage
3273 * @param crit the crit
3274 * @param miss the miss
3275 * @param soulshot the soulshot
3276 * @param shld the shld
3277 */
3278 public HitTask(final L2Character target, final int damage, final boolean crit, final boolean miss, final boolean soulshot, final boolean shld)
3279 {
3280 _hitTarget = target;
3281 _damage = damage;
3282 _crit = crit;
3283 _shld = shld;
3284 _miss = miss;
3285 _soulshot = soulshot;
3286 }
3287
3288 /*
3289 * (non-Javadoc)
3290 * @see java.lang.Runnable#run()
3291 */
3292 @Override
3293 public void run()
3294 {
3295 try
3296 {
3297 onHitTimer(_hitTarget, _damage, _crit, _miss, _soulshot, _shld);
3298 }
3299 catch (final Throwable e)
3300 {
3301 LOGGER.error("fixme:hit task unhandled exception", e);
3302 }
3303 }
3304 }
3305
3306 /**
3307 * Task lauching the magic skill phases.
3308 */
3309 class MagicUseTask implements Runnable
3310 {
3311
3312 /** The _targets. */
3313 L2Object[] _targets;
3314
3315 /** The _skill. */
3316 L2Skill _skill;
3317
3318 /** The _cool time. */
3319 int _coolTime;
3320
3321 /** The _phase. */
3322 int _phase;
3323
3324 /**
3325 * Instantiates a new magic use task.
3326 * @param targets the targets
3327 * @param skill the skill
3328 * @param coolTime the cool time
3329 * @param phase the phase
3330 */
3331 public MagicUseTask(final L2Object[] targets, final L2Skill skill, final int coolTime, final int phase)
3332 {
3333 _targets = targets;
3334 _skill = skill;
3335 _coolTime = coolTime;
3336 _phase = phase;
3337 }
3338
3339 /*
3340 * (non-Javadoc)
3341 * @see java.lang.Runnable#run()
3342 */
3343 @Override
3344 public void run()
3345 {
3346 try
3347 {
3348 switch (_phase)
3349 {
3350 case 1:
3351 onMagicLaunchedTimer(_targets, _skill, _coolTime, false);
3352 break;
3353 case 2:
3354 onMagicHitTimer(_targets, _skill, _coolTime, false);
3355 break;
3356 case 3:
3357 onMagicFinalizer(_targets, _skill);
3358 break;
3359 default:
3360 break;
3361 }
3362 }
3363 catch (final Throwable e)
3364 {
3365 LOGGER.error("", e);
3366 e.printStackTrace();
3367 enableAllSkills();
3368 }
3369 }
3370 }
3371
3372 /**
3373 * Task lauching the function useMagic().
3374 */
3375 class QueuedMagicUseTask implements Runnable
3376 {
3377
3378 /** The _curr player. */
3379 L2PcInstance _currPlayer;
3380
3381 /** The _queued skill. */
3382 L2Skill _queuedSkill;
3383
3384 /** The _is ctrl pressed. */
3385 boolean _isCtrlPressed;
3386
3387 /** The _is shift pressed. */
3388 boolean _isShiftPressed;
3389
3390 /**
3391 * Instantiates a new queued magic use task.
3392 * @param currPlayer the curr player
3393 * @param queuedSkill the queued skill
3394 * @param isCtrlPressed the is ctrl pressed
3395 * @param isShiftPressed the is shift pressed
3396 */
3397 public QueuedMagicUseTask(final L2PcInstance currPlayer, final L2Skill queuedSkill, final boolean isCtrlPressed, final boolean isShiftPressed)
3398 {
3399 _currPlayer = currPlayer;
3400 _queuedSkill = queuedSkill;
3401 _isCtrlPressed = isCtrlPressed;
3402 _isShiftPressed = isShiftPressed;
3403 }
3404
3405 /*
3406 * (non-Javadoc)
3407 * @see java.lang.Runnable#run()
3408 */
3409 @Override
3410 public void run()
3411 {
3412 try
3413 {
3414 _currPlayer.useMagic(_queuedSkill, _isCtrlPressed, _isShiftPressed);
3415 }
3416 catch (final Throwable e)
3417 {
3418 LOGGER.error("", e);
3419 }
3420 }
3421 }
3422
3423 /**
3424 * Task of AI notification.
3425 */
3426 public class NotifyAITask implements Runnable
3427 {
3428
3429 /** The _evt. */
3430 private final CtrlEvent _evt;
3431
3432 /**
3433 * Instantiates a new notify ai task.
3434 * @param evt the evt
3435 */
3436 NotifyAITask(final CtrlEvent evt)
3437 {
3438 _evt = evt;
3439 }
3440
3441 /*
3442 * (non-Javadoc)
3443 * @see java.lang.Runnable#run()
3444 */
3445 @Override
3446 public void run()
3447 {
3448 try
3449 {
3450 getAI().notifyEvent(_evt, null);
3451 }
3452 catch (final Throwable t)
3453 {
3454 LOGGER.warn("", t);
3455 }
3456 }
3457 }
3458
3459 /**
3460 * Task lauching the function stopPvPFlag().
3461 */
3462 class PvPFlag implements Runnable
3463 {
3464
3465 /**
3466 * Instantiates a new pvp flag.
3467 */
3468 public PvPFlag()
3469 {
3470 // null
3471 }
3472
3473 /*
3474 * (non-Javadoc)
3475 * @see java.lang.Runnable#run()
3476 */
3477 @Override
3478 public void run()
3479 {
3480 try
3481 {
3482 // LOGGER.fine("Checking pvp time: " + getlastPvpAttack());
3483 // "lastattack: " _lastAttackTime "currenttime: "
3484 // System.currentTimeMillis());
3485 if (System.currentTimeMillis() > getPvpFlagLasts())
3486 {
3487 // LOGGER.fine("Stopping PvP");
3488 stopPvPFlag();
3489 }
3490 else if (System.currentTimeMillis() > getPvpFlagLasts() - 5000)
3491 {
3492 updatePvPFlag(2);
3493 }
3494 else
3495 {
3496 updatePvPFlag(1);
3497 // Start a new PvP timer check
3498 // checkPvPFlag();
3499 }
3500 }
3501 catch (final Exception e)
3502 {
3503 LOGGER.warn("error in pvp flag task:", e);
3504 }
3505 }
3506 }
3507
3508 // =========================================================
3509
3510 // =========================================================
3511 // Abnormal Effect - NEED TO REMOVE ONCE L2CHARABNORMALEFFECT IS COMPLETE
3512 // Data Field
3513 /** Map 32 bits (0x0000) containing all abnormal effect in progress. */
3514 private int _AbnormalEffects;
3515
3516 /**
3517 * FastTable containing all active skills effects in progress of a L2Character.
3518 */
3519 private final FastTable<L2Effect> _effects = new FastTable<>();
3520
3521 /** The table containing the List of all stacked effect in progress for each Stack group Identifier. */
3522 protected Map<String, List<L2Effect>> _stackedEffects = new FastMap<>();
3523
3524 /** The Constant ABNORMAL_EFFECT_BLEEDING. */
3525 public static final int ABNORMAL_EFFECT_BLEEDING = 0x000001;
3526
3527 /** The Constant ABNORMAL_EFFECT_POISON. */
3528 public static final int ABNORMAL_EFFECT_POISON = 0x000002;
3529
3530 /** The Constant ABNORMAL_EFFECT_REDCIRCLE. */
3531 public static final int ABNORMAL_EFFECT_REDCIRCLE = 0x000004;
3532
3533 /** The Constant ABNORMAL_EFFECT_ICE. */
3534 public static final int ABNORMAL_EFFECT_ICE = 0x000008;
3535
3536 /** The Constant ABNORMAL_EFFECT_WIND. */
3537 public static final int ABNORMAL_EFFECT_WIND = 0x0000010;
3538
3539 /** The Constant ABNORMAL_EFFECT_FEAR. */
3540 public static final int ABNORMAL_EFFECT_FEAR = 0x0000020;
3541
3542 /** The Constant ABNORMAL_EFFECT_STUN. */
3543 public static final int ABNORMAL_EFFECT_STUN = 0x000040;
3544
3545 /** The Constant ABNORMAL_EFFECT_SLEEP. */
3546 public static final int ABNORMAL_EFFECT_SLEEP = 0x000080;
3547
3548 /** The Constant ABNORMAL_EFFECT_MUTED. */
3549 public static final int ABNORMAL_EFFECT_MUTED = 0x000100;
3550
3551 /** The Constant ABNORMAL_EFFECT_ROOT. */
3552 public static final int ABNORMAL_EFFECT_ROOT = 0x000200;
3553
3554 /** The Constant ABNORMAL_EFFECT_HOLD_1. */
3555 public static final int ABNORMAL_EFFECT_HOLD_1 = 0x000400;
3556
3557 /** The Constant ABNORMAL_EFFECT_HOLD_2. */
3558 public static final int ABNORMAL_EFFECT_HOLD_2 = 0x000800;
3559
3560 /** The Constant ABNORMAL_EFFECT_UNKNOWN_13. */
3561 public static final int ABNORMAL_EFFECT_UNKNOWN_13 = 0x001000;
3562
3563 /** The Constant ABNORMAL_EFFECT_BIG_HEAD. */
3564 public static final int ABNORMAL_EFFECT_BIG_HEAD = 0x002000;
3565
3566 /** The Constant ABNORMAL_EFFECT_FLAME. */
3567 public static final int ABNORMAL_EFFECT_FLAME = 0x004000;
3568
3569 /** The Constant ABNORMAL_EFFECT_UNKNOWN_16. */
3570 public static final int ABNORMAL_EFFECT_UNKNOWN_16 = 0x008000;
3571
3572 /** The Constant ABNORMAL_EFFECT_GROW. */
3573 public static final int ABNORMAL_EFFECT_GROW = 0x010000;
3574
3575 /** The Constant ABNORMAL_EFFECT_FLOATING_ROOT. */
3576 public static final int ABNORMAL_EFFECT_FLOATING_ROOT = 0x020000;
3577
3578 /** The Constant ABNORMAL_EFFECT_DANCE_STUNNED. */
3579 public static final int ABNORMAL_EFFECT_DANCE_STUNNED = 0x040000;
3580
3581 /** The Constant ABNORMAL_EFFECT_FIREROOT_STUN. */
3582 public static final int ABNORMAL_EFFECT_FIREROOT_STUN = 0x080000;
3583
3584 /** The Constant ABNORMAL_EFFECT_STEALTH. */
3585 public static final int ABNORMAL_EFFECT_STEALTH = 0x100000;
3586
3587 /** The Constant ABNORMAL_EFFECT_IMPRISIONING_1. */
3588 public static final int ABNORMAL_EFFECT_IMPRISIONING_1 = 0x200000;
3589
3590 /** The Constant ABNORMAL_EFFECT_IMPRISIONING_2. */
3591 public static final int ABNORMAL_EFFECT_IMPRISIONING_2 = 0x400000;
3592
3593 /** The Constant ABNORMAL_EFFECT_MAGIC_CIRCLE. */
3594 public static final int ABNORMAL_EFFECT_MAGIC_CIRCLE = 0x800000;
3595
3596 /** The Constant ABNORMAL_EFFECT_CONFUSED. */
3597 public static final int ABNORMAL_EFFECT_CONFUSED = 0x0020;
3598
3599 /** The Constant ABNORMAL_EFFECT_AFRAID. */
3600 public static final int ABNORMAL_EFFECT_AFRAID = 0x0010;
3601
3602 // Method - Public
3603 /**
3604 * Launch and add L2Effect (including Stack Group management) to L2Character and update client magic icone.<BR>
3605 * <BR>
3606 * <B><U> Concept</U> :</B><BR>
3607 * <BR>
3608 * 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>
3609 * <BR>
3610 * 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
3611 * time on a L2Character, only the more efficient (identified by its priority order) will be preserve.<BR>
3612 * <BR>
3613 * <B><U> Actions</U> :</B><BR>
3614 * <BR>
3615 * <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
3616 * 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>
3617 * @param newEffect the new effect
3618 */
3619 public synchronized void addEffect(final L2Effect newEffect)
3620 {
3621 if (newEffect == null)
3622 return;
3623
3624 final L2Effect[] effects = getAllEffects();
3625
3626 // Make sure there's no same effect previously
3627 for (final L2Effect effect : effects)
3628 {
3629 if (effect == null)
3630 {
3631
3632 synchronized (_effects)
3633 {
3634 _effects.remove(effect);
3635 }
3636 continue;
3637 }
3638
3639 if (effect.getSkill().getId() == newEffect.getSkill().getId() && effect.getEffectType() == newEffect.getEffectType() && effect.getStackType() == newEffect.getStackType())
3640 {
3641 if (this instanceof L2PcInstance)
3642 {
3643
3644 final L2PcInstance player = (L2PcInstance) this;
3645
3646 if (player.isInDuel())
3647 {
3648 DuelManager.getInstance().getDuel(player.getDuelId()).onBuffStop(player, effect);
3649 }
3650
3651 }
3652
3653 if ((newEffect.getSkill().getSkillType() == SkillType.BUFF || newEffect.getEffectType() == L2Effect.EffectType.BUFF || newEffect.getEffectType() == L2Effect.EffectType.HEAL_OVER_TIME) && newEffect.getStackOrder() >= effect.getStackOrder())
3654 {
3655 effect.exit(false);
3656 }
3657 else
3658 {
3659 // newEffect.exit(false);
3660 newEffect.stopEffectTask();
3661 return;
3662 }
3663 }
3664 }
3665
3666 final L2Skill tempskill = newEffect.getSkill();
3667
3668 // Remove first Buff if number of buffs > BUFFS_MAX_AMOUNT
3669 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))
3670 {
3671 if (newEffect.isHerbEffect())
3672 {
3673 newEffect.exit(false);
3674 return;
3675 }
3676 removeFirstBuff(tempskill.getId());
3677 }
3678
3679 // Remove first DeBuff if number of debuffs > DEBUFFS_MAX_AMOUNT
3680 if (getDeBuffCount() >= Config.DEBUFFS_MAX_AMOUNT && !doesStack(tempskill) && tempskill.is_Debuff())
3681 {
3682 removeFirstDeBuff(tempskill.getId());
3683 }
3684
3685 synchronized (_effects)
3686 {
3687 // Add the L2Effect to all effect in progress on the L2Character
3688 if (!newEffect.getSkill().isToggle())
3689 {
3690 int pos = 0;
3691
3692 for (int i = 0; i < _effects.size(); i++)
3693 {
3694 if (_effects.get(i) == null)
3695 {
3696 _effects.remove(i);
3697 i--;
3698 continue;
3699 }
3700
3701 if (_effects.get(i) != null)
3702 {
3703 final int skillid = _effects.get(i).getSkill().getId();
3704
3705 if (!_effects.get(i).getSkill().isToggle() && !(skillid > 4360 && skillid < 4367))
3706 {
3707 pos++;
3708 }
3709 }
3710 else
3711 {
3712 break;
3713 }
3714 }
3715 _effects.add(pos, newEffect);
3716 }
3717 else
3718 {
3719 _effects.addLast(newEffect);
3720 }
3721
3722 }
3723
3724 // Check if a stack group is defined for this effect
3725 if (newEffect.getStackType().equals("none"))
3726 {
3727 // Set this L2Effect to In Use
3728 newEffect.setInUse(true);
3729
3730 // Add Funcs of this effect to the Calculator set of the L2Character
3731 addStatFuncs(newEffect.getStatFuncs());
3732
3733 // Update active skills in progress icones on player client
3734 updateEffectIcons();
3735 return;
3736 }
3737
3738 // Get the list of all stacked effects corresponding to the stack type of the L2Effect to add
3739 List<L2Effect> stackQueue = _stackedEffects.get(newEffect.getStackType());
3740
3741 if (stackQueue == null)
3742 {
3743 stackQueue = new FastList<>();
3744 }
3745
3746 // L2Effect tempEffect = null;
3747
3748 if (stackQueue.size() > 0)
3749 {
3750 // Get the first stacked effect of the Stack group selected
3751 if (_effects.contains(stackQueue.get(0)))
3752 {
3753 // Remove all Func objects corresponding to this stacked effect from the Calculator set of the L2Character
3754 removeStatsOwner(stackQueue.get(0));
3755
3756 // Set the L2Effect to Not In Use
3757 stackQueue.get(0).setInUse(false);
3758 }
3759 }
3760
3761 // Add the new effect to the stack group selected at its position
3762 stackQueue = effectQueueInsert(newEffect, stackQueue);
3763
3764 if (stackQueue == null)
3765 return;
3766
3767 // Update the Stack Group table _stackedEffects of the L2Character
3768 _stackedEffects.put(newEffect.getStackType(), stackQueue);
3769
3770 // Get the first stacked effect of the Stack group selected
3771 if (_effects.contains(stackQueue.get(0)))
3772 {
3773 // Set this L2Effect to In Use
3774 stackQueue.get(0).setInUse(true);
3775
3776 // Add all Func objects corresponding to this stacked effect to the Calculator set of the L2Character
3777 addStatFuncs(stackQueue.get(0).getStatFuncs());
3778 }
3779
3780 // Update active skills in progress (In Use and Not In Use because stacked) icones on client
3781 updateEffectIcons();
3782 }
3783
3784 /**
3785 * Insert an effect at the specified position in a Stack Group.<BR>
3786 * <BR>
3787 * <B><U> Concept</U> :</B><BR>
3788 * <BR>
3789 * 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
3790 * time on a L2Character, only the more efficient (identified by its priority order) will be preserve.<BR>
3791 * <BR>
3792 * @param newStackedEffect the new stacked effect
3793 * @param stackQueue The Stack Group in wich the effect must be added
3794 * @return the list
3795 */
3796 private List<L2Effect> effectQueueInsert(final L2Effect newStackedEffect, final List<L2Effect> stackQueue)
3797 {
3798 // Create an Iterator to go through the list of stacked effects in progress on the L2Character
3799 Iterator<L2Effect> queueIterator = stackQueue.iterator();
3800
3801 int i = 0;
3802 while (queueIterator.hasNext())
3803 {
3804 final L2Effect cur = queueIterator.next();
3805 if (newStackedEffect.getStackOrder() < cur.getStackOrder())
3806 {
3807 i++;
3808 }
3809 else
3810 {
3811 break;
3812 }
3813 }
3814
3815 // Add the new effect to the Stack list in function of its position in the Stack group
3816 stackQueue.add(i, newStackedEffect);
3817
3818 // skill.exit() could be used, if the users don't wish to see "effect
3819 // removed" always when a timer goes off, even if the buff isn't active
3820 // any more (has been replaced). but then check e.g. npc hold and raid petrify.
3821 if (Config.EFFECT_CANCELING && !newStackedEffect.isHerbEffect() && stackQueue.size() > 1)
3822 {
3823 synchronized (_effects)
3824 {
3825
3826 _effects.remove(stackQueue.get(1));
3827
3828 }
3829
3830 stackQueue.remove(1);
3831 }
3832
3833 queueIterator = null;
3834
3835 return stackQueue;
3836 }
3837
3838 /**
3839 * Stop and remove L2Effect (including Stack Group management) from L2Character and update client magic icone.<BR>
3840 * <BR>
3841 * <B><U> Concept</U> :</B><BR>
3842 * <BR>
3843 * 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>
3844 * <BR>
3845 * 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
3846 * time on a L2Character, only the more efficient (identified by its priority order) will be preserve.<BR>
3847 * <BR>
3848 * <B><U> Actions</U> :</B><BR>
3849 * <BR>
3850 * <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
3851 * progress icones on player client</li><BR>
3852 * @param effect the effect
3853 */
3854 public final void removeEffect(final L2Effect effect)
3855 {
3856 if (effect == null/* || _effects == null */)
3857 return;
3858
3859 if (effect.getStackType() == "none")
3860 {
3861 // Remove Func added by this effect from the L2Character Calculator
3862 removeStatsOwner(effect);
3863 }
3864 else
3865 {
3866 if (_stackedEffects == null)
3867 return;
3868
3869 // Get the list of all stacked effects corresponding to the stack type of the L2Effect to add
3870 final List<L2Effect> stackQueue = _stackedEffects.get(effect.getStackType());
3871
3872 if (stackQueue == null || stackQueue.size() < 1)
3873 return;
3874
3875 // Get the Identifier of the first stacked effect of the Stack group selected
3876 final L2Effect frontEffect = stackQueue.get(0);
3877
3878 // Remove the effect from the Stack Group
3879 final boolean removed = stackQueue.remove(effect);
3880
3881 if (removed)
3882 {
3883 // Check if the first stacked effect was the effect to remove
3884 if (frontEffect == effect)
3885 {
3886 // Remove all its Func objects from the L2Character calculator set
3887 removeStatsOwner(effect);
3888
3889 // Check if there's another effect in the Stack Group
3890 if (stackQueue.size() > 0)
3891 {
3892 // Add its list of Funcs to the Calculator set of the L2Character
3893 if (_effects.contains(stackQueue.get(0)))
3894 {
3895
3896 // Add its list of Funcs to the Calculator set of the L2Character
3897 addStatFuncs(stackQueue.get(0).getStatFuncs());
3898 // Set the effect to In Use
3899 stackQueue.get(0).setInUse(true);
3900
3901 }
3902
3903 }
3904 }
3905 if (stackQueue.isEmpty())
3906 {
3907 _stackedEffects.remove(effect.getStackType());
3908 }
3909 else
3910 {
3911 // Update the Stack Group table _stackedEffects of the L2Character
3912 _stackedEffects.put(effect.getStackType(), stackQueue);
3913 }
3914 }
3915
3916 }
3917
3918 synchronized (_effects)
3919 {
3920 // Remove the active skill L2effect from _effects of the L2Character
3921 _effects.remove(effect);
3922
3923 }
3924
3925 // Update active skills in progress (In Use and Not In Use because stacked) icones on client
3926 updateEffectIcons();
3927 }
3928
3929 /**
3930 * Active abnormal effects flags in the binary mask and send Server->Client UserInfo/CharInfo packet.<BR>
3931 * <BR>
3932 * @param mask the mask
3933 */
3934 public final void startAbnormalEffect(final int mask)
3935 {
3936 _AbnormalEffects |= mask;
3937 updateAbnormalEffect();
3938 }
3939
3940 /**
3941 * immobile start.
3942 */
3943 public final void startImmobileUntilAttacked()
3944 {
3945 setIsImmobileUntilAttacked(true);
3946 abortAttack();
3947 abortCast();
3948 getAI().notifyEvent(CtrlEvent.EVT_SLEEPING);
3949 updateAbnormalEffect();
3950 }
3951
3952 /**
3953 * Active the abnormal effect Confused flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
3954 * <BR>
3955 */
3956 public final void startConfused()
3957 {
3958 setIsConfused(true);
3959 getAI().notifyEvent(CtrlEvent.EVT_CONFUSED);
3960 updateAbnormalEffect();
3961 }
3962
3963 /**
3964 * Active the abnormal effect Fake Death flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
3965 * <BR>
3966 */
3967 public final void startFakeDeath()
3968 {
3969 setIsFallsdown(true);
3970 setIsFakeDeath(true);
3971 /* Aborts any attacks/casts if fake dead */
3972 abortAttack();
3973 abortCast();
3974 stopMove(null);
3975 getAI().notifyEvent(CtrlEvent.EVT_FAKE_DEATH, null);
3976 broadcastPacket(new ChangeWaitType(this, ChangeWaitType.WT_START_FAKEDEATH));
3977 }
3978
3979 /**
3980 * Active the abnormal effect Fear flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
3981 * <BR>
3982 */
3983 public final void startFear()
3984 {
3985 setIsAfraid(true);
3986 getAI().notifyEvent(CtrlEvent.EVT_AFFRAID);
3987 updateAbnormalEffect();
3988 }
3989
3990 /**
3991 * Active the abnormal effect Muted flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
3992 * <BR>
3993 */
3994 public final void startMuted()
3995 {
3996 setIsMuted(true);
3997 /* Aborts any casts if muted */
3998 abortCast();
3999 getAI().notifyEvent(CtrlEvent.EVT_MUTED);
4000 updateAbnormalEffect();
4001 }
4002
4003 /**
4004 * Active the abnormal effect Psychical_Muted flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
4005 * <BR>
4006 */
4007 public final void startPsychicalMuted()
4008 {
4009 setIsPsychicalMuted(true);
4010 getAI().notifyEvent(CtrlEvent.EVT_MUTED);
4011 updateAbnormalEffect();
4012 }
4013
4014 /**
4015 * Active the abnormal effect Root flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
4016 * <BR>
4017 */
4018 public final void startRooted()
4019 {
4020 setIsRooted(true);
4021 stopMove(null);
4022 getAI().notifyEvent(CtrlEvent.EVT_ROOTED, null);
4023 updateAbnormalEffect();
4024 }
4025
4026 /**
4027 * Active the abnormal effect Sleep flag, notify the L2Character AI and send Server->Client UserInfo/CharInfo packet.<BR>
4028 * <BR>
4029 */
4030 public final void startSleeping()
4031 {
4032 setIsSleeping(true);
4033 /* Aborts any attacks/casts if sleeped */
4034 abortAttack();
4035 abortCast();
4036 stopMove(null);
4037 getAI().notifyEvent(CtrlEvent.EVT_SLEEPING, null);
4038 updateAbnormalEffect();
4039 }
4040
4041 /**
4042 * Launch a Stun Abnormal Effect on the L2Character.<BR>
4043 * <BR>
4044 * <B><U> Actions</U> :</B><BR>
4045 * <BR>
4046 * <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
4047 * L2PcInstance attacker</li><BR>
4048 * <BR>
4049 */
4050 public final void startStunning()
4051 {
4052 if (isStunned())
4053 return;
4054
4055 setIsStunned(true);
4056 /* Aborts any attacks/casts if stunned */
4057 abortAttack();
4058 abortCast();
4059 getAI().stopFollow(); // Like L2OFF char stop to follow if sticked to another one
4060 stopMove(null);
4061 getAI().notifyEvent(CtrlEvent.EVT_STUNNED, null);
4062 updateAbnormalEffect();
4063 }
4064
4065 /**
4066 * Start betray.
4067 */
4068 public final void startBetray()
4069 {
4070 setIsBetrayed(true);
4071 getAI().notifyEvent(CtrlEvent.EVT_BETRAYED, null);
4072 updateAbnormalEffect();
4073 }
4074
4075 /**
4076 * Stop betray.
4077 */
4078 public final void stopBetray()
4079 {
4080 stopEffects(L2Effect.EffectType.BETRAY);
4081 setIsBetrayed(false);
4082 updateAbnormalEffect();
4083 }
4084
4085 /**
4086 * Modify the abnormal effect map according to the mask.<BR>
4087 * <BR>
4088 * @param mask the mask
4089 */
4090 public final void stopAbnormalEffect(final int mask)
4091 {
4092 _AbnormalEffects &= ~mask;
4093 updateAbnormalEffect();
4094 }
4095
4096 /**
4097 * Stop all active skills effects in progress on the L2Character.<BR>
4098 * <BR>
4099 */
4100 public final void stopAllEffects()
4101 {
4102
4103 final L2Effect[] effects = getAllEffects();
4104
4105 for (final L2Effect effect : effects)
4106 {
4107
4108 if (effect != null)
4109 {
4110 effect.exit(true);
4111 }
4112 else
4113 {
4114 synchronized (_effects)
4115 {
4116 _effects.remove(effect);
4117 }
4118 }
4119 }
4120
4121 if (this instanceof L2PcInstance)
4122 {
4123 ((L2PcInstance) this).updateAndBroadcastStatus(2);
4124 }
4125
4126 }
4127
4128 /**
4129 * Stop immobilization until attacked abnormal L2Effect.<BR>
4130 * <BR>
4131 * <B><U> Actions</U> :</B><BR>
4132 * <BR>
4133 * <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>
4134 * <BR>
4135 * @param effect the effect
4136 */
4137 public final void stopImmobileUntilAttacked(final L2Effect effect)
4138 {
4139 if (effect == null)
4140 {
4141 stopEffects(L2Effect.EffectType.IMMOBILEUNTILATTACKED);
4142 }
4143 else
4144 {
4145 removeEffect(effect);
4146 stopSkillEffects(effect.getSkill().getNegateId());
4147 }
4148
4149 setIsImmobileUntilAttacked(false);
4150 getAI().notifyEvent(CtrlEvent.EVT_THINK);
4151 updateAbnormalEffect();
4152 }
4153
4154 /**
4155 * Stop a specified/all Confused abnormal L2Effect.<BR>
4156 * <BR>
4157 * <B><U> Actions</U> :</B><BR>
4158 * <BR>
4159 * <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>
4160 * <BR>
4161 * @param effect the effect
4162 */
4163 public final void stopConfused(final L2Effect effect)
4164 {
4165 if (effect == null)
4166 {
4167 stopEffects(L2Effect.EffectType.CONFUSION);
4168 }
4169 else
4170 {
4171 removeEffect(effect);
4172 }
4173
4174 setIsConfused(false);
4175 getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
4176 updateAbnormalEffect();
4177 }
4178
4179 /**
4180 * Stop and remove the L2Effects corresponding to the L2Skill Identifier and update client magic icone.<BR>
4181 * <BR>
4182 * <B><U> Concept</U> :</B><BR>
4183 * <BR>
4184 * 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>
4185 * <BR>
4186 * @param skillId the skill id
4187 */
4188 public final void stopSkillEffects(final int skillId)
4189 {
4190 final L2Effect[] effects = getAllEffects();
4191
4192 for (final L2Effect effect : effects)
4193 {
4194
4195 if (effect == null || effect.getSkill() == null)
4196 {
4197
4198 synchronized (_effects)
4199 {
4200 _effects.remove(effect);
4201 }
4202 continue;
4203
4204 }
4205
4206 if (effect.getSkill().getId() == skillId)
4207 {
4208 effect.exit(true);
4209 }
4210
4211 }
4212
4213 }
4214
4215 /**
4216 * Stop and remove all L2Effect of the selected type (ex : BUFF, DMG_OVER_TIME...) from the L2Character and update client magic icone.<BR>
4217 * <BR>
4218 * <B><U> Concept</U> :</B><BR>
4219 * <BR>
4220 * 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>
4221 * <BR>
4222 * <B><U> Actions</U> :</B><BR>
4223 * <BR>
4224 * <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>
4225 * <BR>
4226 * @param type The type of effect to stop ((ex : BUFF, DMG_OVER_TIME...)
4227 */
4228 public final void stopEffects(final L2Effect.EffectType type)
4229 {
4230 final L2Effect[] effects = getAllEffects();
4231
4232 for (final L2Effect effect : effects)
4233 {
4234
4235 if (effect == null)
4236 {
4237
4238 synchronized (_effects)
4239 {
4240 _effects.remove(effect);
4241 }
4242 continue;
4243
4244 }
4245
4246 // LOGGER.info("Character Effect Type: "+effects[i].getEffectType());
4247 if (effect.getEffectType() == type)
4248 {
4249 effect.exit(true);
4250 }
4251
4252 }
4253
4254 }
4255
4256 /**
4257 * Stop and remove the L2Effects corresponding to the L2SkillType and update client magic icon.<BR>
4258 * <BR>
4259 * <B><U> Concept</U> :</B><BR>
4260 * <BR>
4261 * 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>
4262 * <BR>
4263 * @param skillType The L2SkillType of the L2Effect to remove from _effects
4264 * @param power the power
4265 */
4266 public final void stopSkillEffects(final SkillType skillType, final double power)
4267 {
4268 final L2Effect[] effects = getAllEffects();
4269
4270 for (final L2Effect effect : effects)
4271 {
4272
4273 if (effect == null || effect.getSkill() == null)
4274 {
4275
4276 synchronized (_effects)
4277 {
4278 _effects.remove(effect);
4279 }
4280 continue;
4281
4282 }
4283
4284 if (effect.getSkill().getSkillType() == skillType && (power == 0 || effect.getSkill().getPower() <= power))
4285 {
4286 effect.exit(true);
4287 }
4288
4289 }
4290
4291 }
4292
4293 /**
4294 * Stop skill effects.
4295 * @param skillType the skill type
4296 */
4297 public final void stopSkillEffects(final SkillType skillType)
4298 {
4299 stopSkillEffects(skillType, -1);
4300 }
4301
4302 /**
4303 * Stop a specified/all Fake Death abnormal L2Effect.<BR>
4304 * <BR>
4305 * <B><U> Actions</U> :</B><BR>
4306 * <BR>
4307 * <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>
4308 * <BR>
4309 * @param effect the effect
4310 */
4311 public final void stopFakeDeath(final L2Effect effect)
4312 {
4313 if (effect == null)
4314 {
4315 stopEffects(L2Effect.EffectType.FAKE_DEATH);
4316 }
4317 else
4318 {
4319 removeEffect(effect);
4320 }
4321
4322 setIsFakeDeath(false);
4323 setIsFallsdown(false);
4324 // if this is a player instance, start the grace period for this character (grace from mobs only)!
4325 if (this instanceof L2PcInstance)
4326 {
4327 ((L2PcInstance) this).setRecentFakeDeath(true);
4328 }
4329
4330 ChangeWaitType revive = new ChangeWaitType(this, ChangeWaitType.WT_STOP_FAKEDEATH);
4331 broadcastPacket(revive);
4332 broadcastPacket(new Revive(this));
4333 getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
4334
4335 revive = null;
4336 }
4337
4338 /**
4339 * Stop a specified/all Fear abnormal L2Effect.<BR>
4340 * <BR>
4341 * <B><U> Actions</U> :</B><BR>
4342 * <BR>
4343 * <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>
4344 * <BR>
4345 * @param effect the effect
4346 */
4347 public final void stopFear(final L2Effect effect)
4348 {
4349 if (effect == null)
4350 {
4351 stopEffects(L2Effect.EffectType.FEAR);
4352 }
4353 else
4354 {
4355 removeEffect(effect);
4356 }
4357
4358 setIsAfraid(false);
4359 updateAbnormalEffect();
4360 }
4361
4362 /**
4363 * Stop a specified/all Muted abnormal L2Effect.<BR>
4364 * <BR>
4365 * <B><U> Actions</U> :</B><BR>
4366 * <BR>
4367 * <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>
4368 * <BR>
4369 * @param effect the effect
4370 */
4371 public final void stopMuted(final L2Effect effect)
4372 {
4373 if (effect == null)
4374 {
4375 stopEffects(L2Effect.EffectType.MUTE);
4376 }
4377 else
4378 {
4379 removeEffect(effect);
4380 }
4381
4382 setIsMuted(false);
4383 updateAbnormalEffect();
4384 }
4385
4386 /**
4387 * Stop psychical muted.
4388 * @param effect the effect
4389 */
4390 public final void stopPsychicalMuted(final L2Effect effect)
4391 {
4392 if (effect == null)
4393 {
4394 stopEffects(L2Effect.EffectType.PSYCHICAL_MUTE);
4395 }
4396 else
4397 {
4398 removeEffect(effect);
4399 }
4400
4401 setIsPsychicalMuted(false);
4402 updateAbnormalEffect();
4403 }
4404
4405 /**
4406 * Stop a specified/all Root abnormal L2Effect.<BR>
4407 * <BR>
4408 * <B><U> Actions</U> :</B><BR>
4409 * <BR>
4410 * <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>
4411 * <BR>
4412 * @param effect the effect
4413 */
4414 public final void stopRooting(final L2Effect effect)
4415 {
4416 if (effect == null)
4417 {
4418 stopEffects(L2Effect.EffectType.ROOT);
4419 }
4420 else
4421 {
4422 removeEffect(effect);
4423 }
4424
4425 setIsRooted(false);
4426 getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
4427 updateAbnormalEffect();
4428 }
4429
4430 /**
4431 * Stop a specified/all Sleep abnormal L2Effect.<BR>
4432 * <BR>
4433 * <B><U> Actions</U> :</B><BR>
4434 * <BR>
4435 * <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>
4436 * <BR>
4437 * @param effect the effect
4438 */
4439 public final void stopSleeping(final L2Effect effect)
4440 {
4441 if (effect == null)
4442 {
4443 stopEffects(L2Effect.EffectType.SLEEP);
4444 }
4445 else
4446 {
4447 removeEffect(effect);
4448 }
4449
4450 setIsSleeping(false);
4451 getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
4452 updateAbnormalEffect();
4453 }
4454
4455 /**
4456 * Stop a specified/all Stun abnormal L2Effect.<BR>
4457 * <BR>
4458 * <B><U> Actions</U> :</B><BR>
4459 * <BR>
4460 * <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>
4461 * <BR>
4462 * @param effect the effect
4463 */
4464 public final void stopStunning(final L2Effect effect)
4465 {
4466 if (!isStunned())
4467 return;
4468
4469 if (effect == null)
4470 {
4471 stopEffects(L2Effect.EffectType.STUN);
4472 }
4473 else
4474 {
4475 removeEffect(effect);
4476 }
4477
4478 setIsStunned(false);
4479 getAI().notifyEvent(CtrlEvent.EVT_THINK, null);
4480 updateAbnormalEffect();
4481 }
4482
4483 /**
4484 * Not Implemented.<BR>
4485 * <BR>
4486 * <B><U> Overridden in</U> :</B><BR>
4487 * <BR>
4488 * <li>L2NPCInstance</li> <li>L2PcInstance</li> <li>L2Summon</li> <li>L2DoorInstance</li><BR>
4489 * <BR>
4490 */
4491 public abstract void updateAbnormalEffect();
4492
4493 /**
4494 * Update active skills in progress (In Use and Not In Use because stacked) icones on client.<BR>
4495 * <BR>
4496 * <B><U> Concept</U> :</B><BR>
4497 * <BR>
4498 * All active skills effects in progress (In Use and Not In Use because stacked) are represented by an icone on the client.<BR>
4499 * <BR>
4500 * <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>
4501 * <BR>
4502 */
4503 public final void updateEffectIcons()
4504 {
4505 updateEffectIcons(false);
4506 }
4507
4508 /**
4509 * Update effect icons.
4510 * @param partyOnly the party only
4511 */
4512 public final void updateEffectIcons(final boolean partyOnly)
4513 {
4514 // Create a L2PcInstance of this if needed
4515 L2PcInstance player = null;
4516
4517 if (this instanceof L2PcInstance)
4518 {
4519 player = (L2PcInstance) this;
4520 }
4521
4522 // Create a L2Summon of this if needed
4523 L2Summon summon = null;
4524 if (this instanceof L2Summon)
4525 {
4526 summon = (L2Summon) this;
4527 player = summon.getOwner();
4528 summon.getOwner().sendPacket(new PetInfo(summon));
4529 }
4530
4531 // Create the main packet if needed
4532 MagicEffectIcons mi = null;
4533 if (!partyOnly)
4534 {
4535 mi = new MagicEffectIcons();
4536 }
4537
4538 // Create the party packet if needed
4539 PartySpelled ps = null;
4540 if (summon != null)
4541 {
4542 ps = new PartySpelled(summon);
4543 }
4544 else if (player != null && player.isInParty())
4545 {
4546 ps = new PartySpelled(player);
4547 }
4548
4549 // Create the olympiad spectator packet if needed
4550 ExOlympiadSpelledInfo os = null;
4551 if (player != null && player.isInOlympiadMode())
4552 {
4553 os = new ExOlympiadSpelledInfo(player);
4554 }
4555
4556 if (mi == null && ps == null && os == null)
4557 return; // nothing to do (should not happen)
4558
4559 // Add special effects
4560 // Note: Now handled by EtcStatusUpdate packet
4561 // NOTE: CHECK IF THEY WERE EVEN VISIBLE TO OTHERS...
4562 /*
4563 * 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); }
4564 */
4565
4566 // Go through all effects if any
4567 synchronized (_effects)
4568 {
4569
4570 for (int i = 0; i < _effects.size(); i++)
4571 {
4572
4573 if (_effects.get(i) == null || _effects.get(i).getSkill() == null)
4574 {
4575
4576 _effects.remove(i);
4577 i--;
4578 continue;
4579
4580 }
4581
4582 if (_effects.get(i).getEffectType() == L2Effect.EffectType.CHARGE && player != null)
4583 {
4584 // handled by EtcStatusUpdate
4585 continue;
4586 }
4587
4588 if (_effects.get(i).getInUse())
4589 {
4590 if (mi != null)
4591 {
4592 _effects.get(i).addIcon(mi);
4593 }
4594 // Like L2OFF toggle and healing potions must not be showed on party buff list
4595 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))
4596 {
4597 _effects.get(i).addPartySpelledIcon(ps);
4598 }
4599 if (os != null)
4600 {
4601 _effects.get(i).addOlympiadSpelledIcon(os);
4602 }
4603 }
4604
4605 }
4606
4607 }
4608
4609 // Send the packets if needed
4610 if (mi != null)
4611 {
4612 sendPacket(mi);
4613 }
4614
4615 if (ps != null && player != null)
4616 {
4617 // summon info only needs to go to the owner, not to the whole party
4618 // player info: if in party, send to all party members except one's self.
4619 // if not in party, send to self.
4620 if (player.isInParty() && summon == null)
4621 {
4622 player.getParty().broadcastToPartyMembers(player, ps);
4623 }
4624 else
4625 {
4626 player.sendPacket(ps);
4627 }
4628 }
4629
4630 if (os != null)
4631 {
4632 if ((player != null) && Olympiad.getInstance().getSpectators(player.getOlympiadGameId()) != null)
4633 {
4634 for (final L2PcInstance spectator : Olympiad.getInstance().getSpectators(player.getOlympiadGameId()))
4635 {
4636 if (spectator == null)
4637 {
4638 continue;
4639 }
4640 spectator.sendPacket(os);
4641 }
4642 }
4643 }
4644
4645 }
4646
4647 // Property - Public
4648 /**
4649 * Return a map of 16 bits (0x0000) containing all abnormal effect in progress for this L2Character.<BR>
4650 * <BR>
4651 * <B><U> Concept</U> :</B><BR>
4652 * <BR>
4653 * 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>
4654 * <BR>
4655 * <B><U> Example of use </U> :</B><BR>
4656 * <BR>
4657 * <li>Server Packet : CharInfo, NpcInfo, NpcInfoPoly, UserInfo...</li><BR>
4658 * <BR>
4659 * @return the abnormal effect
4660 */
4661 public int getAbnormalEffect()
4662 {
4663 int ae = _AbnormalEffects;
4664
4665 if (isStunned())
4666 {
4667 ae |= ABNORMAL_EFFECT_STUN;
4668 }
4669 if (isRooted())
4670 {
4671 ae |= ABNORMAL_EFFECT_ROOT;
4672 }
4673 if (isSleeping())
4674 {
4675 ae |= ABNORMAL_EFFECT_SLEEP;
4676 }
4677 if (isConfused())
4678 {
4679 ae |= ABNORMAL_EFFECT_CONFUSED;
4680 }
4681 if (isMuted())
4682 {
4683 ae |= ABNORMAL_EFFECT_MUTED;
4684 }
4685 if (isAfraid())
4686 {
4687 ae |= ABNORMAL_EFFECT_AFRAID;
4688 }
4689 if (isPsychicalMuted())
4690 {
4691 ae |= ABNORMAL_EFFECT_MUTED;
4692 }
4693
4694 return ae;
4695 }
4696
4697 /**
4698 * Return all active skills effects in progress on the L2Character.<BR>
4699 * <BR>
4700 * <B><U> Concept</U> :</B><BR>
4701 * <BR>
4702 * 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>
4703 * <BR>
4704 * @return A table containing all active skills effect in progress on the L2Character
4705 */
4706 public final L2Effect[] getAllEffects()
4707 {
4708 synchronized (_effects)
4709 {
4710 final L2Effect[] output = _effects.toArray(new L2Effect[_effects.size()]);
4711
4712 return output;
4713 }
4714 }
4715
4716 /**
4717 * Return L2Effect in progress on the L2Character corresponding to the L2Skill Identifier.<BR>
4718 * <BR>
4719 * <B><U> Concept</U> :</B><BR>
4720 * <BR>
4721 * All active skills effects in progress on the L2Character are identified in <B>_effects</B>.
4722 * @param index The L2Skill Identifier of the L2Effect to return from the _effects
4723 * @return The L2Effect corresponding to the L2Skill Identifier
4724 */
4725 public final L2Effect getFirstEffect(final int index)
4726 {
4727 final L2Effect[] effects = getAllEffects();
4728
4729 L2Effect effNotInUse = null;
4730
4731 for (final L2Effect effect : effects)
4732 {
4733
4734 if (effect == null)
4735 {
4736 synchronized (_effects)
4737 {
4738 _effects.remove(effect);
4739 }
4740 continue;
4741 }
4742
4743 if (effect.getSkill().getId() == index)
4744 {
4745 if (effect.getInUse())
4746 return effect;
4747
4748 if (effNotInUse == null)
4749 effNotInUse = effect;
4750 }
4751
4752 }
4753
4754 return effNotInUse;
4755
4756 }
4757
4758 /**
4759 * Gets the first effect.
4760 * @param type the type
4761 * @return the first effect
4762 */
4763 public final L2Effect getFirstEffect(final SkillType type)
4764 {
4765
4766 final L2Effect[] effects = getAllEffects();
4767
4768 L2Effect effNotInUse = null;
4769
4770 for (final L2Effect effect : effects)
4771 {
4772
4773 if (effect == null)
4774 {
4775 synchronized (_effects)
4776 {
4777 _effects.remove(effect);
4778 }
4779 continue;
4780 }
4781
4782 if (effect.getSkill().getSkillType() == type)
4783 {
4784 if (effect.getInUse())
4785 return effect;
4786
4787 if (effNotInUse == null)
4788 effNotInUse = effect;
4789 }
4790
4791 }
4792
4793 return effNotInUse;
4794
4795 }
4796
4797 /**
4798 * Return the first L2Effect in progress on the L2Character created by the L2Skill.<BR>
4799 * <BR>
4800 * <B><U> Concept</U> :</B><BR>
4801 * <BR>
4802 * All active skills effects in progress on the L2Character are identified in <B>_effects</B>.
4803 * @param skill The L2Skill whose effect must be returned
4804 * @return The first L2Effect created by the L2Skill
4805 */
4806 public final L2Effect getFirstEffect(final L2Skill skill)
4807 {
4808 final L2Effect[] effects = getAllEffects();
4809
4810 L2Effect effNotInUse = null;
4811
4812 for (final L2Effect effect : effects)
4813 {
4814
4815 if (effect == null)
4816 {
4817 synchronized (_effects)
4818 {
4819 _effects.remove(effect);
4820 }
4821 continue;
4822 }
4823
4824 if (effect.getSkill() == skill)
4825 {
4826 if (effect.getInUse())
4827 return effect;
4828
4829 if (effNotInUse == null)
4830 effNotInUse = effect;
4831 }
4832
4833 }
4834
4835 return effNotInUse;
4836
4837 }
4838
4839 /**
4840 * Return the first L2Effect in progress on the L2Character corresponding to the Effect Type (ex : BUFF, STUN, ROOT...).<BR>
4841 * <BR>
4842 * <B><U> Concept</U> :</B><BR>
4843 * <BR>
4844 * 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>
4845 * <BR>
4846 * @param tp The Effect Type of skills whose effect must be returned
4847 * @return The first L2Effect corresponding to the Effect Type
4848 */
4849 public final L2Effect getFirstEffect(final L2Effect.EffectType tp)
4850 {
4851 final L2Effect[] effects = getAllEffects();
4852
4853 L2Effect effNotInUse = null;
4854
4855 for (final L2Effect effect : effects)
4856 {
4857
4858 if (effect == null)
4859 {
4860 synchronized (_effects)
4861 {
4862 _effects.remove(effect);
4863 }
4864 continue;
4865 }
4866
4867 if (effect.getEffectType() == tp)
4868 {
4869 if (effect.getInUse())
4870 return effect;
4871
4872 if (effNotInUse == null)
4873 effNotInUse = effect;
4874 }
4875
4876 }
4877
4878 return effNotInUse;
4879
4880 }
4881
4882 /**
4883 * Gets the charge effect.
4884 * @return the charge effect
4885 */
4886 public EffectCharge getChargeEffect()
4887 {
4888
4889 final L2Effect effect = getFirstEffect(SkillType.CHARGE);
4890 if (effect != null)
4891 return (EffectCharge) effect;
4892
4893 return null;
4894
4895 }
4896
4897 // =========================================================
4898 // NEED TO ORGANIZE AND MOVE TO PROPER PLACE
4899 /**
4900 * This class permit to the L2Character AI to obtain informations and uses L2Character method.
4901 */
4902 public class AIAccessor
4903 {
4904
4905 /**
4906 * Instantiates a new aI accessor.
4907 */
4908 public AIAccessor()
4909 {
4910 // null
4911 }
4912
4913 /**
4914 * Return the L2Character managed by this Accessor AI.<BR>
4915 * <BR>
4916 * @return the actor
4917 */
4918 public L2Character getActor()
4919 {
4920 return L2Character.this;
4921 }
4922
4923 /**
4924 * Accessor to L2Character moveToLocation() method with an interaction area.<BR>
4925 * <BR>
4926 * @param x the x
4927 * @param y the y
4928 * @param z the z
4929 * @param offset the offset
4930 */
4931 public void moveTo(final int x, final int y, final int z, final int offset)
4932 {
4933 moveToLocation(x, y, z, offset);
4934 }
4935
4936 /**
4937 * Accessor to L2Character moveToLocation() method without interaction area.<BR>
4938 * <BR>
4939 * @param x the x
4940 * @param y the y
4941 * @param z the z
4942 */
4943 public void moveTo(final int x, final int y, final int z)
4944 {
4945 moveToLocation(x, y, z, 0);
4946 }
4947
4948 /**
4949 * Accessor to L2Character stopMove() method.<BR>
4950 * <BR>
4951 * @param pos the pos
4952 */
4953 public void stopMove(final L2CharPosition pos)
4954 {
4955 L2Character.this.stopMove(pos);
4956 }
4957
4958 /**
4959 * Accessor to L2Character doAttack() method.<BR>
4960 * <BR>
4961 * @param target the target
4962 */
4963 public void doAttack(final L2Character target)
4964 {
4965 L2Character.this.doAttack(target);
4966 }
4967
4968 /**
4969 * Accessor to L2Character doCast() method.<BR>
4970 * <BR>
4971 * @param skill the skill
4972 */
4973 public void doCast(final L2Skill skill)
4974 {
4975 L2Character.this.doCast(skill);
4976 }
4977
4978 /**
4979 * Create a NotifyAITask.<BR>
4980 * <BR>
4981 * @param evt the evt
4982 * @return the notify ai task
4983 */
4984 public NotifyAITask newNotifyTask(final CtrlEvent evt)
4985 {
4986 return new NotifyAITask(evt);
4987 }
4988
4989 /**
4990 * Cancel the AI.<BR>
4991 * <BR>
4992 */
4993 public void detachAI()
4994 {
4995 _ai = null;
4996 }
4997 }
4998
4999 /**
5000 * This class group all mouvement data.<BR>
5001 * <BR>
5002 * <B><U> Data</U> :</B><BR>
5003 * <BR>
5004 * <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
5005 * between the start and the destination</li> <li>_xSpeedTicks, _ySpeedTicks : Speed in unit/ticks</li><BR>
5006 * <BR>
5007 */
5008 public static class MoveData
5009 {
5010 // when we retrieve x/y/z we use GameTimeControl.getGameTicks()
5011 // if we are moving, but move timestamp==gameticks, we don't need
5012 // to recalculate position
5013 /** The _move start time. */
5014 public int _moveStartTime;
5015
5016 /** The _move timestamp. */
5017 public int _moveTimestamp;
5018
5019 /** The _x destination. */
5020 public int _xDestination;
5021
5022 /** The _y destination. */
5023 public int _yDestination;
5024
5025 /** The _z destination. */
5026 public int _zDestination;
5027
5028 /** The _x accurate. */
5029 public double _xAccurate;
5030
5031 /** The _y accurate. */
5032 public double _yAccurate;
5033
5034 /** The _z accurate. */
5035 public double _zAccurate;
5036
5037 /** The _heading. */
5038 public int _heading;
5039
5040 /** The disregarding geodata. */
5041 public boolean disregardingGeodata;
5042
5043 /** The on geodata path index. */
5044 public int onGeodataPathIndex;
5045
5046 /** The geo path. */
5047 public Node[] geoPath;
5048
5049 /** The geo path accurate tx. */
5050 public int geoPathAccurateTx;
5051
5052 /** The geo path accurate ty. */
5053 public int geoPathAccurateTy;
5054
5055 /** The geo path gtx. */
5056 public int geoPathGtx;
5057
5058 /** The geo path gty. */
5059 public int geoPathGty;
5060 }
5061
5062 /** Table containing all skillId that are disabled. */
5063 protected List<Integer> _disabledSkills;
5064
5065 /** The _all skills disabled. */
5066 private boolean _allSkillsDisabled;
5067
5068 // private int _flyingRunSpeed;
5069 // private int _floatingWalkSpeed;
5070 // private int _flyingWalkSpeed;
5071 // private int _floatingRunSpeed;
5072
5073 /** Movement data of this L2Character. */
5074 protected MoveData _move;
5075
5076 /** Orientation of the L2Character. */
5077 private int _heading;
5078
5079 /** L2Charcater targeted by the L2Character. */
5080 private L2Object _target;
5081
5082 // set by the start of casting, in game ticks
5083 /** The _cast end time. */
5084 private int _castEndTime;
5085
5086 /** The _cast interrupt time. */
5087 private int _castInterruptTime;
5088
5089 // set by the start of casting, in game ticks
5090 /** The _cast potion end time. */
5091 private int _castPotionEndTime;
5092
5093 /** The _cast potion interrupt time. */
5094 @SuppressWarnings("unused")
5095 private int _castPotionInterruptTime;
5096
5097 // set by the start of attack, in game ticks
5098 /** The _attack end time. */
5099 int _attackEndTime;
5100
5101 /** The _attacking. */
5102 private int _attacking;
5103
5104 /** The _disable bow attack end time. */
5105 private int _disableBowAttackEndTime;
5106
5107 /** Table of calculators containing all standard NPC calculator (ex : ACCURACY_COMBAT, EVASION_RATE. */
5108 private static final Calculator[] NPC_STD_CALCULATOR;
5109 static
5110 {
5111 NPC_STD_CALCULATOR = Formulas.getInstance().getStdNPCCalculators();
5112 }
5113
5114 /** The _ai. */
5115 protected L2CharacterAI _ai;
5116
5117 /** Future Skill Cast. */
5118 protected Future<?> _skillCast;
5119
5120 /** Future Potion Cast. */
5121 protected Future<?> _potionCast;
5122
5123 /** Char Coords from Client. */
5124 private int _clientX;
5125
5126 /** The _client y. */
5127 private int _clientY;
5128
5129 /** The _client z. */
5130 private int _clientZ;
5131
5132 /** The _client heading. */
5133 private int _clientHeading;
5134
5135 /** List of all QuestState instance that needs to be notified of this character's death. */
5136 private List<QuestState> _NotifyQuestOfDeathList = new FastList<>();
5137
5138 /**
5139 * Add QuestState instance that is to be notified of character's death.<BR>
5140 * <BR>
5141 * @param qs The QuestState that subscribe to this event
5142 */
5143 public void addNotifyQuestOfDeath(final QuestState qs)
5144 {
5145 if (qs == null || _NotifyQuestOfDeathList.contains(qs))
5146 return;
5147
5148 _NotifyQuestOfDeathList.add(qs);
5149 }
5150
5151 /**
5152 * Return a list of L2Character that attacked.<BR>
5153 * <BR>
5154 * @return the notify quest of death
5155 */
5156 public final List<QuestState> getNotifyQuestOfDeath()
5157 {
5158 if (_NotifyQuestOfDeathList == null)
5159 {
5160 _NotifyQuestOfDeathList = new FastList<>();
5161 }
5162
5163 return _NotifyQuestOfDeathList;
5164 }
5165
5166 /**
5167 * Add a Func to the Calculator set of the L2Character.<BR>
5168 * <BR>
5169 * <B><U> Concept</U> :</B><BR>
5170 * <BR>
5171 * 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,
5172 * L2NPCInstances who don't have skills share the same Calculator set called <B>NPC_STD_CALCULATOR</B>.<BR>
5173 * <BR>
5174 * 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>
5175 * <BR>
5176 * <B><U> Actions</U> :</B><BR>
5177 * <BR>
5178 * <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>
5179 * <BR>
5180 * @param f The Func object to add to the Calculator corresponding to the state affected
5181 */
5182 public final synchronized void addStatFunc(final Func f)
5183 {
5184 if (f == null)
5185 return;
5186
5187 // Check if Calculator set is linked to the standard Calculator set of NPC
5188 if (_calculators == NPC_STD_CALCULATOR)
5189 {
5190 // Create a copy of the standard NPC Calculator set
5191 _calculators = new Calculator[Stats.NUM_STATS];
5192
5193 for (int i = 0; i < Stats.NUM_STATS; i++)
5194 {
5195 if (NPC_STD_CALCULATOR[i] != null)
5196 {
5197 _calculators[i] = new Calculator(NPC_STD_CALCULATOR[i]);
5198 }
5199 }
5200 }
5201
5202 // Select the Calculator of the affected state in the Calculator set
5203 final int stat = f.stat.ordinal();
5204
5205 if (_calculators[stat] == null)
5206 {
5207 _calculators[stat] = new Calculator();
5208 }
5209
5210 // Add the Func to the calculator corresponding to the state
5211 _calculators[stat].addFunc(f);
5212
5213 }
5214
5215 /**
5216 * Add a list of Funcs to the Calculator set of the L2Character.<BR>
5217 * <BR>
5218 * <B><U> Concept</U> :</B><BR>
5219 * <BR>
5220 * 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>
5221 * <BR>
5222 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method is ONLY for L2PcInstance</B></FONT><BR>
5223 * <BR>
5224 * <B><U> Example of use </U> :</B><BR>
5225 * <BR>
5226 * <li>Equip an item from inventory</li> <li>Learn a new passive skill</li> <li>Use an active skill</li><BR>
5227 * <BR>
5228 * @param funcs The list of Func objects to add to the Calculator corresponding to the state affected
5229 */
5230 public final synchronized void addStatFuncs(final Func[] funcs)
5231 {
5232
5233 FastList<Stats> modifiedStats = new FastList<>();
5234
5235 for (final Func f : funcs)
5236 {
5237 modifiedStats.add(f.stat);
5238 addStatFunc(f);
5239 }
5240
5241 broadcastModifiedStats(modifiedStats);
5242
5243 modifiedStats = null;
5244 }
5245
5246 /**
5247 * Remove a Func from the Calculator set of the L2Character.<BR>
5248 * <BR>
5249 * <B><U> Concept</U> :</B><BR>
5250 * <BR>
5251 * 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,
5252 * L2NPCInstances who don't have skills share the same Calculator set called <B>NPC_STD_CALCULATOR</B>.<BR>
5253 * <BR>
5254 * 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>
5255 * <BR>
5256 * <B><U> Actions</U> :</B><BR>
5257 * <BR>
5258 * <li>Remove the Func object from _calculators</li><BR>
5259 * <BR>
5260 * <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>
5261 * <BR>
5262 * @param f The Func object to remove from the Calculator corresponding to the state affected
5263 */
5264 public final synchronized void removeStatFunc(final Func f)
5265 {
5266 if (f == null)
5267 return;
5268
5269 // Select the Calculator of the affected state in the Calculator set
5270 final int stat = f.stat.ordinal();
5271
5272 if (_calculators[stat] == null)
5273 return;
5274
5275 // Remove the Func object from the Calculator
5276 _calculators[stat].removeFunc(f);
5277
5278 if (_calculators[stat].size() == 0)
5279 {
5280 _calculators[stat] = null;
5281 }
5282
5283 // If possible, free the memory and just create a link on NPC_STD_CALCULATOR
5284 if (this instanceof L2NpcInstance)
5285 {
5286 int i = 0;
5287
5288 for (; i < Stats.NUM_STATS; i++)
5289 {
5290 if (!Calculator.equalsCals(_calculators[i], NPC_STD_CALCULATOR[i]))
5291 {
5292 break;
5293 }
5294 }
5295
5296 if (i >= Stats.NUM_STATS)
5297 {
5298 _calculators = NPC_STD_CALCULATOR;
5299 }
5300 }
5301 }
5302
5303 /**
5304 * Remove a list of Funcs from the Calculator set of the L2PcInstance.<BR>
5305 * <BR>
5306 * <B><U> Concept</U> :</B><BR>
5307 * <BR>
5308 * 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>
5309 * <BR>
5310 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method is ONLY for L2PcInstance</B></FONT><BR>
5311 * <BR>
5312 * <B><U> Example of use </U> :</B><BR>
5313 * <BR>
5314 * <li>Unequip an item from inventory</li> <li>Stop an active skill</li><BR>
5315 * <BR>
5316 * @param funcs The list of Func objects to add to the Calculator corresponding to the state affected
5317 */
5318 public final synchronized void removeStatFuncs(final Func[] funcs)
5319 {
5320
5321 FastList<Stats> modifiedStats = new FastList<>();
5322
5323 for (final Func f : funcs)
5324 {
5325 modifiedStats.add(f.stat);
5326 removeStatFunc(f);
5327 }
5328
5329 broadcastModifiedStats(modifiedStats);
5330
5331 modifiedStats = null;
5332 }
5333
5334 /**
5335 * Remove all Func objects with the selected owner from the Calculator set of the L2Character.<BR>
5336 * <BR>
5337 * <B><U> Concept</U> :</B><BR>
5338 * <BR>
5339 * 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,
5340 * L2NPCInstances who don't have skills share the same Calculator set called <B>NPC_STD_CALCULATOR</B>.<BR>
5341 * <BR>
5342 * 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>
5343 * <BR>
5344 * <B><U> Actions</U> :</B><BR>
5345 * <BR>
5346 * <li>Remove all Func objects of the selected owner from _calculators</li><BR>
5347 * <BR>
5348 * <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>
5349 * <BR>
5350 * <B><U> Example of use </U> :</B><BR>
5351 * <BR>
5352 * <li>Unequip an item from inventory</li> <li>Stop an active skill</li><BR>
5353 * <BR>
5354 * @param owner The Object(Skill, Item...) that has created the effect
5355 */
5356 public final void removeStatsOwner(final Object owner)
5357 {
5358 FastList<Stats> modifiedStats = null;
5359
5360 int i = 0;
5361 // Go through the Calculator set
5362 synchronized (_calculators)
5363 {
5364 for (final Calculator calc : _calculators)
5365 {
5366 if (calc != null)
5367 {
5368 // Delete all Func objects of the selected owner
5369 if (modifiedStats != null)
5370 {
5371 modifiedStats.addAll(calc.removeOwner(owner));
5372 }
5373 else
5374 {
5375 modifiedStats = calc.removeOwner(owner);
5376 }
5377
5378 if (calc.size() == 0)
5379 {
5380 _calculators[i] = null;
5381 }
5382 }
5383 i++;
5384 }
5385
5386 // If possible, free the memory and just create a link on NPC_STD_CALCULATOR
5387 if (this instanceof L2NpcInstance)
5388 {
5389 i = 0;
5390 for (; i < Stats.NUM_STATS; i++)
5391 {
5392 if (!Calculator.equalsCals(_calculators[i], NPC_STD_CALCULATOR[i]))
5393 {
5394 break;
5395 }
5396 }
5397
5398 if (i >= Stats.NUM_STATS)
5399 {
5400 _calculators = NPC_STD_CALCULATOR;
5401 }
5402 }
5403
5404 if (owner instanceof L2Effect && !((L2Effect) owner).preventExitUpdate)
5405 {
5406 broadcastModifiedStats(modifiedStats);
5407 }
5408 }
5409
5410 modifiedStats = null;
5411 }
5412
5413 /**
5414 * Broadcast modified stats.
5415 * @param stats the stats
5416 */
5417 public void broadcastModifiedStats(final FastList<Stats> stats)
5418 {
5419 if (stats == null || stats.isEmpty())
5420 return;
5421
5422 boolean broadcastFull = false;
5423 boolean otherStats = false;
5424 StatusUpdate su = null;
5425
5426 for (final Stats stat : stats)
5427 {
5428 if (stat == Stats.POWER_ATTACK_SPEED)
5429 {
5430 if (su == null)
5431 {
5432 su = new StatusUpdate(getObjectId());
5433 }
5434
5435 su.addAttribute(StatusUpdate.ATK_SPD, getPAtkSpd());
5436 }
5437 else if (stat == Stats.MAGIC_ATTACK_SPEED)
5438 {
5439 if (su == null)
5440 {
5441 su = new StatusUpdate(getObjectId());
5442 }
5443
5444 su.addAttribute(StatusUpdate.CAST_SPD, getMAtkSpd());
5445 }
5446 // else if (stat==Stats.MAX_HP) //
5447 // {
5448 // if (su == null) su = new StatusUpdate(getObjectId());
5449 // su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
5450 // }
5451 else if (stat == Stats.MAX_CP)
5452 {
5453 if (this instanceof L2PcInstance)
5454 {
5455 if (su == null)
5456 {
5457 su = new StatusUpdate(getObjectId());
5458 }
5459
5460 su.addAttribute(StatusUpdate.MAX_CP, getMaxCp());
5461 }
5462 }
5463 // else if (stat==Stats.MAX_MP)
5464 // {
5465 // if (su == null) su = new StatusUpdate(getObjectId());
5466 // su.addAttribute(StatusUpdate.MAX_MP, getMaxMp());
5467 // }
5468 else if (stat == Stats.RUN_SPEED)
5469 {
5470 broadcastFull = true;
5471 }
5472 else
5473 {
5474 otherStats = true;
5475 }
5476 }
5477
5478 if (this instanceof L2PcInstance)
5479 {
5480 if (broadcastFull)
5481 {
5482 ((L2PcInstance) this).updateAndBroadcastStatus(2);
5483 }
5484 else
5485 {
5486 if (otherStats)
5487 {
5488 ((L2PcInstance) this).updateAndBroadcastStatus(1);
5489 if (su != null)
5490 {
5491 for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
5492 {
5493 try
5494 {
5495 player.sendPacket(su);
5496 }
5497 catch (final NullPointerException e)
5498 {
5499 e.printStackTrace();
5500 }
5501 }
5502 }
5503 }
5504 else if (su != null)
5505 {
5506 broadcastPacket(su);
5507 }
5508 }
5509 }
5510 else if (this instanceof L2NpcInstance)
5511 {
5512 if (broadcastFull && getKnownList() != null && getKnownList().getKnownPlayers() != null)
5513 {
5514 for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
5515 if (player != null)
5516 {
5517 player.sendPacket(new NpcInfo((L2NpcInstance) this, player));
5518 }
5519 }
5520 else if (su != null)
5521 {
5522 broadcastPacket(su);
5523 }
5524 }
5525 else if (this instanceof L2Summon)
5526 {
5527 if (broadcastFull)
5528 {
5529 for (final L2PcInstance player : getKnownList().getKnownPlayers().values())
5530 if (player != null)
5531 {
5532 player.sendPacket(new NpcInfo((L2Summon) this, player));
5533 }
5534 }
5535 else if (su != null)
5536 {
5537 broadcastPacket(su);
5538 }
5539 }
5540 else if (su != null)
5541 {
5542 broadcastPacket(su);
5543 }
5544
5545 su = null;
5546 }
5547
5548 /**
5549 * Return the orientation of the L2Character.<BR>
5550 * <BR>
5551 * @return the heading
5552 */
5553 public final int getHeading()
5554 {
5555 return _heading;
5556 }
5557
5558 /**
5559 * Set the orientation of the L2Character.<BR>
5560 * <BR>
5561 * @param heading the new heading
5562 */
5563 public final void setHeading(final int heading)
5564 {
5565 _heading = heading;
5566 }
5567
5568 /**
5569 * Return the X destination of the L2Character or the X position if not in movement.<BR>
5570 * <BR>
5571 * @return the client x
5572 */
5573 public final int getClientX()
5574 {
5575 return _clientX;
5576 }
5577
5578 /**
5579 * Gets the client y.
5580 * @return the client y
5581 */
5582 public final int getClientY()
5583 {
5584 return _clientY;
5585 }
5586
5587 /**
5588 * Gets the client z.
5589 * @return the client z
5590 */
5591 public final int getClientZ()
5592 {
5593 return _clientZ;
5594 }
5595
5596 /**
5597 * Gets the client heading.
5598 * @return the client heading
5599 */
5600 public final int getClientHeading()
5601 {
5602 return _clientHeading;
5603 }
5604
5605 /**
5606 * Sets the client x.
5607 * @param val the new client x
5608 */
5609 public final void setClientX(final int val)
5610 {
5611 _clientX = val;
5612 }
5613
5614 /**
5615 * Sets the client y.
5616 * @param val the new client y
5617 */
5618 public final void setClientY(final int val)
5619 {
5620 _clientY = val;
5621 }
5622
5623 /**
5624 * Sets the client z.
5625 * @param val the new client z
5626 */
5627 public final void setClientZ(final int val)
5628 {
5629 _clientZ = val;
5630 }
5631
5632 /**
5633 * Sets the client heading.
5634 * @param val the new client heading
5635 */
5636 public final void setClientHeading(final int val)
5637 {
5638 _clientHeading = val;
5639 }
5640
5641 /**
5642 * Gets the xdestination.
5643 * @return the xdestination
5644 */
5645 public final int getXdestination()
5646 {
5647 final MoveData m = _move;
5648
5649 if (m != null)
5650 return m._xDestination;
5651
5652 return getX();
5653 }
5654
5655 /**
5656 * Return the Y destination of the L2Character or the Y position if not in movement.<BR>
5657 * <BR>
5658 * @return the ydestination
5659 */
5660 public final int getYdestination()
5661 {
5662 final MoveData m = _move;
5663
5664 if (m != null)
5665 return m._yDestination;
5666
5667 return getY();
5668 }
5669
5670 /**
5671 * Return the Z destination of the L2Character or the Z position if not in movement.<BR>
5672 * <BR>
5673 * @return the zdestination
5674 */
5675 public final int getZdestination()
5676 {
5677 final MoveData m = _move;
5678
5679 if (m != null)
5680 return m._zDestination;
5681
5682 return getZ();
5683 }
5684
5685 /**
5686 * Return True if the L2Character is in combat.<BR>
5687 * <BR>
5688 * @return true, if is in combat
5689 */
5690 public boolean isInCombat()
5691 {
5692 return (getAI().getAttackTarget() != null || getAI().isAutoAttacking());
5693 }
5694
5695 /**
5696 * Return True if the L2Character is moving.<BR>
5697 * <BR>
5698 * @return true, if is moving
5699 */
5700 public final boolean isMoving()
5701 {
5702 return _move != null;
5703 }
5704
5705 /**
5706 * Return True if the L2Character is travelling a calculated path.<BR>
5707 * <BR>
5708 * @return true, if is on geodata path
5709 */
5710 public final boolean isOnGeodataPath()
5711 {
5712 final MoveData move = _move;
5713
5714 if (move == null)
5715 return false;
5716
5717 try
5718 {
5719 if (move.onGeodataPathIndex == -1)
5720 return false;
5721
5722 if (move.onGeodataPathIndex == move.geoPath.length - 1)
5723 return false;
5724 }
5725 catch (final NullPointerException e)
5726 {
5727 e.printStackTrace();
5728 return false;
5729 }
5730
5731 return true;
5732 }
5733
5734 /**
5735 * Return True if the L2Character is casting.<BR>
5736 * <BR>
5737 * @return true, if is casting now
5738 */
5739 public final boolean isCastingNow()
5740 {
5741
5742 final L2Effect mog = getFirstEffect(L2Effect.EffectType.SIGNET_GROUND);
5743 if (mog != null)
5744 {
5745 return true;
5746 }
5747
5748 return _castEndTime > GameTimeController.getGameTicks();
5749 }
5750
5751 /**
5752 * Return True if the L2Character is casting.<BR>
5753 * <BR>
5754 * @return true, if is casting potion now
5755 */
5756 public final boolean isCastingPotionNow()
5757 {
5758 return _castPotionEndTime > GameTimeController.getGameTicks();
5759 }
5760
5761 /**
5762 * Return True if the cast of the L2Character can be aborted.<BR>
5763 * <BR>
5764 * @return true, if successful
5765 */
5766 public final boolean canAbortCast()
5767 {
5768 return _castInterruptTime > GameTimeController.getGameTicks();
5769 }
5770
5771 /**
5772 * Return True if the L2Character is attacking.<BR>
5773 * <BR>
5774 * @return true, if is attacking now
5775 */
5776 public final boolean isAttackingNow()
5777 {
5778 return _attackEndTime > GameTimeController.getGameTicks();
5779 }
5780
5781 /**
5782 * Return True if the L2Character has aborted its attack.<BR>
5783 * <BR>
5784 * @return true, if is attack aborted
5785 */
5786 public final boolean isAttackAborted()
5787 {
5788 return _attacking <= 0;
5789 }
5790
5791 /**
5792 * Abort the attack of the L2Character and send Server->Client ActionFailed packet.<BR>
5793 * <BR>
5794 * see com.l2jfrozen.gameserver.model.L2Character
5795 */
5796 public final void abortAttack()
5797 {
5798 if (isAttackingNow())
5799 {
5800 _attacking = 0;
5801 sendPacket(ActionFailed.STATIC_PACKET);
5802 }
5803 }
5804
5805 /**
5806 * Returns body part (paperdoll slot) we are targeting right now.
5807 * @return the attacking body part
5808 */
5809 public final int getAttackingBodyPart()
5810 {
5811 return _attacking;
5812 }
5813
5814 /**
5815 * Abort the cast of the L2Character and send Server->Client MagicSkillCanceld/ActionFailed packet.<BR>
5816 * <BR>
5817 */
5818 public final void abortCast()
5819 {
5820 abortCast(false);
5821
5822 }
5823
5824 /**
5825 * Abort the cast of the L2Character and send Server->Client MagicSkillCanceld/ActionFailed packet.<BR>
5826 * <BR>
5827 * @param force the force
5828 */
5829 public final void abortCast(final boolean force)
5830 {
5831 if (isCastingNow() || force)
5832 {
5833 _castEndTime = 0;
5834 _castInterruptTime = 0;
5835
5836 if (_skillCast != null)
5837 {
5838 _skillCast.cancel(true);
5839 _skillCast = null;
5840 }
5841
5842 if (getForceBuff() != null)
5843 {
5844 getForceBuff().onCastAbort();
5845 }
5846
5847 final L2Effect mog = getFirstEffect(L2Effect.EffectType.SIGNET_GROUND);
5848 if (mog != null)
5849 {
5850 mog.exit(true);
5851 }
5852
5853 // cancels the skill hit scheduled task
5854 enableAllSkills(); // re-enables the skills
5855 if (this instanceof L2PcInstance)
5856 {
5857 getAI().notifyEvent(CtrlEvent.EVT_FINISH_CASTING); // setting back previous intention
5858 }
5859
5860 broadcastPacket(new MagicSkillCanceld(getObjectId())); // broadcast packet to stop animations client-side
5861 sendPacket(ActionFailed.STATIC_PACKET); // send an "action failed" packet to the caster
5862
5863 }
5864 /*
5865 * can't abort potion cast if(isCastingPotionNow()){ _castPotionEndTime = 0; _castPotionInterruptTime = 0; if(_potionCast != null) { _potionCast.cancel(true); _potionCast = null; } }
5866 */
5867 }
5868
5869 /**
5870 * Update the position of the L2Character during a movement and return True if the movement is finished.<BR>
5871 * <BR>
5872 * <B><U> Concept</U> :</B><BR>
5873 * <BR>
5874 * 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>
5875 * <BR>
5876 * 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
5877 * 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>
5878 * <BR>
5879 * 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>
5880 * <BR>
5881 * <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>
5882 * <BR>
5883 * @param gameTicks Nb of ticks since the server start
5884 * @return True if the movement is finished
5885 */
5886 public boolean updatePosition(final int gameTicks)
5887 {
5888 // Get movement data
5889 final MoveData m = _move;
5890
5891 if (m == null)
5892 return true;
5893
5894 if (!isVisible())
5895 {
5896 _move = null;
5897 return true;
5898 }
5899
5900 if (m._moveTimestamp == 0)
5901 {
5902 m._moveTimestamp = m._moveStartTime;
5903 m._xAccurate = getX();
5904 m._yAccurate = getY();
5905 }
5906
5907 // Check if the position has alreday be calculated
5908 if (m._moveTimestamp == gameTicks)
5909 return false;
5910
5911 final int xPrev = getX();
5912 final int yPrev = getY();
5913 int zPrev = getZ();
5914
5915 double dx, dy, dz, distFraction;
5916 if (Config.COORD_SYNCHRONIZE == 1)
5917 // the only method that can modify x,y while moving (otherwise _move would/should be set null)
5918 {
5919 dx = m._xDestination - xPrev;
5920 dy = m._yDestination - yPrev;
5921 }
5922 else
5923 // otherwise we need saved temporary values to avoid rounding errors
5924 {
5925 dx = m._xDestination - m._xAccurate;
5926 dy = m._yDestination - m._yAccurate;
5927 }
5928 // Z coordinate will follow geodata or client values
5929 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
5930 && !(this instanceof L2BoatInstance))
5931 {
5932 final short geoHeight = GeoData.getInstance().getSpawnHeight(xPrev, yPrev, zPrev - 30, zPrev + 30, getObjectId());
5933 dz = m._zDestination - geoHeight;
5934 // quite a big difference, compare to validatePosition packet
5935 if (this instanceof L2PcInstance && Math.abs(((L2PcInstance) this).getClientZ() - geoHeight) > 200 && Math.abs(((L2PcInstance) this).getClientZ() - geoHeight) < 1500)
5936 {
5937 dz = m._zDestination - zPrev; // allow diff
5938 }
5939 else if (isInCombat() && Math.abs(dz) > 200 && dx * dx + dy * dy < 40000) // allow mob to climb up to pcinstance
5940 {
5941 dz = m._zDestination - zPrev; // climbing
5942 }
5943 else
5944 {
5945 zPrev = geoHeight;
5946 }
5947 }
5948 else
5949 {
5950 dz = m._zDestination - zPrev;
5951 }
5952
5953 float speed;
5954 if (this instanceof L2BoatInstance)
5955 {
5956 speed = ((L2BoatInstance) this).boatSpeed;
5957 }
5958 else
5959 {
5960 speed = getStat().getMoveSpeed();
5961 }
5962
5963 final double distPassed = speed * (gameTicks - m._moveTimestamp) / GameTimeController.TICKS_PER_SECOND;
5964 if (dx * dx + dy * dy < 10000 && dz * dz > 2500) // close enough, allows error between client and server geodata if it cannot be avoided
5965 {
5966 distFraction = distPassed / Math.sqrt(dx * dx + dy * dy);
5967 }
5968 else
5969 {
5970 distFraction = distPassed / Math.sqrt(dx * dx + dy * dy + dz * dz);
5971 }
5972
5973 // if (Config.DEVELOPER) LOGGER.warn("Move Ticks:" + (gameTicks - m._moveTimestamp) + ", distPassed:" + distPassed + ", distFraction:" + distFraction);
5974
5975 if (distFraction > 1) // already there
5976 {
5977 // Set the position of the L2Character to the destination
5978 super.getPosition().setXYZ(m._xDestination, m._yDestination, m._zDestination);
5979 if (this instanceof L2BoatInstance)
5980 {
5981 ((L2BoatInstance) this).updatePeopleInTheBoat(m._xDestination, m._yDestination, m._zDestination);
5982 }
5983 else
5984 {
5985 revalidateZone();
5986 }
5987 }
5988 else
5989 {
5990 m._xAccurate += dx * distFraction;
5991 m._yAccurate += dy * distFraction;
5992
5993 // Set the position of the L2Character to estimated after parcial move
5994 super.getPosition().setXYZ((int) m._xAccurate, (int) m._yAccurate, zPrev + (int) (dz * distFraction + 0.5));
5995 if (this instanceof L2BoatInstance)
5996 {
5997 ((L2BoatInstance) this).updatePeopleInTheBoat((int) m._xAccurate, (int) m._yAccurate, zPrev + (int) (dz * distFraction + 0.5));
5998 }
5999 else
6000 {
6001 revalidateZone();
6002 }
6003 }
6004
6005 // Set the timer of last position update to now
6006 m._moveTimestamp = gameTicks;
6007
6008 return distFraction > 1;
6009 }
6010
6011 /**
6012 * Revalidate zone.
6013 */
6014 public void revalidateZone()
6015 {
6016 if (getWorldRegion() == null)
6017 return;
6018
6019 getWorldRegion().revalidateZones(this);
6020 }
6021
6022 /**
6023 * Stop movement of the L2Character (Called by AI Accessor only).<BR>
6024 * <BR>
6025 * <B><U> Actions</U> :</B><BR>
6026 * <BR>
6027 * <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
6028 * L2WorldRegion L2Characters</li><BR>
6029 * <BR>
6030 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T send Server->Client packet StopMove/StopRotation </B></FONT><BR>
6031 * <BR>
6032 * @param pos the pos
6033 */
6034 public void stopMove(final L2CharPosition pos)
6035 {
6036 stopMove(pos, true);
6037 }
6038
6039 /**
6040 * TODO: test broadcast head packets ffro !in boat.
6041 * @param pos the pos
6042 * @param updateKnownObjects the update known objects
6043 */
6044 public void stopMove(final L2CharPosition pos, final boolean updateKnownObjects)
6045 {
6046 // Delete movement data of the L2Character
6047 _move = null;
6048
6049 // Set AI_INTENTION_IDLE
6050 if (this instanceof L2PcInstance && getAI() != null)
6051 ((L2PcInstance) this).getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
6052
6053 // Set the current position (x,y,z), its current L2WorldRegion if necessary and its heading
6054 // All data are contained in a L2CharPosition object
6055 if (pos != null)
6056 {
6057 getPosition().setXYZ(pos.x, pos.y, GeoData.getInstance().getHeight(pos.x, pos.y, pos.z));
6058 setHeading(pos.heading);
6059
6060 if (this instanceof L2PcInstance)
6061 {
6062 ((L2PcInstance) this).revalidateZone(true);
6063
6064 if (((L2PcInstance) this).isInBoat())
6065 broadcastPacket(new ValidateLocationInVehicle(this));
6066 }
6067 }
6068
6069 broadcastPacket(new StopMove(this));
6070
6071 if (updateKnownObjects)
6072 ThreadPoolManager.getInstance().executeTask(new KnownListAsynchronousUpdateTask(this));
6073 }
6074
6075 /**
6076 * Target a L2Object (add the target to the L2Character _target, _knownObject and L2Character to _KnownObject of the L2Object).<BR>
6077 * <BR>
6078 * <B><U> Concept</U> :</B><BR>
6079 * <BR>
6080 * The L2Object (including L2Character) targeted is identified in <B>_target</B> of the L2Character<BR>
6081 * <BR>
6082 * <B><U> Actions</U> :</B><BR>
6083 * <BR>
6084 * <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>
6085 * <BR>
6086 * <B><U> Overriden in </U> :</B><BR>
6087 * <BR>
6088 * <li>L2PcInstance : Remove the L2PcInstance from the old target _statusListener and add it to the new target if it was a L2Character</li><BR>
6089 * <BR>
6090 * @param object L2object to target
6091 */
6092 public void setTarget(L2Object object)
6093 {
6094 if (object != null && !object.isVisible())
6095 {
6096 object = null;
6097 }
6098
6099 if (object != null && object != _target)
6100 {
6101 getKnownList().addKnownObject(object);
6102 object.getKnownList().addKnownObject(this);
6103 }
6104
6105 // If object==null, Cancel Attak or Cast
6106 if (object == null)
6107 {
6108 if (_target != null)
6109 {
6110 final TargetUnselected my = new TargetUnselected(this);
6111
6112 // No need to broadcast the packet to all players
6113 if (this instanceof L2PcInstance)
6114 {
6115 // Send packet just to me and to party, not to any other that does not use the information
6116 if (!this.isInParty())
6117 {
6118 this.sendPacket(my);
6119 }
6120 else
6121 {
6122 this.getParty().broadcastToPartyMembers(my);
6123 }
6124 }
6125 else
6126 {
6127 sendPacket(new TargetUnselected(this));
6128 }
6129 }
6130 }
6131
6132 _target = object;
6133 }
6134
6135 /**
6136 * Return the identifier of the L2Object targeted or -1.<BR>
6137 * <BR>
6138 * @return the target id
6139 */
6140 public final int getTargetId()
6141 {
6142 if (_target != null)
6143 return _target.getObjectId();
6144
6145 return -1;
6146 }
6147
6148 /**
6149 * Return the L2Object targeted or null.<BR>
6150 * <BR>
6151 * @return the target
6152 */
6153 public final L2Object getTarget()
6154 {
6155 return _target;
6156 }
6157
6158 // called from AIAccessor only
6159 /**
6160 * Calculate movement data for a move to location action and add the L2Character to movingObjects of GameTimeController (only called by AI Accessor).<BR>
6161 * <BR>
6162 * <B><U> Concept</U> :</B><BR>
6163 * <BR>
6164 * 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>
6165 * <BR>
6166 * 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>
6167 * <BR>
6168 * <B><U> Actions</U> :</B><BR>
6169 * <BR>
6170 * <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
6171 * the GameTimeController</li> <li>Create a task to notify the AI that L2Character arrives at a check point of the movement</li><BR>
6172 * <BR>
6173 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T send Server->Client packet MoveToPawn/CharMoveToLocation </B></FONT><BR>
6174 * <BR>
6175 * <B><U> Example of use </U> :</B><BR>
6176 * <BR>
6177 * <li>AI : onIntentionMoveTo(L2CharPosition), onIntentionPickUp(L2Object), onIntentionInteract(L2Object)</li> <li>FollowTask</li><BR>
6178 * <BR>
6179 * @param x The X position of the destination
6180 * @param y The Y position of the destination
6181 * @param z The Y position of the destination
6182 * @param offset The size of the interaction area of the L2Character targeted
6183 */
6184 protected void moveToLocation(int x, int y, int z, int offset)
6185 {
6186 // Block movment during Event start
6187 if (this instanceof L2PcInstance)
6188 {
6189 if (L2Event.active && ((L2PcInstance) this).eventSitForced)
6190 {
6191 ((L2PcInstance) this).sendMessage("A dark force beyond your mortal understanding makes your knees to shake when you try to stand up...");
6192 ((L2PcInstance) this).getClient().sendPacket(ActionFailed.STATIC_PACKET);
6193 return;
6194 }
6195 else if ((TvT.is_sitForced() && ((L2PcInstance) this)._inEventTvT) || (CTF.is_sitForced() && ((L2PcInstance) this)._inEventCTF) || (DM.is_sitForced() && ((L2PcInstance) this)._inEventDM))
6196 {
6197 ((L2PcInstance) this).sendMessage("A dark force beyond your mortal understanding makes your knees to shake when you try to stand up...");
6198 ((L2PcInstance) this).getClient().sendPacket(ActionFailed.STATIC_PACKET);
6199 return;
6200 }
6201 else if (VIP._sitForced && ((L2PcInstance) this)._inEventVIP)
6202 {
6203 ((L2PcInstance) this).sendMessage("A dark force beyond your mortal understanding makes your knees to shake when you try to stand up...");
6204 ((L2PcInstance) this).sendPacket(ActionFailed.STATIC_PACKET);
6205 return;
6206 }
6207 }
6208
6209 // when start to move again, it has to stop sitdown task
6210 if (this instanceof L2PcInstance)
6211 ((L2PcInstance) this).setPosticipateSit(false);
6212
6213 // Fix archer bug with movment/hittask
6214 if (this instanceof L2PcInstance && this.isAttackingNow())
6215 {
6216 final L2ItemInstance rhand = ((L2PcInstance) this).getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
6217 if ((rhand != null && rhand.getItemType() == L2WeaponType.BOW))
6218 return;
6219 }
6220
6221 // Get the Move Speed of the L2Charcater
6222 final float speed = getStat().getMoveSpeed();
6223
6224 if (speed <= 0 || isMovementDisabled())
6225 return;
6226
6227 // Get current position of the L2Character
6228 final int curX = super.getX();
6229 final int curY = super.getY();
6230 final int curZ = super.getZ();
6231
6232 // Calculate distance (dx,dy) between current position and destination
6233 //
6234 double dx = x - curX;
6235 double dy = y - curY;
6236 double dz = z - curZ;
6237 double distance = Math.sqrt(dx * dx + dy * dy);
6238
6239 if (Config.GEODATA > 0 && isInsideZone(ZONE_WATER) && distance > 700)
6240 {
6241 final double divider = 700 / distance;
6242 x = curX + (int) (divider * dx);
6243 y = curY + (int) (divider * dy);
6244 z = curZ + (int) (divider * dz);
6245 dx = x - curX;
6246 dy = y - curY;
6247 dz = z - curZ;
6248 distance = Math.sqrt(dx * dx + dy * dy);
6249 }
6250
6251 /*
6252 * if(Config.DEBUG) { LOGGER.fine("distance to target:" + distance); }
6253 */
6254
6255 // Define movement angles needed
6256 // ^
6257 // | X (x,y)
6258 // | /
6259 // | /distance
6260 // | /
6261 // |/ angle
6262 // X ---------->
6263 // (curx,cury)
6264
6265 double cos;
6266 double sin;
6267
6268 // Check if a movement offset is defined or no distance to go through
6269 if (offset > 0 || distance < 1)
6270 {
6271 // approximation for moving closer when z coordinates are different
6272 //
6273 offset -= Math.abs(dz);
6274
6275 if (offset < 5)
6276 {
6277 offset = 5;
6278 }
6279
6280 // If no distance to go through, the movement is canceled
6281 if (distance < 1 || distance - offset <= 0)
6282 {
6283 sin = 0;
6284 cos = 1;
6285 distance = 0;
6286 x = curX;
6287 y = curY;
6288
6289 if (Config.DEBUG)
6290 {
6291 LOGGER.debug("Already in range, no movement needed.");
6292 }
6293
6294 // Notify the AI that the L2Character is arrived at destination
6295 getAI().notifyEvent(CtrlEvent.EVT_ARRIVED, null);
6296
6297 return;
6298 }
6299 // Calculate movement angles needed
6300 sin = dy / distance;
6301 cos = dx / distance;
6302
6303 distance -= offset - 5; // due to rounding error, we have to move a bit closer to be in range
6304
6305 // Calculate the new destination with offset included
6306 x = curX + (int) (distance * cos);
6307 y = curY + (int) (distance * sin);
6308
6309 }
6310 else
6311 {
6312 // Calculate movement angles needed
6313 sin = dy / distance;
6314 cos = dx / distance;
6315 }
6316
6317 // Create and Init a MoveData object
6318 MoveData m = new MoveData();
6319
6320 // GEODATA MOVEMENT CHECKS AND PATHFINDING
6321
6322 m.onGeodataPathIndex = -1; // Initialize not on geodata path
6323 m.disregardingGeodata = false;
6324
6325 if (Config.GEODATA > 0 && !isFlying() && (!isInsideZone(ZONE_WATER) || isInsideZone(ZONE_SIEGE)) && !(this instanceof L2NpcWalkerInstance))
6326 {
6327 final double originalDistance = distance;
6328 final int originalX = x;
6329 final int originalY = y;
6330 final int originalZ = z;
6331 final int gtx = originalX - L2World.MAP_MIN_X >> 4;
6332 final int gty = originalY - L2World.MAP_MIN_Y >> 4;
6333
6334 // Movement checks:
6335 // when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails)
6336 // when geodata == 1, for l2playableinstance and l2riftinstance only
6337 if (Config.GEODATA > 0 && !(this instanceof L2Attackable && ((L2Attackable) this).isReturningToSpawnPoint()) || this instanceof L2PcInstance || this instanceof L2Summon && !(getAI().getIntention() == AI_INTENTION_FOLLOW) || this instanceof L2RiftInvaderInstance || isAfraid())
6338 {
6339 if (isOnGeodataPath())
6340 {
6341 try
6342 {
6343 if (gtx == _move.geoPathGtx && gty == _move.geoPathGty)
6344 return;
6345 _move.onGeodataPathIndex = -1; // Set not on geodata path
6346 }
6347 catch (final NullPointerException e)
6348 {
6349 e.printStackTrace();
6350 }
6351 }
6352
6353 if (curX < L2World.MAP_MIN_X || curX > L2World.MAP_MAX_X || curY < L2World.MAP_MIN_Y || curY > L2World.MAP_MAX_Y)
6354 {
6355 // Temporary fix for character outside world region errors
6356 LOGGER.warn("Character " + getName() + " outside world area, in coordinates x:" + curX + " y:" + curY);
6357 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
6358 if (this instanceof L2PcInstance)
6359 {
6360 ((L2PcInstance) this).deleteMe();
6361 }
6362 else
6363 {
6364 onDecay();
6365 }
6366
6367 return;
6368 }
6369 final Location destiny = GeoData.getInstance().moveCheck(curX, curY, curZ, x, y, z);
6370 // location different if destination wasn't reached (or just z coord is different)
6371 x = destiny.getX();
6372 y = destiny.getY();
6373 z = destiny.getZ();
6374 distance = Math.sqrt((x - curX) * (x - curX) + (y - curY) * (y - curY));
6375
6376 }
6377 // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result
6378 // than the original movement was and the LoS gives a shorter distance than 2000
6379 // This way of detecting need for pathfinding could be changed.
6380 if (((this instanceof L2PcInstance) && Config.ALLOW_PLAYERS_PATHNODE || !(this instanceof L2PcInstance)) && Config.GEODATA == 2 && originalDistance - distance > 100 && distance < 2000 && !isAfraid())
6381 {
6382 // Path calculation
6383 // Overrides previous movement check
6384 if (this instanceof L2PlayableInstance || isInCombat() || this instanceof L2MinionInstance)
6385 {
6386 // int gx = (curX - L2World.MAP_MIN_X) >> 4;
6387 // int gy = (curY - L2World.MAP_MIN_Y) >> 4;
6388
6389 m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ);
6390 if (m.geoPath == null || m.geoPath.length < 2) // No path found
6391 {
6392 // Even though there's no path found (remember geonodes aren't perfect),
6393 // the mob is attacking and right now we set it so that the mob will go
6394 // after target anyway, is dz is small enough. Summons will follow their masters no matter what.
6395 if (Config.ALLOW_PLAYERS_PATHNODE && (this instanceof L2PcInstance)/* this instanceof L2PcInstance || */
6396 || (!(this instanceof L2PlayableInstance) && Math.abs(z - curZ) > 140) || (this instanceof L2Summon && !((L2Summon) this).getFollowStatus()))
6397 {
6398 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
6399 return;
6400 }
6401 m.disregardingGeodata = true;
6402 x = originalX;
6403 y = originalY;
6404 z = originalZ;
6405 distance = originalDistance;
6406 }
6407 else
6408 {
6409 m.onGeodataPathIndex = 0; // on first segment
6410 m.geoPathGtx = gtx;
6411 m.geoPathGty = gty;
6412 m.geoPathAccurateTx = originalX;
6413 m.geoPathAccurateTy = originalY;
6414
6415 x = m.geoPath[m.onGeodataPathIndex].getX();
6416 y = m.geoPath[m.onGeodataPathIndex].getY();
6417 z = m.geoPath[m.onGeodataPathIndex].getZ();
6418
6419 // check for doors in the route
6420 if (DoorTable.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z))
6421 {
6422 m.geoPath = null;
6423 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
6424 return;
6425 }
6426
6427 for (int i = 0; i < m.geoPath.length - 1; i++)
6428 {
6429 if (DoorTable.getInstance().checkIfDoorsBetween(m.geoPath[i], m.geoPath[i + 1]))
6430 {
6431 m.geoPath = null;
6432 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
6433 return;
6434 }
6435 }
6436
6437 dx = x - curX;
6438 dy = y - curY;
6439 distance = Math.sqrt(dx * dx + dy * dy);
6440 sin = dy / distance;
6441 cos = dx / distance;
6442 }
6443 }
6444 }
6445 // If no distance to go through, the movement is canceled
6446 if (((this instanceof L2PcInstance) && Config.ALLOW_PLAYERS_PATHNODE || !(this instanceof L2PcInstance)) && distance < 1 && (Config.GEODATA == 2 || this instanceof L2PlayableInstance || this instanceof L2RiftInvaderInstance || isAfraid()))
6447 {
6448 /*
6449 * sin = 0; cos = 1; distance = 0; x = curX; y = curY;
6450 */
6451
6452 if (this instanceof L2Summon)
6453 {
6454 ((L2Summon) this).setFollowStatus(false);
6455 }
6456
6457 // getAI().notifyEvent(CtrlEvent.EVT_ARRIVED, null);
6458 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
6459
6460 return;
6461 }
6462 }
6463
6464 // Caclulate the Nb of ticks between the current position and the destination
6465 // One tick added for rounding reasons
6466 final int ticksToMove = 1 + (int) (GameTimeController.TICKS_PER_SECOND * distance / speed);
6467
6468 // Calculate and set the heading of the L2Character
6469 setHeading((int) (Math.atan2(-sin, -cos) * 10430.37835) + 32768);
6470
6471 /*
6472 * if(Config.DEBUG) { LOGGER.fine("dist:" + distance + "speed:" + speed + " ttt:" + ticksToMove + " heading:" + getHeading()); }
6473 */
6474
6475 m._xDestination = x;
6476 m._yDestination = y;
6477 m._zDestination = z; // this is what was requested from client
6478 m._heading = 0;
6479
6480 m._moveStartTime = GameTimeController.getGameTicks();
6481
6482 /*
6483 * if(Config.DEBUG) { LOGGER.fine("time to target:" + ticksToMove); }
6484 */
6485
6486 // Set the L2Character _move object to MoveData object
6487 _move = m;
6488
6489 // Add the L2Character to movingObjects of the GameTimeController
6490 // The GameTimeController manage objects movement
6491 GameTimeController.getInstance().registerMovingObject(this);
6492
6493 // Create a task to notify the AI that L2Character arrives at a check point of the movement
6494 if (ticksToMove * GameTimeController.MILLIS_IN_TICK > 3000)
6495 {
6496 ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000);
6497 }
6498
6499 // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive
6500 // to destination by GameTimeController
6501
6502 m = null;
6503 }
6504
6505 /**
6506 * Move to next route point.
6507 * @return true, if successful
6508 */
6509 public boolean moveToNextRoutePoint()
6510 {
6511 if (!isOnGeodataPath())
6512 {
6513 // Cancel the move action
6514 _move = null;
6515 return false;
6516 }
6517
6518 // Get the Move Speed of the L2Charcater
6519 final float speed = getStat().getMoveSpeed();
6520
6521 if (speed <= 0 || isMovementDisabled())
6522 {
6523 // Cancel the move action
6524 _move = null;
6525 return false;
6526 }
6527
6528 MoveData md = _move;
6529 if (md == null)
6530 return false;
6531
6532 // Create and Init a MoveData object
6533 MoveData m = new MoveData();
6534
6535 // Update MoveData object
6536 m.onGeodataPathIndex = md.onGeodataPathIndex + 1; // next segment
6537 m.geoPath = md.geoPath;
6538 m.geoPathGtx = md.geoPathGtx;
6539 m.geoPathGty = md.geoPathGty;
6540 m.geoPathAccurateTx = md.geoPathAccurateTx;
6541 m.geoPathAccurateTy = md.geoPathAccurateTy;
6542
6543 if (md.onGeodataPathIndex == md.geoPath.length - 2)
6544 {
6545 m._xDestination = md.geoPathAccurateTx;
6546 m._yDestination = md.geoPathAccurateTy;
6547 m._zDestination = md.geoPath[m.onGeodataPathIndex].getZ();
6548 }
6549 else
6550 {
6551 m._xDestination = md.geoPath[m.onGeodataPathIndex].getX();
6552 m._yDestination = md.geoPath[m.onGeodataPathIndex].getY();
6553 m._zDestination = md.geoPath[m.onGeodataPathIndex].getZ();
6554 }
6555
6556 final double dx = m._xDestination - super.getX();
6557 final double dy = m._yDestination - super.getY();
6558 final double distance = Math.sqrt(dx * dx + dy * dy);
6559 final double sin = dy / distance;
6560 final double cos = dx / distance;
6561
6562 // Caclulate the Nb of ticks between the current position and the destination
6563 // One tick added for rounding reasons
6564 final int ticksToMove = 1 + (int) (GameTimeController.TICKS_PER_SECOND * distance / speed);
6565
6566 setHeading((int) (Math.atan2(-sin, -cos) * 10430.37835) + 32768);
6567 m._heading = 0; // ?
6568
6569 m._moveStartTime = GameTimeController.getGameTicks();
6570
6571 if (Config.DEBUG)
6572 {
6573 LOGGER.debug("Time to target:" + ticksToMove);
6574 }
6575
6576 // Set the L2Character _move object to MoveData object
6577 _move = m;
6578
6579 // Add the L2Character to movingObjects of the GameTimeController
6580 // The GameTimeController manage objects movement
6581 GameTimeController.getInstance().registerMovingObject(this);
6582
6583 // Create a task to notify the AI that L2Character arrives at a check point of the movement
6584 if (ticksToMove * GameTimeController.MILLIS_IN_TICK > 3000)
6585 {
6586 ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000);
6587 }
6588
6589 // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive
6590 // to destination by GameTimeController
6591
6592 // Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
6593 CharMoveToLocation msg = new CharMoveToLocation(this);
6594 broadcastPacket(msg);
6595
6596 msg = null;
6597 m = null;
6598 md = null;
6599
6600 return true;
6601 }
6602
6603 /**
6604 * Validate movement heading.
6605 * @param heading the heading
6606 * @return true, if successful
6607 */
6608 public boolean validateMovementHeading(final int heading)
6609 {
6610 MoveData md = _move;
6611
6612 if (md == null)
6613 return true;
6614
6615 boolean result = true;
6616
6617 if (md._heading != heading)
6618 {
6619 result = md._heading == 0;
6620 md._heading = heading;
6621 }
6622
6623 md = null;
6624
6625 return result;
6626 }
6627
6628 /**
6629 * Return the distance between the current position of the L2Character and the target (x,y).<BR>
6630 * <BR>
6631 * @param x X position of the target
6632 * @param y Y position of the target
6633 * @return the plan distance
6634 * @deprecated use getPlanDistanceSq(int x, int y, int z)
6635 */
6636 @Deprecated
6637 public final double getDistance(final int x, final int y)
6638 {
6639 final double dx = x - getX();
6640 final double dy = y - getY();
6641
6642 return Math.sqrt(dx * dx + dy * dy);
6643 }
6644
6645 /**
6646 * Return the distance between the current position of the L2Character and the target (x,y).<BR>
6647 * <BR>
6648 * @param x X position of the target
6649 * @param y Y position of the target
6650 * @param z the z
6651 * @return the plan distance
6652 * @deprecated use getPlanDistanceSq(int x, int y, int z)
6653 */
6654 @Deprecated
6655 public final double getDistance(final int x, final int y, final int z)
6656 {
6657 final double dx = x - getX();
6658 final double dy = y - getY();
6659 final double dz = z - getZ();
6660
6661 return Math.sqrt(dx * dx + dy * dy + dz * dz);
6662 }
6663
6664 /**
6665 * Return the squared distance between the current position of the L2Character and the given object.<BR>
6666 * <BR>
6667 * @param object L2Object
6668 * @return the squared distance
6669 */
6670 public final double getDistanceSq(final L2Object object)
6671 {
6672 return getDistanceSq(object.getX(), object.getY(), object.getZ());
6673 }
6674
6675 /**
6676 * Return the squared distance between the current position of the L2Character and the given x, y, z.<BR>
6677 * <BR>
6678 * @param x X position of the target
6679 * @param y Y position of the target
6680 * @param z Z position of the target
6681 * @return the squared distance
6682 */
6683 public final double getDistanceSq(final int x, final int y, final int z)
6684 {
6685 final double dx = x - getX();
6686 final double dy = y - getY();
6687 final double dz = z - getZ();
6688
6689 return dx * dx + dy * dy + dz * dz;
6690 }
6691
6692 /**
6693 * Return the squared plan distance between the current position of the L2Character and the given object.<BR>
6694 * (check only x and y, not z)<BR>
6695 * <BR>
6696 * @param object L2Object
6697 * @return the squared plan distance
6698 */
6699 public final double getPlanDistanceSq(final L2Object object)
6700 {
6701 return getPlanDistanceSq(object.getX(), object.getY());
6702 }
6703
6704 /**
6705 * Return the squared plan distance between the current position of the L2Character and the given x, y, z.<BR>
6706 * (check only x and y, not z)<BR>
6707 * <BR>
6708 * @param x X position of the target
6709 * @param y Y position of the target
6710 * @return the squared plan distance
6711 */
6712 public final double getPlanDistanceSq(final int x, final int y)
6713 {
6714 final double dx = x - getX();
6715 final double dy = y - getY();
6716
6717 return dx * dx + dy * dy;
6718 }
6719
6720 /**
6721 * Check if this object is inside the given radius around the given object. Warning: doesn't cover collision radius!<BR>
6722 * <BR>
6723 * @param object the target
6724 * @param radius the radius around the target
6725 * @param checkZ should we check Z axis also
6726 * @param strictCheck true if (distance < radius), false if (distance <= radius)
6727 * @return true is the L2Character is inside the radius.
6728 */
6729 public final boolean isInsideRadius(final L2Object object, final int radius, final boolean checkZ, final boolean strictCheck)
6730 {
6731 if (object != null)
6732 return isInsideRadius(object.getX(), object.getY(), object.getZ(), radius, checkZ, strictCheck);
6733 return false;
6734 }
6735
6736 /**
6737 * Check if this object is inside the given plan radius around the given point. Warning: doesn't cover collision radius!<BR>
6738 * <BR>
6739 * @param x X position of the target
6740 * @param y Y position of the target
6741 * @param radius the radius around the target
6742 * @param strictCheck true if (distance < radius), false if (distance <= radius)
6743 * @return true is the L2Character is inside the radius.
6744 */
6745 public final boolean isInsideRadius(final int x, final int y, final int radius, final boolean strictCheck)
6746 {
6747 return isInsideRadius(x, y, 0, radius, false, strictCheck);
6748 }
6749
6750 /**
6751 * Check if this object is inside the given radius around the given point.<BR>
6752 * <BR>
6753 * @param x X position of the target
6754 * @param y Y position of the target
6755 * @param z Z position of the target
6756 * @param radius the radius around the target
6757 * @param checkZ should we check Z axis also
6758 * @param strictCheck true if (distance < radius), false if (distance <= radius)
6759 * @return true is the L2Character is inside the radius.
6760 */
6761 public final boolean isInsideRadius(final int x, final int y, final int z, final int radius, final boolean checkZ, final boolean strictCheck)
6762 {
6763 final double dx = x - getX();
6764 final double dy = y - getY();
6765 final double dz = z - getZ();
6766
6767 if (strictCheck)
6768 {
6769 if (checkZ)
6770 return dx * dx + dy * dy + dz * dz < radius * radius;
6771 return dx * dx + dy * dy < radius * radius;
6772 }
6773 if (checkZ)
6774 return dx * dx + dy * dy + dz * dz <= radius * radius;
6775 return dx * dx + dy * dy <= radius * radius;
6776 }
6777
6778 // /**
6779 // * event that is called when the destination coordinates are reached
6780 // */
6781 // public void onTargetReached()
6782 // {
6783 // L2Character pawn = getPawnTarget();
6784 //
6785 // if (pawn != null)
6786 // {
6787 // int x = pawn.getX(), y=pawn.getY(),z = pawn.getZ();
6788 //
6789 // double distance = getDistance(x,y);
6790 // if (getCurrentState() == STATE_FOLLOW)
6791 // {
6792 // calculateMovement(x,y,z,distance);
6793 // return;
6794 // }
6795 //
6796 // // takes care of moving away but distance is 0 so i won't follow problem
6797 //
6798 //
6799 // if (((distance > getAttackRange()) && (getCurrentState() == STATE_ATTACKING)) || (pawn.isMoving() && getCurrentState() != STATE_ATTACKING))
6800 // {
6801 // calculateMovement(x,y,z,distance);
6802 // return;
6803 // }
6804 //
6805 // }
6806 // // update x,y,z with the current calculated position
6807 // stopMove();
6808 //
6809 // if (Config.DEBUG)
6810 // LOGGER.fine(this.getName() +":: target reached at: x "+getX()+" y "+getY()+ " z:" + getZ());
6811 //
6812 // if (getPawnTarget() != null)
6813 // {
6814 //
6815 // setPawnTarget(null);
6816 // setMovingToPawn(false);
6817 // }
6818 // }
6819 //
6820 // public void setTo(int x, int y, int z, int heading)
6821 // {
6822 // setX(x);
6823 // setY(y);
6824 // setZ(z);
6825 // setHeading(heading);
6826 // updateCurrentWorldRegion();
6827 // if (isMoving())
6828 // {
6829 // setCurrentState(STATE_IDLE);
6830 // StopMove setto = new StopMove(this);
6831 // broadcastPacket(setto);
6832 // }
6833 // else
6834 // {
6835 // ValidateLocation setto = new ValidateLocation(this);
6836 // broadcastPacket(setto);
6837 // }
6838 //
6839 // FinishRotation fr = new FinishRotation(this);
6840 // broadcastPacket(fr);
6841 // }
6842
6843 // protected void startCombat()
6844 // {
6845 // if (_currentAttackTask == null )//&& !isInCombat())
6846 // {
6847 // _currentAttackTask = ThreadPoolManager.getInstance().scheduleMed(new AttackTask(), 0);
6848 // }
6849 // else
6850 // {
6851 // LOGGER.info("multiple attacks want to start in parallel. prevented.");
6852 // }
6853 // }
6854 //
6855
6856 /**
6857 * Return the Weapon Expertise Penalty of the L2Character.<BR>
6858 * <BR>
6859 * @return the weapon expertise penalty
6860 */
6861 public float getWeaponExpertisePenalty()
6862 {
6863 return 1.f;
6864 }
6865
6866 /**
6867 * Return the Armour Expertise Penalty of the L2Character.<BR>
6868 * <BR>
6869 * @return the armour expertise penalty
6870 */
6871 public float getArmourExpertisePenalty()
6872 {
6873 return 1.f;
6874 }
6875
6876 /**
6877 * Set _attacking corresponding to Attacking Body part to CHEST.<BR>
6878 * <BR>
6879 */
6880 public void setAttackingBodypart()
6881 {
6882 _attacking = Inventory.PAPERDOLL_CHEST;
6883 }
6884
6885 /**
6886 * Retun True if arrows are available.<BR>
6887 * <BR>
6888 * <B><U> Overriden in </U> :</B><BR>
6889 * <BR>
6890 * <li>L2PcInstance</li><BR>
6891 * <BR>
6892 * @return true, if successful
6893 */
6894 protected boolean checkAndEquipArrows()
6895 {
6896 return true;
6897 }
6898
6899 /**
6900 * Add Exp and Sp to the L2Character.<BR>
6901 * <BR>
6902 * <B><U> Overriden in </U> :</B><BR>
6903 * <BR>
6904 * <li>L2PcInstance</li> <li>L2PetInstance</li><BR>
6905 * <BR>
6906 * @param addToExp the add to exp
6907 * @param addToSp the add to sp
6908 */
6909 public void addExpAndSp(final long addToExp, final int addToSp)
6910 {
6911 // Dummy method (overridden by players and pets)
6912 }
6913
6914 /**
6915 * Return the active weapon instance (always equiped in the right hand).<BR>
6916 * <BR>
6917 * <B><U> Overriden in </U> :</B><BR>
6918 * <BR>
6919 * <li>L2PcInstance</li><BR>
6920 * <BR>
6921 * @return the active weapon instance
6922 */
6923 public abstract L2ItemInstance getActiveWeaponInstance();
6924
6925 /**
6926 * Return the active weapon item (always equiped in the right hand).<BR>
6927 * <BR>
6928 * <B><U> Overriden in </U> :</B><BR>
6929 * <BR>
6930 * <li>L2PcInstance</li><BR>
6931 * <BR>
6932 * @return the active weapon item
6933 */
6934 public abstract L2Weapon getActiveWeaponItem();
6935
6936 /**
6937 * Return the secondary weapon instance (always equiped in the left hand).<BR>
6938 * <BR>
6939 * <B><U> Overriden in </U> :</B><BR>
6940 * <BR>
6941 * <li>L2PcInstance</li><BR>
6942 * <BR>
6943 * @return the secondary weapon instance
6944 */
6945 public abstract L2ItemInstance getSecondaryWeaponInstance();
6946
6947 /**
6948 * Return the secondary weapon item (always equiped in the left hand).<BR>
6949 * <BR>
6950 * <B><U> Overriden in </U> :</B><BR>
6951 * <BR>
6952 * <li>L2PcInstance</li><BR>
6953 * <BR>
6954 * @return the secondary weapon item
6955 */
6956 public abstract L2Weapon getSecondaryWeaponItem();
6957
6958 /**
6959 * Manage hit process (called by Hit Task).<BR>
6960 * <BR>
6961 * <B><U> Actions</U> :</B><BR>
6962 * <BR>
6963 * <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>
6964 * <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>
6965 * <BR>
6966 * @param target The L2Character targeted
6967 * @param damage Nb of HP to reduce
6968 * @param crit True if hit is critical
6969 * @param miss True if hit is missed
6970 * @param soulshot True if SoulShot are charged
6971 * @param shld True if shield is efficient
6972 */
6973 protected void onHitTimer(final L2Character target, int damage, final boolean crit, final boolean miss, final boolean soulshot, final boolean shld)
6974 {
6975 // If the attacker/target is dead or use fake death, notify the AI with EVT_CANCEL
6976 // and send a Server->Client packet ActionFailed (if attacker is a L2PcInstance)
6977 if (target == null || isAlikeDead() || this instanceof L2NpcInstance && ((L2NpcInstance) this).isEventMob)
6978 {
6979 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
6980 return;
6981 }
6982
6983 if (this instanceof L2NpcInstance && target.isAlikeDead() || target.isDead() || !getKnownList().knowsObject(target) && !(this instanceof L2DoorInstance))
6984 {
6985 // getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE, null);
6986 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
6987
6988 sendPacket(ActionFailed.STATIC_PACKET);
6989 return;
6990 }
6991
6992 if (miss)
6993 {
6994 if (target instanceof L2PcInstance)
6995 {
6996 SystemMessage sm = new SystemMessage(SystemMessageId.AVOIDED_S1S_ATTACK);
6997
6998 if (this instanceof L2Summon)
6999 {
7000 final int mobId = ((L2Summon) this).getTemplate().npcId;
7001 sm.addNpcName(mobId);
7002 }
7003 else
7004 {
7005 sm.addString(getName());
7006 }
7007
7008 ((L2PcInstance) target).sendPacket(sm);
7009
7010 sm = null;
7011 }
7012 }
7013
7014 // If attack isn't aborted, send a message system (critical hit, missed...) to attacker/target if they are L2PcInstance
7015 if (!isAttackAborted())
7016 {
7017 if (Config.ALLOW_RAID_BOSS_PETRIFIED && (this instanceof L2PcInstance || this instanceof L2Summon)) // Check if option is True Or False.
7018 {
7019 boolean to_be_cursed = false;
7020
7021 // check on BossZone raid lvl
7022 if (!(target instanceof L2PlayableInstance) && !(target instanceof L2SummonInstance))
7023 { // this must work just on mobs/raids
7024
7025 if ((target.isRaid() && getLevel() > target.getLevel() + 8) || (!(target instanceof L2PcInstance) && (target.getTarget() != null && target.getTarget() instanceof L2RaidBossInstance && getLevel() > ((L2RaidBossInstance) target.getTarget()).getLevel() + 8)) || (!(target instanceof L2PcInstance) && (target.getTarget() != null && target.getTarget() instanceof L2GrandBossInstance && getLevel() > ((L2GrandBossInstance) target.getTarget()).getLevel() + 8)))
7026
7027 {
7028 to_be_cursed = true;
7029 }
7030
7031 // advanced check too if not already cursed
7032 if (!to_be_cursed)
7033 {
7034 int boss_id = -1;
7035 L2NpcTemplate boss_template = null;
7036 final L2BossZone boss_zone = GrandBossManager.getInstance().getZone(this);
7037
7038 if (boss_zone != null)
7039 {
7040 boss_id = boss_zone.getBossId();
7041 }
7042
7043 // boolean alive = false;
7044
7045 if (boss_id != -1)
7046 {
7047 boss_template = NpcTable.getInstance().getTemplate(boss_id);
7048
7049 if (boss_template != null && getLevel() > boss_template.getLevel() + 8)
7050 {
7051 L2MonsterInstance boss_instance = null;
7052
7053 if (boss_template.type.equals("L2RaidBoss"))
7054 {
7055 final StatsSet actual_boss_stat = RaidBossSpawnManager.getInstance().getStatsSet(boss_id);
7056 if (actual_boss_stat != null)
7057 {
7058 // alive = actual_boss_stat.getLong("respawnTime") == 0;
7059 boss_instance = RaidBossSpawnManager.getInstance().getBoss(boss_id);
7060 }
7061 }
7062 else if (boss_template.type.equals("L2GrandBoss"))
7063 {
7064 final StatsSet actual_boss_stat = GrandBossManager.getInstance().getStatsSet(boss_id);
7065 if (actual_boss_stat != null)
7066 {
7067 // alive = actual_boss_stat.getLong("respawn_time") == 0;
7068 boss_instance = GrandBossManager.getInstance().getBoss(boss_id);
7069 }
7070 }
7071
7072 // max allowed rage into take cursed is 3000
7073 if (boss_instance != null/* && alive */&& boss_instance.isInsideRadius(this, 3000, false, false))
7074 {
7075 to_be_cursed = true;
7076 }
7077 }
7078 }
7079 }
7080 }
7081
7082 if (to_be_cursed)
7083 {
7084 L2Skill skill = SkillTable.getInstance().getInfo(4515, 1);
7085
7086 if (skill != null)
7087 {
7088 abortAttack();
7089 abortCast();
7090 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
7091 skill.getEffects(target, this, false, false, false);
7092
7093 if (this instanceof L2Summon)
7094 {
7095 final L2Summon src = ((L2Summon) this);
7096 if (src.getOwner() != null)
7097 {
7098 src.getOwner().abortAttack();
7099 src.getOwner().abortCast();
7100 src.getOwner().getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
7101 skill.getEffects(target, src.getOwner(), false, false, false);
7102 }
7103 }
7104 }
7105 else
7106 LOGGER.warn("Skill 4515 at level 1 is missing in DP.");
7107
7108 skill = null;
7109
7110 if (target instanceof L2MinionInstance)
7111 {
7112 ((L2MinionInstance) target).getLeader().stopHating(this);
7113
7114 List<L2MinionInstance> spawnedMinions = ((L2MinionInstance) target).getLeader().getSpawnedMinions();
7115 if (spawnedMinions != null && spawnedMinions.size() > 0)
7116 {
7117 Iterator<L2MinionInstance> itr = spawnedMinions.iterator();
7118 L2MinionInstance minion;
7119 while (itr.hasNext())
7120 {
7121 minion = itr.next();
7122 if (((L2MinionInstance) target).getLeader().getMostHated() == null)
7123 {
7124 ((L2AttackableAI) minion.getAI()).setGlobalAggro(-25);
7125 minion.clearAggroList();
7126 minion.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
7127 minion.setWalking();
7128 }
7129 if (minion != null && !minion.isDead())
7130 {
7131 ((L2AttackableAI) minion.getAI()).setGlobalAggro(-25);
7132 minion.clearAggroList();
7133 minion.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
7134 minion.addDamage(((L2MinionInstance) target).getLeader().getMostHated(), 100);
7135 }
7136 }
7137 itr = null;
7138 spawnedMinions = null;
7139 minion = null;
7140 }
7141 }
7142 else
7143 {
7144 ((L2Attackable) target).stopHating(this);
7145 List<L2MinionInstance> spawnedMinions = ((L2MonsterInstance) target).getSpawnedMinions();
7146 if (spawnedMinions != null && spawnedMinions.size() > 0)
7147 {
7148 Iterator<L2MinionInstance> itr = spawnedMinions.iterator();
7149 L2MinionInstance minion;
7150 while (itr.hasNext())
7151 {
7152 minion = itr.next();
7153 if (((L2Attackable) target).getMostHated() == null)
7154 {
7155 ((L2AttackableAI) minion.getAI()).setGlobalAggro(-25);
7156 minion.clearAggroList();
7157 minion.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
7158 minion.setWalking();
7159 }
7160 if (minion != null && !minion.isDead())
7161 {
7162 ((L2AttackableAI) minion.getAI()).setGlobalAggro(-25);
7163 minion.clearAggroList();
7164 minion.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
7165 minion.addDamage(((L2Attackable) target).getMostHated(), 100);
7166 }
7167 }
7168 itr = null;
7169 spawnedMinions = null;
7170 minion = null;
7171 }
7172 }
7173
7174 damage = 0; // prevents messing up drop calculation
7175 }
7176 }
7177
7178 sendDamageMessage(target, damage, false, crit, miss);
7179
7180 // If L2Character target is a L2PcInstance, send a system message
7181 if (target instanceof L2PcInstance)
7182 {
7183 L2PcInstance enemy = (L2PcInstance) target;
7184
7185 // Check if shield is efficient
7186 if (shld)
7187 {
7188 enemy.sendPacket(new SystemMessage(SystemMessageId.SHIELD_DEFENCE_SUCCESSFULL));
7189 // else if (!miss && damage < 1)
7190 // enemy.sendMessage("You hit the target's armor.");
7191 }
7192
7193 enemy = null;
7194 }
7195 else if (target instanceof L2Summon)
7196 {
7197 L2Summon activeSummon = (L2Summon) target;
7198
7199 SystemMessage sm = new SystemMessage(SystemMessageId.PET_RECEIVED_S2_DAMAGE_BY_S1);
7200 sm.addString(getName());
7201 sm.addNumber(damage);
7202 activeSummon.getOwner().sendPacket(sm);
7203
7204 sm = null;
7205 activeSummon = null;
7206 }
7207
7208 if (!miss && damage > 0)
7209 {
7210 L2Weapon weapon = getActiveWeaponItem();
7211 final boolean isBow = weapon != null && weapon.getItemType().toString().equalsIgnoreCase("Bow");
7212
7213 if (!isBow) // Do not reflect or absorb if weapon is of type bow
7214 {
7215 // Absorb HP from the damage inflicted
7216 final double absorbPercent = getStat().calcStat(Stats.ABSORB_DAMAGE_PERCENT, 0, null, null);
7217
7218 if (absorbPercent > 0)
7219 {
7220 final int maxCanAbsorb = (int) (getMaxHp() - getCurrentHp());
7221 int absorbDamage = (int) (absorbPercent / 100. * damage);
7222
7223 if (absorbDamage > maxCanAbsorb)
7224 {
7225 absorbDamage = maxCanAbsorb; // Can't absord more than max hp
7226 }
7227
7228 if (absorbDamage > 0)
7229 {
7230 setCurrentHp(getCurrentHp() + absorbDamage);
7231
7232 // Custom messages - nice but also more network load
7233 /*
7234 * if (this instanceof L2PcInstance) ((L2PcInstance)this).sendMessage("You absorbed " + absorbDamage + " damage."); else if (this instanceof L2Summon) ((L2Summon)this).getOwner().sendMessage("Summon absorbed " + absorbDamage + " damage."); else if (Config.DEBUG)
7235 * LOGGER.info(getName() + " absorbed " + absorbDamage + " damage.");
7236 */
7237 }
7238 }
7239
7240 // Reduce HP of the target and calculate reflection damage to reduce HP of attacker if necessary
7241 final double reflectPercent = target.getStat().calcStat(Stats.REFLECT_DAMAGE_PERCENT, 0, null, null);
7242
7243 if (reflectPercent > 0)
7244 {
7245 int reflectedDamage = (int) (reflectPercent / 100. * damage);
7246 damage -= reflectedDamage;
7247
7248 if (reflectedDamage > target.getMaxHp())
7249 {
7250 reflectedDamage = target.getMaxHp();
7251 }
7252
7253 getStatus().reduceHp(reflectedDamage, target, true);
7254
7255 // Custom messages - nice but also more network load
7256 /*
7257 * if (target instanceof L2PcInstance) ((L2PcInstance)target).sendMessage("You reflected " + reflectedDamage + " damage."); else if (target instanceof L2Summon) ((L2Summon)target).getOwner().sendMessage("Summon reflected " + reflectedDamage + " damage."); if (this instanceof
7258 * L2PcInstance) ((L2PcInstance)this).sendMessage("Target reflected to you " + reflectedDamage + " damage."); else if (this instanceof L2Summon) ((L2Summon)this).getOwner().sendMessage("Target reflected to your summon " + reflectedDamage + " damage.");
7259 */
7260 }
7261 }
7262
7263 target.reduceCurrentHp(damage, this);
7264
7265 // Notify AI with EVT_ATTACKED
7266 target.getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, this);
7267 getAI().clientStartAutoAttack();
7268
7269 // Manage attack or cast break of the target (calculating rate, sending message...)
7270 if (!target.isRaid() && Formulas.calcAtkBreak(target, damage))
7271 {
7272 target.breakAttack();
7273 target.breakCast();
7274 }
7275
7276 // Maybe launch chance skills on us
7277 if (_chanceSkills != null)
7278 {
7279 _chanceSkills.onHit(target, false, crit);
7280 }
7281
7282 // Maybe launch chance skills on target
7283 if (target.getChanceSkills() != null)
7284 {
7285 target.getChanceSkills().onHit(this, true, crit);
7286 }
7287
7288 weapon = null;
7289 }
7290
7291 // Launch weapon Special ability effect if available
7292 L2Weapon activeWeapon = getActiveWeaponItem();
7293
7294 if (activeWeapon != null)
7295 {
7296 activeWeapon.getSkillEffects(this, target, crit);
7297 }
7298
7299 /*
7300 * COMMENTED OUT BY nexus - 2006-08-17 We must not discharge the soulshouts at the onHitTimer method, as this can cause unwanted soulshout consumption if the attacker recharges the soulshot right after an attack request but before his hit actually lands on the target. The soulshot
7301 * discharging has been moved to the doAttack method: As soon as we know that we didn't missed the hit there, then we must discharge any charged soulshots.
7302 */
7303 /*
7304 * L2ItemInstance weapon = getActiveWeaponInstance(); if (!miss) { if (this instanceof L2Summon && !(this instanceof L2PetInstance)) { if (((L2Summon)this).getChargedSoulShot() != L2ItemInstance.CHARGED_NONE) ((L2Summon)this).setChargedSoulShot(L2ItemInstance.CHARGED_NONE); } else { if
7305 * (weapon != null && weapon.getChargedSoulshot() != L2ItemInstance.CHARGED_NONE) weapon.setChargedSoulshot(L2ItemInstance.CHARGED_NONE); } }
7306 */
7307
7308 activeWeapon = null;
7309
7310 if (this instanceof L2PcInstance && ((L2PcInstance) this).isMovingTaskDefined())
7311 {
7312 final L2ItemInstance rhand = ((L2PcInstance) this).getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
7313 if (rhand != null && rhand.getItemType() == L2WeaponType.BOW)
7314 ((L2PcInstance) this).startMovingTask();
7315 }
7316 return;
7317 }
7318
7319 if (this instanceof L2PcInstance && ((L2PcInstance) this).isMovingTaskDefined())
7320 {
7321 final L2ItemInstance rhand = ((L2PcInstance) this).getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
7322 if (rhand != null && rhand.getItemType() == L2WeaponType.BOW)
7323 ((L2PcInstance) this).startMovingTask();
7324 }
7325
7326 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
7327 }
7328
7329 /**
7330 * Break an attack and send Server->Client ActionFailed packet and a System Message to the L2Character.<BR>
7331 * <BR>
7332 */
7333 public void breakAttack()
7334 {
7335 if (isAttackingNow())
7336 {
7337 // Abort the attack of the L2Character and send Server->Client ActionFailed packet
7338 abortAttack();
7339
7340 if (this instanceof L2PcInstance)
7341 {
7342 sendPacket(ActionFailed.STATIC_PACKET);
7343
7344 // Send a system message
7345 sendPacket(new SystemMessage(SystemMessageId.ATTACK_FAILED));
7346 }
7347 }
7348 }
7349
7350 /**
7351 * Break a cast and send Server->Client ActionFailed packet and a System Message to the L2Character.<BR>
7352 * <BR>
7353 */
7354 public void breakCast()
7355 {
7356 // damage can only cancel magical skills
7357 if (isCastingNow() && canAbortCast() && getLastSkillCast() != null && getLastSkillCast().isMagic())
7358 {
7359 // Abort the cast of the L2Character and send Server->Client MagicSkillCanceld/ActionFailed packet.
7360 abortCast();
7361
7362 if (this instanceof L2PcInstance)
7363 {
7364 // Send a system message
7365 sendPacket(new SystemMessage(SystemMessageId.CASTING_INTERRUPTED));
7366 }
7367 }
7368 }
7369
7370 /**
7371 * Reduce the arrow number of the L2Character.<BR>
7372 * <BR>
7373 * <B><U> Overriden in </U> :</B><BR>
7374 * <BR>
7375 * <li>L2PcInstance</li><BR>
7376 * <BR>
7377 */
7378 protected void reduceArrowCount()
7379 {
7380 // default is to do nothin
7381 }
7382
7383 /**
7384 * Manage Forced attack (shift + select target).<BR>
7385 * <BR>
7386 * <B><U> Actions</U> :</B><BR>
7387 * <BR>
7388 * <li>If L2Character or target is in a town area, send a system message TARGET_IN_PEACEZONE a Server->Client packet ActionFailed</li> <li>If target is confused, send a Server->Client packet ActionFailed</li> <li>If L2Character is a L2ArtefactInstance, send a Server->Client packet ActionFailed</li>
7389 * <li>Send a Server->Client packet MyTargetSelected to start attack and Notify AI with AI_INTENTION_ATTACK</li><BR>
7390 * <BR>
7391 * @param player The L2PcInstance to attack
7392 */
7393 @Override
7394 public void onForcedAttack(final L2PcInstance player)
7395 {
7396 if (player.getTarget() == null || !(player.getTarget() instanceof L2Character))
7397 {
7398 // If target is not attackable, send a Server->Client packet ActionFailed
7399 player.sendPacket(ActionFailed.STATIC_PACKET);
7400 return;
7401 }
7402
7403 if (isInsidePeaceZone(player))
7404 {
7405 // If L2Character or target is in a peace zone, send a system message TARGET_IN_PEACEZONE a Server->Client packet ActionFailed
7406 player.sendPacket(new SystemMessage(SystemMessageId.TARGET_IN_PEACEZONE));
7407 player.sendPacket(ActionFailed.STATIC_PACKET);
7408 return;
7409 }
7410
7411 if (player.isInOlympiadMode() && player.getTarget() != null && player.getTarget() instanceof L2PlayableInstance)
7412 {
7413 L2PcInstance target;
7414
7415 if (player.getTarget() instanceof L2Summon)
7416 {
7417 target = ((L2Summon) player.getTarget()).getOwner();
7418 }
7419 else
7420 {
7421 target = (L2PcInstance) player.getTarget();
7422 }
7423
7424 if (target.isInOlympiadMode() && !player.isOlympiadStart() && player.getOlympiadGameId() == target.getOlympiadGameId())
7425 {
7426 // if L2PcInstance is in Olympia and the match isn't already start, send a Server->Client packet ActionFailed
7427 player.sendPacket(ActionFailed.STATIC_PACKET);
7428 return;
7429 }
7430
7431 target = null;
7432 }
7433
7434 if (player.isConfused() || player.isBlocked())
7435 {
7436 // If target is confused, send a Server->Client packet ActionFailed
7437 player.sendPacket(ActionFailed.STATIC_PACKET);
7438 return;
7439 }
7440
7441 // GeoData Los Check or dz > 1000
7442 if (!GeoData.getInstance().canSeeTarget(player, this))
7443 {
7444 player.sendPacket(new SystemMessage(SystemMessageId.CANT_SEE_TARGET));
7445 player.sendPacket(ActionFailed.STATIC_PACKET);
7446 return;
7447 }
7448 // Notify AI with AI_INTENTION_ATTACK
7449 player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
7450 }
7451
7452 /**
7453 * Return True if inside peace zone.<BR>
7454 * <BR>
7455 * @param attacker the attacker
7456 * @return true, if is inside peace zone
7457 */
7458 public boolean isInsidePeaceZone(final L2PcInstance attacker)
7459 {
7460 return isInsidePeaceZone(attacker, this);
7461
7462 }
7463
7464 /**
7465 * Checks if is inside peace zone.
7466 * @param attacker the attacker
7467 * @param target the target
7468 * @return true, if is inside peace zone
7469 */
7470 public static boolean isInsidePeaceZone(final L2Object attacker, final L2Object target)
7471 {
7472 if (target == null)
7473 return false;
7474
7475 if (target instanceof L2NpcInstance && Config.DISABLE_ATTACK_NPC_TYPE)
7476 {
7477 final String mobtype = ((L2NpcInstance) target).getTemplate().type;
7478 if (Config.LIST_ALLOWED_NPC_TYPES.contains(mobtype))
7479 {
7480 return false;
7481 }
7482 }
7483
7484 // Attack Monster on Peace Zone like L2OFF.
7485 if (target instanceof L2MonsterInstance || attacker instanceof L2MonsterInstance && Config.ALT_MOB_AGRO_IN_PEACEZONE)
7486 return false;
7487
7488 // Attack Guard on Peace Zone like L2OFF.
7489 if (target instanceof L2GuardInstance || attacker instanceof L2GuardInstance)
7490 return false;
7491 // Attack NPC on Peace Zone like L2OFF.
7492 if (target instanceof L2NpcInstance || attacker instanceof L2NpcInstance)
7493 return false;
7494
7495 if (Config.ALT_GAME_KARMA_PLAYER_CAN_BE_KILLED_IN_PEACEZONE)
7496 {
7497 // allows red to be attacked and red to attack flagged players
7498 if (target instanceof L2PcInstance && ((L2PcInstance) target).getKarma() > 0)
7499 return false;
7500
7501 if (target instanceof L2Summon && ((L2Summon) target).getOwner().getKarma() > 0)
7502 return false;
7503
7504 if (attacker instanceof L2PcInstance && ((L2PcInstance) attacker).getKarma() > 0)
7505 {
7506 if (target instanceof L2PcInstance && ((L2PcInstance) target).getPvpFlag() > 0)
7507 return false;
7508
7509 if (target instanceof L2Summon && ((L2Summon) target).getOwner().getPvpFlag() > 0)
7510 return false;
7511 }
7512
7513 if (attacker instanceof L2Summon && ((L2Summon) attacker).getOwner().getKarma() > 0)
7514 {
7515 if (target instanceof L2PcInstance && ((L2PcInstance) target).getPvpFlag() > 0)
7516 return false;
7517
7518 if (target instanceof L2Summon && ((L2Summon) target).getOwner().getPvpFlag() > 0)
7519 return false;
7520 }
7521 }
7522
7523 // Right now only L2PcInstance has up-to-date zone status...
7524 //
7525 L2PcInstance src = null;
7526 L2PcInstance dst = null;
7527
7528 if (attacker instanceof L2PlayableInstance && target instanceof L2PlayableInstance)
7529 {
7530 if (attacker instanceof L2PcInstance)
7531 {
7532 src = (L2PcInstance) attacker;
7533 }
7534 else if (attacker instanceof L2Summon)
7535 {
7536 src = ((L2Summon) attacker).getOwner();
7537 }
7538
7539 if (target instanceof L2PcInstance)
7540 {
7541 dst = (L2PcInstance) target;
7542 }
7543 else if (target instanceof L2Summon)
7544 {
7545 dst = ((L2Summon) target).getOwner();
7546 }
7547 }
7548
7549 if (src != null && src.getAccessLevel().allowPeaceAttack())
7550 {
7551 return false;
7552 }
7553
7554 // checks on event status
7555 if (src != null && dst != null)
7556 {
7557 // Attacker and target can fight in olympiad with peace zone
7558 if (src.isInOlympiadMode() && src.isOlympiadStart() && dst.isInOlympiadMode() && dst.isOlympiadStart())
7559 return false;
7560
7561 if (dst.isInFunEvent() && src.isInFunEvent())
7562 {
7563
7564 if (src.isInStartedTVTEvent() && dst.isInStartedTVTEvent())
7565 return false;
7566 else if (src.isInStartedDMEvent() && dst.isInStartedDMEvent())
7567 return false;
7568 else if (src.isInStartedCTFEvent() && dst.isInStartedCTFEvent())
7569 return false;
7570 else if (src.isInStartedVIPEvent() && dst.isInStartedVIPEvent())
7571 return false;
7572 else if (src.isInStartedVIPEvent() && dst.isInStartedVIPEvent())
7573 return false;
7574 // else
7575 // different events in same location --> already checked
7576 }
7577 }
7578
7579 if (attacker instanceof L2Character && ((L2Character) attacker).isInsideZone(ZONE_PEACE)
7580 // the townzone has to be already peace zone
7581 // || TownManager.getInstance().getTown(attacker.getX(), attacker.getY(), attacker.getZ())!= null
7582 )
7583 return true;
7584
7585 if (target instanceof L2Character && ((L2Character) target).isInsideZone(ZONE_PEACE)
7586 // the townzone has to be already peace zone
7587 // || TownManager.getInstance().getTown(target.getX(), target.getY(), target.getZ())!= null
7588 )
7589 return true;
7590
7591 return false;
7592 }
7593
7594 /**
7595 * return true if this character is inside an active grid.
7596 * @return the boolean
7597 */
7598 public Boolean isInActiveRegion()
7599 {
7600 try
7601 {
7602 final L2WorldRegion region = L2World.getInstance().getRegion(getX(), getY());
7603 return region != null && region.isActive();
7604 }
7605 catch (final Exception e)
7606 {
7607 if (this instanceof L2PcInstance)
7608 {
7609 LOGGER.warn("Player " + getName() + " at bad coords: (x: " + getX() + ", y: " + getY() + ", z: " + getZ() + ").");
7610
7611 ((L2PcInstance) this).sendMessage("Error with your coordinates! Please reboot your game fully!");
7612 ((L2PcInstance) this).teleToLocation(80753, 145481, -3532, false); // Near Giran luxury shop
7613 }
7614 else
7615 {
7616 LOGGER.warn("Object " + getName() + " at bad coords: (x: " + getX() + ", y: " + getY() + ", z: " + getZ() + ").");
7617 decayMe();
7618 }
7619 return false;
7620 }
7621 }
7622
7623 /**
7624 * Return True if the L2Character has a Party in progress.<BR>
7625 * <BR>
7626 * @return true, if is in party
7627 */
7628 public boolean isInParty()
7629 {
7630 return false;
7631 }
7632
7633 /**
7634 * Return the L2Party object of the L2Character.<BR>
7635 * <BR>
7636 * @return the party
7637 */
7638 public L2Party getParty()
7639 {
7640 return null;
7641 }
7642
7643 /**
7644 * Return the Attack Speed of the L2Character (delay (in milliseconds) before next attack).<BR>
7645 * <BR>
7646 * @param target the target
7647 * @param weapon the weapon
7648 * @return the int
7649 */
7650 public int calculateTimeBetweenAttacks(final L2Character target, final L2Weapon weapon)
7651 {
7652 double atkSpd = 0;
7653 if (weapon != null)
7654 {
7655 switch (weapon.getItemType())
7656 {
7657 case BOW:
7658 atkSpd = getStat().getPAtkSpd();
7659 return (int) (1500 * 345 / atkSpd);
7660 case DAGGER:
7661 atkSpd = getStat().getPAtkSpd();
7662 // atkSpd /= 1.15;
7663 break;
7664 default:
7665 atkSpd = getStat().getPAtkSpd();
7666 }
7667 }
7668 else
7669 {
7670 atkSpd = getPAtkSpd();
7671 }
7672
7673 return Formulas.getInstance().calcPAtkSpd(this, target, atkSpd);
7674 }
7675
7676 /**
7677 * Calculate reuse time.
7678 * @param target the target
7679 * @param weapon the weapon
7680 * @return the int
7681 */
7682 public int calculateReuseTime(final L2Character target, final L2Weapon weapon)
7683 {
7684 if (weapon == null)
7685 return 0;
7686
7687 int reuse = weapon.getAttackReuseDelay();
7688
7689 // only bows should continue for now
7690 if (reuse == 0)
7691 return 0;
7692
7693 // else if (reuse < 10) reuse = 1500;
7694 reuse *= getStat().getReuseModifier(target);
7695
7696 final double atkSpd = getStat().getPAtkSpd();
7697
7698 switch (weapon.getItemType())
7699 {
7700 case BOW:
7701 return (int) (reuse * 345 / atkSpd);
7702 default:
7703 return (int) (reuse * 312 / atkSpd);
7704 }
7705 }
7706
7707 /**
7708 * Return True if the L2Character use a dual weapon.<BR>
7709 * <BR>
7710 * @return true, if is using dual weapon
7711 */
7712 public boolean isUsingDualWeapon()
7713 {
7714 return false;
7715 }
7716
7717 /**
7718 * Add a skill to the L2Character _skills and its Func objects to the calculator set of the L2Character.<BR>
7719 * <BR>
7720 * <B><U> Concept</U> :</B><BR>
7721 * <BR>
7722 * All skills own by a L2Character are identified in <B>_skills</B><BR>
7723 * <BR>
7724 * <B><U> Actions</U> :</B><BR>
7725 * <BR>
7726 * <li>Replace oldSkill by newSkill or Add the newSkill</li> <li>If an old skill has been replaced, remove all its Func objects of L2Character calculator set</li> <li>Add Func objects of newSkill to the calculator set of the L2Character</li><BR>
7727 * <BR>
7728 * <B><U> Overriden in </U> :</B><BR>
7729 * <BR>
7730 * <li>L2PcInstance : Save update in the character_skills table of the database</li><BR>
7731 * <BR>
7732 * @param newSkill The L2Skill to add to the L2Character
7733 * @return The L2Skill replaced or null if just added a new L2Skill
7734 */
7735 @Override
7736 public L2Skill addSkill(final L2Skill newSkill)
7737 {
7738 L2Skill oldSkill = null;
7739
7740 if (newSkill != null)
7741 {
7742 // Replace oldSkill by newSkill or Add the newSkill
7743 oldSkill = _skills.put(newSkill.getId(), newSkill);
7744
7745 // If an old skill has been replaced, remove all its Func objects
7746 if (oldSkill != null)
7747 {
7748 // if skill came with another one, we should delete the other one too.
7749 if (oldSkill.triggerAnotherSkill())
7750 {
7751 if (Config.DEBUG)
7752 LOGGER.info("Removing Triggherable Skill: " + oldSkill.getTriggeredId());
7753
7754 _triggeredSkills.remove(oldSkill.getTriggeredId());
7755 removeSkill(oldSkill.getTriggeredId(), true);
7756 }
7757 removeStatsOwner(oldSkill);
7758
7759 // final Func[] skill_funcs = oldSkill.getStatFuncs(null, this);
7760
7761 // // Remove old func if single effect skill is defined
7762 // if(newSkill.is_singleEffect()
7763 // && skill_funcs.length>0)
7764 // removeStatFuncs(skill_funcs);
7765
7766 }
7767
7768 // Add Func objects of newSkill to the calculator set of the L2Character
7769 addStatFuncs(newSkill.getStatFuncs(null, this));
7770
7771 if (oldSkill != null && _chanceSkills != null)
7772 {
7773 removeChanceSkill(oldSkill.getId());
7774 }
7775 if (newSkill.isChance())
7776 {
7777 addChanceSkill(newSkill);
7778 }
7779
7780 if (newSkill.isChance() && newSkill.triggerAnotherSkill())
7781 {
7782 final L2Skill triggeredSkill = SkillTable.getInstance().getInfo(newSkill.getTriggeredId(), newSkill.getTriggeredLevel());
7783 addSkill(triggeredSkill);
7784 }
7785
7786 if (newSkill.triggerAnotherSkill())
7787 {
7788 if (Config.DEBUG)
7789 LOGGER.info("Adding Triggherable Skill: " + newSkill.getTriggeredId());
7790 _triggeredSkills.put(newSkill.getTriggeredId(), SkillTable.getInstance().getInfo(newSkill.getTriggeredId(), newSkill.getTriggeredLevel()));
7791 }
7792
7793 }
7794
7795 return oldSkill;
7796 }
7797
7798 /**
7799 * Adds the chance skill.
7800 * @param skill the skill
7801 */
7802 public void addChanceSkill(final L2Skill skill)
7803 {
7804 synchronized (this)
7805 {
7806 if (_chanceSkills == null)
7807 {
7808 _chanceSkills = new ChanceSkillList(this);
7809 }
7810
7811 _chanceSkills.put(skill, skill.getChanceCondition());
7812 }
7813 }
7814
7815 /**
7816 * Removes the chance skill.
7817 * @param id the id
7818 */
7819 public void removeChanceSkill(final int id)
7820 {
7821 synchronized (this)
7822 {
7823 for (final L2Skill skill : _chanceSkills.keySet())
7824 {
7825 if (skill.getId() == id)
7826 {
7827 _chanceSkills.remove(skill);
7828 }
7829 }
7830
7831 if (_chanceSkills.size() == 0)
7832 {
7833 _chanceSkills = null;
7834 }
7835 }
7836 }
7837
7838 /**
7839 * Remove a skill from the L2Character and its Func objects from calculator set of the L2Character.<BR>
7840 * <BR>
7841 * <B><U> Concept</U> :</B><BR>
7842 * <BR>
7843 * All skills own by a L2Character are identified in <B>_skills</B><BR>
7844 * <BR>
7845 * <B><U> Actions</U> :</B><BR>
7846 * <BR>
7847 * <li>Remove the skill from the L2Character _skills</li> <li>Remove all its Func objects from the L2Character calculator set</li><BR>
7848 * <BR>
7849 * <B><U> Overriden in </U> :</B><BR>
7850 * <BR>
7851 * <li>L2PcInstance : Save update in the character_skills table of the database</li><BR>
7852 * <BR>
7853 * @param skill The L2Skill to remove from the L2Character
7854 * @return The L2Skill removed
7855 */
7856 public synchronized L2Skill removeSkill(final L2Skill skill)
7857 {
7858 if (skill == null)
7859 return null;
7860
7861 // Remove the skill from the L2Character _skills
7862 return removeSkill(skill.getId());
7863 }
7864
7865 /**
7866 * Removes the skill.
7867 * @param skillId the skill id
7868 * @return the l2 skill
7869 */
7870 public L2Skill removeSkill(final int skillId)
7871 {
7872 return removeSkill(skillId, true);
7873 }
7874
7875 /**
7876 * Removes the skill.
7877 * @param skillId the skill id
7878 * @param cancelEffect the cancel effect
7879 * @return the l2 skill
7880 */
7881 public L2Skill removeSkill(final int skillId, final boolean cancelEffect)
7882 {
7883 // Remove the skill from the L2Character _skills
7884 final L2Skill oldSkill = _skills.remove(skillId);
7885 // Remove all its Func objects from the L2Character calculator set
7886 if (oldSkill != null)
7887 {
7888 // this is just a fail-safe againts buggers and gm dummies...
7889 if (oldSkill.triggerAnotherSkill())
7890 {
7891 if (Config.DEBUG)
7892 LOGGER.info("Removing Triggherable Skill: " + oldSkill.getTriggeredId());
7893 removeSkill(oldSkill.getTriggeredId(), true);
7894 _triggeredSkills.remove(oldSkill.getTriggeredId());
7895 }
7896
7897 // Stop casting if this skill is used right now
7898 if (getLastSkillCast() != null && isCastingNow())
7899 {
7900 if (oldSkill.getId() == getLastSkillCast().getId())
7901 {
7902 abortCast();
7903 }
7904 }
7905
7906 if (cancelEffect || oldSkill.isToggle())
7907 {
7908 final L2Effect e = getFirstEffect(oldSkill);
7909 if (e == null)
7910 {
7911 removeStatsOwner(oldSkill);
7912 stopSkillEffects(oldSkill.getId());
7913 }
7914 }
7915
7916 if (oldSkill.isChance() && _chanceSkills != null)
7917 {
7918 removeChanceSkill(oldSkill.getId());
7919 }
7920 removeStatsOwner(oldSkill);
7921 }
7922 return oldSkill;
7923 }
7924
7925 /**
7926 * Return all skills own by the L2Character in a table of L2Skill.<BR>
7927 * <BR>
7928 * <B><U> Concept</U> :</B><BR>
7929 * <BR>
7930 * All skills own by a L2Character are identified in <B>_skills</B> the L2Character <BR>
7931 * <BR>
7932 * @return the all skills
7933 */
7934 public final L2Skill[] getAllSkills()
7935 {
7936 return _skills.values().toArray(new L2Skill[_skills.values().size()]);
7937 }
7938
7939 /**
7940 * @return the map containing this character skills.
7941 */
7942 @Override
7943 public Map<Integer, L2Skill> getSkills()
7944 {
7945 return _skills;
7946 }
7947
7948 /**
7949 * Gets the chance skills.
7950 * @return the chance skills
7951 */
7952 public ChanceSkillList getChanceSkills()
7953 {
7954 return _chanceSkills;
7955 }
7956
7957 /**
7958 * Return the level of a skill owned by the L2Character.<BR>
7959 * <BR>
7960 * @param skillId The identifier of the L2Skill whose level must be returned
7961 * @return The level of the L2Skill identified by skillId
7962 */
7963 @Override
7964 public int getSkillLevel(final int skillId)
7965 {
7966 final L2Skill skill = _skills.get(skillId);
7967
7968 if (skill == null)
7969 return -1;
7970
7971 return skill.getLevel();
7972 }
7973
7974 /**
7975 * Return True if the skill is known by the L2Character.<BR>
7976 * <BR>
7977 * @param skillId The identifier of the L2Skill to check the knowledge
7978 * @return the known skill
7979 */
7980 @Override
7981 public final L2Skill getKnownSkill(final int skillId)
7982 {
7983 return _skills.get(skillId);
7984 }
7985
7986 /**
7987 * Return the number of skills of type(Buff, Debuff, HEAL_PERCENT, MANAHEAL_PERCENT) affecting this L2Character.<BR>
7988 * <BR>
7989 * @return The number of Buffs affecting this L2Character
7990 */
7991 public int getBuffCount()
7992 {
7993 final L2Effect[] effects = getAllEffects();
7994
7995 int numBuffs = 0;
7996
7997 for (final L2Effect e : effects)
7998 {
7999 if (e == null)
8000 {
8001 synchronized (_effects)
8002 {
8003 _effects.remove(e);
8004 }
8005 continue;
8006 }
8007
8008 if ((e.getSkill().getSkillType() == L2Skill.SkillType.BUFF || e.getSkill().getId() == 1416 || e.getSkill().getSkillType() == L2Skill.SkillType.REFLECT || e.getSkill().getSkillType() == L2Skill.SkillType.HEAL_PERCENT || e.getSkill().getSkillType() == L2Skill.SkillType.MANAHEAL_PERCENT) && !(e.getSkill().getId() > 4360 && e.getSkill().getId() < 4367)) // 7s
8009 // buffs
8010 {
8011 numBuffs++;
8012 }
8013 }
8014
8015 return numBuffs;
8016 }
8017
8018 /**
8019 * Return the number of skills of type(Debuff, poison, slow, etc.) affecting this L2Character.<BR>
8020 * <BR>
8021 * @return The number of debuff affecting this L2Character
8022 */
8023 public int getDeBuffCount()
8024 {
8025 final L2Effect[] effects = getAllEffects();
8026 int numDeBuffs = 0;
8027
8028 for (final L2Effect e : effects)
8029 {
8030 if (e == null)
8031 {
8032 synchronized (_effects)
8033 {
8034 _effects.remove(e);
8035 }
8036 continue;
8037 }
8038
8039 // Check for all debuff skills
8040 if (e.getSkill().is_Debuff())
8041 {
8042 numDeBuffs++;
8043 }
8044 }
8045
8046 return numDeBuffs;
8047 }
8048
8049 /**
8050 * Gets the max buff count.
8051 * @return the max buff count
8052 */
8053 public int getMaxBuffCount()
8054 {
8055 return Config.BUFFS_MAX_AMOUNT + Math.max(0, getSkillLevel(L2Skill.SKILL_DIVINE_INSPIRATION));
8056 }
8057
8058 /**
8059 * Removes the first Buff of this L2Character.<BR>
8060 * <BR>
8061 * @param preferSkill If != 0 the given skill Id will be removed instead of first
8062 */
8063 public void removeFirstBuff(final int preferSkill)
8064 {
8065 final L2Effect[] effects = getAllEffects();
8066
8067 L2Effect removeMe = null;
8068
8069 for (final L2Effect e : effects)
8070 {
8071 if (e == null)
8072 {
8073 synchronized (_effects)
8074 {
8075 _effects.remove(e);
8076 }
8077 continue;
8078 }
8079
8080 if ((e.getSkill().getSkillType() == L2Skill.SkillType.BUFF || e.getSkill().getSkillType() == L2Skill.SkillType.REFLECT || e.getSkill().getSkillType() == L2Skill.SkillType.HEAL_PERCENT || e.getSkill().getSkillType() == L2Skill.SkillType.MANAHEAL_PERCENT) && !(e.getSkill().getId() > 4360 && e.getSkill().getId() < 4367))
8081 {
8082 if (preferSkill == 0)
8083 {
8084 removeMe = e;
8085 break;
8086 }
8087 else if (e.getSkill().getId() == preferSkill)
8088 {
8089 removeMe = e;
8090 break;
8091 }
8092 else if (removeMe == null)
8093 {
8094 removeMe = e;
8095 }
8096 }
8097 }
8098
8099 if (removeMe != null)
8100 {
8101 removeMe.exit(true);
8102 }
8103 }
8104
8105 /**
8106 * Removes the first DeBuff of this L2Character.<BR>
8107 * <BR>
8108 * @param preferSkill If != 0 the given skill Id will be removed instead of first
8109 */
8110 public void removeFirstDeBuff(final int preferSkill)
8111 {
8112 final L2Effect[] effects = getAllEffects();
8113
8114 L2Effect removeMe = null;
8115
8116 for (final L2Effect e : effects)
8117 {
8118 if (e == null)
8119 {
8120
8121 synchronized (_effects)
8122 {
8123 _effects.remove(e);
8124 }
8125 continue;
8126 }
8127
8128 if (e.getSkill().is_Debuff())
8129 {
8130 if (preferSkill == 0)
8131 {
8132 removeMe = e;
8133 break;
8134 }
8135 else if (e.getSkill().getId() == preferSkill)
8136 {
8137 removeMe = e;
8138 break;
8139 }
8140 else if (removeMe == null)
8141 {
8142 removeMe = e;
8143 }
8144 }
8145 }
8146
8147 if (removeMe != null)
8148 {
8149 removeMe.exit(true);
8150 }
8151 }
8152
8153 /**
8154 * Gets the dance count.
8155 * @return the dance count
8156 */
8157 public int getDanceCount()
8158 {
8159 int danceCount = 0;
8160
8161 final L2Effect[] effects = getAllEffects();
8162
8163 for (final L2Effect e : effects)
8164 {
8165 if (e == null)
8166 {
8167 synchronized (_effects)
8168 {
8169 _effects.remove(e);
8170 }
8171 continue;
8172 }
8173
8174 if (e.getSkill().isDance() && e.getInUse())
8175 {
8176 danceCount++;
8177 }
8178 }
8179
8180 return danceCount;
8181 }
8182
8183 /**
8184 * Checks if the given skill stacks with an existing one.<BR>
8185 * <BR>
8186 * @param checkSkill the skill to be checked
8187 * @return Returns whether or not this skill will stack
8188 */
8189 public boolean doesStack(final L2Skill checkSkill)
8190 {
8191 if (_effects.size() < 1 || checkSkill._effectTemplates == null || checkSkill._effectTemplates.length < 1 || checkSkill._effectTemplates[0].stackType == null)
8192 return false;
8193
8194 final String stackType = checkSkill._effectTemplates[0].stackType;
8195
8196 if (stackType.equals("none"))
8197 return false;
8198
8199 final L2Effect[] effects = getAllEffects();
8200
8201 for (final L2Effect e : effects)
8202 {
8203 if (e == null)
8204 {
8205 synchronized (_effects)
8206 {
8207 _effects.remove(e);
8208 }
8209 continue;
8210 }
8211
8212 if (e.getStackType() != null && e.getStackType().equals(stackType))
8213 return true;
8214 }
8215
8216 return false;
8217 }
8218
8219 /**
8220 * Manage the magic skill launching task (MP, HP, Item consummation...) and display the magic skill animation on client.<BR>
8221 * <BR>
8222 * <B><U> Actions</U> :</B><BR>
8223 * <BR>
8224 * <li>Send a Server->Client packet MagicSkillLaunched (to display magic skill animation) to all L2PcInstance of L2Charcater _knownPlayers</li> <li>Consumme MP, HP and Item if necessary</li> <li>Send a Server->Client packet StatusUpdate with MP modification to the L2PcInstance</li> <li>Launch
8225 * the magic skill in order to calculate its effects</li> <li>If the skill type is PDAM, notify the AI of the target with AI_INTENTION_ATTACK</li> <li>Notify the AI of the L2Character with EVT_FINISH_CASTING</li><BR>
8226 * <BR>
8227 * <FONT COLOR=#FF0000><B> <U>Caution</U> : A magic skill casting MUST BE in progress</B></FONT><BR>
8228 * <BR>
8229 * @param targets the targets
8230 * @param skill The L2Skill to use
8231 * @param coolTime the cool time
8232 * @param instant the instant
8233 */
8234 public void onMagicLaunchedTimer(final L2Object[] targets, final L2Skill skill, final int coolTime, final boolean instant)
8235 {
8236 if (skill == null || (targets == null || targets.length <= 0) && skill.getTargetType() != SkillTargetType.TARGET_AURA)
8237 {
8238 _skillCast = null;
8239 enableAllSkills();
8240 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
8241
8242 return;
8243 }
8244
8245 // Escaping from under skill's radius and peace zone check. First version, not perfect in AoE skills.
8246 int escapeRange = 0;
8247
8248 if (skill.getEffectRange() > escapeRange)
8249 {
8250 escapeRange = skill.getEffectRange();
8251 }
8252 else if (skill.getCastRange() < 0 && skill.getSkillRadius() > 80)
8253 {
8254 escapeRange = skill.getSkillRadius();
8255 }
8256
8257 L2Object[] final_targets = null;
8258 int _skipped = 0;
8259
8260 if (escapeRange > 0)
8261 {
8262 List<L2Character> targetList = new FastList<>();
8263
8264 for (int i = 0; targets != null && i < targets.length; i++)
8265 {
8266 if (targets[i] instanceof L2Character)
8267 {
8268 if (!Util.checkIfInRange(escapeRange, this, targets[i], true))
8269 {
8270 continue;
8271 }
8272
8273 // Check if the target is behind a wall
8274 if (skill.getSkillRadius() > 0 && skill.isOffensive() && Config.GEODATA > 0 && !GeoData.getInstance().canSeeTarget(this, targets[i]))
8275 {
8276 _skipped++;
8277 continue;
8278 }
8279
8280 if (skill.isOffensive())
8281 {
8282 if (this instanceof L2PcInstance)
8283 {
8284 if (((L2Character) targets[i]).isInsidePeaceZone((L2PcInstance) this))
8285 {
8286 continue;
8287 }
8288 }
8289 else
8290 {
8291 if (L2Character.isInsidePeaceZone(this, targets[i]))
8292 {
8293 continue;
8294 }
8295 }
8296 }
8297 targetList.add((L2Character) targets[i]);
8298 }
8299 // else
8300 // {
8301 // if (Config.DEBUG)
8302 // LOGGER.warn("Class cast bad: "+targets[i].getClass().toString());
8303 // }
8304 }
8305 if (targetList.isEmpty() && skill.getTargetType() != SkillTargetType.TARGET_AURA)
8306 {
8307 if (this instanceof L2PcInstance)
8308 {
8309 for (int i = 0; i < _skipped; i++)
8310 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CANT_SEE_TARGET));
8311
8312 }
8313
8314 abortCast();
8315 return;
8316 }
8317 final_targets = targetList.toArray(new L2Character[targetList.size()]);
8318 targetList = null;
8319
8320 }
8321 else
8322 {
8323
8324 final_targets = targets;
8325
8326 }
8327
8328 // if the skill is not a potion and player
8329 // is not casting now
8330 // Ensure that a cast is in progress
8331 // Check if player is using fake death.
8332 // Potions can be used while faking death.
8333 if (!skill.isPotion())
8334 {
8335 if (!isCastingNow() || isAlikeDead())
8336 {
8337 _skillCast = null;
8338 enableAllSkills();
8339
8340 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
8341
8342 _castEndTime = 0;
8343 _castInterruptTime = 0;
8344 return;
8345 }
8346 }/*
8347 * else{ if(!isCastingPotionNow()) { _potionCast = null; enableAllSkills(); getAI().notifyEvent(CtrlEvent.EVT_CANCEL); _castPotionEndTime = 0; _castPotionInterruptTime = 0; return; } }
8348 */
8349
8350 // Get the display identifier of the skill
8351 final int magicId = skill.getDisplayId();
8352
8353 // Get the level of the skill
8354 int level = getSkillLevel(skill.getId());
8355
8356 if (level < 1)
8357 {
8358 level = 1;
8359 }
8360
8361 // Send a Server->Client packet MagicSkillLaunched to the L2Character AND to all L2PcInstance in the _KnownPlayers of the L2Character
8362 if (!skill.isPotion())
8363 {
8364 broadcastPacket(new MagicSkillLaunched(this, magicId, level, final_targets));
8365 }
8366
8367 if (instant)
8368 {
8369 onMagicHitTimer(final_targets, skill, coolTime, true);
8370 }
8371 else
8372 {
8373 if (skill.isPotion())
8374 _potionCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(final_targets, skill, coolTime, 2), 200);
8375 else
8376 _skillCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(final_targets, skill, coolTime, 2), 200);
8377
8378 }
8379
8380 }
8381
8382 /*
8383 * Runs in the end of skill casting
8384 */
8385 /**
8386 * On magic hit timer.
8387 * @param targets the targets
8388 * @param skill the skill
8389 * @param coolTime the cool time
8390 * @param instant the instant
8391 */
8392 public void onMagicHitTimer(final L2Object[] targets, final L2Skill skill, final int coolTime, final boolean instant)
8393 {
8394 if (skill == null || (targets == null || targets.length <= 0) && skill.getTargetType() != SkillTargetType.TARGET_AURA)
8395 {
8396 _skillCast = null;
8397 enableAllSkills();
8398 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
8399
8400 return;
8401 }
8402
8403 if (getForceBuff() != null)
8404 {
8405 _skillCast = null;
8406 enableAllSkills();
8407
8408 getForceBuff().onCastAbort();
8409
8410 return;
8411 }
8412
8413 final L2Effect mog = getFirstEffect(L2Effect.EffectType.SIGNET_GROUND);
8414 if (mog != null)
8415 {
8416 _skillCast = null;
8417 enableAllSkills();
8418
8419 // close skill if it's not SIGNET_CASTTIME
8420 if (mog.getSkill().getSkillType() != SkillType.SIGNET_CASTTIME)
8421 {
8422 mog.exit(true);
8423 }
8424
8425 final L2Object target = targets == null ? null : targets[0];
8426 if (target != null)
8427 {
8428 notifyQuestEventSkillFinished(skill, target);
8429 }
8430 return;
8431 }
8432
8433 final L2Object[] targets2 = targets;
8434 try
8435 {
8436 if (targets2 != null && targets2.length != 0)
8437 {
8438
8439 // Go through targets table
8440 for (final L2Object target2 : targets2)
8441 {
8442 if (target2 == null)
8443 {
8444 continue;
8445 }
8446
8447 if (target2 instanceof L2PlayableInstance)
8448 {
8449 L2Character target = (L2Character) target2;
8450
8451 // If the skill is type STEALTH(ex: Dance of Shadow)
8452 if (skill.isAbnormalEffectByName(ABNORMAL_EFFECT_STEALTH))
8453 {
8454 final L2Effect silentMove = target.getFirstEffect(L2Effect.EffectType.SILENT_MOVE);
8455 if (silentMove != null)
8456 silentMove.exit(true);
8457 }
8458
8459 if (skill.getSkillType() == SkillType.BUFF || skill.getSkillType() == SkillType.SEED)
8460 {
8461 SystemMessage smsg = new SystemMessage(SystemMessageId.YOU_FEEL_S1_EFFECT);
8462 smsg.addString(skill.getName());
8463 target.sendPacket(smsg);
8464 smsg = null;
8465 }
8466
8467 if (this instanceof L2PcInstance && target instanceof L2Summon)
8468 {
8469 ((L2Summon) target).getOwner().sendPacket(new PetInfo((L2Summon) target));
8470 sendPacket(new NpcInfo((L2Summon) target, this));
8471
8472 // The PetInfo packet wipes the PartySpelled (list of active spells' icons). Re-add them
8473 ((L2Summon) target).updateEffectIcons(true);
8474 }
8475
8476 target = null;
8477 }
8478 }
8479
8480 }
8481
8482 }
8483 catch (final Exception e)
8484 {
8485 e.printStackTrace();
8486 }
8487
8488 try
8489 {
8490
8491 StatusUpdate su = new StatusUpdate(getObjectId());
8492 boolean isSendStatus = false;
8493
8494 // Consume MP of the L2Character and Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform
8495 final double mpConsume = getStat().getMpConsume(skill);
8496
8497 if (mpConsume > 0)
8498 {
8499 if (skill.isDance())
8500 {
8501 getStatus().reduceMp(calcStat(Stats.DANCE_MP_CONSUME_RATE, mpConsume, null, null));
8502 }
8503 else if (skill.isMagic())
8504 {
8505 getStatus().reduceMp(calcStat(Stats.MAGICAL_MP_CONSUME_RATE, mpConsume, null, null));
8506 }
8507 else
8508 {
8509 getStatus().reduceMp(calcStat(Stats.PHYSICAL_MP_CONSUME_RATE, mpConsume, null, null));
8510 }
8511
8512 su.addAttribute(StatusUpdate.CUR_MP, (int) getCurrentMp());
8513 isSendStatus = true;
8514 }
8515
8516 // Consume HP if necessary and Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform
8517 if (skill.getHpConsume() > 0)
8518 {
8519 double consumeHp;
8520
8521 consumeHp = calcStat(Stats.HP_CONSUME_RATE, skill.getHpConsume(), null, null);
8522
8523 if (consumeHp + 1 >= getCurrentHp())
8524 {
8525 consumeHp = getCurrentHp() - 1.0;
8526 }
8527
8528 getStatus().reduceHp(consumeHp, this);
8529
8530 su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
8531 isSendStatus = true;
8532 }
8533
8534 // Send a Server->Client packet StatusUpdate with MP modification to the L2PcInstance
8535 if (isSendStatus)
8536 {
8537 sendPacket(su);
8538 }
8539
8540 // Consume Items if necessary and Send the Server->Client packet InventoryUpdate with Item modification to all the L2Character
8541 if (skill.getItemConsume() > 0)
8542 {
8543 consumeItem(skill.getItemConsumeId(), skill.getItemConsume());
8544 }
8545
8546 // Launch the magic skill in order to calculate its effects
8547 callSkill(skill, targets);
8548
8549 su = null;
8550
8551 }
8552 catch (final Exception e)
8553 {
8554 e.printStackTrace();
8555 }
8556
8557 if (instant || coolTime == 0)
8558 {
8559
8560 onMagicFinalizer(targets, skill);
8561
8562 }
8563 else
8564 {
8565 if (skill.isPotion())
8566 _potionCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 3), coolTime);
8567 else
8568 _skillCast = ThreadPoolManager.getInstance().scheduleEffect(new MagicUseTask(targets, skill, coolTime, 3), coolTime);
8569
8570 }
8571 }
8572
8573 /*
8574 * Runs after skill hitTime+coolTime
8575 */
8576 /**
8577 * On magic finalizer.
8578 * @param targets the targets
8579 * @param skill the skill
8580 */
8581 public void onMagicFinalizer(final L2Object[] targets, final L2Skill skill)
8582 {
8583 if (skill.isPotion())
8584 {
8585 _potionCast = null;
8586 _castPotionEndTime = 0;
8587 _castPotionInterruptTime = 0;
8588 }
8589 else
8590 {
8591 _skillCast = null;
8592 _castEndTime = 0;
8593 _castInterruptTime = 0;
8594
8595 enableAllSkills();
8596
8597 // if the skill has changed the character's state to something other than STATE_CASTING
8598 // then just leave it that way, otherwise switch back to STATE_IDLE.
8599 // if(isCastingNow())
8600 // getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE, null);
8601 if (skill.getId() != 345 && skill.getId() != 346)
8602 {
8603 // Like L2OFF while use a skill and next interntion == null the char stop auto attack
8604 if (getAI().getNextIntention() == null && (skill.getSkillType() == SkillType.PDAM && skill.getCastRange() < 400) || skill.getSkillType() == SkillType.BLOW || skill.getSkillType() == SkillType.DRAIN_SOUL || skill.getSkillType() == SkillType.SOW || skill.getSkillType() == SkillType.SPOIL)
8605 {
8606 if (this instanceof L2PcInstance)
8607 {
8608 final L2PcInstance currPlayer = (L2PcInstance) this;
8609 final SkillDat skilldat = currPlayer.getCurrentSkill();
8610 // Like L2OFF if the skill is BLOW the player doesn't auto attack
8611 // If on XML skill nextActionAttack = true the char auto attack
8612 // If CTRL is pressed the autoattack is aborted (like L2OFF)
8613 if (skilldat != null && !skilldat.isCtrlPressed() && skill.nextActionIsAttack() && getTarget() != null && getTarget() instanceof L2Character)
8614 {
8615 getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, getTarget());
8616 }
8617 }
8618 else
8619 // case NPC
8620 {
8621 if (skill.nextActionIsAttack() && getTarget() != null && getTarget() instanceof L2Character)
8622 {
8623 getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, getTarget());
8624 }
8625 else if ((skill.isOffensive()) && !(skill.getSkillType() == SkillType.UNLOCK) && !(skill.getSkillType() == SkillType.BLOW) && !(skill.getSkillType() == SkillType.DELUXE_KEY_UNLOCK) && skill.getId() != 345 && skill.getId() != 346)
8626 {
8627 getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, getTarget());
8628 getAI().clientStartAutoAttack();
8629 }
8630 }
8631 }
8632 if (this instanceof L2PcInstance)
8633 {
8634 final L2PcInstance currPlayer = (L2PcInstance) this;
8635 final SkillDat skilldat = currPlayer.getCurrentSkill();
8636 if (skilldat != null && !skilldat.isCtrlPressed() && (skill.isOffensive()) && !(skill.getSkillType() == SkillType.UNLOCK) && !(skill.getSkillType() == SkillType.BLOW) && !(skill.getSkillType() == SkillType.DELUXE_KEY_UNLOCK) && skill.getId() != 345 && skill.getId() != 346)
8637 {
8638 if (!skill.isMagic() && skill.nextActionIsAttack())
8639 getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, getTarget());
8640
8641 getAI().clientStartAutoAttack();
8642 }
8643 }
8644 else
8645 // case npc
8646 {
8647 if ((skill.isOffensive()) && !(skill.getSkillType() == SkillType.UNLOCK) && !(skill.getSkillType() == SkillType.BLOW) && !(skill.getSkillType() == SkillType.DELUXE_KEY_UNLOCK) && skill.getId() != 345 && skill.getId() != 346)
8648 {
8649 if (!skill.isMagic())
8650 getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, getTarget());
8651
8652 getAI().clientStartAutoAttack();
8653 }
8654 }
8655 }
8656 else
8657 {
8658 getAI().clientStopAutoAttack();
8659 }
8660
8661 // Notify the AI of the L2Character with EVT_FINISH_CASTING
8662 getAI().notifyEvent(CtrlEvent.EVT_FINISH_CASTING);
8663
8664 notifyQuestEventSkillFinished(skill, getTarget());
8665
8666 /*
8667 * If character is a player, then wipe their current cast state and check if a skill is queued. If there is a queued skill, launch it and wipe the queue.
8668 */
8669 if (this instanceof L2PcInstance)
8670 {
8671 L2PcInstance currPlayer = (L2PcInstance) this;
8672 SkillDat queuedSkill = currPlayer.getQueuedSkill();
8673
8674 currPlayer.setCurrentSkill(null, false, false);
8675
8676 if (queuedSkill != null)
8677 {
8678 currPlayer.setQueuedSkill(null, false, false);
8679
8680 // DON'T USE : Recursive call to useMagic() method
8681 // currPlayer.useMagic(queuedSkill.getSkill(), queuedSkill.isCtrlPressed(), queuedSkill.isShiftPressed());
8682 ThreadPoolManager.getInstance().executeTask(new QueuedMagicUseTask(currPlayer, queuedSkill.getSkill(), queuedSkill.isCtrlPressed(), queuedSkill.isShiftPressed()));
8683 }
8684
8685 queuedSkill = null;
8686
8687 final L2Weapon activeWeapon = getActiveWeaponItem();
8688 // Launch weapon Special ability skill effect if available
8689 if (activeWeapon != null)
8690 {
8691 try
8692 {
8693 if (targets != null && targets.length > 0)
8694 {
8695 for (final L2Object target : targets)
8696 {
8697 if (target != null && target instanceof L2Character && !((L2Character) target).isDead())
8698 {
8699 final L2Character player = (L2Character) target;
8700
8701 if (activeWeapon.getSkillEffects(this, player, skill))
8702 {
8703 sendPacket(SystemMessage.sendString("Target affected by weapon special ability!"));
8704 }
8705 }
8706
8707 }
8708 }
8709 }
8710 catch (final Exception e)
8711 {
8712 e.printStackTrace();
8713 }
8714 }
8715
8716 currPlayer = null;
8717 }
8718 }
8719 }
8720
8721 // Quest event ON_SPELL_FNISHED
8722 /**
8723 * Notify quest event skill finished.
8724 * @param skill the skill
8725 * @param target the target
8726 */
8727 private void notifyQuestEventSkillFinished(final L2Skill skill, final L2Object target)
8728 {
8729 if (this instanceof L2NpcInstance && (target instanceof L2PcInstance || target instanceof L2Summon))
8730 {
8731
8732 final L2PcInstance player = target instanceof L2PcInstance ? (L2PcInstance) target : ((L2Summon) target).getOwner();
8733
8734 for (final Quest quest : ((L2NpcTemplate) getTemplate()).getEventQuests(Quest.QuestEventType.ON_SPELL_FINISHED))
8735 {
8736 quest.notifySpellFinished(((L2NpcInstance) this), player, skill);
8737 }
8738 }
8739 }
8740
8741 /**
8742 * Reduce the item number of the L2Character.<BR>
8743 * <BR>
8744 * <B><U> Overriden in </U> :</B><BR>
8745 * <BR>
8746 * <li>L2PcInstance</li><BR>
8747 * <BR>
8748 * @param itemConsumeId the item consume id
8749 * @param itemCount the item count
8750 */
8751 public void consumeItem(final int itemConsumeId, final int itemCount)
8752 {
8753 }
8754
8755 /**
8756 * Enable a skill (remove it from _disabledSkills of the L2Character).<BR>
8757 * <BR>
8758 * <B><U> Concept</U> :</B><BR>
8759 * <BR>
8760 * All skills disabled are identified by their skillId in <B>_disabledSkills</B> of the L2Character <BR>
8761 * <BR>
8762 * @param _skill
8763 */
8764 public void enableSkill(final L2Skill _skill)
8765 {
8766 if (_disabledSkills == null)
8767 return;
8768
8769 _disabledSkills.remove(new Integer(_skill.getReuseHashCode()));
8770
8771 if (this instanceof L2PcInstance)
8772 {
8773 removeTimeStamp(_skill);
8774 }
8775 }
8776
8777 /**
8778 * Disable a skill (add it to _disabledSkills of the L2Character).<BR>
8779 * <BR>
8780 * <B><U> Concept</U> :</B><BR>
8781 * <BR>
8782 * All skills disabled are identified by their skillId in <B>_disabledSkills</B> of the L2Character <BR>
8783 * <BR>
8784 * @param skill The identifier of the L2Skill to disable
8785 */
8786 public void disableSkill(final L2Skill skill)
8787 {
8788 if (_disabledSkills == null)
8789 {
8790 _disabledSkills = Collections.synchronizedList(new FastList<Integer>());
8791 }
8792
8793 _disabledSkills.add(skill.getReuseHashCode());
8794 }
8795
8796 /**
8797 * Disable this skill id for the duration of the delay in milliseconds.
8798 * @param skill the skill thats going to be disabled
8799 * @param delay (seconds * 1000)
8800 */
8801 public void disableSkill(final L2Skill skill, final long delay)
8802 {
8803 if (skill == null)
8804 return;
8805
8806 disableSkill(skill);
8807
8808 if (delay > 10)
8809 {
8810 ThreadPoolManager.getInstance().scheduleAi(new EnableSkill(skill), delay);
8811 }
8812 }
8813
8814 /**
8815 * Check if a skill is disabled.<BR>
8816 * <BR>
8817 * <B><U> Concept</U> :</B><BR>
8818 * <BR>
8819 * All skills disabled are identified by their skillId in <B>_disabledSkills</B> of the L2Character <BR>
8820 * <BR>
8821 * @param _skill the skill to know if its disabled
8822 * @return true, if is skill disabled
8823 */
8824 public boolean isSkillDisabled(final L2Skill _skill)
8825 {
8826 final L2Skill skill = _skill;
8827
8828 if (isAllSkillsDisabled() && !skill.isPotion())
8829 return true;
8830
8831 if (this instanceof L2PcInstance)
8832 {
8833 final L2PcInstance activeChar = (L2PcInstance) this;
8834
8835 if ((skill.getSkillType() == SkillType.FISHING || skill.getSkillType() == SkillType.REELING || skill.getSkillType() == SkillType.PUMPING) && !activeChar.isFishing() && (activeChar.getActiveWeaponItem() != null && activeChar.getActiveWeaponItem().getItemType() != L2WeaponType.ROD))
8836 {
8837 if (skill.getSkillType() == SkillType.PUMPING)
8838 {
8839 // Pumping skill is available only while fishing
8840 activeChar.sendPacket(new SystemMessage(SystemMessageId.CAN_USE_PUMPING_ONLY_WHILE_FISHING));
8841 }
8842 else if (skill.getSkillType() == SkillType.REELING)
8843 {
8844 // Reeling skill is available only while fishing
8845 activeChar.sendPacket(new SystemMessage(SystemMessageId.CAN_USE_REELING_ONLY_WHILE_FISHING));
8846 }
8847 else if (skill.getSkillType() == SkillType.FISHING)
8848 {
8849 // Player hasn't fishing pole equiped
8850 activeChar.sendPacket(new SystemMessage(SystemMessageId.FISHING_POLE_NOT_EQUIPPED));
8851 }
8852
8853 final SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
8854 sm.addString(skill.getName());
8855 activeChar.sendPacket(sm);
8856 return true;
8857 }
8858
8859 if ((skill.getSkillType() == SkillType.FISHING || skill.getSkillType() == SkillType.REELING || skill.getSkillType() == SkillType.PUMPING) && activeChar.getActiveWeaponItem() == null)
8860 {
8861 final SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
8862 sm.addString(skill.getName());
8863 activeChar.sendPacket(sm);
8864 return true;
8865 }
8866
8867 if ((skill.getSkillType() == SkillType.REELING || skill.getSkillType() == SkillType.PUMPING) && !activeChar.isFishing() && (activeChar.getActiveWeaponItem() != null && activeChar.getActiveWeaponItem().getItemType() == L2WeaponType.ROD))
8868 {
8869 if (skill.getSkillType() == SkillType.PUMPING)
8870 {
8871 // Pumping skill is available only while fishing
8872 activeChar.sendPacket(new SystemMessage(SystemMessageId.CAN_USE_PUMPING_ONLY_WHILE_FISHING));
8873 }
8874 else if (skill.getSkillType() == SkillType.REELING)
8875 {
8876 // Reeling skill is available only while fishing
8877 activeChar.sendPacket(new SystemMessage(SystemMessageId.CAN_USE_REELING_ONLY_WHILE_FISHING));
8878 }
8879
8880 final SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
8881 sm.addString(skill.getName());
8882 activeChar.sendPacket(sm);
8883 return true;
8884 }
8885
8886 if (activeChar.isHero() && HeroSkillTable.isHeroSkill(_skill.getId()) && activeChar.isInOlympiadMode() && activeChar.isOlympiadStart())
8887 {
8888 activeChar.sendMessage("You can't use Hero skills during Olympiad match.");
8889 return true;
8890 }
8891 }
8892
8893 if (_disabledSkills == null)
8894 return false;
8895
8896 return _disabledSkills.contains(_skill.getReuseHashCode());
8897 }
8898
8899 /**
8900 * Disable all skills (set _allSkillsDisabled to True).<BR>
8901 * <BR>
8902 */
8903 public void disableAllSkills()
8904 {
8905 if (Config.DEBUG)
8906 {
8907 LOGGER.debug("All skills disabled");
8908 }
8909
8910 _allSkillsDisabled = true;
8911 }
8912
8913 /**
8914 * Enable all skills (set _allSkillsDisabled to False).<BR>
8915 * <BR>
8916 */
8917 public void enableAllSkills()
8918 {
8919 if (Config.DEBUG)
8920 {
8921 LOGGER.debug("All skills enabled");
8922 }
8923
8924 _allSkillsDisabled = false;
8925 }
8926
8927 /**
8928 * Launch the magic skill and calculate its effects on each target contained in the targets table.<BR>
8929 * <BR>
8930 * @param skill The L2Skill to use
8931 * @param targets The table of L2Object targets
8932 */
8933 public void callSkill(final L2Skill skill, final L2Object[] targets)
8934 {
8935 try
8936 {
8937 if (skill.isToggle() && getFirstEffect(skill.getId()) != null)
8938 return;
8939
8940 if (targets == null || targets.length == 0)
8941 {
8942 getAI().notifyEvent(CtrlEvent.EVT_CANCEL);
8943 return;
8944 }
8945
8946 // Do initial checkings for skills and set pvp flag/draw aggro when needed
8947 for (final L2Object target : targets)
8948 {
8949 if (target instanceof L2Character)
8950 {
8951 // Set some values inside target's instance for later use
8952 L2Character player = (L2Character) target;
8953
8954 if (skill.getEffectType() == L2Skill.SkillType.BUFF)
8955 if (player.isBlockBuff())
8956 continue;
8957
8958 /*
8959 * LOGGER.info("--"+skill.getId()); L2Weapon activeWeapon = getActiveWeaponItem(); // Launch weapon Special ability skill effect if available if(activeWeapon != null && !((L2Character) target).isDead()) { if(activeWeapon.getSkillEffects(this, player, skill).length > 0 && this
8960 * instanceof L2PcInstance) { sendPacket(SystemMessage.sendString("Target affected by weapon special ability!")); } }
8961 */
8962
8963 if (target instanceof L2Character)
8964 {
8965 final L2Character targ = (L2Character) target;
8966
8967 if (ChanceSkillList.canTriggerByCast(this, targ, skill))
8968 {
8969 // Maybe launch chance skills on us
8970 if (_chanceSkills != null)
8971 {
8972 _chanceSkills.onSkillHit(targ, false, skill.isMagic(), skill.isOffensive());
8973 }
8974 // Maybe launch chance skills on target
8975 if (targ.getChanceSkills() != null)
8976 {
8977 targ.getChanceSkills().onSkillHit(this, true, skill.isMagic(), skill.isOffensive());
8978 }
8979 }
8980 }
8981
8982 if (Config.ALLOW_RAID_BOSS_PETRIFIED && (this instanceof L2PcInstance || this instanceof L2Summon)) // Check if option is True Or False.
8983 {
8984 boolean to_be_cursed = false;
8985
8986 // check on BossZone raid lvl
8987 if (!(player.getTarget() instanceof L2PlayableInstance) && !(player.getTarget() instanceof L2SummonInstance))
8988 { // this must work just on mobs/raids
8989
8990 if ((player.isRaid() && getLevel() > player.getLevel() + 8) || (!(player instanceof L2PcInstance) && (player.getTarget() != null && player.getTarget() instanceof L2RaidBossInstance && getLevel() > ((L2RaidBossInstance) player.getTarget()).getLevel() + 8)) || (!(player instanceof L2PcInstance) && (player.getTarget() != null && player.getTarget() instanceof L2GrandBossInstance && getLevel() > ((L2GrandBossInstance) player.getTarget()).getLevel() + 8)))
8991 {
8992 to_be_cursed = true;
8993 }
8994
8995 // advanced check too if not already cursed
8996 if (!to_be_cursed)
8997 {
8998 int boss_id = -1;
8999 L2NpcTemplate boss_template = null;
9000 final L2BossZone boss_zone = GrandBossManager.getInstance().getZone(this);
9001
9002 if (boss_zone != null)
9003 {
9004 boss_id = boss_zone.getBossId();
9005 }
9006
9007 // boolean alive = false;
9008
9009 if (boss_id != -1)
9010 {
9011 boss_template = NpcTable.getInstance().getTemplate(boss_id);
9012
9013 if (boss_template != null && getLevel() > boss_template.getLevel() + 8)
9014 {
9015 L2MonsterInstance boss_instance = null;
9016
9017 if (boss_template.type.equals("L2RaidBoss"))
9018 {
9019 final StatsSet actual_boss_stat = RaidBossSpawnManager.getInstance().getStatsSet(boss_id);
9020 if (actual_boss_stat != null)
9021 {
9022 // alive = actual_boss_stat.getLong("respawnTime") == 0;
9023 boss_instance = RaidBossSpawnManager.getInstance().getBoss(boss_id);
9024 }
9025 }
9026 else if (boss_template.type.equals("L2GrandBoss"))
9027 {
9028 final StatsSet actual_boss_stat = GrandBossManager.getInstance().getStatsSet(boss_id);
9029 if (actual_boss_stat != null)
9030 {
9031 // alive = actual_boss_stat.getLong("respawn_time") == 0;
9032 boss_instance = GrandBossManager.getInstance().getBoss(boss_id);
9033 }
9034 }
9035
9036 // max allowed rage into take cursed is 3000
9037 if (boss_instance != null/* && alive */&& boss_instance.isInsideRadius(this, 3000, false, false))
9038 {
9039 to_be_cursed = true;
9040 }
9041 }
9042 }
9043 }
9044 }
9045
9046 if (to_be_cursed)
9047 {
9048 if (skill.isMagic())
9049 {
9050 L2Skill tempSkill = SkillTable.getInstance().getInfo(4215, 1);
9051 if (tempSkill != null)
9052 {
9053 abortAttack();
9054 abortCast();
9055 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
9056 tempSkill.getEffects(player, this, false, false, false);
9057
9058 if (this instanceof L2Summon)
9059 {
9060
9061 final L2Summon src = ((L2Summon) this);
9062 if (src.getOwner() != null)
9063 {
9064 src.getOwner().abortAttack();
9065 src.getOwner().abortCast();
9066 src.getOwner().getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
9067 tempSkill.getEffects(player, src.getOwner(), false, false, false);
9068 }
9069 }
9070
9071 }
9072 else
9073 LOGGER.warn("Skill 4215 at level 1 is missing in DP.");
9074
9075 tempSkill = null;
9076 }
9077 else
9078 {
9079 L2Skill tempSkill = SkillTable.getInstance().getInfo(4515, 1);
9080 if (tempSkill != null)
9081 {
9082 tempSkill.getEffects(player, this, false, false, false);
9083 }
9084 else
9085 {
9086 LOGGER.warn("Skill 4515 at level 1 is missing in DP.");
9087 }
9088
9089 tempSkill = null;
9090
9091 if (player instanceof L2MinionInstance)
9092 {
9093 ((L2MinionInstance) player).getLeader().stopHating(this);
9094 List<L2MinionInstance> spawnedMinions = ((L2MonsterInstance) player).getSpawnedMinions();
9095 if (spawnedMinions != null && spawnedMinions.size() > 0)
9096 {
9097 Iterator<L2MinionInstance> itr = spawnedMinions.iterator();
9098 L2MinionInstance minion;
9099 while (itr.hasNext())
9100 {
9101 minion = itr.next();
9102 if (((L2Attackable) player).getMostHated() == null)
9103 {
9104 ((L2AttackableAI) minion.getAI()).setGlobalAggro(-25);
9105 minion.clearAggroList();
9106 minion.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
9107 minion.setWalking();
9108 }
9109 if (minion != null && !minion.isDead())
9110 {
9111 ((L2AttackableAI) minion.getAI()).setGlobalAggro(-25);
9112 minion.clearAggroList();
9113 minion.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
9114 minion.addDamage(((L2Attackable) player).getMostHated(), 100);
9115 }
9116 }
9117 itr = null;
9118 spawnedMinions = null;
9119 minion = null;
9120 }
9121 }
9122 else
9123 {
9124 ((L2Attackable) player).stopHating(this);
9125 List<L2MinionInstance> spawnedMinions = ((L2MonsterInstance) player).getSpawnedMinions();
9126 if (spawnedMinions != null && spawnedMinions.size() > 0)
9127 {
9128 Iterator<L2MinionInstance> itr = spawnedMinions.iterator();
9129 L2MinionInstance minion;
9130 while (itr.hasNext())
9131 {
9132 minion = itr.next();
9133 if (((L2Attackable) player).getMostHated() == null)
9134 {
9135 ((L2AttackableAI) minion.getAI()).setGlobalAggro(-25);
9136 minion.clearAggroList();
9137 minion.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
9138 minion.setWalking();
9139 }
9140 if (minion != null && !minion.isDead())
9141 {
9142 ((L2AttackableAI) minion.getAI()).setGlobalAggro(-25);
9143 minion.clearAggroList();
9144 minion.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
9145 minion.addDamage(((L2Attackable) player).getMostHated(), 100);
9146 }
9147 }
9148 itr = null;
9149 spawnedMinions = null;
9150 minion = null;
9151 }
9152 }
9153 }
9154 return;
9155 }
9156 }
9157
9158 L2PcInstance activeChar = null;
9159
9160 if (this instanceof L2PcInstance)
9161 {
9162 activeChar = (L2PcInstance) this;
9163 }
9164 else if (this instanceof L2Summon)
9165 {
9166 activeChar = ((L2Summon) this).getOwner();
9167 }
9168
9169 if (activeChar != null)
9170 {
9171 if (skill.isOffensive())
9172 {
9173 if (player instanceof L2PcInstance || player instanceof L2Summon)
9174 {
9175 // Signets are a special case, casted on target_self but don't harm self
9176 if (skill.getSkillType() != L2Skill.SkillType.SIGNET && skill.getSkillType() != L2Skill.SkillType.SIGNET_CASTTIME)
9177 {
9178 player.getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, activeChar);
9179 activeChar.updatePvPStatus(player);
9180 }
9181 }
9182 else if (player instanceof L2Attackable)
9183 {
9184 switch (skill.getSkillType())
9185 {
9186 case AGGREDUCE:
9187 case AGGREDUCE_CHAR:
9188 case AGGREMOVE:
9189 break;
9190 default:
9191 ((L2Character) target).addAttackerToAttackByList(this);
9192 /*
9193 * ((L2Character) target).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, this); - Deprecated Notify the AI that is being attacked. It should be notified once the skill is finished in order to avoid AI action previous to skill end. IE: Backstab on monsters, the AI
9194 * rotates previous to skill end so it doesn't make affect. We calculate the hit time to know when the AI should rotate.
9195 */
9196 int hitTime = Formulas.getInstance().calcMAtkSpd(activeChar, skill, skill.getHitTime());
9197 if ((checkBss() || checkSps()) && !skill.isStaticHitTime() && !skill.isPotion() && skill.isMagic())
9198 hitTime = (int) (0.70 * hitTime);
9199 ThreadPoolManager.getInstance().scheduleGeneral(new notifyAiTaskDelayed(CtrlEvent.EVT_ATTACKED, this, target), hitTime);
9200 break;
9201 }
9202 }
9203 }
9204 else
9205 {
9206 if (player instanceof L2PcInstance)
9207 {
9208 // Casting non offensive skill on player with pvp flag set or with karma
9209 if (!player.equals(this) && (((L2PcInstance) player).getPvpFlag() > 0 || ((L2PcInstance) player).getKarma() > 0))
9210 {
9211 activeChar.updatePvPStatus();
9212 }
9213 }
9214 else if (player instanceof L2Attackable && !(skill.getSkillType() == L2Skill.SkillType.SUMMON) && !(skill.getSkillType() == L2Skill.SkillType.BEAST_FEED) && !(skill.getSkillType() == L2Skill.SkillType.UNLOCK) && !(skill.getSkillType() == L2Skill.SkillType.DELUXE_KEY_UNLOCK))
9215 {
9216 activeChar.updatePvPStatus(this);
9217 }
9218 }
9219 player = null;
9220 // activeWeapon = null;
9221 }
9222 activeChar = null;
9223 }
9224 if (target instanceof L2MonsterInstance)
9225 {
9226 if (!skill.isOffensive() && skill.getSkillType() != SkillType.UNLOCK && skill.getSkillType() != SkillType.SUMMON && skill.getSkillType() != SkillType.DELUXE_KEY_UNLOCK && skill.getSkillType() != SkillType.BEAST_FEED)
9227 {
9228 L2PcInstance activeChar = null;
9229
9230 if (this instanceof L2PcInstance)
9231 {
9232 activeChar = (L2PcInstance) this;
9233 activeChar.updatePvPStatus(activeChar);
9234 }
9235 else if (this instanceof L2Summon)
9236 {
9237 activeChar = ((L2Summon) this).getOwner();
9238 }
9239 }
9240 }
9241 }
9242
9243 ISkillHandler handler = null;
9244
9245 if (skill.isToggle())
9246 {
9247 // Check if the skill effects are already in progress on the L2Character
9248 if (getFirstEffect(skill.getId()) != null)
9249 {
9250 handler = SkillHandler.getInstance().getSkillHandler(skill.getSkillType());
9251
9252 if (handler != null)
9253 {
9254 handler.useSkill(this, skill, targets);
9255 }
9256 else
9257 {
9258 skill.useSkill(this, targets);
9259 }
9260
9261 return;
9262 }
9263 }/*
9264 * TODO else { if(this instanceof L2PcInstance || this instanceof L2Summon) { L2PcInstance caster = this instanceof L2PcInstance ? (L2PcInstance) this : ((L2Summon) this).getOwner(); for(L2Object target : targets) { if(target instanceof L2NpcInstance) { if (((L2NpcInstance)
9265 * target).getTemplate().getEventQuests(Quest.QuestEventType.ON_SKILL_USE) != null) { for(Quest quest : ((L2NpcInstance) target).getTemplate().getEventQuests(Quest.QuestEventType.ON_SKILL_USE)) { quest.notifySkillUse((L2NpcInstance) target, caster, skill); } } } } caster = null; } }
9266 */
9267
9268 // Check if over-hit is possible
9269 if (skill.isOverhit())
9270 {
9271 // Set the "over-hit enabled" flag on each of the possible targets
9272 for (final L2Object target : targets)
9273 {
9274 L2Character player = (L2Character) target;
9275 if (player instanceof L2Attackable)
9276 {
9277 ((L2Attackable) player).overhitEnabled(true);
9278 }
9279
9280 player = null;
9281 }
9282 }
9283
9284 // Get the skill handler corresponding to the skill type (PDAM, MDAM, SWEEP...) started in gameserver
9285 handler = SkillHandler.getInstance().getSkillHandler(skill.getSkillType());
9286
9287 // Launch the magic skill and calculate its effects
9288 if (handler != null)
9289 {
9290 handler.useSkill(this, skill, targets);
9291 }
9292 else
9293 {
9294 skill.useSkill(this, targets);
9295 }
9296
9297 // if the skill is a potion, must delete the potion item
9298 if (skill.isPotion() && this instanceof L2PlayableInstance)
9299 {
9300 Potions.delete_Potion_Item((L2PlayableInstance) this, skill.getId(), skill.getLevel());
9301 }
9302
9303 if (this instanceof L2PcInstance || this instanceof L2Summon)
9304 {
9305 L2PcInstance caster = this instanceof L2PcInstance ? (L2PcInstance) this : ((L2Summon) this).getOwner();
9306 for (final L2Object target : targets)
9307 {
9308 if (target instanceof L2NpcInstance)
9309 {
9310 L2NpcInstance npc = (L2NpcInstance) target;
9311
9312 for (final Quest quest : npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_SKILL_USE))
9313 {
9314 quest.notifySkillUse(npc, caster, skill);
9315 }
9316
9317 npc = null;
9318 }
9319 }
9320
9321 if (skill.getAggroPoints() > 0)
9322 {
9323 for (final L2Object spMob : caster.getKnownList().getKnownObjects().values())
9324 if (spMob instanceof L2NpcInstance)
9325 {
9326 L2NpcInstance npcMob = (L2NpcInstance) spMob;
9327
9328 if (npcMob.isInsideRadius(caster, 1000, true, true) && npcMob.hasAI() && npcMob.getAI().getIntention() == AI_INTENTION_ATTACK)
9329 {
9330 L2Object npcTarget = npcMob.getTarget();
9331
9332 for (final L2Object target : targets)
9333 if (npcTarget == target || npcMob == target)
9334 {
9335 npcMob.seeSpell(caster, target, skill);
9336 }
9337
9338 npcTarget = null;
9339 }
9340
9341 npcMob = null;
9342 }
9343 }
9344
9345 caster = null;
9346 }
9347
9348 handler = null;
9349 }
9350 catch (final Exception e)
9351 {
9352 LOGGER.warn("", e);
9353 }
9354
9355 if (this instanceof L2PcInstance && ((L2PcInstance) this).isMovingTaskDefined() && !skill.isPotion())
9356 ((L2PcInstance) this).startMovingTask();
9357 }
9358
9359 /**
9360 * See spell.
9361 * @param caster the caster
9362 * @param target the target
9363 * @param skill the skill
9364 */
9365 public void seeSpell(final L2PcInstance caster, final L2Object target, final L2Skill skill)
9366 {
9367 if (this instanceof L2Attackable)
9368 {
9369 ((L2Attackable) this).addDamageHate(caster, 0, -skill.getAggroPoints());
9370 }
9371 }
9372
9373 /**
9374 * Return True if the L2Character is behind the target and can't be seen.<BR>
9375 * <BR>
9376 * @param target the target
9377 * @return true, if is behind
9378 */
9379 public boolean isBehind(final L2Object target)
9380 {
9381 double angleChar, angleTarget, angleDiff; //
9382 final double maxAngleDiff = 40;
9383
9384 if (target == null)
9385 return false;
9386
9387 if (target instanceof L2Character)
9388 {
9389 ((L2Character) target).sendPacket(new ValidateLocation(this));
9390 this.sendPacket(new ValidateLocation(((L2Character) target)));
9391
9392 L2Character target1 = (L2Character) target;
9393 angleChar = Util.calculateAngleFrom(target1, this);
9394 angleTarget = Util.convertHeadingToDegree(target1.getHeading());
9395 angleDiff = angleChar - angleTarget;
9396
9397 if (angleDiff <= -360 + maxAngleDiff)
9398 {
9399 angleDiff += 360;
9400 }
9401
9402 if (angleDiff >= 360 - maxAngleDiff)
9403 {
9404 angleDiff -= 360;
9405 }
9406
9407 if (Math.abs(angleDiff) <= maxAngleDiff)
9408 {
9409 if (Config.DEBUG)
9410 {
9411 LOGGER.info("Char " + getName() + " is behind " + target.getName());
9412 }
9413
9414 return true;
9415 }
9416
9417 target1 = null;
9418 }
9419
9420 return false;
9421 }
9422
9423 /**
9424 * Checks if is behind target.
9425 * @return true, if is behind target
9426 */
9427 public boolean isBehindTarget()
9428 {
9429 return isBehind(getTarget());
9430 }
9431
9432 /**
9433 * Returns true if target is in front of L2Character (shield def etc).
9434 * @param target the target
9435 * @param maxAngle the max angle
9436 * @return true, if is facing
9437 */
9438 public boolean isFacing(final L2Object target, final int maxAngle)
9439 {
9440 double angleChar, angleTarget, angleDiff, maxAngleDiff;
9441 if (target == null)
9442 return false;
9443 maxAngleDiff = maxAngle / 2;
9444 angleTarget = Util.calculateAngleFrom(this, target);
9445 angleChar = Util.convertHeadingToDegree(this.getHeading());
9446 angleDiff = angleChar - angleTarget;
9447 if (angleDiff <= -360 + maxAngleDiff)
9448 angleDiff += 360;
9449 if (angleDiff >= 360 - maxAngleDiff)
9450 angleDiff -= 360;
9451 if (Math.abs(angleDiff) <= maxAngleDiff)
9452 return true;
9453 return false;
9454 }
9455
9456 /**
9457 * Return True if the L2Character is behind the target and can't be seen.<BR>
9458 * <BR>
9459 * @param target the target
9460 * @return true, if is front
9461 */
9462 public boolean isFront(final L2Object target)
9463 {
9464 double angleChar, angleTarget, angleDiff;
9465 final double maxAngleDiff = 40;
9466
9467 if (target == null)
9468 return false;
9469
9470 if (target instanceof L2Character)
9471 {
9472 ((L2Character) target).sendPacket(new ValidateLocation(this));
9473 this.sendPacket(new ValidateLocation(((L2Character) target)));
9474
9475 L2Character target1 = (L2Character) target;
9476 angleChar = Util.calculateAngleFrom(target1, this);
9477 angleTarget = Util.convertHeadingToDegree(target1.getHeading());
9478 angleDiff = angleChar - angleTarget;
9479
9480 if (angleDiff <= -180 + maxAngleDiff)
9481 {
9482 angleDiff += 180;
9483 }
9484
9485 if (angleDiff >= 180 - maxAngleDiff)
9486 {
9487 angleDiff -= 180;
9488 }
9489
9490 if (Math.abs(angleDiff) <= maxAngleDiff)
9491 {
9492 if (isBehindTarget())
9493 return false;
9494
9495 if (Config.DEBUG)
9496 {
9497 LOGGER.info("Char " + getName() + " is side " + target.getName());
9498 }
9499
9500 return true;
9501 }
9502
9503 target1 = null;
9504 }
9505
9506 return false;
9507 }
9508
9509 /**
9510 * Checks if is front target.
9511 * @return true, if is front target
9512 */
9513 public boolean isFrontTarget()
9514 {
9515 return isFront(getTarget());
9516 }
9517
9518 /**
9519 * Return True if the L2Character is side the target and can't be seen.<BR>
9520 * <BR>
9521 * @param target the target
9522 * @return true, if is side
9523 */
9524 public boolean isSide(final L2Object target)
9525 {
9526 if (target == null)
9527 return false;
9528
9529 if (target instanceof L2Character)
9530 {
9531 if (isBehindTarget() || isFrontTarget())
9532 return false;
9533 }
9534
9535 return true;
9536 }
9537
9538 /**
9539 * Checks if is side target.
9540 * @return true, if is side target
9541 */
9542 public boolean isSideTarget()
9543 {
9544 return isSide(getTarget());
9545 }
9546
9547 /**
9548 * Return 1.<BR>
9549 * <BR>
9550 * @return the level mod
9551 */
9552 public double getLevelMod()
9553 {
9554 return 1;
9555 }
9556
9557 /**
9558 * Sets the skill cast.
9559 * @param newSkillCast the new skill cast
9560 */
9561 public final void setSkillCast(final Future<?> newSkillCast)
9562 {
9563 _skillCast = newSkillCast;
9564 }
9565
9566 /**
9567 * Sets the skill cast end time.
9568 * @param newSkillCastEndTime the new skill cast end time
9569 */
9570 public final void setSkillCastEndTime(final int newSkillCastEndTime)
9571 {
9572 _castEndTime = newSkillCastEndTime;
9573 // for interrupt -12 ticks; first removing the extra second and then -200 ms
9574 _castInterruptTime = newSkillCastEndTime - 12;
9575 }
9576
9577 /** The _ pvp reg task. */
9578 private Future<?> _PvPRegTask;
9579
9580 /** The _pvp flag lasts. */
9581 private long _pvpFlagLasts;
9582
9583 /**
9584 * Sets the pvp flag lasts.
9585 * @param time the new pvp flag lasts
9586 */
9587 public void setPvpFlagLasts(final long time)
9588 {
9589 _pvpFlagLasts = time;
9590 }
9591
9592 /**
9593 * Gets the pvp flag lasts.
9594 * @return the pvp flag lasts
9595 */
9596 public long getPvpFlagLasts()
9597 {
9598 return _pvpFlagLasts;
9599 }
9600
9601 /**
9602 * Start pvp flag.
9603 */
9604 public void startPvPFlag()
9605 {
9606 updatePvPFlag(1);
9607
9608 _PvPRegTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new PvPFlag(), 1000, 1000);
9609 }
9610
9611 /**
9612 * Stop pvp reg task.
9613 */
9614 public void stopPvpRegTask()
9615 {
9616 if (_PvPRegTask != null)
9617 {
9618 _PvPRegTask.cancel(true);
9619 }
9620 }
9621
9622 /**
9623 * Stop pvp flag.
9624 */
9625 public void stopPvPFlag()
9626 {
9627 stopPvpRegTask();
9628
9629 updatePvPFlag(0);
9630
9631 _PvPRegTask = null;
9632 }
9633
9634 /**
9635 * Update pvp flag.
9636 * @param value the value
9637 */
9638 public void updatePvPFlag(final int value)
9639 {
9640 // Overridden in L2PcInstance
9641 //
9642 // if (!(this instanceof L2PcInstance))
9643 // return;
9644 // L2PcInstance player = (L2PcInstance)this;
9645 // if (player.getPvpFlag() == value)
9646 // return;
9647 // player.setPvpFlag(value);
9648 //
9649 // player.sendPacket(new UserInfo(player));
9650 // for (L2PcInstance target : getKnownList().getKnownPlayers().values())
9651 // {
9652 // target.sendPacket(new RelationChanged(player, player.getRelation(player), player.isAutoAttackable(target)));
9653 // }
9654 }
9655
9656 // public void checkPvPFlag()
9657 // {
9658 // if (Config.DEBUG) LOGGER.fine("Checking PvpFlag");
9659 // _PvPRegTask = ThreadPoolManager.getInstance().scheduleLowAtFixedRate(new PvPFlag(), 1000, 5000);
9660 // _PvPRegActive = true;
9661 // // LOGGER.fine("PvP recheck");
9662 // }
9663 //
9664
9665 /**
9666 * Return a Random Damage in function of the weapon.<BR>
9667 * <BR>
9668 * @param target the target
9669 * @return the random damage
9670 */
9671 public final int getRandomDamage(final L2Character target)
9672 {
9673 final L2Weapon weaponItem = getActiveWeaponItem();
9674
9675 if (weaponItem == null)
9676 return 5 + (int) Math.sqrt(getLevel());
9677
9678 return weaponItem.getRandomDamage();
9679 }
9680
9681 /*
9682 * (non-Javadoc)
9683 * @see com.l2jfrozen.gameserver.model.L2Object#toString()
9684 */
9685 @Override
9686 public String toString()
9687 {
9688 return "mob " + getObjectId();
9689 }
9690
9691 /**
9692 * Gets the attack end time.
9693 * @return the attack end time
9694 */
9695 public int getAttackEndTime()
9696 {
9697 return _attackEndTime;
9698 }
9699
9700 /**
9701 * Not Implemented.<BR>
9702 * <BR>
9703 * @return the level
9704 */
9705 public abstract int getLevel();
9706
9707 // =========================================================
9708
9709 // =========================================================
9710 // Stat - NEED TO REMOVE ONCE L2CHARSTAT IS COMPLETE
9711 // Property - Public
9712 /**
9713 * Calc stat.
9714 * @param stat the stat
9715 * @param init the init
9716 * @param target the target
9717 * @param skill the skill
9718 * @return the double
9719 */
9720 public final double calcStat(final Stats stat, final double init, final L2Character target, final L2Skill skill)
9721 {
9722 return getStat().calcStat(stat, init, target, skill);
9723 }
9724
9725 // Property - Public
9726 /**
9727 * Gets the accuracy.
9728 * @return the accuracy
9729 */
9730 public int getAccuracy()
9731 {
9732 return getStat().getAccuracy();
9733 }
9734
9735 /**
9736 * Gets the attack speed multiplier.
9737 * @return the attack speed multiplier
9738 */
9739 public final float getAttackSpeedMultiplier()
9740 {
9741 return getStat().getAttackSpeedMultiplier();
9742 }
9743
9744 /**
9745 * Gets the cON.
9746 * @return the cON
9747 */
9748 public int getCON()
9749 {
9750 return getStat().getCON();
9751 }
9752
9753 /**
9754 * Gets the dEX.
9755 * @return the dEX
9756 */
9757 public int getDEX()
9758 {
9759 return getStat().getDEX();
9760 }
9761
9762 /**
9763 * Gets the critical dmg.
9764 * @param target the target
9765 * @param init the init
9766 * @return the critical dmg
9767 */
9768 public final double getCriticalDmg(final L2Character target, final double init)
9769 {
9770 return getStat().getCriticalDmg(target, init);
9771 }
9772
9773 /**
9774 * Gets the critical hit.
9775 * @param target the target
9776 * @param skill the skill
9777 * @return the critical hit
9778 */
9779 public int getCriticalHit(final L2Character target, final L2Skill skill)
9780 {
9781 return getStat().getCriticalHit(target, skill);
9782 }
9783
9784 /**
9785 * Gets the evasion rate.
9786 * @param target the target
9787 * @return the evasion rate
9788 */
9789 public int getEvasionRate(final L2Character target)
9790 {
9791 return getStat().getEvasionRate(target);
9792 }
9793
9794 /**
9795 * Gets the iNT.
9796 * @return the iNT
9797 */
9798 public int getINT()
9799 {
9800 return getStat().getINT();
9801 }
9802
9803 /**
9804 * Gets the magical attack range.
9805 * @param skill the skill
9806 * @return the magical attack range
9807 */
9808 public final int getMagicalAttackRange(final L2Skill skill)
9809 {
9810 return getStat().getMagicalAttackRange(skill);
9811 }
9812
9813 /**
9814 * Gets the max cp.
9815 * @return the max cp
9816 */
9817 public final int getMaxCp()
9818 {
9819 return getStat().getMaxCp();
9820 }
9821
9822 /**
9823 * Gets the m atk.
9824 * @param target the target
9825 * @param skill the skill
9826 * @return the m atk
9827 */
9828 public int getMAtk(final L2Character target, final L2Skill skill)
9829 {
9830 return getStat().getMAtk(target, skill);
9831 }
9832
9833 /**
9834 * Gets the m atk spd.
9835 * @return the m atk spd
9836 */
9837 public int getMAtkSpd()
9838 {
9839 return getStat().getMAtkSpd();
9840 }
9841
9842 /**
9843 * Gets the max mp.
9844 * @return the max mp
9845 */
9846 public int getMaxMp()
9847 {
9848 return getStat().getMaxMp();
9849 }
9850
9851 /**
9852 * Gets the max hp.
9853 * @return the max hp
9854 */
9855 public int getMaxHp()
9856 {
9857 return getStat().getMaxHp();
9858 }
9859
9860 /**
9861 * Gets the m critical hit.
9862 * @param target the target
9863 * @param skill the skill
9864 * @return the m critical hit
9865 */
9866 public final int getMCriticalHit(final L2Character target, final L2Skill skill)
9867 {
9868 return getStat().getMCriticalHit(target, skill);
9869 }
9870
9871 /**
9872 * Gets the m def.
9873 * @param target the target
9874 * @param skill the skill
9875 * @return the m def
9876 */
9877 public int getMDef(final L2Character target, final L2Skill skill)
9878 {
9879 return getStat().getMDef(target, skill);
9880 }
9881
9882 /**
9883 * Gets the mEN.
9884 * @return the mEN
9885 */
9886 public int getMEN()
9887 {
9888 return getStat().getMEN();
9889 }
9890
9891 /**
9892 * Gets the m reuse rate.
9893 * @param skill the skill
9894 * @return the m reuse rate
9895 */
9896 public double getMReuseRate(final L2Skill skill)
9897 {
9898 return getStat().getMReuseRate(skill);
9899 }
9900
9901 /**
9902 * Gets the movement speed multiplier.
9903 * @return the movement speed multiplier
9904 */
9905 public float getMovementSpeedMultiplier()
9906 {
9907 return getStat().getMovementSpeedMultiplier();
9908 }
9909
9910 /**
9911 * Gets the p atk.
9912 * @param target the target
9913 * @return the p atk
9914 */
9915 public int getPAtk(final L2Character target)
9916 {
9917 return getStat().getPAtk(target);
9918 }
9919
9920 /**
9921 * Gets the p atk animals.
9922 * @param target the target
9923 * @return the p atk animals
9924 */
9925 public double getPAtkAnimals(final L2Character target)
9926 {
9927 return getStat().getPAtkAnimals(target);
9928 }
9929
9930 /**
9931 * Gets the p atk dragons.
9932 * @param target the target
9933 * @return the p atk dragons
9934 */
9935 public double getPAtkDragons(final L2Character target)
9936 {
9937 return getStat().getPAtkDragons(target);
9938 }
9939
9940 /**
9941 * Gets the p atk angels.
9942 * @param target the target
9943 * @return the p atk angels
9944 */
9945 public double getPAtkAngels(final L2Character target)
9946 {
9947 return getStat().getPAtkAngels(target);
9948 }
9949
9950 /**
9951 * Gets the p atk insects.
9952 * @param target the target
9953 * @return the p atk insects
9954 */
9955 public double getPAtkInsects(final L2Character target)
9956 {
9957 return getStat().getPAtkInsects(target);
9958 }
9959
9960 /**
9961 * Gets the p atk monsters.
9962 * @param target the target
9963 * @return the p atk monsters
9964 */
9965 public double getPAtkMonsters(final L2Character target)
9966 {
9967 return getStat().getPAtkMonsters(target);
9968 }
9969
9970 /**
9971 * Gets the p atk plants.
9972 * @param target the target
9973 * @return the p atk plants
9974 */
9975 public double getPAtkPlants(final L2Character target)
9976 {
9977 return getStat().getPAtkPlants(target);
9978 }
9979
9980 /**
9981 * Gets the p atk spd.
9982 * @return the p atk spd
9983 */
9984 public int getPAtkSpd()
9985 {
9986 return getStat().getPAtkSpd();
9987 }
9988
9989 /**
9990 * Gets the p atk undead.
9991 * @param target the target
9992 * @return the p atk undead
9993 */
9994 public double getPAtkUndead(final L2Character target)
9995 {
9996 return getStat().getPAtkUndead(target);
9997 }
9998
9999 /**
10000 * Gets the p def undead.
10001 * @param target the target
10002 * @return the p def undead
10003 */
10004 public double getPDefUndead(final L2Character target)
10005 {
10006 return getStat().getPDefUndead(target);
10007 }
10008
10009 /**
10010 * Gets the p def plants.
10011 * @param target the target
10012 * @return the p def plants
10013 */
10014 public double getPDefPlants(final L2Character target)
10015 {
10016 return getStat().getPDefPlants(target);
10017 }
10018
10019 /**
10020 * Gets the p def insects.
10021 * @param target the target
10022 * @return the p def insects
10023 */
10024 public double getPDefInsects(final L2Character target)
10025 {
10026 return getStat().getPDefInsects(target);
10027 }
10028
10029 /**
10030 * Gets the p def animals.
10031 * @param target the target
10032 * @return the p def animals
10033 */
10034 public double getPDefAnimals(final L2Character target)
10035 {
10036 return getStat().getPDefAnimals(target);
10037 }
10038
10039 /**
10040 * Gets the p def monsters.
10041 * @param target the target
10042 * @return the p def monsters
10043 */
10044 public double getPDefMonsters(final L2Character target)
10045 {
10046 return getStat().getPDefMonsters(target);
10047 }
10048
10049 /**
10050 * Gets the p def dragons.
10051 * @param target the target
10052 * @return the p def dragons
10053 */
10054 public double getPDefDragons(final L2Character target)
10055 {
10056 return getStat().getPDefDragons(target);
10057 }
10058
10059 /**
10060 * Gets the p def angels.
10061 * @param target the target
10062 * @return the p def angels
10063 */
10064 public double getPDefAngels(final L2Character target)
10065 {
10066 return getStat().getPDefAngels(target);
10067 }
10068
10069 /**
10070 * Gets the p def.
10071 * @param target the target
10072 * @return the p def
10073 */
10074 public int getPDef(final L2Character target)
10075 {
10076 return getStat().getPDef(target);
10077 }
10078
10079 /**
10080 * Gets the p atk giants.
10081 * @param target the target
10082 * @return the p atk giants
10083 */
10084 public double getPAtkGiants(final L2Character target)
10085 {
10086 return getStat().getPAtkGiants(target);
10087 }
10088
10089 /**
10090 * Gets the p atk magic creatures.
10091 * @param target the target
10092 * @return the p atk magic creatures
10093 */
10094 public double getPAtkMagicCreatures(final L2Character target)
10095 {
10096 return getStat().getPAtkMagicCreatures(target);
10097 }
10098
10099 /**
10100 * Gets the p def giants.
10101 * @param target the target
10102 * @return the p def giants
10103 */
10104 public double getPDefGiants(final L2Character target)
10105 {
10106 return getStat().getPDefGiants(target);
10107 }
10108
10109 /**
10110 * Gets the p def magic creatures.
10111 * @param target the target
10112 * @return the p def magic creatures
10113 */
10114 public double getPDefMagicCreatures(final L2Character target)
10115 {
10116 return getStat().getPDefMagicCreatures(target);
10117 }
10118
10119 /**
10120 * Gets the physical attack range.
10121 * @return the physical attack range
10122 */
10123 public final int getPhysicalAttackRange()
10124 {
10125 return getStat().getPhysicalAttackRange();
10126 }
10127
10128 /**
10129 * Gets the run speed.
10130 * @return the run speed
10131 */
10132 public int getRunSpeed()
10133 {
10134 return getStat().getRunSpeed();
10135 }
10136
10137 /**
10138 * Gets the shld def.
10139 * @return the shld def
10140 */
10141 public final int getShldDef()
10142 {
10143 return getStat().getShldDef();
10144 }
10145
10146 /**
10147 * Gets the sTR.
10148 * @return the sTR
10149 */
10150 public int getSTR()
10151 {
10152 return getStat().getSTR();
10153 }
10154
10155 /**
10156 * Gets the walk speed.
10157 * @return the walk speed
10158 */
10159 public final int getWalkSpeed()
10160 {
10161 return getStat().getWalkSpeed();
10162 }
10163
10164 /**
10165 * Gets the wIT.
10166 * @return the wIT
10167 */
10168 public int getWIT()
10169 {
10170 return getStat().getWIT();
10171 }
10172
10173 // =========================================================
10174
10175 // =========================================================
10176 // Status - NEED TO REMOVE ONCE L2CHARTATUS IS COMPLETE
10177 // Method - Public
10178 /**
10179 * Adds the status listener.
10180 * @param object the object
10181 */
10182 public void addStatusListener(final L2Character object)
10183 {
10184 getStatus().addStatusListener(object);
10185 }
10186
10187 /**
10188 * Reduce current hp.
10189 * @param i the i
10190 * @param attacker the attacker
10191 */
10192 public void reduceCurrentHp(final double i, final L2Character attacker)
10193 {
10194 reduceCurrentHp(i, attacker, true);
10195 }
10196
10197 /**
10198 * Reduce current hp.
10199 * @param i the i
10200 * @param attacker the attacker
10201 * @param awake the awake
10202 */
10203 public void reduceCurrentHp(final double i, final L2Character attacker, final boolean awake)
10204 {
10205 if (this instanceof L2NpcInstance)
10206 if (Config.INVUL_NPC_LIST.contains(Integer.valueOf(((L2NpcInstance) this).getNpcId())))
10207 return;
10208
10209 if (Config.L2JMOD_CHAMPION_ENABLE && isChampion() && Config.L2JMOD_CHAMPION_HP != 0)
10210 {
10211 getStatus().reduceHp(i / Config.L2JMOD_CHAMPION_HP, attacker, awake);
10212 }
10213 else if (is_advanceFlag())
10214 {
10215 getStatus().reduceHp(i / _advanceMultiplier, attacker, awake);
10216 }
10217 else if (isUnkillable())
10218 {
10219 final double hpToReduce = this.getCurrentHp() - 1;
10220 if (i > this.getCurrentHp())
10221 getStatus().reduceHp(hpToReduce, attacker, awake);
10222 else
10223 getStatus().reduceHp(i, attacker, awake);
10224 }
10225 else
10226 {
10227 getStatus().reduceHp(i, attacker, awake);
10228 }
10229 }
10230
10231 private long _nextReducingHPByOverTime = -1;
10232
10233 public void reduceCurrentHpByDamOverTime(final double i, final L2Character attacker, final boolean awake, final int period)
10234 {
10235 if (_nextReducingHPByOverTime > System.currentTimeMillis())
10236 {
10237 return;
10238 }
10239
10240 _nextReducingHPByOverTime = System.currentTimeMillis() + (period * 1000);
10241 reduceCurrentHp(i, attacker, awake);
10242
10243 }
10244
10245 private long _nextReducingMPByOverTime = -1;
10246
10247 public void reduceCurrentMpByDamOverTime(final double i, final int period)
10248 {
10249 if (_nextReducingMPByOverTime > System.currentTimeMillis())
10250 {
10251 return;
10252 }
10253
10254 _nextReducingMPByOverTime = System.currentTimeMillis() + (period * 1000);
10255 reduceCurrentMp(i);
10256
10257 }
10258
10259 /**
10260 * Reduce current mp.
10261 * @param i the i
10262 */
10263 public void reduceCurrentMp(final double i)
10264 {
10265 getStatus().reduceMp(i);
10266 }
10267
10268 /**
10269 * Removes the status listener.
10270 * @param object the object
10271 */
10272 public void removeStatusListener(final L2Character object)
10273 {
10274 getStatus().removeStatusListener(object);
10275 }
10276
10277 /**
10278 * Stop hp mp regeneration.
10279 */
10280 protected void stopHpMpRegeneration()
10281 {
10282 getStatus().stopHpMpRegeneration();
10283 }
10284
10285 // Property - Public
10286 /**
10287 * Gets the current cp.
10288 * @return the current cp
10289 */
10290 public final double getCurrentCp()
10291 {
10292 return getStatus().getCurrentCp();
10293 }
10294
10295 /**
10296 * Sets the current cp.
10297 * @param newCp the new current cp
10298 */
10299 public final void setCurrentCp(final Double newCp)
10300 {
10301 setCurrentCp((double) newCp);
10302 }
10303
10304 /**
10305 * Sets the current cp.
10306 * @param newCp the new current cp
10307 */
10308 public final void setCurrentCp(final double newCp)
10309 {
10310 getStatus().setCurrentCp(newCp);
10311 }
10312
10313 /**
10314 * Gets the current hp.
10315 * @return the current hp
10316 */
10317 public final double getCurrentHp()
10318 {
10319 return getStatus().getCurrentHp();
10320 }
10321
10322 /**
10323 * Sets the current hp.
10324 * @param newHp the new current hp
10325 */
10326 public final void setCurrentHp(final double newHp)
10327 {
10328 getStatus().setCurrentHp(newHp);
10329 }
10330
10331 /**
10332 * Sets the current hp direct.
10333 * @param newHp the new current hp direct
10334 */
10335 public final void setCurrentHpDirect(final double newHp)
10336 {
10337 getStatus().setCurrentHpDirect(newHp);
10338 }
10339
10340 /**
10341 * Sets the current cp direct.
10342 * @param newCp the new current cp direct
10343 */
10344 public final void setCurrentCpDirect(final double newCp)
10345 {
10346 getStatus().setCurrentCpDirect(newCp);
10347 }
10348
10349 /**
10350 * Sets the current mp direct.
10351 * @param newMp the new current mp direct
10352 */
10353 public final void setCurrentMpDirect(final double newMp)
10354 {
10355 getStatus().setCurrentMpDirect(newMp);
10356 }
10357
10358 /**
10359 * Sets the current hp mp.
10360 * @param newHp the new hp
10361 * @param newMp the new mp
10362 */
10363 public final void setCurrentHpMp(final double newHp, final double newMp)
10364 {
10365 getStatus().setCurrentHpMp(newHp, newMp);
10366 }
10367
10368 /**
10369 * Gets the current mp.
10370 * @return the current mp
10371 */
10372 public final double getCurrentMp()
10373 {
10374 return getStatus().getCurrentMp();
10375 }
10376
10377 /**
10378 * Sets the current mp.
10379 * @param newMp the new current mp
10380 */
10381 public final void setCurrentMp(final Double newMp)
10382 {
10383 setCurrentMp((double) newMp);
10384 }
10385
10386 /**
10387 * Sets the current mp.
10388 * @param newMp the new current mp
10389 */
10390 public final void setCurrentMp(final double newMp)
10391 {
10392 getStatus().setCurrentMp(newMp);
10393 }
10394
10395 // =========================================================
10396
10397 /**
10398 * Sets the ai class.
10399 * @param aiClass the new ai class
10400 */
10401 public void setAiClass(final String aiClass)
10402 {
10403 _aiClass = aiClass;
10404 }
10405
10406 /**
10407 * Gets the ai class.
10408 * @return the ai class
10409 */
10410 public String getAiClass()
10411 {
10412 return _aiClass;
10413 }
10414
10415 /*
10416 * public L2Character getLastBuffer() { return _lastBuffer; }
10417 */
10418
10419 /**
10420 * Sets the champion.
10421 * @param champ the new champion
10422 */
10423 public void setChampion(final boolean champ)
10424 {
10425 _champion = champ;
10426 }
10427
10428 /**
10429 * Checks if is champion.
10430 * @return true, if is champion
10431 */
10432 public boolean isChampion()
10433 {
10434 return _champion;
10435 }
10436
10437 /**
10438 * Gets the last heal amount.
10439 * @return the last heal amount
10440 */
10441 public int getLastHealAmount()
10442 {
10443 return _lastHealAmount;
10444 }
10445
10446 /*
10447 * public void setLastBuffer(L2Character buffer) { _lastBuffer = buffer; }
10448 */
10449
10450 /**
10451 * Sets the last heal amount.
10452 * @param hp the new last heal amount
10453 */
10454 public void setLastHealAmount(final int hp)
10455 {
10456 _lastHealAmount = hp;
10457 }
10458
10459 /**
10460 * @return the _advanceFlag
10461 */
10462 public boolean is_advanceFlag()
10463 {
10464 return _advanceFlag;
10465 }
10466
10467 /**
10468 * @param advanceFlag
10469 */
10470 public void set_advanceFlag(final boolean advanceFlag)
10471 {
10472 _advanceFlag = advanceFlag;
10473 }
10474
10475 /**
10476 * @param advanceMultiplier
10477 */
10478 public void set_advanceMultiplier(final int advanceMultiplier)
10479 {
10480 _advanceMultiplier = advanceMultiplier;
10481 }
10482
10483 /**
10484 * Check if character reflected skill.
10485 * @param skill the skill
10486 * @return true, if successful
10487 */
10488 public boolean reflectSkill(final L2Skill skill)
10489 {
10490 final double reflect = calcStat(skill.isMagic() ? Stats.REFLECT_SKILL_MAGIC : Stats.REFLECT_SKILL_PHYSIC, 0, null, null);
10491
10492 if (Rnd.get(100) < reflect)
10493 return true;
10494
10495 return false;
10496 }
10497
10498 /**
10499 * Vengeance skill.
10500 * @param skill the skill
10501 * @return true, if successful
10502 */
10503 public boolean vengeanceSkill(final L2Skill skill)
10504 {
10505 if (!skill.isMagic() && skill.getCastRange() <= 40)
10506 {
10507 final double venganceChance = calcStat(Stats.VENGEANCE_SKILL_PHYSICAL_DAMAGE, 0, null, skill);
10508 if (venganceChance > Rnd.get(100))
10509 return true;
10510 }
10511 return false;
10512 }
10513
10514 /**
10515 * Send system message about damage.<BR>
10516 * <BR>
10517 * <B><U> Overriden in </U> :</B><BR>
10518 * <BR>
10519 * <li>L2PcInstance <li>L2SummonInstance <li>L2PetInstance</li><BR>
10520 * <BR>
10521 * @param target the target
10522 * @param damage the damage
10523 * @param mcrit the mcrit
10524 * @param pcrit the pcrit
10525 * @param miss the miss
10526 */
10527 public void sendDamageMessage(final L2Character target, final int damage, final boolean mcrit, final boolean pcrit, final boolean miss)
10528 {
10529 }
10530
10531 /**
10532 * Gets the force buff.
10533 * @return the force buff
10534 */
10535 public ForceBuff getForceBuff()
10536 {
10537 return _forceBuff;
10538 }
10539
10540 /**
10541 * Sets the force buff.
10542 * @param fb the new force buff
10543 */
10544 public void setForceBuff(final ForceBuff fb)
10545 {
10546 _forceBuff = fb;
10547 }
10548
10549 /**
10550 * Checks if is fear immune.
10551 * @return true, if is fear immune
10552 */
10553 public boolean isFearImmune()
10554 {
10555 return false;
10556 }
10557
10558 /**
10559 * Restore hpmp.
10560 */
10561 public void restoreHPMP()
10562 {
10563 getStatus().setCurrentHpMp(getMaxHp(), getMaxMp());
10564 }
10565
10566 /**
10567 * Restore cp.
10568 */
10569 public void restoreCP()
10570 {
10571 getStatus().setCurrentCp(getMaxCp());
10572 }
10573
10574 /**
10575 * Block.
10576 */
10577 public void block()
10578 {
10579 _blocked = true;
10580 }
10581
10582 /**
10583 * Unblock.
10584 */
10585 public void unblock()
10586 {
10587 _blocked = false;
10588 }
10589
10590 /**
10591 * Checks if is blocked.
10592 * @return true, if is blocked
10593 */
10594 public boolean isBlocked()
10595 {
10596 return _blocked;
10597 }
10598
10599 /**
10600 * Checks if is meditated.
10601 * @return true, if is meditated
10602 */
10603 public boolean isMeditated()
10604 {
10605 return _meditated;
10606 }
10607
10608 /**
10609 * Sets the meditated.
10610 * @param meditated the new meditated
10611 */
10612 public void setMeditated(final boolean meditated)
10613 {
10614 _meditated = meditated;
10615 }
10616
10617 /**
10618 * Update attack stance.
10619 */
10620 public void updateAttackStance()
10621 {
10622 attackStance = System.currentTimeMillis();
10623 }
10624
10625 /**
10626 * Gets the attack stance.
10627 * @return the attack stance
10628 */
10629 public long getAttackStance()
10630 {
10631 return attackStance;
10632 }
10633
10634 /** The _petrified. */
10635 private boolean _petrified = false;
10636
10637 /**
10638 * Checks if is petrified.
10639 * @return the petrified
10640 */
10641 public boolean isPetrified()
10642 {
10643 return _petrified;
10644 }
10645
10646 /**
10647 * Sets the petrified.
10648 * @param petrified the petrified to set
10649 */
10650 public void setPetrified(final boolean petrified)
10651 {
10652 if (petrified)
10653 {
10654 setIsParalyzed(petrified);
10655 setIsInvul(petrified);
10656 _petrified = petrified;
10657 }
10658 else
10659 {
10660 _petrified = petrified;
10661 setIsParalyzed(petrified);
10662 setIsInvul(petrified);
10663 }
10664 }
10665
10666 /**
10667 * Check bss.
10668 * @return true, if successful
10669 */
10670 public boolean checkBss()
10671 {
10672
10673 boolean bss = false;
10674
10675 final L2ItemInstance weaponInst = this.getActiveWeaponInstance();
10676
10677 if (weaponInst != null)
10678 {
10679 if (weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_BLESSED_SPIRITSHOT)
10680 {
10681 bss = true;
10682 // ponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
10683 }
10684
10685 }
10686 // If there is no weapon equipped, check for an active summon.
10687 else if (this instanceof L2Summon)
10688 {
10689 final L2Summon activeSummon = (L2Summon) this;
10690
10691 if (activeSummon.getChargedSpiritShot() == L2ItemInstance.CHARGED_BLESSED_SPIRITSHOT)
10692 {
10693 bss = true;
10694 // activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
10695 }
10696
10697 }
10698
10699 return bss;
10700 }
10701
10702 /**
10703 * Removes the bss.
10704 */
10705 synchronized public void removeBss()
10706 {
10707
10708 final L2ItemInstance weaponInst = this.getActiveWeaponInstance();
10709
10710 if (weaponInst != null)
10711 {
10712 if (weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_BLESSED_SPIRITSHOT)
10713 {
10714 weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
10715 }
10716
10717 }
10718 // If there is no weapon equipped, check for an active summon.
10719 else if (this instanceof L2Summon)
10720 {
10721 final L2Summon activeSummon = (L2Summon) this;
10722
10723 if (activeSummon.getChargedSpiritShot() == L2ItemInstance.CHARGED_BLESSED_SPIRITSHOT)
10724 {
10725 activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
10726 }
10727
10728 }
10729
10730 reloadShots(true);
10731 }
10732
10733 /**
10734 * Check sps.
10735 * @return true, if successful
10736 */
10737 public boolean checkSps()
10738 {
10739
10740 boolean ss = false;
10741
10742 final L2ItemInstance weaponInst = this.getActiveWeaponInstance();
10743
10744 if (weaponInst != null)
10745 {
10746 if (weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_SPIRITSHOT)
10747 {
10748 ss = true;
10749 // weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
10750 }
10751 }
10752 // If there is no weapon equipped, check for an active summon.
10753 else if (this instanceof L2Summon)
10754 {
10755 final L2Summon activeSummon = (L2Summon) this;
10756
10757 if (activeSummon.getChargedSpiritShot() == L2ItemInstance.CHARGED_SPIRITSHOT)
10758 {
10759 ss = true;
10760 // activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
10761 }
10762 }
10763
10764 return ss;
10765
10766 }
10767
10768 /**
10769 * Removes the sps.
10770 */
10771 synchronized public void removeSps()
10772 {
10773
10774 final L2ItemInstance weaponInst = this.getActiveWeaponInstance();
10775
10776 if (weaponInst != null)
10777 {
10778 if (weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_SPIRITSHOT)
10779 {
10780 weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
10781 }
10782 }
10783 // If there is no weapon equipped, check for an active summon.
10784 else if (this instanceof L2Summon)
10785 {
10786 final L2Summon activeSummon = (L2Summon) this;
10787
10788 if (activeSummon.getChargedSpiritShot() == L2ItemInstance.CHARGED_SPIRITSHOT)
10789 {
10790 activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
10791 }
10792 }
10793
10794 reloadShots(true);
10795 }
10796
10797 /**
10798 * Check ss.
10799 * @return true, if successful
10800 */
10801 public boolean checkSs()
10802 {
10803
10804 boolean ss = false;
10805
10806 final L2ItemInstance weaponInst = this.getActiveWeaponInstance();
10807
10808 if (weaponInst != null)
10809 {
10810 if (weaponInst.getChargedSoulshot() == L2ItemInstance.CHARGED_SOULSHOT)
10811 {
10812 ss = true;
10813 // weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
10814 }
10815 }
10816 // If there is no weapon equipped, check for an active summon.
10817 else if (this instanceof L2Summon)
10818 {
10819 final L2Summon activeSummon = (L2Summon) this;
10820
10821 if (activeSummon.getChargedSoulShot() == L2ItemInstance.CHARGED_SOULSHOT)
10822 {
10823 ss = true;
10824 // activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
10825 }
10826 }
10827
10828 return ss;
10829
10830 }
10831
10832 /**
10833 * Removes the ss.
10834 */
10835 public void removeSs()
10836 {
10837
10838 final L2ItemInstance weaponInst = this.getActiveWeaponInstance();
10839
10840 if (weaponInst != null)
10841 {
10842 if (weaponInst.getChargedSoulshot() == L2ItemInstance.CHARGED_SOULSHOT)
10843 {
10844 weaponInst.setChargedSoulshot(L2ItemInstance.CHARGED_NONE);
10845 }
10846 }
10847 // If there is no weapon equipped, check for an active summon.
10848 else if (this instanceof L2Summon)
10849 {
10850 final L2Summon activeSummon = (L2Summon) this;
10851
10852 if (activeSummon.getChargedSoulShot() == L2ItemInstance.CHARGED_SOULSHOT)
10853 {
10854 activeSummon.setChargedSoulShot(L2ItemInstance.CHARGED_NONE);
10855 }
10856 }
10857 reloadShots(false);
10858 }
10859
10860 /**
10861 * Return a multiplier based on weapon random damage<BR>
10862 * <BR>
10863 * .
10864 * @return the random damage multiplier
10865 */
10866 public final double getRandomDamageMultiplier()
10867 {
10868 final L2Weapon activeWeapon = getActiveWeaponItem();
10869 int random;
10870
10871 if (activeWeapon != null)
10872 random = activeWeapon.getRandomDamage();
10873 else
10874 random = 5 + (int) Math.sqrt(getLevel());
10875
10876 return (1 + ((double) Rnd.get(0 - random, random) / 100));
10877 }
10878
10879 /**
10880 * Sets the checks if is buff protected.
10881 * @param value the new checks if is buff protected
10882 */
10883 public final void setIsBuffProtected(final boolean value)
10884 {
10885 _isBuffProtected = value;
10886 }
10887
10888 /**
10889 * Checks if is buff protected.
10890 * @return true, if is buff protected
10891 */
10892 public boolean isBuffProtected()
10893 {
10894 return _isBuffProtected;
10895 }
10896
10897 /**
10898 * Gets the _triggered skills.
10899 * @return the _triggeredSkills
10900 */
10901 public Map<Integer, L2Skill> get_triggeredSkills()
10902 {
10903 return _triggeredSkills;
10904 }
10905
10906 /**
10907 * Set target of L2Attackable and update it.
10908 * @author: Nefer
10909 * @param trasformedNpc
10910 */
10911 public void setTargetTrasformedNpc(final L2Attackable trasformedNpc)
10912 {
10913 if (trasformedNpc == null)
10914 return;
10915
10916 // Set the target of the L2PcInstance player
10917 this.setTarget(trasformedNpc);
10918
10919 // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
10920 // The player.getLevel() - getLevel() permit to display the correct color in the select window
10921 MyTargetSelected my = new MyTargetSelected(trasformedNpc.getObjectId(), this.getLevel() - trasformedNpc.getLevel());
10922 this.sendPacket(my);
10923 my = null;
10924
10925 // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
10926 StatusUpdate su = new StatusUpdate(trasformedNpc.getObjectId());
10927 su.addAttribute(StatusUpdate.CUR_HP, (int) trasformedNpc.getCurrentHp());
10928 su.addAttribute(StatusUpdate.MAX_HP, trasformedNpc.getMaxHp());
10929 this.sendPacket(su);
10930 su = null;
10931 }
10932
10933 /**
10934 * @return if the object can be killed
10935 */
10936 public boolean isUnkillable()
10937 {
10938 return _isUnkillable;
10939 }
10940
10941 /**
10942 * @param value the _isKillable to set
10943 */
10944 public void setIsUnkillable(final boolean value)
10945 {
10946 _isUnkillable = value;
10947 }
10948
10949 /**
10950 * @return the _isAttackDisabled
10951 */
10952 public boolean isAttackDisabled()
10953 {
10954 return _isAttackDisabled;
10955 }
10956
10957 /**
10958 * @param value the _isAttackDisabled to set
10959 */
10960 public void setIsAttackDisabled(final boolean value)
10961 {
10962 _isAttackDisabled = value;
10963 }
10964
10965 /*
10966 * AI not. Task
10967 */
10968 static class notifyAiTaskDelayed implements Runnable
10969 {
10970
10971 CtrlEvent event;
10972 Object object;
10973 L2Object tgt;
10974
10975 notifyAiTaskDelayed(final CtrlEvent evt, final Object obj, final L2Object target)
10976 {
10977 event = evt;
10978 object = obj;
10979 tgt = target;
10980 }
10981
10982 @Override
10983 public void run()
10984 {
10985 ((L2Character) tgt).getAI().notifyEvent(event, object);
10986 }
10987
10988 }
10989
10990 public synchronized void reloadShots(boolean isMagic)
10991 {
10992 if ((this instanceof L2PcInstance)) {
10993 ((L2PcInstance)this).rechargeAutoSoulShot(!isMagic, isMagic, false);
10994 } else if ((this instanceof L2Summon)) {
10995 ((L2Summon)this).getOwner().rechargeAutoSoulShot(!isMagic, isMagic, true);
10996 }
10997 }
10998
10999 }