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