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