· 6 years ago · Mar 13, 2019, 10:24 AM
1package net.sf.l2j.gameserver.model.actor.instance;
2
3import java.sql.Connection;
4import java.sql.PreparedStatement;
5import java.sql.ResultSet;
6import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.Collection;
9import java.util.Comparator;
10import java.util.HashMap;
11import java.util.List;
12import java.util.Map;
13import java.util.Optional;
14import java.util.Set;
15import java.util.concurrent.*;
16import java.util.concurrent.atomic.AtomicInteger;
17import java.util.concurrent.locks.ReentrantLock;
18import java.util.logging.Level;
19import java.util.stream.Collectors;
20
21import com.elfocrash.roboto.FakePlayer;
22import net.sf.l2j.Config;
23import net.sf.l2j.L2DatabaseFactory;
24import net.sf.l2j.commons.concurrent.ThreadPool;
25import net.sf.l2j.commons.math.MathUtil;
26import net.sf.l2j.commons.random.Rnd;
27import net.sf.l2j.gameserver.LoginServerThread;
28import net.sf.l2j.gameserver.communitybbs.BB.Forum;
29import net.sf.l2j.gameserver.communitybbs.Manager.ForumsBBSManager;
30import net.sf.l2j.gameserver.data.ItemTable;
31import net.sf.l2j.gameserver.data.SkillTable;
32import net.sf.l2j.gameserver.data.SkillTable.FrequentSkill;
33import net.sf.l2j.gameserver.data.manager.CastleManager;
34import net.sf.l2j.gameserver.data.manager.CoupleManager;
35import net.sf.l2j.gameserver.data.manager.CursedWeaponManager;
36import net.sf.l2j.gameserver.data.manager.DuelManager;
37import net.sf.l2j.gameserver.data.manager.ZoneManager;
38import net.sf.l2j.gameserver.data.sql.ClanTable;
39import net.sf.l2j.gameserver.data.sql.PlayerInfoTable;
40import net.sf.l2j.gameserver.data.xml.AdminData;
41import net.sf.l2j.gameserver.data.xml.FishData;
42import net.sf.l2j.gameserver.data.xml.HennaData;
43import net.sf.l2j.gameserver.data.xml.MapRegionData;
44import net.sf.l2j.gameserver.data.xml.MapRegionData.TeleportType;
45import net.sf.l2j.gameserver.data.xml.NpcData;
46import net.sf.l2j.gameserver.data.xml.PlayerData;
47import net.sf.l2j.gameserver.data.xml.RecipeData;
48import net.sf.l2j.gameserver.events.EventManager;
49import net.sf.l2j.gameserver.events.dailylord.DailyLord;
50import net.sf.l2j.gameserver.geoengine.GeoEngine;
51import net.sf.l2j.gameserver.handler.IItemHandler;
52import net.sf.l2j.gameserver.handler.ItemHandler;
53import net.sf.l2j.gameserver.handler.admincommandhandlers.AdminEditChar;
54import net.sf.l2j.gameserver.instancemanager.DimensionalRiftManager;
55import net.sf.l2j.gameserver.instancemanager.InstanceManager;
56import net.sf.l2j.gameserver.instancemanager.SevenSigns;
57import net.sf.l2j.gameserver.instancemanager.SevenSigns.CabalType;
58import net.sf.l2j.gameserver.instancemanager.SevenSigns.SealType;
59import net.sf.l2j.gameserver.instancemanager.SevenSignsFestival;
60import net.sf.l2j.gameserver.model.AccessLevel;
61import net.sf.l2j.gameserver.model.BlockList;
62import net.sf.l2j.gameserver.model.Fish;
63import net.sf.l2j.gameserver.model.L2Effect;
64import net.sf.l2j.gameserver.model.L2Fishing;
65import net.sf.l2j.gameserver.model.L2Macro;
66import net.sf.l2j.gameserver.model.L2Radar;
67import net.sf.l2j.gameserver.model.L2ShortCut;
68import net.sf.l2j.gameserver.model.L2Skill;
69import net.sf.l2j.gameserver.model.L2Skill.SkillTargetType;
70import net.sf.l2j.gameserver.model.MacroList;
71import net.sf.l2j.gameserver.model.PetDataEntry;
72import net.sf.l2j.gameserver.model.Request;
73import net.sf.l2j.gameserver.model.RewardInfo;
74import net.sf.l2j.gameserver.model.ShortCuts;
75import net.sf.l2j.gameserver.model.ShotType;
76import net.sf.l2j.gameserver.model.World;
77import net.sf.l2j.gameserver.model.WorldObject;
78import net.sf.l2j.gameserver.model.WorldRegion;
79import net.sf.l2j.gameserver.model.actor.Attackable;
80import net.sf.l2j.gameserver.model.actor.Boat;
81import net.sf.l2j.gameserver.model.actor.Creature;
82import net.sf.l2j.gameserver.model.actor.Npc;
83import net.sf.l2j.gameserver.model.actor.Playable;
84import net.sf.l2j.gameserver.model.actor.Summon;
85import net.sf.l2j.gameserver.model.actor.ai.CtrlEvent;
86import net.sf.l2j.gameserver.model.actor.ai.CtrlIntention;
87import net.sf.l2j.gameserver.model.actor.ai.NextAction;
88import net.sf.l2j.gameserver.model.actor.ai.type.CreatureAI;
89import net.sf.l2j.gameserver.model.actor.ai.type.PlayerAI;
90import net.sf.l2j.gameserver.model.actor.ai.type.SummonAI;
91import net.sf.l2j.gameserver.model.actor.appearance.PcAppearance;
92import net.sf.l2j.gameserver.model.actor.stat.PlayerStat;
93import net.sf.l2j.gameserver.model.actor.status.PlayerStatus;
94import net.sf.l2j.gameserver.model.actor.template.PetTemplate;
95import net.sf.l2j.gameserver.model.actor.template.PlayerTemplate;
96import net.sf.l2j.gameserver.model.base.ClassId;
97import net.sf.l2j.gameserver.model.base.ClassRace;
98import net.sf.l2j.gameserver.model.base.ClassType;
99import net.sf.l2j.gameserver.model.base.Experience;
100import net.sf.l2j.gameserver.model.base.Sex;
101import net.sf.l2j.gameserver.model.base.SubClass;
102import net.sf.l2j.gameserver.model.craft.ManufactureList;
103import net.sf.l2j.gameserver.model.entity.Castle;
104import net.sf.l2j.gameserver.model.entity.Duel.DuelState;
105import net.sf.l2j.gameserver.model.entity.Hero;
106import net.sf.l2j.gameserver.model.entity.Instance;
107import net.sf.l2j.gameserver.model.entity.Siege;
108import net.sf.l2j.gameserver.model.entity.Siege.SiegeSide;
109import net.sf.l2j.gameserver.model.group.CommandChannel;
110import net.sf.l2j.gameserver.model.group.Party;
111import net.sf.l2j.gameserver.model.group.Party.LootRule;
112import net.sf.l2j.gameserver.model.group.Party.MessageType;
113import net.sf.l2j.gameserver.model.holder.IntIntHolder;
114import net.sf.l2j.gameserver.model.holder.SkillUseHolder;
115import net.sf.l2j.gameserver.model.holder.skillnode.GeneralSkillNode;
116import net.sf.l2j.gameserver.model.item.Henna;
117import net.sf.l2j.gameserver.model.item.Recipe;
118import net.sf.l2j.gameserver.model.item.instance.ItemInstance;
119import net.sf.l2j.gameserver.model.item.instance.ItemInstance.ItemLocation;
120import net.sf.l2j.gameserver.model.item.instance.ItemInstance.ItemState;
121import net.sf.l2j.gameserver.model.item.kind.Item;
122import net.sf.l2j.gameserver.model.item.kind.Weapon;
123import net.sf.l2j.gameserver.model.item.type.ActionType;
124import net.sf.l2j.gameserver.model.item.type.ArmorType;
125import net.sf.l2j.gameserver.model.item.type.EtcItemType;
126import net.sf.l2j.gameserver.model.item.type.WeaponType;
127import net.sf.l2j.gameserver.model.itemcontainer.Inventory;
128import net.sf.l2j.gameserver.model.itemcontainer.ItemContainer;
129import net.sf.l2j.gameserver.model.itemcontainer.PcFreight;
130import net.sf.l2j.gameserver.model.itemcontainer.PcInventory;
131import net.sf.l2j.gameserver.model.itemcontainer.PcWarehouse;
132import net.sf.l2j.gameserver.model.itemcontainer.PetInventory;
133import net.sf.l2j.gameserver.model.itemcontainer.listeners.ItemPassiveSkillsListener;
134import net.sf.l2j.gameserver.model.location.Location;
135import net.sf.l2j.gameserver.model.location.SpawnLocation;
136import net.sf.l2j.gameserver.model.memo.PlayerMemo;
137import net.sf.l2j.gameserver.model.multisell.PreparedListContainer;
138import net.sf.l2j.gameserver.model.olympiad.OlympiadGameManager;
139import net.sf.l2j.gameserver.model.olympiad.OlympiadGameTask;
140import net.sf.l2j.gameserver.model.olympiad.OlympiadManager;
141import net.sf.l2j.gameserver.model.partymatching.PartyMatchRoom;
142import net.sf.l2j.gameserver.model.partymatching.PartyMatchRoomList;
143import net.sf.l2j.gameserver.model.partymatching.PartyMatchWaitingList;
144import net.sf.l2j.gameserver.model.pledge.Clan;
145import net.sf.l2j.gameserver.model.pledge.ClanMember;
146import net.sf.l2j.gameserver.model.tradelist.TradeList;
147import net.sf.l2j.gameserver.model.zone.ZoneId;
148import net.sf.l2j.gameserver.model.zone.type.BossZone;
149import net.sf.l2j.gameserver.model.zone.type.MultiFunctionZone;
150import net.sf.l2j.gameserver.network.L2GameClient;
151import net.sf.l2j.gameserver.network.SystemMessageId;
152import net.sf.l2j.gameserver.network.clientpackets.Say2;
153import net.sf.l2j.gameserver.network.serverpackets.*;
154import net.sf.l2j.gameserver.network.serverpackets.SetupGauge.GaugeColor;
155import net.sf.l2j.gameserver.scripting.EventType;
156import net.sf.l2j.gameserver.scripting.Quest;
157import net.sf.l2j.gameserver.scripting.QuestState;
158import net.sf.l2j.gameserver.scripting.ScriptManager;
159import net.sf.l2j.gameserver.skills.Env;
160import net.sf.l2j.gameserver.skills.Formulas;
161import net.sf.l2j.gameserver.skills.Stats;
162import net.sf.l2j.gameserver.skills.effects.EffectTemplate;
163import net.sf.l2j.gameserver.skills.funcs.FuncHennaCON;
164import net.sf.l2j.gameserver.skills.funcs.FuncHennaDEX;
165import net.sf.l2j.gameserver.skills.funcs.FuncHennaINT;
166import net.sf.l2j.gameserver.skills.funcs.FuncHennaMEN;
167import net.sf.l2j.gameserver.skills.funcs.FuncHennaSTR;
168import net.sf.l2j.gameserver.skills.funcs.FuncHennaWIT;
169import net.sf.l2j.gameserver.skills.funcs.FuncMaxCpMul;
170import net.sf.l2j.gameserver.skills.l2skills.L2SkillSiegeFlag;
171import net.sf.l2j.gameserver.skills.l2skills.L2SkillSummon;
172import net.sf.l2j.gameserver.taskmanager.AioTaskManager;
173import net.sf.l2j.gameserver.taskmanager.AttackStanceTaskManager;
174import net.sf.l2j.gameserver.taskmanager.GameTimeTaskManager;
175import net.sf.l2j.gameserver.taskmanager.ItemsOnGroundTaskManager;
176import net.sf.l2j.gameserver.taskmanager.PvpFlagTaskManager;
177import net.sf.l2j.gameserver.taskmanager.ShadowItemTaskManager;
178import net.sf.l2j.gameserver.taskmanager.VipTimeTaskManager;
179import net.sf.l2j.gameserver.taskmanager.WaterTaskManager;
180import net.sf.l2j.gameserver.templates.skills.L2EffectFlag;
181import net.sf.l2j.gameserver.templates.skills.L2EffectType;
182import net.sf.l2j.gameserver.templates.skills.L2SkillType;
183import net.sf.l2j.gameserver.util.Broadcast;
184
185/**
186 * This class represents a player in the world.<br>
187 * There is always a client-thread connected to this (except if a player-store is activated upon logout).
188 */
189public class Player extends Playable
190{
191
192 private FakePlayer _fakePlayerUnderControl = null;
193
194 public boolean isControllingFakePlayer() {
195 return _fakePlayerUnderControl != null;
196 }
197
198 public FakePlayer getPlayerUnderControl() {
199 return _fakePlayerUnderControl;
200 }
201
202 public void setPlayerUnderControl(FakePlayer fakePlayer) {
203 _fakePlayerUnderControl = fakePlayer;
204 }
205
206 private Map<Integer, Future<?>> _autoPotTasks = new HashMap<>();
207
208 public boolean isAutoPot(int id)
209 {
210 return _autoPotTasks.keySet().contains(id);
211 }
212
213 public void setAutoPot(int id, Future<?> task, boolean add)
214 {
215 if (add)
216 _autoPotTasks.put(id, task);
217 else
218 {
219 _autoPotTasks.get(id).cancel(true);
220 _autoPotTasks.remove(id);
221 }
222 }
223
224 public enum StoreType
225 {
226 NONE(0),
227 SELL(1),
228 SELL_MANAGE(2),
229 BUY(3),
230 BUY_MANAGE(4),
231 MANUFACTURE(5),
232 PACKAGE_SELL(8);
233
234 private int _id;
235
236 private StoreType(int id)
237 {
238 _id = id;
239 }
240
241 public int getId()
242 {
243 return _id;
244 }
245
246 public static StoreType findById(int id)
247 {
248 for (StoreType StoreType : values())
249 {
250 if (StoreType.getId() == id)
251 return StoreType;
252 }
253 return null;
254 }
255 }
256
257 public enum PunishLevel
258 {
259 NONE(0, ""),
260 CHAT(1, "chat banned"),
261 JAIL(2, "jailed"),
262 CHAR(3, "banned"),
263 ACC(4, "banned");
264
265 private final int punValue;
266 private final String punString;
267
268 PunishLevel(int value, String string)
269 {
270 punValue = value;
271 punString = string;
272 }
273
274 public int value()
275 {
276 return punValue;
277 }
278
279 public String string()
280 {
281 return punString;
282 }
283 }
284
285 private static final String RESTORE_SKILLS_FOR_CHAR = "SELECT skill_id,skill_level FROM character_skills WHERE char_obj_id=? AND class_index=?";
286 private static final String ADD_OR_UPDATE_SKILL = "INSERT INTO character_skills (char_obj_id,skill_id,skill_level,class_index) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE skill_level=VALUES(skill_level)";
287 private static final String DELETE_SKILL_FROM_CHAR = "DELETE FROM character_skills WHERE skill_id=? AND char_obj_id=? AND class_index=?";
288 private static final String DELETE_CHAR_SKILLS = "DELETE FROM character_skills WHERE char_obj_id=? AND class_index=?";
289
290 private static final String ADD_SKILL_SAVE = "INSERT INTO character_skills_save (char_obj_id,skill_id,skill_level,effect_count,effect_cur_time,reuse_delay,systime,restore_type,class_index,buff_index) VALUES (?,?,?,?,?,?,?,?,?,?)";
291 private static final String RESTORE_SKILL_SAVE = "SELECT skill_id,skill_level,effect_count,effect_cur_time, reuse_delay, systime, restore_type FROM character_skills_save WHERE char_obj_id=? AND class_index=? ORDER BY buff_index ASC";
292 private static final String DELETE_SKILL_SAVE = "DELETE FROM character_skills_save WHERE char_obj_id=? AND class_index=?";
293
294 private static final String INSERT_CHARACTER = "INSERT INTO characters (account_name,obj_Id,char_name,level,maxHp,curHp,maxCp,curCp,maxMp,curMp,face,hairStyle,hairColor,sex,exp,sp,karma,pvpkills,pkkills,clanid,race,classid,deletetime,cancraft,title,accesslevel,online,isin7sdungeon,clan_privs,wantspeace,base_class,nobless,power_grade,last_hop_vote,last_top_vote,last_net_vote) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
295 private static final String UPDATE_CHARACTER = "UPDATE characters SET level=?,maxHp=?,curHp=?,maxCp=?,curCp=?,maxMp=?,curMp=?,face=?,hairStyle=?,hairColor=?,sex=?,heading=?,x=?,y=?,z=?,exp=?,expBeforeDeath=?,sp=?,karma=?,pvpkills=?,pkkills=?,clanid=?,race=?,classid=?,deletetime=?,title=?,accesslevel=?,online=?,isin7sdungeon=?,clan_privs=?,wantspeace=?,base_class=?,onlinetime=?,punish_level=?,punish_timer=?,nobless=?,power_grade=?,subpledge=?,lvl_joined_academy=?,apprentice=?,sponsor=?,varka_ketra_ally=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=?,pc_point=?,lastInstance=? WHERE obj_id=?";
296 private static final String RESTORE_CHARACTER = "SELECT * FROM characters WHERE obj_id=?";
297
298 private static final String RESTORE_CHAR_SUBCLASSES = "SELECT class_id,exp,sp,level,class_index FROM character_subclasses WHERE char_obj_id=? ORDER BY class_index ASC";
299 private static final String ADD_CHAR_SUBCLASS = "INSERT INTO character_subclasses (char_obj_id,class_id,exp,sp,level,class_index) VALUES (?,?,?,?,?,?)";
300 private static final String UPDATE_CHAR_SUBCLASS = "UPDATE character_subclasses SET exp=?,sp=?,level=?,class_id=? WHERE char_obj_id=? AND class_index =?";
301 private static final String DELETE_CHAR_SUBCLASS = "DELETE FROM character_subclasses WHERE char_obj_id=? AND class_index=?";
302
303 private static final String RESTORE_CHAR_HENNAS = "SELECT slot,symbol_id FROM character_hennas WHERE char_obj_id=? AND class_index=?";
304 private static final String ADD_CHAR_HENNA = "INSERT INTO character_hennas (char_obj_id,symbol_id,slot,class_index) VALUES (?,?,?,?)";
305 private static final String DELETE_CHAR_HENNA = "DELETE FROM character_hennas WHERE char_obj_id=? AND slot=? AND class_index=?";
306 private static final String DELETE_CHAR_HENNAS = "DELETE FROM character_hennas WHERE char_obj_id=? AND class_index=?";
307 private static final String DELETE_CHAR_SHORTCUTS = "DELETE FROM character_shortcuts WHERE char_obj_id=? AND class_index=?";
308
309 private static final String RESTORE_CHAR_RECOMS = "SELECT char_id,target_id FROM character_recommends WHERE char_id=?";
310 private static final String ADD_CHAR_RECOM = "INSERT INTO character_recommends (char_id,target_id) VALUES (?,?)";
311 private static final String UPDATE_TARGET_RECOM_HAVE = "UPDATE characters SET rec_have=? WHERE obj_Id=?";
312 private static final String UPDATE_CHAR_RECOM_LEFT = "UPDATE characters SET rec_left=? WHERE obj_Id=?";
313
314 private static final String UPDATE_NOBLESS = "UPDATE characters SET nobless=? WHERE obj_Id=?";
315
316 public static final int REQUEST_TIMEOUT = 15;
317
318 private static final Comparator<GeneralSkillNode> COMPARE_SKILLS_BY_MIN_LVL = Comparator.comparing(GeneralSkillNode::getMinLvl);
319 private static final Comparator<GeneralSkillNode> COMPARE_SKILLS_BY_LVL = Comparator.comparing(GeneralSkillNode::getValue);
320
321 private L2GameClient _client;
322 private final Map<Integer, String> _chars = new HashMap<>();
323
324 //Player watch private msg
325 private final List<Player> _watchers = new CopyOnWriteArrayList<>();
326
327 private String _accountName;
328 private long _deleteTimer;
329
330 private boolean _isOnline;
331 private long _onlineTime;
332 private long _onlineBeginTime;
333 private long _lastAccess;
334 private long _uptime;
335 private long _lastHopVote;
336 private long _lastTopVote;
337 private long _lastNetVote;
338
339 protected int _baseClass;
340 protected int _activeClass;
341 protected int _classIndex;
342
343 private final Map<Integer, SubClass> _subClasses = new ConcurrentSkipListMap<>();
344 private final ReentrantLock _subclassLock = new ReentrantLock();
345
346 private PcAppearance _appearance;
347
348 private long _expBeforeDeath;
349 private int pcBangPoint = 0;
350 public int _tvtkills;
351 public int _killCount;
352 private int antiAfkTime;
353 private int _karma;
354 private int _pvpKills;
355 private int _pkKills;
356 private byte _pvpFlag;
357 private byte _siegeState;
358 private int _curWeightPenalty;
359
360 private int _lastCompassZone; // the last compass zone update send to the client
361
362 private boolean _isIn7sDungeon;
363
364 private PunishLevel _punishLevel = PunishLevel.NONE;
365 private long _punishTimer;
366 private ScheduledFuture<?> _punishTask;
367
368 private boolean _isInOlympiadMode;
369 private boolean _isInOlympiadStart;
370 private int _olympiadGameId = -1;
371 private int _olympiadSide = -1;
372
373 private DuelState _duelState = DuelState.NO_DUEL;
374 private int _duelId;
375 private SystemMessageId _noDuelReason = SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL;
376
377 private Boat _boat;
378 private SpawnLocation _boatPosition = new SpawnLocation(0, 0, 0, 0);
379
380 private ScheduledFuture<?> _fishingTask;
381
382 private boolean _canFeed;
383 protected PetTemplate _petTemplate;
384 private PetDataEntry _petData;
385 private int _controlItemId;
386 private int _curFeed;
387 protected Future<?> _mountFeedTask;
388 private ScheduledFuture<?> _dismountTask;
389
390 private int _mountType;
391 private int _mountNpcId;
392 private int _mountLevel;
393 private int _mountObjectId;
394
395 protected int _throneId;
396
397 private int _teleMode;
398 private boolean _isCrystallizing;
399 private boolean _isCrafting;
400 private long _offlineShopStart = 0;
401 private boolean _isVoting;
402
403 private final Map<Integer, Recipe> _dwarvenRecipeBook = new HashMap<>();
404 private final Map<Integer, Recipe> _commonRecipeBook = new HashMap<>();
405
406 private boolean _isSitting;
407
408 private final Location _savedLocation = new Location(0, 0, 0);
409
410 private int _recomHave;
411 private int _recomLeft;
412 private final List<Integer> _recomChars = new ArrayList<>();
413
414 private final PcInventory _inventory = new PcInventory(this);
415 private PcWarehouse _warehouse;
416 private PcFreight _freight;
417 private final List<PcFreight> _depositedFreight = new ArrayList<>();
418
419 private StoreType _storeType = StoreType.NONE;
420
421 private TradeList _activeTradeList;
422 private ItemContainer _activeWarehouse;
423 private ManufactureList _createList;
424 private TradeList _sellList;
425 private TradeList _buyList;
426
427 private PreparedListContainer _currentMultiSell;
428
429 private boolean _isNoble;
430 private boolean _isHero;
431 private boolean _isAio;
432
433 private boolean _Afk = false;
434
435 private int _lastInstance = 0;
436
437 private Folk _currentFolk;
438
439 private int _questNpcObject;
440
441 private final List<QuestState> _quests = new ArrayList<>();
442 private final List<QuestState> _notifyQuestOfDeathList = new ArrayList<>();
443
444 private final PlayerMemo _vars = new PlayerMemo(getObjectId());
445
446 private final ShortCuts _shortCuts = new ShortCuts(this);
447
448 private final MacroList _macroses = new MacroList(this);
449
450 private final Henna[] _henna = new Henna[3];
451 private int _hennaSTR;
452 private int _hennaINT;
453 private int _hennaDEX;
454 private int _hennaMEN;
455 private int _hennaWIT;
456 private int _hennaCON;
457
458 private Summon _summon;
459 private TamedBeast _tamedBeast;
460
461 // TODO: This needs to be better integrated and saved/loaded
462 private L2Radar _radar;
463
464 private int _partyroom;
465
466 private int _clanId;
467 private Clan _clan;
468 private int _apprentice;
469 private int _sponsor;
470 private long _clanJoinExpiryTime;
471 private long _clanCreateExpiryTime;
472 private int _powerGrade;
473 private int _clanPrivileges;
474 private int _pledgeClass;
475 private int _pledgeType;
476 private int _lvlJoinedAcademy;
477
478 private boolean _wantsPeace;
479
480 private int _deathPenaltyBuffLevel;
481
482 private final AtomicInteger _charges = new AtomicInteger();
483 private ScheduledFuture<?> _chargeTask;
484
485 private Location _currentSkillWorldPosition;
486
487 private AccessLevel _accessLevel;
488
489 private boolean _messageRefusal; // message refusal mode
490 private boolean _tradeRefusal; // Trade refusal
491 private boolean _exchangeRefusal; // Exchange refusal
492
493 private Party _party;
494 private LootRule _lootRule;
495
496 private Player _activeRequester;
497 private long _requestExpireTime;
498 private final Request _request = new Request(this);
499
500 private ScheduledFuture<?> _protectTask;
501
502 private long _recentFakeDeathEndTime;
503 private boolean _isFakeDeath;
504
505 private int _expertiseArmorPenalty;
506 private boolean _expertiseWeaponPenalty;
507
508 private ItemInstance _activeEnchantItem;
509
510 protected boolean _inventoryDisable;
511
512 protected Map<Integer, Cubic> _cubics = new ConcurrentSkipListMap<>();
513
514 protected Set<Integer> _activeSoulShots = ConcurrentHashMap.newKeySet(1);
515
516 private final int _loto[] = new int[5];
517 private final int _race[] = new int[2];
518
519 private final BlockList _blockList = new BlockList(this);
520
521 private int _team;
522
523 private int _alliedVarkaKetra; // lvl of alliance with ketra orcs or varka silenos, used in quests and aggro checks [-5,-1] varka, 0 neutral, [1,5] ketra
524
525 private Location _fishingLoc;
526 private ItemInstance _lure;
527 private L2Fishing _fishCombat;
528 private Fish _fish;
529
530 private final List<String> _validBypass = new ArrayList<>();
531 private final List<String> _validBypass2 = new ArrayList<>();
532
533 private Forum _forumMemo;
534
535 private boolean _isInSiege;
536
537 private final Map<Integer, L2Skill> _skills = new ConcurrentSkipListMap<>();
538
539 private final SkillUseHolder _currentSkill = new SkillUseHolder();
540 private final SkillUseHolder _currentPetSkill = new SkillUseHolder();
541 private final SkillUseHolder _queuedSkill = new SkillUseHolder();
542
543 private int _cursedWeaponEquippedId;
544
545 private int _reviveRequested;
546 private double _revivePower = .0;
547 private boolean _revivePet;
548
549 private double _cpUpdateIncCheck = .0;
550 private double _cpUpdateDecCheck = .0;
551 private double _cpUpdateInterval = .0;
552 private double _mpUpdateIncCheck = .0;
553 private double _mpUpdateDecCheck = .0;
554 private double _mpUpdateInterval = .0;
555
556 private int _clientX;
557 private int _clientY;
558 private int _clientZ;
559 private int _clientHeading;
560
561 private int _mailPosition;
562 private boolean _isVipStatus;
563
564 private static final int FALLING_VALIDATION_DELAY = 10000;
565 private volatile long _fallingTimestamp;
566
567 private ScheduledFuture<?> _shortBuffTask;
568 private int _shortBuffTaskSkillId;
569
570 private int _coupleId;
571 private boolean _isUnderMarryRequest;
572 private int _requesterId;
573
574 private final List<Integer> _friendList = new ArrayList<>(); // Related to CB.
575 private final List<Integer> _selectedFriendList = new ArrayList<>(); // Related to CB.
576 private final List<Integer> _selectedBlocksList = new ArrayList<>(); // Related to CB.
577
578 private Player _summonTargetRequest;
579 private L2Skill _summonSkillRequest;
580
581 private Door _requestedGate;
582
583 private List<WorldObject> _knownObjects = new ArrayList<>();
584
585 /**
586 * Constructor of Player (use Creature constructor).
587 * <ul>
588 * <li>Call the Creature constructor to create an empty _skills slot and copy basic Calculator set to this Player</li>
589 * <li>Set the name of the Player</li>
590 * </ul>
591 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method SET the level of the Player to 1</B></FONT>
592 * @param objectId Identifier of the object to initialized
593 * @param template The L2PcTemplate to apply to the Player
594 * @param accountName The name of the account including this Player
595 * @param app The PcAppearance of the Player
596 */
597 protected Player(int objectId, PlayerTemplate template, String accountName, PcAppearance app)
598 {
599 super(objectId, template);
600
601 initCharStatusUpdateValues();
602
603 _accountName = accountName;
604 _appearance = app;
605
606 // Create an AI
607 _ai = new PlayerAI(this);
608
609 // Create a L2Radar object
610 _radar = new L2Radar(this);
611
612 // Retrieve from the database all items of this Player and add them to _inventory
613 getInventory().restore();
614 getWarehouse();
615 getFreight();
616 }
617
618 protected Player(int objectId)
619 {
620 super(objectId, null);
621
622 initCharStatusUpdateValues();
623 }
624
625 /**
626 * Create a new Player and add it in the characters table of the database.
627 * <ul>
628 * <li>Create a new Player with an account name</li>
629 * <li>Set the name, the Hair Style, the Hair Color and the Face type of the Player</li>
630 * <li>Add the player in the characters table of the database</li>
631 * </ul>
632 * @param objectId Identifier of the object to initialized
633 * @param template The L2PcTemplate to apply to the Player
634 * @param accountName The name of the Player
635 * @param name The name of the Player
636 * @param hairStyle The hair style Identifier of the Player
637 * @param hairColor The hair color Identifier of the Player
638 * @param face The face type Identifier of the Player
639 * @param sex The sex type Identifier of the Player
640 * @return The Player added to the database or null
641 */
642 public static Player create(int objectId, PlayerTemplate template, String accountName, String name, byte hairStyle, byte hairColor, byte face, Sex sex)
643 {
644 // Create a new Player with an account name
645 PcAppearance app = new PcAppearance(face, hairColor, hairStyle, sex);
646 Player player = new Player(objectId, template, accountName, app);
647
648 // Set the name of the Player
649 player.setName(name);
650
651 // Set access level
652 player.setAccessLevel(Config.DEFAULT_ACCESS_LEVEL);
653
654 // Cache few informations into CharNameTable.
655 PlayerInfoTable.getInstance().addPlayer(objectId, accountName, name, player.getAccessLevel().getLevel());
656
657 // Set the base class ID to that of the actual class ID.
658 player.setBaseClass(player.getClassId());
659
660 // Add the player in the characters table of the database
661 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
662 {
663 PreparedStatement statement = con.prepareStatement(INSERT_CHARACTER);
664 statement.setString(1, accountName);
665 statement.setInt(2, player.getObjectId());
666 statement.setString(3, player.getName());
667 statement.setInt(4, player.getLevel());
668 statement.setInt(5, player.getMaxHp());
669 statement.setDouble(6, player.getCurrentHp());
670 statement.setInt(7, player.getMaxCp());
671 statement.setDouble(8, player.getCurrentCp());
672 statement.setInt(9, player.getMaxMp());
673 statement.setDouble(10, player.getCurrentMp());
674 statement.setInt(11, player.getAppearance().getFace());
675 statement.setInt(12, player.getAppearance().getHairStyle());
676 statement.setInt(13, player.getAppearance().getHairColor());
677 statement.setInt(14, player.getAppearance().getSex().ordinal());
678 statement.setLong(15, player.getExp());
679 statement.setInt(16, player.getSp());
680 statement.setInt(17, player.getKarma());
681 statement.setInt(18, player.getPvpKills());
682 statement.setInt(19, player.getPkKills());
683 statement.setInt(20, player.getClanId());
684 statement.setInt(21, player.getRace().ordinal());
685 statement.setInt(22, player.getClassId().getId());
686 statement.setLong(23, player.getDeleteTimer());
687 statement.setInt(24, player.hasDwarvenCraft() ? 1 : 0);
688 statement.setString(25, player.getTitle());
689 statement.setInt(26, player.getAccessLevel().getLevel());
690 statement.setInt(27, player.isOnlineInt());
691 statement.setInt(28, player.isIn7sDungeon() ? 1 : 0);
692 statement.setInt(29, player.getClanPrivileges());
693 statement.setInt(30, player.wantsPeace() ? 1 : 0);
694 statement.setInt(31, player.getBaseClass());
695 statement.setInt(32, player.isNoble() ? 1 : 0);
696 statement.setLong(33, 0);
697 statement.setLong(34, System.currentTimeMillis()-43200000);
698 statement.setLong(35, System.currentTimeMillis()-43200000);
699 statement.setLong(36, System.currentTimeMillis()-43200000);
700 statement.executeUpdate();
701 statement.close();
702 }
703 catch (Exception e)
704 {
705 _log.severe("Could not insert char data: " + e);
706 return null;
707 }
708
709 return player;
710 }
711
712 @Override
713 public void addFuncsToNewCharacter()
714 {
715 // Add Creature functionalities.
716 super.addFuncsToNewCharacter();
717
718 addStatFunc(FuncMaxCpMul.getInstance());
719
720 addStatFunc(FuncHennaSTR.getInstance());
721 addStatFunc(FuncHennaDEX.getInstance());
722 addStatFunc(FuncHennaINT.getInstance());
723 addStatFunc(FuncHennaMEN.getInstance());
724 addStatFunc(FuncHennaCON.getInstance());
725 addStatFunc(FuncHennaWIT.getInstance());
726 }
727
728 @Override
729 protected void initCharStatusUpdateValues()
730 {
731 super.initCharStatusUpdateValues();
732
733 _cpUpdateInterval = getMaxCp() / 352.0;
734 _cpUpdateIncCheck = getMaxCp();
735 _cpUpdateDecCheck = getMaxCp() - _cpUpdateInterval;
736 _mpUpdateInterval = getMaxMp() / 352.0;
737 _mpUpdateIncCheck = getMaxMp();
738 _mpUpdateDecCheck = getMaxMp() - _mpUpdateInterval;
739 }
740
741 @Override
742 public void initCharStat()
743 {
744 setStat(new PlayerStat(this));
745 }
746
747 @Override
748 public final PlayerStat getStat()
749 {
750 return (PlayerStat) super.getStat();
751 }
752
753 @Override
754 public void initCharStatus()
755 {
756 setStatus(new PlayerStatus(this));
757 }
758
759 @Override
760 public final PlayerStatus getStatus()
761 {
762 return (PlayerStatus) super.getStatus();
763 }
764
765 public final PcAppearance getAppearance()
766 {
767 return _appearance;
768 }
769
770 /**
771 * @return the base L2PcTemplate link to the Player.
772 */
773 public final PlayerTemplate getBaseTemplate()
774 {
775 return PlayerData.getInstance().getTemplate(_baseClass);
776 }
777
778 /** Return the L2PcTemplate link to the Player. */
779 @Override
780 public final PlayerTemplate getTemplate()
781 {
782 return (PlayerTemplate) super.getTemplate();
783 }
784
785 public void setTemplate(ClassId newclass)
786 {
787 super.setTemplate(PlayerData.getInstance().getTemplate(newclass));
788 }
789
790 /**
791 * Return the AI of the Player (create it if necessary).
792 */
793 @Override
794 public CreatureAI getAI()
795 {
796 CreatureAI ai = _ai;
797 if (ai == null)
798 {
799 synchronized (this)
800 {
801 if (_ai == null)
802 _ai = new PlayerAI(this);
803
804 return _ai;
805 }
806 }
807 return ai;
808 }
809
810 /** Return the Level of the Player. */
811 @Override
812 public final int getLevel()
813 {
814 return getStat().getLevel();
815 }
816
817 /**
818 * A newbie is a player reaching level 6. He isn't considered newbie at lvl 25.<br>
819 * Since IL newbie isn't anymore the first character of an account reaching that state, but any.
820 * @return True if newbie.
821 */
822 public boolean isNewbie()
823 {
824 return getClassId().level() <= 1 && getLevel() >= 6 && getLevel() <= 25;
825 }
826
827 public void setBaseClass(int baseClass)
828 {
829 _baseClass = baseClass;
830 }
831
832 public void setBaseClass(ClassId classId)
833 {
834 _baseClass = classId.ordinal();
835 }
836
837 public boolean isInStoreMode()
838 {
839 return _storeType != StoreType.NONE;
840 }
841
842 public boolean isCrafting()
843 {
844 return _isCrafting;
845 }
846
847 public void setCrafting(boolean state)
848 {
849 _isCrafting = state;
850 }
851
852 public void logout()
853 {
854 logout(true);
855 }
856
857 public void logout(boolean closeClient)
858 {
859 try
860 {
861 closeNetConnection(closeClient);
862 }
863 catch (Exception e)
864 {
865 _log.log(Level.WARNING, "Exception on logout(): " + e.getMessage(), e);
866 }
867 }
868
869 /**
870 * @return a table containing all Common RecipeList of the Player.
871 */
872 public Collection<Recipe> getCommonRecipeBook()
873 {
874 return _commonRecipeBook.values();
875 }
876
877 /**
878 * @return a table containing all Dwarf RecipeList of the Player.
879 */
880 public Collection<Recipe> getDwarvenRecipeBook()
881 {
882 return _dwarvenRecipeBook.values();
883 }
884
885 /**
886 * Add a new L2RecipList to the table _commonrecipebook containing all RecipeList of the Player.
887 * @param recipe The RecipeList to add to the _recipebook
888 */
889 public void registerCommonRecipeList(Recipe recipe)
890 {
891 _commonRecipeBook.put(recipe.getId(), recipe);
892 }
893
894 /**
895 * Add a new L2RecipList to the table _recipebook containing all RecipeList of the Player.
896 * @param recipe The RecipeList to add to the _recipebook
897 */
898 public void registerDwarvenRecipeList(Recipe recipe)
899 {
900 _dwarvenRecipeBook.put(recipe.getId(), recipe);
901 }
902
903 /**
904 * @param recipeId The Identifier of the RecipeList to check in the player's recipe books
905 * @return <b>TRUE</b> if player has the recipe on Common or Dwarven Recipe book else returns <b>FALSE</b>
906 */
907 public boolean hasRecipeList(int recipeId)
908 {
909 return _dwarvenRecipeBook.containsKey(recipeId) || _commonRecipeBook.containsKey(recipeId);
910 }
911
912 /**
913 * Tries to remove a L2RecipList from the table _DwarvenRecipeBook or from table _CommonRecipeBook, those table contain all RecipeList of the Player.
914 * @param recipeId The Identifier of the RecipeList to remove from the _recipebook.
915 */
916 public void unregisterRecipeList(int recipeId)
917 {
918 if (_dwarvenRecipeBook.containsKey(recipeId))
919 _dwarvenRecipeBook.remove(recipeId);
920 else if (_commonRecipeBook.containsKey(recipeId))
921 _commonRecipeBook.remove(recipeId);
922 else
923 _log.warning("Attempted to remove unknown RecipeList: " + recipeId);
924
925 for (L2ShortCut sc : getAllShortCuts())
926 {
927 if (sc != null && sc.getId() == recipeId && sc.getType() == L2ShortCut.TYPE_RECIPE)
928 deleteShortCut(sc.getSlot(), sc.getPage());
929 }
930 }
931
932 /**
933 * @return the Id for the last talked quest NPC.
934 */
935 public int getLastQuestNpcObject()
936 {
937 return _questNpcObject;
938 }
939
940 public void setLastQuestNpcObject(int npcId)
941 {
942 _questNpcObject = npcId;
943 }
944
945 /**
946 * @param name The name of the quest.
947 * @return The QuestState object corresponding to the quest name.
948 */
949 public QuestState getQuestState(String name)
950 {
951 for (QuestState qs : _quests)
952 {
953 if (name.equals(qs.getQuest().getName()))
954 return qs;
955 }
956 return null;
957 }
958
959 /**
960 * Add a QuestState to the table _quest containing all quests began by the Player.
961 * @param qs The QuestState to add to _quest.
962 */
963 public void setQuestState(QuestState qs)
964 {
965 _quests.add(qs);
966 }
967
968 /**
969 * Remove a QuestState from the table _quest containing all quests began by the Player.
970 * @param qs : The QuestState to be removed from _quest.
971 */
972 public void delQuestState(QuestState qs)
973 {
974 _quests.remove(qs);
975 }
976
977 /**
978 * @param completed : If true, include completed quests to the list.
979 * @return list of started and eventually completed quests of the player.
980 */
981 public List<Quest> getAllQuests(boolean completed)
982 {
983 List<Quest> quests = new ArrayList<>();
984
985 for (QuestState qs : _quests)
986 {
987 if (qs == null || completed && qs.isCreated() || !completed && !qs.isStarted())
988 continue;
989
990 Quest quest = qs.getQuest();
991 if (quest == null || !quest.isRealQuest())
992 continue;
993
994 quests.add(quest);
995 }
996
997 return quests;
998 }
999
1000 public void processQuestEvent(String questName, String event)
1001 {
1002 Quest quest = ScriptManager.getInstance().getQuest(questName);
1003 if (quest == null)
1004 return;
1005
1006 QuestState qs = getQuestState(questName);
1007 if (qs == null)
1008 return;
1009
1010 WorldObject object = World.getInstance().getObject(getLastQuestNpcObject());
1011 if (!(object instanceof Npc) || !isInsideRadius(object, Npc.INTERACTION_DISTANCE, false, false))
1012 return;
1013
1014 Npc npc = (Npc) object;
1015 List<Quest> quests = npc.getTemplate().getEventQuests(EventType.ON_TALK);
1016 if (quests != null)
1017 {
1018 for (Quest onTalk : quests)
1019 {
1020 if (onTalk == null || !onTalk.equals(quest))
1021 continue;
1022
1023 quest.notifyEvent(event, npc, this);
1024 break;
1025 }
1026 }
1027 }
1028
1029 /**
1030 * Add QuestState instance that is to be notified of Player's death.
1031 * @param qs The QuestState that subscribe to this event
1032 */
1033 public void addNotifyQuestOfDeath(QuestState qs)
1034 {
1035 if (qs == null)
1036 return;
1037
1038 if (!_notifyQuestOfDeathList.contains(qs))
1039 _notifyQuestOfDeathList.add(qs);
1040 }
1041
1042 /**
1043 * Remove QuestState instance that is to be notified of Player's death.
1044 * @param qs The QuestState that subscribe to this event
1045 */
1046 public void removeNotifyQuestOfDeath(QuestState qs)
1047 {
1048 if (qs == null)
1049 return;
1050
1051 _notifyQuestOfDeathList.remove(qs);
1052 }
1053
1054 /**
1055 * @return A list of QuestStates which registered for notify of death of this Player.
1056 */
1057 public final List<QuestState> getNotifyQuestOfDeath()
1058 {
1059 return _notifyQuestOfDeathList;
1060 }
1061
1062 /**
1063 * @return player memos.
1064 */
1065 public PlayerMemo getMemos()
1066 {
1067 return _vars;
1068 }
1069
1070 /**
1071 * @return A table containing all L2ShortCut of the Player.
1072 */
1073 public L2ShortCut[] getAllShortCuts()
1074 {
1075 return _shortCuts.getAllShortCuts();
1076 }
1077
1078 /**
1079 * @param slot The slot in wich the shortCuts is equipped
1080 * @param page The page of shortCuts containing the slot
1081 * @return The L2ShortCut of the Player corresponding to the position (page-slot).
1082 */
1083 public L2ShortCut getShortCut(int slot, int page)
1084 {
1085 return _shortCuts.getShortCut(slot, page);
1086 }
1087
1088 /**
1089 * Add a L2shortCut to the Player _shortCuts
1090 * @param shortcut The shortcut to add.
1091 */
1092 public void registerShortCut(L2ShortCut shortcut)
1093 {
1094 _shortCuts.registerShortCut(shortcut);
1095 }
1096
1097 /**
1098 * Delete the L2ShortCut corresponding to the position (page-slot) from the Player _shortCuts.
1099 * @param slot
1100 * @param page
1101 */
1102 public void deleteShortCut(int slot, int page)
1103 {
1104 _shortCuts.deleteShortCut(slot, page);
1105 }
1106
1107 /**
1108 * Add a L2Macro to the Player _macroses.
1109 * @param macro The Macro object to add.
1110 */
1111 public void registerMacro(L2Macro macro)
1112 {
1113 _macroses.registerMacro(macro);
1114 }
1115
1116 /**
1117 * Delete the L2Macro corresponding to the Identifier from the Player _macroses.
1118 * @param id
1119 */
1120 public void deleteMacro(int id)
1121 {
1122 _macroses.deleteMacro(id);
1123 }
1124
1125 /**
1126 * @return all L2Macro of the Player.
1127 */
1128 public MacroList getMacroses()
1129 {
1130 return _macroses;
1131 }
1132
1133 /**
1134 * Set the siege state of the Player.
1135 * @param siegeState 1 = attacker, 2 = defender, 0 = not involved
1136 */
1137 public void setSiegeState(byte siegeState)
1138 {
1139 _siegeState = siegeState;
1140 }
1141
1142 /**
1143 * @return the siege state of the Player.
1144 */
1145 public byte getSiegeState()
1146 {
1147 return _siegeState;
1148 }
1149
1150 /**
1151 * Set the PvP Flag of the Player.
1152 * @param pvpFlag 0 or 1.
1153 */
1154 public void setPvpFlag(int pvpFlag)
1155 {
1156 _pvpFlag = (byte) pvpFlag;
1157 }
1158
1159 @Override
1160 public byte getPvpFlag()
1161 {
1162 return _pvpFlag;
1163 }
1164
1165 public void updatePvPFlag(int value)
1166 {
1167 if (getPvpFlag() == value)
1168 return;
1169
1170 setPvpFlag(value);
1171 sendPacket(new UserInfo(this));
1172
1173 if (getPet() != null)
1174 sendPacket(new RelationChanged(getPet(), getRelation(this), false));
1175
1176 broadcastRelationsChanges();
1177 }
1178
1179 public int getRelation(Player target)
1180 {
1181 int result = 0;
1182
1183 // karma and pvp may not be required
1184 if (getPvpFlag() != 0)
1185 result |= RelationChanged.RELATION_PVP_FLAG;
1186 if (getKarma() > 0)
1187 result |= RelationChanged.RELATION_HAS_KARMA;
1188
1189 if (isClanLeader())
1190 result |= RelationChanged.RELATION_LEADER;
1191
1192 if (getSiegeState() != 0)
1193 {
1194 result |= RelationChanged.RELATION_INSIEGE;
1195 if (getSiegeState() != target.getSiegeState())
1196 result |= RelationChanged.RELATION_ENEMY;
1197 else
1198 result |= RelationChanged.RELATION_ALLY;
1199 if (getSiegeState() == 1)
1200 result |= RelationChanged.RELATION_ATTACKER;
1201 }
1202
1203 if (getClan() != null && target.getClan() != null)
1204 {
1205 if (target.getPledgeType() != Clan.SUBUNIT_ACADEMY && getPledgeType() != Clan.SUBUNIT_ACADEMY && target.getClan().isAtWarWith(getClan().getClanId()))
1206 {
1207 result |= RelationChanged.RELATION_1SIDED_WAR;
1208 if (getClan().isAtWarWith(target.getClan().getClanId()))
1209 result |= RelationChanged.RELATION_MUTUAL_WAR;
1210 }
1211 }
1212 return result;
1213 }
1214
1215 @Override
1216 public void revalidateZone(boolean force)
1217 {
1218 super.revalidateZone(force);
1219
1220 if (Config.ALLOW_WATER)
1221 {
1222 if (isInsideZone(ZoneId.WATER))
1223 WaterTaskManager.getInstance().add(this);
1224 else
1225 WaterTaskManager.getInstance().remove(this);
1226 }
1227
1228 if (isInsideZone(ZoneId.SIEGE))
1229 {
1230 if (_lastCompassZone == ExSetCompassZoneCode.SIEGEWARZONE2)
1231 return;
1232
1233 _lastCompassZone = ExSetCompassZoneCode.SIEGEWARZONE2;
1234 sendPacket(new ExSetCompassZoneCode(ExSetCompassZoneCode.SIEGEWARZONE2));
1235 }
1236 else if (isInsideZone(ZoneId.PVP))
1237 {
1238 if (_lastCompassZone == ExSetCompassZoneCode.PVPZONE)
1239 return;
1240
1241 _lastCompassZone = ExSetCompassZoneCode.PVPZONE;
1242 sendPacket(new ExSetCompassZoneCode(ExSetCompassZoneCode.PVPZONE));
1243 }
1244 else if (isIn7sDungeon())
1245 {
1246 if (_lastCompassZone == ExSetCompassZoneCode.SEVENSIGNSZONE)
1247 return;
1248
1249 _lastCompassZone = ExSetCompassZoneCode.SEVENSIGNSZONE;
1250 sendPacket(new ExSetCompassZoneCode(ExSetCompassZoneCode.SEVENSIGNSZONE));
1251 }
1252 else if (isInsideZone(ZoneId.PEACE))
1253 {
1254 if (_lastCompassZone == ExSetCompassZoneCode.PEACEZONE)
1255 return;
1256
1257 _lastCompassZone = ExSetCompassZoneCode.PEACEZONE;
1258 sendPacket(new ExSetCompassZoneCode(ExSetCompassZoneCode.PEACEZONE));
1259 }
1260 else
1261 {
1262 if (_lastCompassZone == ExSetCompassZoneCode.GENERALZONE)
1263 return;
1264
1265 if (_lastCompassZone == ExSetCompassZoneCode.SIEGEWARZONE2)
1266 updatePvPStatus();
1267
1268 _lastCompassZone = ExSetCompassZoneCode.GENERALZONE;
1269 sendPacket(new ExSetCompassZoneCode(ExSetCompassZoneCode.GENERALZONE));
1270 }
1271 }
1272
1273 /**
1274 * @return the PK counter of the Player.
1275 */
1276 public int getPkKills()
1277 {
1278 return _pkKills;
1279 }
1280
1281 /**
1282 * Set the PK counter of the Player.
1283 * @param pkKills A number.
1284 */
1285 public void setPkKills(int pkKills)
1286 {
1287 _pkKills = pkKills;
1288 }
1289
1290 /**
1291 * @return The _deleteTimer of the Player.
1292 */
1293 public long getDeleteTimer()
1294 {
1295 return _deleteTimer;
1296 }
1297
1298 /**
1299 * Set the _deleteTimer of the Player.
1300 * @param deleteTimer Time in ms.
1301 */
1302 public void setDeleteTimer(long deleteTimer)
1303 {
1304 _deleteTimer = deleteTimer;
1305 }
1306
1307 /**
1308 * @return The current weight of the Player.
1309 */
1310 public int getCurrentLoad()
1311 {
1312 return _inventory.getTotalWeight();
1313 }
1314
1315 /**
1316 * @return The number of recommandation obtained by the Player.
1317 */
1318 public int getRecomHave()
1319 {
1320 return _recomHave;
1321 }
1322
1323 /**
1324 * Increment the number of recommandation obtained by the Player (Max : 255).
1325 * Set the number of recommandations obtained by the Player (Max : 255).
1326 * @param value Number of recommandations obtained.
1327 */
1328 public void setRecomHave(int value)
1329 {
1330 _recomHave = MathUtil.limit(value, 0, 255);
1331 }
1332
1333 /**
1334 * Edit the number of recommandation obtained by the Player (Max : 255).
1335 * @param value : The value to add or remove.
1336 */
1337 public void editRecomHave(int value)
1338 {
1339 _recomHave = MathUtil.limit(_recomHave + value, 0, 255);
1340 }
1341
1342 /**
1343 * @return The number of recommandation that the Player can give.
1344 */
1345 public int getRecomLeft()
1346 {
1347 return _recomLeft;
1348 }
1349
1350 /**
1351 * Set the number of givable recommandations by the {@link Player} (Max : 9).
1352 * @param value : The number of recommendations a player can give.
1353 */
1354 public void setRecomLeft(int value)
1355 {
1356 _recomLeft = MathUtil.limit(value, 0, 9);
1357 }
1358
1359 /**
1360 * Increment the number of recommandation that the Player can give.
1361 */
1362 protected void decRecomLeft()
1363 {
1364 if (_recomLeft > 0)
1365 _recomLeft--;
1366 }
1367
1368 public List<Integer> getRecomChars()
1369 {
1370 return _recomChars;
1371 }
1372
1373 public void giveRecom(Player target)
1374 {
1375 target.editRecomHave(1);
1376 decRecomLeft();
1377
1378 _recomChars.add(target.getObjectId());
1379
1380 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
1381 {
1382 PreparedStatement ps = con.prepareStatement(ADD_CHAR_RECOM);
1383 ps.setInt(1, getObjectId());
1384 ps.setInt(2, target.getObjectId());
1385 ps.execute();
1386 ps.close();
1387
1388 ps = con.prepareStatement(UPDATE_TARGET_RECOM_HAVE);
1389 ps.setInt(1, target.getRecomHave());
1390 ps.setInt(2, target.getObjectId());
1391 ps.execute();
1392 ps.close();
1393
1394 ps = con.prepareStatement(UPDATE_CHAR_RECOM_LEFT);
1395 ps.setInt(1, getRecomLeft());
1396 ps.setInt(2, getObjectId());
1397 ps.execute();
1398 ps.close();
1399 }
1400 catch (Exception e)
1401 {
1402 _log.warning("Could not update char recommendations: " + e);
1403 }
1404 }
1405
1406 public boolean canRecom(Player target)
1407 {
1408 return !_recomChars.contains(target.getObjectId());
1409 }
1410
1411 /**
1412 * Set the exp of the Player before a death
1413 * @param exp
1414 */
1415 public void setExpBeforeDeath(long exp)
1416 {
1417 _expBeforeDeath = exp;
1418 }
1419
1420 public long getExpBeforeDeath()
1421 {
1422 return _expBeforeDeath;
1423 }
1424
1425 /**
1426 * Return the Karma of the Player.
1427 */
1428 @Override
1429 public int getKarma()
1430 {
1431 return _karma;
1432 }
1433
1434 /**
1435 * Set the Karma of the Player and send StatusUpdate (broadcast).
1436 * @param karma A value.
1437 */
1438 public void setKarma(int karma)
1439 {
1440 if (karma < 0)
1441 karma = 0;
1442
1443 if (_karma > 0 && karma == 0)
1444 {
1445 sendPacket(new UserInfo(this));
1446 broadcastRelationsChanges();
1447 }
1448
1449 // send message with new karma value
1450 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_KARMA_HAS_BEEN_CHANGED_TO_S1).addNumber(karma));
1451
1452 _karma = karma;
1453 broadcastKarma();
1454 }
1455
1456 /**
1457 * Weight Limit = (CON Modifier*69000)*Skills
1458 * @return The max weight that the Player can load.
1459 */
1460 public int getMaxLoad()
1461 {
1462 int con = getCON();
1463 if (con < 1)
1464 return 31000;
1465
1466 if (con > 59)
1467 return 176000;
1468
1469 double baseLoad = Math.pow(1.029993928, con) * 30495.627366;
1470 return (int) calcStat(Stats.MAX_LOAD, baseLoad * Config.ALT_WEIGHT_LIMIT, this, null);
1471 }
1472
1473 public int getExpertiseArmorPenalty()
1474 {
1475 return _expertiseArmorPenalty;
1476 }
1477
1478 public boolean getExpertiseWeaponPenalty()
1479 {
1480 return _expertiseWeaponPenalty;
1481 }
1482
1483 public int getWeightPenalty()
1484 {
1485 return _curWeightPenalty;
1486 }
1487
1488 /**
1489 * Update the overloaded status of the Player.
1490 */
1491 public void refreshOverloaded()
1492 {
1493 int maxLoad = getMaxLoad();
1494 if (maxLoad > 0)
1495 {
1496 int weightproc = getCurrentLoad() * 1000 / maxLoad;
1497 int newWeightPenalty;
1498
1499 if (weightproc < 500)
1500 newWeightPenalty = 0;
1501 else if (weightproc < 666)
1502 newWeightPenalty = 1;
1503 else if (weightproc < 800)
1504 newWeightPenalty = 2;
1505 else if (weightproc < 1000)
1506 newWeightPenalty = 3;
1507 else
1508 newWeightPenalty = 4;
1509
1510 if (_curWeightPenalty != newWeightPenalty)
1511 {
1512 _curWeightPenalty = newWeightPenalty;
1513
1514 if (newWeightPenalty > 0)
1515 {
1516 addSkill(SkillTable.getInstance().getInfo(4270, newWeightPenalty), false);
1517 setIsOverloaded(getCurrentLoad() > maxLoad);
1518 }
1519 else
1520 {
1521 removeSkill(4270, false);
1522 setIsOverloaded(false);
1523 }
1524
1525 sendPacket(new UserInfo(this));
1526 sendPacket(new EtcStatusUpdate(this));
1527 broadcastCharInfo();
1528 }
1529 }
1530 }
1531
1532 /**
1533 * Refresh expertise level ; weapon got one rank, when armor got 4 ranks.<br>
1534 */
1535 public void refreshExpertisePenalty()
1536 {
1537 final int expertiseLevel = getSkillLevel(L2Skill.SKILL_EXPERTISE);
1538
1539 int armorPenalty = 0;
1540 boolean weaponPenalty = false;
1541
1542 for (ItemInstance item : getInventory().getPaperdollItems())
1543 {
1544 if (item.getItemType() != EtcItemType.ARROW && item.getItem().getCrystalType().getId() > expertiseLevel)
1545 {
1546 if (item.isWeapon())
1547 weaponPenalty = true;
1548 else
1549 armorPenalty += (item.getItem().getBodyPart() == Item.SLOT_FULL_ARMOR) ? 2 : 1;
1550 }
1551 }
1552
1553 armorPenalty = Math.min(armorPenalty, 4);
1554
1555 // Found a different state than previous ; update it.
1556 if (_expertiseWeaponPenalty != weaponPenalty || _expertiseArmorPenalty != armorPenalty)
1557 {
1558 _expertiseWeaponPenalty = weaponPenalty;
1559 _expertiseArmorPenalty = armorPenalty;
1560
1561 // Passive skill "Grade Penalty" is either granted or dropped.
1562 if (_expertiseWeaponPenalty || _expertiseArmorPenalty > 0)
1563 addSkill(SkillTable.getInstance().getInfo(4267, 1), false);
1564 else
1565 removeSkill(4267, false);
1566
1567 sendSkillList();
1568 sendPacket(new EtcStatusUpdate(this));
1569
1570 final ItemInstance weapon = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
1571 if (weapon != null)
1572 {
1573 if (_expertiseWeaponPenalty)
1574 ItemPassiveSkillsListener.getInstance().onUnequip(0, weapon, this);
1575 else
1576 ItemPassiveSkillsListener.getInstance().onEquip(0, weapon, this);
1577 }
1578 }
1579 }
1580
1581 /**
1582 * Equip or unequip the item.
1583 * <UL>
1584 * <LI>If item is equipped, shots are applied if automation is on.</LI>
1585 * <LI>If item is unequipped, shots are discharged.</LI>
1586 * </UL>
1587 * @param item The item to charge/discharge.
1588 * @param abortAttack If true, the current attack will be aborted in order to equip the item.
1589 */
1590 public void useEquippableItem(ItemInstance item, boolean abortAttack)
1591 {
1592 ItemInstance[] items = null;
1593 final boolean isEquipped = item.isEquipped();
1594 final int oldInvLimit = getInventoryLimit();
1595
1596 if (item.getItem() instanceof Weapon)
1597 item.unChargeAllShots();
1598
1599 if (isEquipped)
1600 {
1601 if (item.getEnchantLevel() > 0)
1602 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED).addNumber(item.getEnchantLevel()).addItemName(item));
1603 else
1604 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_DISARMED).addItemName(item));
1605
1606 items = getInventory().unEquipItemInBodySlotAndRecord(item);
1607 }
1608 else
1609 {
1610 items = getInventory().equipItemAndRecord(item);
1611
1612 if (item.isEquipped())
1613 {
1614 if (item.getEnchantLevel() > 0)
1615 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_S2_EQUIPPED).addNumber(item.getEnchantLevel()).addItemName(item));
1616 else
1617 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_EQUIPPED).addItemName(item));
1618
1619 if ((item.getItem().getBodyPart() & Item.SLOT_ALLWEAPON) != 0)
1620 rechargeShots(true, true);
1621 }
1622 else
1623 sendPacket(SystemMessageId.CANNOT_EQUIP_ITEM_DUE_TO_BAD_CONDITION);
1624 }
1625 refreshExpertisePenalty();
1626 broadcastUserInfo();
1627
1628 InventoryUpdate iu = new InventoryUpdate();
1629 iu.addItems(Arrays.asList(items));
1630 sendPacket(iu);
1631
1632 if (abortAttack)
1633 abortAttack();
1634
1635 if (getInventoryLimit() != oldInvLimit)
1636 sendPacket(new ExStorageMaxCount(this));
1637 }
1638
1639 /**
1640 * @return PvP Kills of the Player (number of player killed during a PvP).
1641 */
1642 public int getPvpKills()
1643 {
1644 return _pvpKills;
1645 }
1646
1647 /**
1648 * Set PvP Kills of the Player (number of player killed during a PvP).
1649 * @param pvpKills A value.
1650 */
1651 public void setPvpKills(int pvpKills)
1652 {
1653 _pvpKills = pvpKills;
1654 }
1655
1656 /**
1657 * @return The ClassId object of the Player contained in L2PcTemplate.
1658 */
1659 public ClassId getClassId()
1660 {
1661 return getTemplate().getClassId();
1662 }
1663
1664 /**
1665 * Set the template of the Player.
1666 * @param Id The Identifier of the L2PcTemplate to set to the Player
1667 */
1668 public void setClassId(int Id)
1669 {
1670 if (!_subclassLock.tryLock())
1671 return;
1672
1673 if (EventManager.getInstance().players.contains(this))
1674 return;
1675
1676 try
1677 {
1678 if (getLvlJoinedAcademy() != 0 && _clan != null && ClassId.VALUES[Id].level() == 2)
1679 {
1680 if (getLvlJoinedAcademy() <= 16)
1681 _clan.addReputationScore(400);
1682 else if (getLvlJoinedAcademy() >= 39)
1683 _clan.addReputationScore(170);
1684 else
1685 _clan.addReputationScore((400 - (getLvlJoinedAcademy() - 16) * 10));
1686
1687 setLvlJoinedAcademy(0);
1688
1689 // Oust pledge member from the academy, because he has finished his 2nd class transfer.
1690 _clan.broadcastToOnlineMembers(new PledgeShowMemberListDelete(getName()), SystemMessage.getSystemMessage(SystemMessageId.CLAN_MEMBER_S1_EXPELLED).addString(getName()));
1691 _clan.removeClanMember(getObjectId(), 0);
1692 sendPacket(SystemMessageId.ACADEMY_MEMBERSHIP_TERMINATED);
1693
1694 // receive graduation gift : academy circlet
1695 addItem("Gift", 8181, 1, this, true);
1696 }
1697
1698 if (isSubClassActive())
1699 _subClasses.get(_classIndex).setClassId(Id);
1700
1701 broadcastPacket(new MagicSkillUse(this, this, 5103, 1, 1000, 0));
1702 setClassTemplate(Id);
1703
1704 if (getClassId().level() == 3)
1705 sendPacket(SystemMessageId.THIRD_CLASS_TRANSFER);
1706 else
1707 sendPacket(SystemMessageId.CLASS_TRANSFER);
1708
1709 // Update class icon in party and clan
1710 if (_party != null)
1711 _party.broadcastPacket(new PartySmallWindowUpdate(this));
1712
1713 if (_clan != null)
1714 _clan.broadcastToOnlineMembers(new PledgeShowMemberListUpdate(this));
1715
1716 if (Config.AUTO_LEARN_SKILLS && !isAio())
1717 rewardSkills();
1718 }
1719 finally
1720 {
1721 _subclassLock.unlock();
1722 }
1723 }
1724
1725 /**
1726 * @return the Experience of the Player.
1727 */
1728 public long getExp()
1729 {
1730 return getStat().getExp();
1731 }
1732
1733 public void setActiveEnchantItem(ItemInstance scroll)
1734 {
1735 _activeEnchantItem = scroll;
1736 }
1737
1738 public ItemInstance getActiveEnchantItem()
1739 {
1740 return _activeEnchantItem;
1741 }
1742 /**
1743 * @return The Race object of the Player.
1744 */
1745 public ClassRace getRace()
1746 {
1747 return (isSubClassActive()) ? getBaseTemplate().getRace() : getTemplate().getRace();
1748 }
1749
1750 public L2Radar getRadar()
1751 {
1752 return _radar;
1753 }
1754
1755 /**
1756 * @return the SP amount of the Player.
1757 */
1758 public int getSp()
1759 {
1760 return getStat().getSp();
1761 }
1762
1763 /**
1764 * @param castleId The castle to check.
1765 * @return True if this Player is a clan leader in ownership of the passed castle.
1766 */
1767 public boolean isCastleLord(int castleId)
1768 {
1769 final Clan clan = getClan();
1770 if (clan != null && clan.getLeader().getPlayerInstance() == this)
1771 {
1772 final Castle castle = CastleManager.getInstance().getCastleByOwner(clan);
1773 return castle != null && castle.getCastleId() == castleId;
1774 }
1775 return false;
1776 }
1777
1778 /**
1779 * @return The Clan Identifier of the Player.
1780 */
1781 public int getClanId()
1782 {
1783 return _clanId;
1784 }
1785
1786 /**
1787 * @return The Clan Crest Identifier of the Player or 0.
1788 */
1789 public int getClanCrestId()
1790 {
1791 return (_clan != null) ? _clan.getCrestId() : 0;
1792 }
1793
1794 /**
1795 * @return The Clan CrestLarge Identifier or 0
1796 */
1797 public int getClanCrestLargeId()
1798 {
1799 return (_clan != null) ? _clan.getCrestLargeId() : 0;
1800 }
1801
1802 public long getClanJoinExpiryTime()
1803 {
1804 return _clanJoinExpiryTime;
1805 }
1806
1807 public void setClanJoinExpiryTime(long time)
1808 {
1809 _clanJoinExpiryTime = time;
1810 }
1811
1812 public long getClanCreateExpiryTime()
1813 {
1814 return _clanCreateExpiryTime;
1815 }
1816
1817 public void setClanCreateExpiryTime(long time)
1818 {
1819 _clanCreateExpiryTime = time;
1820 }
1821
1822 public void setOnlineTime(long time)
1823 {
1824 _onlineTime = time;
1825 _onlineBeginTime = System.currentTimeMillis();
1826 }
1827
1828 /**
1829 * Return the PcInventory Inventory of the Player contained in _inventory.
1830 */
1831 @Override
1832 public PcInventory getInventory()
1833 {
1834 return _inventory;
1835 }
1836
1837 /**
1838 * Delete a ShortCut of the Player _shortCuts.
1839 * @param objectId The shortcut id.
1840 */
1841 public void removeItemFromShortCut(int objectId)
1842 {
1843 _shortCuts.deleteShortCutByObjectId(objectId);
1844 }
1845
1846 /**
1847 * @return True if the Player is sitting.
1848 */
1849 public boolean isSitting()
1850 {
1851 return _isSitting;
1852 }
1853
1854 /**
1855 * Set _isSitting to given value.
1856 * @param state A boolean.
1857 */
1858 public void setSitting(boolean state)
1859 {
1860 _isSitting = state;
1861 }
1862
1863 /**
1864 * Sit down the Player, set the AI Intention to REST and send ChangeWaitType packet (broadcast)
1865 */
1866 public void sitDown()
1867 {
1868 sitDown(true);
1869 }
1870
1871 public void sitDown(boolean checkCast)
1872 {
1873 if (checkCast && isCastingNow())
1874 return;
1875
1876 if (!_isSitting && !isAttackingDisabled() && !isOutOfControl() && !isImmobilized())
1877 {
1878 breakAttack();
1879 setSitting(true);
1880 broadcastPacket(new ChangeWaitType(this, ChangeWaitType.WT_SITTING));
1881
1882 // Schedule a sit down task to wait for the animation to finish
1883 getAI().setIntention(CtrlIntention.REST);
1884
1885 ThreadPool.schedule(() -> setIsParalyzed(false), 2500);
1886 setIsParalyzed(true);
1887 }
1888 }
1889
1890 /**
1891 * Stand up the Player, set the AI Intention to IDLE and send ChangeWaitType packet (broadcast)
1892 */
1893 public void standUp()
1894 {
1895 if (_isSitting && !isInStoreMode() && !isAlikeDead() && !isParalyzed())
1896 {
1897 if (_effects.isAffected(L2EffectFlag.RELAXING))
1898 stopEffects(L2EffectType.RELAXING);
1899
1900 broadcastPacket(new ChangeWaitType(this, ChangeWaitType.WT_STANDING));
1901
1902 // Schedule a stand up task to wait for the animation to finish
1903 ThreadPool.schedule(() ->
1904 {
1905 setSitting(false);
1906 setIsParalyzed(false);
1907 getAI().setIntention(CtrlIntention.IDLE);
1908 }, 2500);
1909 setIsParalyzed(true);
1910 }
1911 }
1912
1913 /**
1914 * Stands up and close any opened shop window, if any.
1915 */
1916 public void forceStandUp()
1917 {
1918 // Cancels any shop types.
1919 if (isInStoreMode())
1920 {
1921 setStoreType(StoreType.NONE);
1922 broadcastUserInfo();
1923 }
1924
1925 // Stand up.
1926 standUp();
1927 }
1928
1929 /**
1930 * Used to sit or stand. If not possible, queue the action.
1931 * @param target The target, used for thrones types.
1932 * @param sittingState The sitting state, inheritated from packet or player status.
1933 */
1934 public void tryToSitOrStand(final WorldObject target, final boolean sittingState)
1935 {
1936 if (isFakeDeath())
1937 {
1938 stopFakeDeath(true);
1939 return;
1940 }
1941
1942 final boolean isThrone = target instanceof StaticObject && ((StaticObject) target).getType() == 1;
1943
1944 // Player wants to sit on a throne but is out of radius, move to the throne delaying the sit action.
1945 if (isThrone && !sittingState && !isInsideRadius(target, Npc.INTERACTION_DISTANCE, false, false))
1946 {
1947 getAI().setIntention(CtrlIntention.MOVE_TO, new Location(target.getX(), target.getY(), target.getZ()));
1948
1949 NextAction nextAction = new NextAction(CtrlEvent.EVT_ARRIVED, CtrlIntention.MOVE_TO, () ->
1950 {
1951 if (getMountType() != 0)
1952 return;
1953
1954 sitDown();
1955
1956 if (!((StaticObject) target).isBusy())
1957 {
1958 _throneId = target.getObjectId();
1959
1960 ((StaticObject) target).setBusy(true);
1961 broadcastPacket(new ChairSit(getObjectId(), ((StaticObject) target).getStaticObjectId()));
1962 }
1963 });
1964
1965 // Binding next action to AI.
1966 getAI().setNextAction(nextAction);
1967 return;
1968 }
1969
1970 // Player isn't moving, sit directly.
1971 if (!isMoving())
1972 {
1973 if (getMountType() != 0)
1974 return;
1975
1976 if (sittingState)
1977 {
1978 if (_throneId != 0)
1979 {
1980 final WorldObject object = World.getInstance().getObject(_throneId);
1981 if (object instanceof StaticObject)
1982 ((StaticObject) object).setBusy(false);
1983
1984 _throneId = 0;
1985 }
1986
1987 standUp();
1988 }
1989 else
1990 {
1991 sitDown();
1992
1993 if (isThrone && !((StaticObject) target).isBusy() && isInsideRadius(target, Npc.INTERACTION_DISTANCE, false, false))
1994 {
1995 _throneId = target.getObjectId();
1996
1997 ((StaticObject) target).setBusy(true);
1998 broadcastPacket(new ChairSit(getObjectId(), ((StaticObject) target).getStaticObjectId()));
1999 }
2000 }
2001 }
2002 // Player is moving, wait the current action is done, then sit.
2003 else
2004 {
2005 NextAction nextAction = new NextAction(CtrlEvent.EVT_ARRIVED, CtrlIntention.MOVE_TO, () ->
2006 {
2007 if (getMountType() != 0)
2008 return;
2009
2010 if (sittingState)
2011 {
2012 if (_throneId != 0)
2013 {
2014 final WorldObject object = World.getInstance().getObject(_throneId);
2015 if (object instanceof StaticObject)
2016 ((StaticObject) object).setBusy(false);
2017
2018 _throneId = 0;
2019 }
2020
2021 standUp();
2022 }
2023 else
2024 {
2025 sitDown();
2026
2027 if (isThrone && !((StaticObject) target).isBusy() && isInsideRadius(target, Npc.INTERACTION_DISTANCE, false, false))
2028 {
2029 _throneId = target.getObjectId();
2030
2031 ((StaticObject) target).setBusy(true);
2032 broadcastPacket(new ChairSit(getObjectId(), ((StaticObject) target).getStaticObjectId()));
2033 }
2034 }
2035 });
2036
2037 // Binding next action to AI.
2038 getAI().setNextAction(nextAction);
2039 }
2040 }
2041
2042 /**
2043 * @return The PcWarehouse object of the Player.
2044 */
2045 public PcWarehouse getWarehouse()
2046 {
2047 if (_warehouse == null)
2048 {
2049 _warehouse = new PcWarehouse(this);
2050 _warehouse.restore();
2051 }
2052 return _warehouse;
2053 }
2054
2055 /**
2056 * Free memory used by Warehouse
2057 */
2058 public void clearWarehouse()
2059 {
2060 if (_warehouse != null)
2061 _warehouse.deleteMe();
2062
2063 _warehouse = null;
2064 }
2065
2066 /**
2067 * @return The PcFreight object of the Player.
2068 */
2069 public PcFreight getFreight()
2070 {
2071 if (_freight == null)
2072 {
2073 _freight = new PcFreight(this);
2074 _freight.restore();
2075 }
2076 return _freight;
2077 }
2078
2079 /**
2080 * Free memory used by Freight
2081 */
2082 public void clearFreight()
2083 {
2084 if (_freight != null)
2085 _freight.deleteMe();
2086
2087 _freight = null;
2088 }
2089
2090 /**
2091 * @param objectId The id of the owner.
2092 * @return deposited PcFreight object for the objectId or create new if not existing.
2093 */
2094 public PcFreight getDepositedFreight(int objectId)
2095 {
2096 for (PcFreight freight : _depositedFreight)
2097 {
2098 if (freight != null && freight.getOwnerId() == objectId)
2099 return freight;
2100 }
2101
2102 PcFreight freight = new PcFreight(null);
2103 freight.doQuickRestore(objectId);
2104 _depositedFreight.add(freight);
2105 return freight;
2106 }
2107
2108 /**
2109 * Clear memory used by deposited freight
2110 */
2111 public void clearDepositedFreight()
2112 {
2113 for (PcFreight freight : _depositedFreight)
2114 {
2115 if (freight != null)
2116 freight.deleteMe();
2117 }
2118 _depositedFreight.clear();
2119 }
2120
2121 /**
2122 * @return The Adena amount of the Player.
2123 */
2124 public int getAdena()
2125 {
2126 return _inventory.getAdena();
2127 }
2128
2129 /**
2130 * @return The Ancient Adena amount of the Player.
2131 */
2132 public int getAncientAdena()
2133 {
2134 return _inventory.getAncientAdena();
2135 }
2136
2137 /**
2138 * Add adena to Inventory of the Player and send InventoryUpdate packet to the Player.
2139 * @param process String Identifier of process triggering this action
2140 * @param count int Quantity of adena to be added
2141 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2142 * @param sendMessage boolean Specifies whether to send message to Client about this action
2143 */
2144 public void addAdena(String process, int count, WorldObject reference, boolean sendMessage)
2145 {
2146 if (sendMessage)
2147 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.EARNED_S1_ADENA).addNumber(count));
2148
2149 if (count > 0)
2150 {
2151 _inventory.addAdena(process, count, this, reference);
2152
2153 InventoryUpdate iu = new InventoryUpdate();
2154 if (_inventory.getAdenaInstance() != null)
2155 iu.addModifiedItem(_inventory.getAdenaInstance());
2156 else
2157 iu.addItem(_inventory.getAdenaInstance());
2158 sendPacket(iu);
2159 }
2160 }
2161
2162 /**
2163 * Reduce adena in Inventory of the Player and send InventoryUpdate packet to the Player.
2164 * @param process String Identifier of process triggering this action
2165 * @param count int Quantity of adena to be reduced
2166 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2167 * @param sendMessage boolean Specifies whether to send message to Client about this action
2168 * @return boolean informing if the action was successfull
2169 */
2170 public boolean reduceAdena(String process, int count, WorldObject reference, boolean sendMessage)
2171 {
2172 if (count > getAdena())
2173 {
2174 if (sendMessage)
2175 sendPacket(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
2176
2177 return false;
2178 }
2179
2180 if (count > 0)
2181 {
2182 ItemInstance adenaItem = _inventory.getAdenaInstance();
2183 if (!_inventory.reduceAdena(process, count, this, reference))
2184 return false;
2185
2186 // Send update packet
2187 InventoryUpdate iu = new InventoryUpdate();
2188 iu.addItem(adenaItem);
2189 sendPacket(iu);
2190
2191 if (sendMessage)
2192 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED_ADENA).addNumber(count));
2193 }
2194 return true;
2195 }
2196
2197 /**
2198 * Add ancient adena to Inventory of the Player and send InventoryUpdate packet to the Player.
2199 * @param process String Identifier of process triggering this action
2200 * @param count int Quantity of ancient adena to be added
2201 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2202 * @param sendMessage boolean Specifies whether to send message to Client about this action
2203 */
2204 public void addAncientAdena(String process, int count, WorldObject reference, boolean sendMessage)
2205 {
2206 if (sendMessage)
2207 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S).addItemName(PcInventory.ANCIENT_ADENA_ID).addNumber(count));
2208
2209 if (count > 0)
2210 {
2211 _inventory.addAncientAdena(process, count, this, reference);
2212
2213 InventoryUpdate iu = new InventoryUpdate();
2214 iu.addItem(_inventory.getAncientAdenaInstance());
2215 sendPacket(iu);
2216 }
2217 }
2218
2219 /**
2220 * Reduce ancient adena in Inventory of the Player and send InventoryUpdate packet to the Player.
2221 * @param process String Identifier of process triggering this action
2222 * @param count int Quantity of ancient adena to be reduced
2223 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2224 * @param sendMessage boolean Specifies whether to send message to Client about this action
2225 * @return boolean informing if the action was successfull
2226 */
2227 public boolean reduceAncientAdena(String process, int count, WorldObject reference, boolean sendMessage)
2228 {
2229 if (count > getAncientAdena())
2230 {
2231 if (sendMessage)
2232 sendPacket(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
2233
2234 return false;
2235 }
2236
2237 if (count > 0)
2238 {
2239 ItemInstance ancientAdenaItem = _inventory.getAncientAdenaInstance();
2240 if (!_inventory.reduceAncientAdena(process, count, this, reference))
2241 return false;
2242
2243 InventoryUpdate iu = new InventoryUpdate();
2244 iu.addItem(ancientAdenaItem);
2245 sendPacket(iu);
2246
2247 if (sendMessage)
2248 {
2249 if (count > 1)
2250 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S2_S1_DISAPPEARED).addItemName(PcInventory.ANCIENT_ADENA_ID).addItemNumber(count));
2251 else
2252 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED).addItemName(PcInventory.ANCIENT_ADENA_ID));
2253 }
2254 }
2255 return true;
2256 }
2257
2258 /**
2259 * Adds item to inventory and send InventoryUpdate packet to the Player.
2260 * @param process String Identifier of process triggering this action
2261 * @param item ItemInstance to be added
2262 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2263 * @param sendMessage boolean Specifies whether to send message to Client about this action
2264 */
2265 public void addItem(String process, ItemInstance item, WorldObject reference, boolean sendMessage)
2266 {
2267 if (item.getCount() > 0)
2268 {
2269 // Sends message to client if requested
2270 if (sendMessage)
2271 {
2272 if (item.getCount() > 1)
2273 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S2_S1).addItemName(item).addNumber(item.getCount()));
2274 else if (item.getEnchantLevel() > 0)
2275 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_A_S1_S2).addNumber(item.getEnchantLevel()).addItemName(item));
2276 else
2277 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S1).addItemName(item));
2278 }
2279
2280 // Add the item to inventory
2281 ItemInstance newitem = _inventory.addItem(process, item, this, reference);
2282
2283 // Send inventory update packet
2284 InventoryUpdate playerIU = new InventoryUpdate();
2285 playerIU.addItem(newitem);
2286 sendPacket(playerIU);
2287
2288 // Update current load as well
2289 StatusUpdate su = new StatusUpdate(this);
2290 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
2291 sendPacket(su);
2292
2293 // Cursed Weapon
2294 if (CursedWeaponManager.getInstance().isCursed(newitem.getItemId()))
2295 CursedWeaponManager.getInstance().activate(this, newitem);
2296 // If you pickup arrows and a bow is equipped, try to equip them if no arrows is currently equipped.
2297 else if (item.getItem().getItemType() == EtcItemType.ARROW && getAttackType() == WeaponType.BOW && getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND) == null)
2298 checkAndEquipArrows();
2299 }
2300 }
2301
2302 /**
2303 * Adds item to Inventory and send InventoryUpdate packet to the Player.
2304 * @param process String Identifier of process triggering this action
2305 * @param itemId int Item Identifier of the item to be added
2306 * @param count int Quantity of items to be added
2307 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2308 * @param sendMessage boolean Specifies whether to send message to Client about this action
2309 * @return The created ItemInstance.
2310 */
2311 public ItemInstance addItem(String process, int itemId, int count, WorldObject reference, boolean sendMessage)
2312 {
2313 if (count > 0)
2314 {
2315 // Retrieve the template of the item.
2316 final Item item = ItemTable.getInstance().getTemplate(itemId);
2317 if (item == null)
2318 {
2319 _log.log(Level.SEVERE, "Item id " + itemId + "doesn't exist, so it can't be added.");
2320 return null;
2321 }
2322
2323 // Sends message to client if requested.
2324 if (sendMessage && ((!isCastingNow() && item.getItemType() == EtcItemType.HERB) || item.getItemType() != EtcItemType.HERB))
2325 {
2326 if (count > 1)
2327 {
2328 if (process.equalsIgnoreCase("Sweep") || process.equalsIgnoreCase("Quest"))
2329 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S).addItemName(itemId).addItemNumber(count));
2330 else
2331 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S2_S1).addItemName(itemId).addItemNumber(count));
2332 }
2333 else
2334 {
2335 if (process.equalsIgnoreCase("Sweep") || process.equalsIgnoreCase("Quest"))
2336 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1).addItemName(itemId));
2337 else
2338 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S1).addItemName(itemId));
2339 }
2340 }
2341
2342 // If the item is herb type, dont add it to inventory.
2343 if (item.getItemType() == EtcItemType.HERB)
2344 {
2345 final ItemInstance herb = new ItemInstance(0, itemId);
2346
2347 final IItemHandler handler = ItemHandler.getInstance().getHandler(herb.getEtcItem());
2348 if (handler != null)
2349 handler.useItem(this, herb, false);
2350 }
2351 else
2352 {
2353 // Add the item to inventory
2354 final ItemInstance createdItem = _inventory.addItem(process, itemId, count, this, reference);
2355
2356 // Cursed Weapon
2357 if (CursedWeaponManager.getInstance().isCursed(createdItem.getItemId()))
2358 CursedWeaponManager.getInstance().activate(this, createdItem);
2359 // If you pickup arrows and a bow is equipped, try to equip them if no arrows is currently equipped.
2360 else if (item.getItemType() == EtcItemType.ARROW && getAttackType() == WeaponType.BOW && getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND) == null)
2361 checkAndEquipArrows();
2362
2363 return createdItem;
2364 }
2365 }
2366 return null;
2367 }
2368
2369 /**
2370 * Destroy item from inventory and send InventoryUpdate packet to the Player.
2371 * @param process String Identifier of process triggering this action
2372 * @param item ItemInstance to be destroyed
2373 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2374 * @param sendMessage boolean Specifies whether to send message to Client about this action
2375 * @return boolean informing if the action was successfull
2376 */
2377 public boolean destroyItem(String process, ItemInstance item, WorldObject reference, boolean sendMessage)
2378 {
2379 return destroyItem(process, item, item.getCount(), reference, sendMessage);
2380 }
2381
2382 /**
2383 * Destroy item from inventory and send InventoryUpdate packet to the Player.
2384 * @param process String Identifier of process triggering this action
2385 * @param item ItemInstance to be destroyed
2386 * @param count int Quantity of ancient adena to be reduced
2387 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2388 * @param sendMessage boolean Specifies whether to send message to Client about this action
2389 * @return boolean informing if the action was successfull
2390 */
2391 public boolean destroyItem(String process, ItemInstance item, int count, WorldObject reference, boolean sendMessage)
2392 {
2393 item = _inventory.destroyItem(process, item, count, this, reference);
2394
2395 if (item == null)
2396 {
2397 if (sendMessage)
2398 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
2399
2400 return false;
2401 }
2402
2403 // Send inventory update packet
2404 final InventoryUpdate iu = new InventoryUpdate();
2405 if (item.getCount() == 0)
2406 iu.addRemovedItem(item);
2407 else
2408 iu.addModifiedItem(item);
2409 sendPacket(iu);
2410
2411 // Update current load as well
2412 final StatusUpdate su = new StatusUpdate(this);
2413 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
2414 sendPacket(su);
2415
2416 // Sends message to client if requested
2417 if (sendMessage)
2418 {
2419 if (count > 1)
2420 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S2_S1_DISAPPEARED).addItemName(item).addItemNumber(count));
2421 else
2422 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED).addItemName(item));
2423 }
2424 return true;
2425 }
2426
2427 /**
2428 * Destroys item from inventory and send InventoryUpdate packet to the Player.
2429 * @param process String Identifier of process triggering this action
2430 * @param objectId int Item Instance identifier of the item to be destroyed
2431 * @param count int Quantity of items to be destroyed
2432 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2433 * @param sendMessage boolean Specifies whether to send message to Client about this action
2434 * @return boolean informing if the action was successfull
2435 */
2436 @Override
2437 public boolean destroyItem(String process, int objectId, int count, WorldObject reference, boolean sendMessage)
2438 {
2439 final ItemInstance item = _inventory.getItemByObjectId(objectId);
2440
2441 if (item == null)
2442 {
2443 if (sendMessage)
2444 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
2445
2446 return false;
2447 }
2448 return destroyItem(process, item, count, reference, sendMessage);
2449 }
2450
2451 /**
2452 * Destroys shots from inventory without logging and only occasional saving to database. Sends InventoryUpdate packet to the Player.
2453 * @param process String Identifier of process triggering this action
2454 * @param objectId int Item Instance identifier of the item to be destroyed
2455 * @param count int Quantity of items to be destroyed
2456 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2457 * @param sendMessage boolean Specifies whether to send message to Client about this action
2458 * @return boolean informing if the action was successfull
2459 */
2460 public boolean destroyItemWithoutTrace(String process, int objectId, int count, WorldObject reference, boolean sendMessage)
2461 {
2462 ItemInstance item = _inventory.getItemByObjectId(objectId);
2463
2464 if (item == null || item.getCount() < count)
2465 {
2466 if (sendMessage)
2467 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
2468
2469 return false;
2470 }
2471 return destroyItem(null, item, count, reference, sendMessage);
2472 }
2473
2474 /**
2475 * Destroy item from inventory by using its <B>itemId</B> and send InventoryUpdate packet to the Player.
2476 * @param process String Identifier of process triggering this action
2477 * @param itemId int Item identifier of the item to be destroyed
2478 * @param count int Quantity of items to be destroyed
2479 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2480 * @param sendMessage boolean Specifies whether to send message to Client about this action
2481 * @return boolean informing if the action was successfull
2482 */
2483 @Override
2484 public boolean destroyItemByItemId(String process, int itemId, int count, WorldObject reference, boolean sendMessage)
2485 {
2486 if (itemId == 57)
2487 return reduceAdena(process, count, reference, sendMessage);
2488
2489 ItemInstance item = _inventory.getItemByItemId(itemId);
2490
2491 if (item == null || item.getCount() < count || _inventory.destroyItemByItemId(process, itemId, count, this, reference) == null)
2492 {
2493 if (sendMessage)
2494 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
2495
2496 return false;
2497 }
2498
2499 // Send inventory update packet
2500 InventoryUpdate playerIU = new InventoryUpdate();
2501 playerIU.addItem(item);
2502 sendPacket(playerIU);
2503
2504 // Update current load as well
2505 StatusUpdate su = new StatusUpdate(this);
2506 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
2507 sendPacket(su);
2508
2509 // Sends message to client if requested
2510 if (sendMessage)
2511 {
2512 if (count > 1)
2513 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S2_S1_DISAPPEARED).addItemName(itemId).addItemNumber(count));
2514 else
2515 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED).addItemName(itemId));
2516 }
2517 return true;
2518 }
2519
2520 /**
2521 * Transfers item to another ItemContainer and send InventoryUpdate packet to the Player.
2522 * @param process String Identifier of process triggering this action
2523 * @param objectId int Item Identifier of the item to be transfered
2524 * @param count int Quantity of items to be transfered
2525 * @param target Inventory the Inventory target.
2526 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2527 * @return ItemInstance corresponding to the new item or the updated item in inventory
2528 */
2529 public ItemInstance transferItem(String process, int objectId, int count, Inventory target, WorldObject reference)
2530 {
2531 final ItemInstance oldItem = checkItemManipulation(objectId, count);
2532 if (oldItem == null)
2533 return null;
2534
2535 final ItemInstance newItem = getInventory().transferItem(process, objectId, count, target, this, reference);
2536 if (newItem == null)
2537 return null;
2538
2539 // Send inventory update packet
2540 InventoryUpdate playerIU = new InventoryUpdate();
2541
2542 if (oldItem.getCount() > 0 && oldItem != newItem)
2543 playerIU.addModifiedItem(oldItem);
2544 else
2545 playerIU.addRemovedItem(oldItem);
2546
2547 sendPacket(playerIU);
2548
2549 // Update current load as well
2550 StatusUpdate playerSU = new StatusUpdate(this);
2551 playerSU.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
2552 sendPacket(playerSU);
2553
2554 // Send target update packet
2555 if (target instanceof PcInventory)
2556 {
2557 final Player targetPlayer = ((PcInventory) target).getOwner();
2558
2559 InventoryUpdate playerIU2 = new InventoryUpdate();
2560 if (newItem.getCount() > count)
2561 playerIU2.addModifiedItem(newItem);
2562 else
2563 playerIU2.addNewItem(newItem);
2564 targetPlayer.sendPacket(playerIU2);
2565
2566 // Update current load as well
2567 playerSU = new StatusUpdate(targetPlayer);
2568 playerSU.addAttribute(StatusUpdate.CUR_LOAD, targetPlayer.getCurrentLoad());
2569 targetPlayer.sendPacket(playerSU);
2570 }
2571 else if (target instanceof PetInventory)
2572 {
2573 PetInventoryUpdate petIU = new PetInventoryUpdate();
2574 if (newItem.getCount() > count)
2575 petIU.addModifiedItem(newItem);
2576 else
2577 petIU.addNewItem(newItem);
2578 ((PetInventory) target).getOwner().getOwner().sendPacket(petIU);
2579 }
2580 return newItem;
2581 }
2582
2583 /**
2584 * Drop item from inventory and send InventoryUpdate packet to the Player.
2585 * @param process String Identifier of process triggering this action
2586 * @param item ItemInstance to be dropped
2587 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2588 * @param sendMessage boolean Specifies whether to send message to Client about this action
2589 * @return boolean informing if the action was successfull
2590 */
2591 public boolean dropItem(String process, ItemInstance item, WorldObject reference, boolean sendMessage)
2592 {
2593 item = _inventory.dropItem(process, item, this, reference);
2594
2595 if (item == null)
2596 {
2597 if (sendMessage)
2598 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
2599
2600 return false;
2601 }
2602
2603 item.dropMe(this, getX() + Rnd.get(-25, 25), getY() + Rnd.get(-25, 25), getZ() + 20);
2604
2605 // Send inventory update packet
2606 InventoryUpdate playerIU = new InventoryUpdate();
2607 playerIU.addItem(item);
2608 sendPacket(playerIU);
2609
2610 // Update current load as well
2611 StatusUpdate su = new StatusUpdate(this);
2612 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
2613 sendPacket(su);
2614
2615 // Sends message to client if requested
2616 if (sendMessage)
2617 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_DROPPED_S1).addItemName(item));
2618
2619 return true;
2620 }
2621
2622 /**
2623 * Drop item from inventory by using its <B>objectID</B> and send InventoryUpdate packet to the Player.
2624 * @param process String Identifier of process triggering this action
2625 * @param objectId int Item Instance identifier of the item to be dropped
2626 * @param count int Quantity of items to be dropped
2627 * @param x int coordinate for drop X
2628 * @param y int coordinate for drop Y
2629 * @param z int coordinate for drop Z
2630 * @param reference WorldObject Object referencing current action like NPC selling item or previous item in transformation
2631 * @param sendMessage boolean Specifies whether to send message to Client about this action
2632 * @return ItemInstance corresponding to the new item or the updated item in inventory
2633 */
2634 public ItemInstance dropItem(String process, int objectId, int count, int x, int y, int z, WorldObject reference, boolean sendMessage)
2635 {
2636 ItemInstance invItem = _inventory.getItemByObjectId(objectId);
2637 ItemInstance item = _inventory.dropItem(process, objectId, count, this, reference);
2638
2639 if (item == null)
2640 {
2641 if (sendMessage)
2642 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
2643
2644 return null;
2645 }
2646
2647 item.dropMe(this, x, y, z);
2648
2649 // Send inventory update packet
2650 InventoryUpdate playerIU = new InventoryUpdate();
2651 playerIU.addItem(invItem);
2652 sendPacket(playerIU);
2653
2654 // Update current load as well
2655 StatusUpdate su = new StatusUpdate(this);
2656 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
2657 sendPacket(su);
2658
2659 // Sends message to client if requested
2660 if (sendMessage)
2661 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_DROPPED_S1).addItemName(item));
2662
2663 return item;
2664 }
2665
2666 public ItemInstance checkItemManipulation(int objectId, int count)
2667 {
2668 if (World.getInstance().getObject(objectId) == null)
2669 return null;
2670
2671 final ItemInstance item = getInventory().getItemByObjectId(objectId);
2672
2673 if (item == null || item.getOwnerId() != getObjectId())
2674 return null;
2675
2676 if (count < 1 || (count > 1 && !item.isStackable()))
2677 return null;
2678
2679 if (count > item.getCount())
2680 return null;
2681
2682 // Pet is summoned and not the item that summoned the pet AND not the buggle from strider you're mounting
2683 if (getPet() != null && getPet().getControlItemId() == objectId || _mountObjectId == objectId)
2684 return null;
2685
2686 if (getActiveEnchantItem() != null && getActiveEnchantItem().getObjectId() == objectId)
2687 return null;
2688
2689 // We cannot put a Weapon with Augmention in WH while casting (Possible Exploit)
2690 if (item.isAugmented() && (isCastingNow() || isCastingSimultaneouslyNow()))
2691 return null;
2692
2693 return item;
2694 }
2695
2696 /**
2697 * Launch a task corresponding to Config time.
2698 * @param protect boolean Drop timer or activate it.
2699 */
2700 public void setSpawnProtection(boolean protect)
2701 {
2702 if (EventManager.getInstance().isRunning())
2703 return;
2704
2705 if (protect)
2706 {
2707 if (_protectTask == null)
2708 _protectTask = ThreadPool.schedule(() ->
2709 {
2710 setSpawnProtection(false);
2711 sendMessage("The spawn protection has ended.");
2712 }, Config.PLAYER_SPAWN_PROTECTION * 1000);
2713 }
2714 else
2715 {
2716 _protectTask.cancel(true);
2717 _protectTask = null;
2718 }
2719 broadcastUserInfo();
2720 }
2721
2722 public boolean isSpawnProtected()
2723 {
2724 return _protectTask != null;
2725 }
2726
2727 /**
2728 * Set protection from agro mobs when getting up from fake death, according settings.
2729 */
2730 public void setRecentFakeDeath()
2731 {
2732 _recentFakeDeathEndTime = System.currentTimeMillis() + Config.PLAYER_FAKEDEATH_UP_PROTECTION * 1000;
2733 }
2734
2735 public void clearRecentFakeDeath()
2736 {
2737 _recentFakeDeathEndTime = 0;
2738 }
2739
2740 public boolean isRecentFakeDeath()
2741 {
2742 return _recentFakeDeathEndTime > System.currentTimeMillis();
2743 }
2744
2745 public final boolean isFakeDeath()
2746 {
2747 return _isFakeDeath;
2748 }
2749
2750 public final void setIsFakeDeath(boolean value)
2751 {
2752 _isFakeDeath = value;
2753 }
2754
2755 @Override
2756 public final boolean isAlikeDead()
2757 {
2758 if (super.isAlikeDead())
2759 return true;
2760
2761 return isFakeDeath();
2762 }
2763
2764 /**
2765 * @return The client owner of this char.
2766 */
2767 public L2GameClient getClient()
2768 {
2769 return _client;
2770 }
2771
2772 public void setClient(L2GameClient client)
2773 {
2774 _client = client;
2775 }
2776
2777 public String getAccountName()
2778 {
2779 if (getClient() == null)
2780 return getAccountNamePlayer();
2781
2782 return getClient().getAccountName();
2783 }
2784
2785 public String getAccountNamePlayer()
2786 {
2787 return _accountName;
2788 }
2789
2790 public Map<Integer, String> getAccountChars()
2791 {
2792 return _chars;
2793 }
2794
2795 /**
2796 * Close the active connection with the client.
2797 * @param closeClient
2798 */
2799 private void closeNetConnection(boolean closeClient)
2800 {
2801 L2GameClient client = _client;
2802 if (client != null)
2803 {
2804 if (client.isDetached())
2805 client.cleanMe(true);
2806 else
2807 {
2808 if (!client.getConnection().isClosed())
2809 {
2810 if (closeClient)
2811 client.close(LeaveWorld.STATIC_PACKET);
2812 else
2813 client.close(ServerClose.STATIC_PACKET);
2814 }
2815 }
2816 }
2817 }
2818
2819 public Location getCurrentSkillWorldPosition()
2820 {
2821 return _currentSkillWorldPosition;
2822 }
2823
2824 public void setCurrentSkillWorldPosition(Location worldPosition)
2825 {
2826 _currentSkillWorldPosition = worldPosition;
2827 }
2828
2829 /**
2830 * @see net.sf.l2j.gameserver.model.actor.Creature#enableSkill(net.sf.l2j.gameserver.model.L2Skill)
2831 */
2832 @Override
2833 public void enableSkill(L2Skill skill)
2834 {
2835 super.enableSkill(skill);
2836 _reuseTimeStamps.remove(skill.getReuseHashCode());
2837 }
2838
2839 @Override
2840 protected boolean checkDoCastConditions(L2Skill skill)
2841 {
2842 if (!super.checkDoCastConditions(skill))
2843 return false;
2844
2845 // Can't summon multiple servitors.
2846 if (skill.getSkillType() == L2SkillType.SUMMON)
2847 {
2848 if (!((L2SkillSummon) skill).isCubic() && (getPet() != null || isMounted()))
2849 {
2850 sendPacket(SystemMessageId.SUMMON_ONLY_ONE);
2851 return false;
2852 }
2853 }
2854 // Can't use ressurect skills on siege if you are defender and control towers is not alive, if you are attacker and flag isn't spawned or if you aren't part of that siege.
2855// else if (skill.getSkillType() == L2SkillType.RESURRECT)
2856// {
2857// final Siege siege = CastleManager.getInstance().getActiveSiege(this);
2858// if (siege != null)
2859// {
2860// if (getClan() == null)
2861// {
2862// sendPacket(SystemMessageId.CANNOT_BE_RESURRECTED_DURING_SIEGE);
2863// return false;
2864// }
2865//
2866// final SiegeSide side = siege.getSide(getClan());
2867// if (side == SiegeSide.DEFENDER || side == SiegeSide.OWNER)
2868// {
2869// if (siege.getControlTowerCount() == 0)
2870// {
2871// sendPacket(SystemMessageId.TOWER_DESTROYED_NO_RESURRECTION);
2872// return false;
2873// }
2874// }
2875// else if (side == SiegeSide.ATTACKER)
2876// {
2877// if (getClan().getFlag() == null)
2878// {
2879// sendPacket(SystemMessageId.NO_RESURRECTION_WITHOUT_BASE_CAMP);
2880// return false;
2881// }
2882// }
2883// else
2884// {
2885// sendPacket(SystemMessageId.CANNOT_BE_RESURRECTED_DURING_SIEGE);
2886// return false;
2887// }
2888// }
2889// }
2890 // Can't casting signets on peace zone.
2891 else if (skill.getSkillType() == L2SkillType.SIGNET || skill.getSkillType() == L2SkillType.SIGNET_CASTTIME)
2892 {
2893 final WorldRegion region = getRegion();
2894 if (region == null)
2895 return false;
2896
2897 if (!region.checkEffectRangeInsidePeaceZone(skill, (skill.getTargetType() == SkillTargetType.TARGET_GROUND) ? getCurrentSkillWorldPosition() : getPosition()))
2898 {
2899 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED).addSkillName(skill));
2900 return false;
2901 }
2902 }
2903
2904 // Can't use Hero and resurrect skills during Olympiad
2905 if (isInOlympiadMode() && (skill.isHeroSkill() || skill.getSkillType() == L2SkillType.RESURRECT))
2906 {
2907 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.THIS_SKILL_IS_NOT_AVAILABLE_FOR_THE_OLYMPIAD_EVENT));
2908 return false;
2909 }
2910
2911 // Check if the spell uses charges
2912 if (skill.getMaxCharges() == 0 && getCharges() < skill.getNumCharges())
2913 {
2914 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED).addSkillName(skill));
2915 return false;
2916 }
2917
2918 return true;
2919 }
2920
2921 @Override
2922 public void onAction(Player player)
2923 {
2924 if (!EventManager.getInstance().canTargetPlayer(this, player))
2925 {
2926 player.sendPacket(ActionFailed.STATIC_PACKET);
2927 return;
2928 }
2929
2930 if(player.isInsideZone(ZoneId.PVP_FLAG))
2931 {
2932 player.updatePvPFlag(1);
2933 }
2934
2935 // Set the target of the player
2936 if (player.getTarget() != this)
2937 player.setTarget(this);
2938 else
2939 {
2940 // Check if this Player has a Private Store
2941 if (isInStoreMode())
2942 {
2943 player.getAI().setIntention(CtrlIntention.INTERACT, this);
2944 return;
2945 }
2946
2947 // Check if this Player is autoAttackable
2948 if (isAutoAttackable(player))
2949 {
2950 // Player with lvl < 21 can't attack a cursed weapon holder and a cursed weapon holder can't attack players with lvl < 21
2951 if ((isCursedWeaponEquipped() && player.getLevel() < 21) || (player.isCursedWeaponEquipped() && getLevel() < 21))
2952 {
2953 player.sendPacket(ActionFailed.STATIC_PACKET);
2954 return;
2955 }
2956
2957 if (GeoEngine.getInstance().canSeeTarget(player, this))
2958 {
2959 player.getAI().setIntention(CtrlIntention.ATTACK, this);
2960 player.onActionRequest();
2961 }
2962 }
2963 else
2964 {
2965 // avoids to stuck when clicking two or more times
2966 player.sendPacket(ActionFailed.STATIC_PACKET);
2967
2968 if (player != this && GeoEngine.getInstance().canSeeTarget(player, this))
2969 player.getAI().setIntention(CtrlIntention.FOLLOW, this);
2970 }
2971 }
2972 }
2973
2974 @Override
2975 public void onActionShift(Player player)
2976 {
2977 if (player.isGM())
2978 AdminEditChar.showCharacterInfo(player, this);
2979
2980 super.onActionShift(player);
2981 }
2982
2983 /**
2984 * @param barPixels
2985 * @return true if cp update should be done, false if not
2986 */
2987 private boolean needCpUpdate(int barPixels)
2988 {
2989 double currentCp = getCurrentCp();
2990
2991 if (currentCp <= 1.0 || getMaxCp() < barPixels)
2992 return true;
2993
2994 if (currentCp <= _cpUpdateDecCheck || currentCp >= _cpUpdateIncCheck)
2995 {
2996 if (currentCp == getMaxCp())
2997 {
2998 _cpUpdateIncCheck = currentCp + 1;
2999 _cpUpdateDecCheck = currentCp - _cpUpdateInterval;
3000 }
3001 else
3002 {
3003 double doubleMulti = currentCp / _cpUpdateInterval;
3004 int intMulti = (int) doubleMulti;
3005
3006 _cpUpdateDecCheck = _cpUpdateInterval * (doubleMulti < intMulti ? intMulti-- : intMulti);
3007 _cpUpdateIncCheck = _cpUpdateDecCheck + _cpUpdateInterval;
3008 }
3009
3010 return true;
3011 }
3012
3013 return false;
3014 }
3015
3016 /**
3017 * @param barPixels
3018 * @return true if mp update should be done, false if not
3019 */
3020 private boolean needMpUpdate(int barPixels)
3021 {
3022 double currentMp = getCurrentMp();
3023
3024 if (currentMp <= 1.0 || getMaxMp() < barPixels)
3025 return true;
3026
3027 if (currentMp <= _mpUpdateDecCheck || currentMp >= _mpUpdateIncCheck)
3028 {
3029 if (currentMp == getMaxMp())
3030 {
3031 _mpUpdateIncCheck = currentMp + 1;
3032 _mpUpdateDecCheck = currentMp - _mpUpdateInterval;
3033 }
3034 else
3035 {
3036 double doubleMulti = currentMp / _mpUpdateInterval;
3037 int intMulti = (int) doubleMulti;
3038
3039 _mpUpdateDecCheck = _mpUpdateInterval * (doubleMulti < intMulti ? intMulti-- : intMulti);
3040 _mpUpdateIncCheck = _mpUpdateDecCheck + _mpUpdateInterval;
3041 }
3042
3043 return true;
3044 }
3045
3046 return false;
3047 }
3048
3049 /**
3050 * Send packet StatusUpdate with current HP,MP and CP to the Player and only current HP, MP and Level to all other Player of the Party.
3051 * <ul>
3052 * <li>Send StatusUpdate with current HP, MP and CP to this Player</li>
3053 * <li>Send PartySmallWindowUpdate with current HP, MP and Level to all other Player of the Party</li>
3054 * </ul>
3055 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND current HP and MP to all Player of the _statusListener</B></FONT>
3056 */
3057 @Override
3058 public void broadcastStatusUpdate()
3059 {
3060 // Send StatusUpdate with current HP, MP and CP to this Player
3061 StatusUpdate su = new StatusUpdate(this);
3062 su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
3063 su.addAttribute(StatusUpdate.CUR_MP, (int) getCurrentMp());
3064 su.addAttribute(StatusUpdate.CUR_CP, (int) getCurrentCp());
3065 su.addAttribute(StatusUpdate.MAX_CP, getMaxCp());
3066 sendPacket(su);
3067 sendPacket(new UserInfo(this));
3068
3069 final boolean needCpUpdate = needCpUpdate(352);
3070 final boolean needHpUpdate = needHpUpdate(352);
3071
3072 // Check if a party is in progress and party window update is needed.
3073 if (_party != null && (needCpUpdate || needHpUpdate || needMpUpdate(352)))
3074 _party.broadcastToPartyMembers(this, new PartySmallWindowUpdate(this));
3075
3076 if (isInOlympiadMode() && isOlympiadStart() && (needCpUpdate || needHpUpdate))
3077 {
3078 final OlympiadGameTask game = OlympiadGameManager.getInstance().getOlympiadTask(getOlympiadGameId());
3079 if (game != null && game.isBattleStarted())
3080 game.getZone().broadcastStatusUpdate(this);
3081 }
3082
3083 // In duel, MP updated only with CP or HP
3084 if (isInDuel() && (needCpUpdate || needHpUpdate))
3085 {
3086 ExDuelUpdateUserInfo update = new ExDuelUpdateUserInfo(this);
3087 DuelManager.getInstance().broadcastToOppositeTeam(this, update);
3088 }
3089 }
3090
3091 /**
3092 * Broadcast informations from a user to himself and his knownlist.<BR>
3093 * If player is morphed, it sends informations from the template the player is using.
3094 * <ul>
3095 * <li>Send a UserInfo packet (public and private data) to this Player.</li>
3096 * <li>Send a CharInfo packet (public data only) to Player's knownlist.</li>
3097 * </ul>
3098 */
3099 public final void broadcastUserInfo()
3100 {
3101 sendPacket(new UserInfo(this));
3102
3103 if (getPolyType() == PolyType.NPC)
3104 Broadcast.toKnownPlayers(this, new AbstractNpcInfo.PcMorphInfo(this, getPolyTemplate()));
3105 else
3106 broadcastCharInfo();
3107 }
3108
3109 public final void broadcastCharInfo()
3110 {
3111 for (Player player : getKnownType(Player.class))
3112 {
3113 if (getInstanceId() != player.getInstanceId())
3114 continue;
3115
3116 player.sendPacket(new CharInfo(this));
3117
3118 final int relation = getRelation(player);
3119 final boolean isAutoAttackable = isAutoAttackable(player);
3120
3121 player.sendPacket(new RelationChanged(this, relation, isAutoAttackable));
3122 if (getPet() != null)
3123 player.sendPacket(new RelationChanged(getPet(), relation, isAutoAttackable));
3124 }
3125 }
3126
3127 /**
3128 * Broadcast player title information.
3129 */
3130 public final void broadcastTitleInfo()
3131 {
3132 sendPacket(new UserInfo(this));
3133 broadcastPacket(new TitleUpdate(this));
3134 }
3135
3136 /**
3137 * @return the Alliance Identifier of the Player.
3138 */
3139 public int getAllyId()
3140 {
3141 if (_clan == null)
3142 return 0;
3143
3144 return _clan.getAllyId();
3145 }
3146
3147 public int getAllyCrestId()
3148 {
3149 if (getClanId() == 0)
3150 return 0;
3151
3152 if (getClan().getAllyId() == 0)
3153 return 0;
3154
3155 return getClan().getAllyCrestId();
3156 }
3157
3158 /**
3159 * Send a packet to the Player.
3160 */
3161 @Override
3162 public void sendPacket(L2GameServerPacket packet)
3163 {
3164 if (_client != null)
3165 _client.sendPacket(packet);
3166 }
3167
3168 /**
3169 * Send SystemMessage packet.
3170 * @param id SystemMessageId
3171 */
3172 @Override
3173 public void sendPacket(SystemMessageId id)
3174 {
3175 sendPacket(SystemMessage.getSystemMessage(id));
3176 }
3177
3178 /**
3179 * Manage Interact Task with another Player.<BR>
3180 * Turn the character in front of the target.<BR>
3181 * In case of private stores, send the related packet.
3182 * @param target The Creature targeted
3183 */
3184 public void doInteract(Creature target)
3185 {
3186 if (target instanceof Player)
3187 {
3188 Player temp = (Player) target;
3189 sendPacket(new MoveToPawn(this, temp, Npc.INTERACTION_DISTANCE));
3190
3191 switch (temp.getStoreType())
3192 {
3193 case SELL:
3194 case PACKAGE_SELL:
3195 sendPacket(new PrivateStoreListSell(this, temp));
3196 break;
3197
3198 case BUY:
3199 sendPacket(new PrivateStoreListBuy(this, temp));
3200 break;
3201
3202 case MANUFACTURE:
3203 sendPacket(new RecipeShopSellList(this, temp));
3204 break;
3205 default:
3206 break;
3207 }
3208 }
3209 else
3210 {
3211 // _interactTarget=null should never happen but one never knows ^^;
3212 if (target != null)
3213 target.onAction(this);
3214 }
3215 }
3216
3217 /**
3218 * Manage AutoLoot Task.
3219 * <ul>
3220 * <li>Send a System Message to the Player : YOU_PICKED_UP_S1_ADENA or YOU_PICKED_UP_S1_S2</li>
3221 * <li>Add the Item to the Player inventory</li>
3222 * <li>Send InventoryUpdate to this Player with NewItem (use a new slot) or ModifiedItem (increase amount)</li>
3223 * <li>Send StatusUpdate to this Player with current weight</li>
3224 * </ul>
3225 * <FONT COLOR=#FF0000><B> <U>Caution</U> : If a Party is in progress, distribute Items between party members</B></FONT>
3226 * @param target The reference Object.
3227 * @param item The dropped ItemHolder.
3228 */
3229 public void doAutoLoot(Attackable target, IntIntHolder item)
3230 {
3231 if (isInParty())
3232 getParty().distributeItem(this, item, false, target);
3233 else if (item.getId() == 57)
3234 addAdena("Loot", item.getValue(), target, true);
3235 else
3236 addItem("Loot", item.getId(), item.getValue(), target, true);
3237 }
3238
3239 /**
3240 * Manage Pickup Task.
3241 * <ul>
3242 * <li>Send StopMove to this Player</li>
3243 * <li>Remove the ItemInstance from the world and send GetItem packets</li>
3244 * <li>Send a System Message to the Player : YOU_PICKED_UP_S1_ADENA or YOU_PICKED_UP_S1_S2</li>
3245 * <li>Add the Item to the Player inventory</li>
3246 * <li>Send InventoryUpdate to this Player with NewItem (use a new slot) or ModifiedItem (increase amount)</li>
3247 * <li>Send StatusUpdate to this Player with current weight</li>
3248 * </ul>
3249 * <FONT COLOR=#FF0000><B> <U>Caution</U> : If a Party is in progress, distribute Items between party members</B></FONT>
3250 * @param object The ItemInstance to pick up
3251 */
3252 @Override
3253 public void doPickupItem(WorldObject object)
3254 {
3255 if (isAlikeDead() || isFakeDeath())
3256 return;
3257
3258 // Set the AI Intention to IDLE
3259 getAI().setIntention(CtrlIntention.IDLE);
3260
3261 // Check if the WorldObject to pick up is a ItemInstance
3262 if (!(object instanceof ItemInstance))
3263 {
3264 // dont try to pickup anything that is not an item :)
3265 _log.warning(getName() + " tried to pickup a wrong target: " + object);
3266 return;
3267 }
3268
3269 ItemInstance item = (ItemInstance) object;
3270
3271 // Send ActionFailed to this Player
3272 sendPacket(ActionFailed.STATIC_PACKET);
3273 sendPacket(new StopMove(this));
3274
3275 synchronized (item)
3276 {
3277 if (!item.isVisible())
3278 return;
3279
3280 if (isInStoreMode())
3281 return;
3282
3283 if (!_inventory.validateWeight(item.getCount() * item.getItem().getWeight()))
3284 {
3285 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.WEIGHT_LIMIT_EXCEEDED));
3286 return;
3287 }
3288
3289 if (((isInParty() && getParty().getLootRule() == LootRule.ITEM_LOOTER) || !isInParty()) && !_inventory.validateCapacity(item))
3290 {
3291 sendPacket(SystemMessageId.SLOTS_FULL);
3292 return;
3293 }
3294
3295 if (getActiveTradeList() != null)
3296 {
3297 sendPacket(SystemMessageId.CANNOT_PICKUP_OR_USE_ITEM_WHILE_TRADING);
3298 return;
3299 }
3300
3301 if (item.getOwnerId() != 0 && !isLooterOrInLooterParty(item.getOwnerId()))
3302 {
3303 if (item.getItemId() == 57)
3304 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1_ADENA).addNumber(item.getCount()));
3305 else if (item.getCount() > 1)
3306 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S2_S1_S).addItemName(item).addNumber(item.getCount()));
3307 else
3308 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1).addItemName(item));
3309
3310 return;
3311 }
3312
3313 if (item.hasDropProtection())
3314 item.removeDropProtection();
3315
3316 // Remove the ItemInstance from the world and send GetItem packets
3317 item.pickupMe(this);
3318
3319 // item must be removed from ItemsOnGroundManager if is active
3320 ItemsOnGroundTaskManager.getInstance().remove(item);
3321 }
3322
3323 // Auto use herbs - pick up
3324 if (item.getItemType() == EtcItemType.HERB)
3325 {
3326 IItemHandler handler = ItemHandler.getInstance().getHandler(item.getEtcItem());
3327 if (handler != null)
3328 handler.useItem(this, item, false);
3329
3330 ItemTable.getInstance().destroyItem("Consume", item, this, null);
3331 }
3332 // Cursed Weapons are not distributed
3333 else if (CursedWeaponManager.getInstance().isCursed(item.getItemId()))
3334 {
3335 addItem("Pickup", item, null, true);
3336 }
3337 else
3338 {
3339 // if item is instance of L2ArmorType or WeaponType broadcast an "Attention" system message
3340 if (item.getItemType() instanceof ArmorType || item.getItemType() instanceof WeaponType)
3341 {
3342 SystemMessage msg;
3343 if (item.getEnchantLevel() > 0)
3344 msg = SystemMessage.getSystemMessage(SystemMessageId.ATTENTION_S1_PICKED_UP_S2_S3).addString(getName()).addNumber(item.getEnchantLevel()).addItemName(item.getItemId());
3345 else
3346 msg = SystemMessage.getSystemMessage(SystemMessageId.ATTENTION_S1_PICKED_UP_S2).addString(getName()).addItemName(item.getItemId());
3347
3348 broadcastPacket(msg, 1400);
3349 }
3350
3351 // Check if a Party is in progress
3352 if (isInParty())
3353 getParty().distributeItem(this, item);
3354 // Target is adena
3355 else if (item.getItemId() == 57 && getInventory().getAdenaInstance() != null)
3356 {
3357 addAdena("Pickup", item.getCount(), null, true);
3358 ItemTable.getInstance().destroyItem("Pickup", item, this, null);
3359 }
3360 // Target is regular item
3361 else
3362 addItem("Pickup", item, null, true);
3363 }
3364
3365 // Schedule a paralyzed task to wait for the animation to finish
3366 ThreadPool.schedule(() -> setIsParalyzed(false), (int) (700 / getStat().getMovementSpeedMultiplier()));
3367 setIsParalyzed(true);
3368 }
3369
3370 @Override
3371 public void doAttack(Creature target)
3372 {
3373 super.doAttack(target);
3374 clearRecentFakeDeath();
3375 }
3376
3377 @Override
3378 public void doCast(L2Skill skill)
3379 {
3380 super.doCast(skill);
3381 clearRecentFakeDeath();
3382 }
3383
3384 public boolean canOpenPrivateStore()
3385 {
3386 if (getActiveTradeList() != null)
3387 cancelActiveTrade();
3388
3389 return !isAlikeDead() && !isInOlympiadMode() && !isMounted() && !isInsideZone(ZoneId.NO_STORE) && !isCastingNow();
3390 }
3391
3392 public void tryOpenPrivateBuyStore()
3393 {
3394 if (canOpenPrivateStore())
3395 {
3396 if (getStoreType() == StoreType.BUY || getStoreType() == StoreType.BUY_MANAGE)
3397 setStoreType(StoreType.NONE);
3398
3399 if (getStoreType() == StoreType.NONE)
3400 {
3401 standUp();
3402
3403 setStoreType(StoreType.BUY_MANAGE);
3404 sendPacket(new PrivateStoreManageListBuy(this));
3405 }
3406 }
3407 else
3408 {
3409 if (!isInsideZone(ZoneId.STORE))
3410 sendPacket(SystemMessageId.NO_PRIVATE_STORE_HERE);
3411
3412 sendPacket(ActionFailed.STATIC_PACKET);
3413 }
3414 }
3415
3416 public void tryOpenPrivateSellStore(boolean isPackageSale)
3417 {
3418 if (canOpenPrivateStore())
3419 {
3420 if (getStoreType() == StoreType.SELL || getStoreType() == StoreType.SELL_MANAGE || getStoreType() == StoreType.PACKAGE_SELL)
3421 setStoreType(StoreType.NONE);
3422
3423 if (getStoreType() == StoreType.NONE)
3424 {
3425 standUp();
3426
3427 setStoreType(StoreType.SELL_MANAGE);
3428 sendPacket(new PrivateStoreManageListSell(this, isPackageSale));
3429 }
3430 }
3431 else
3432 {
3433 if (!isInsideZone(ZoneId.STORE))
3434 sendPacket(SystemMessageId.NO_PRIVATE_STORE_HERE);
3435
3436 sendPacket(ActionFailed.STATIC_PACKET);
3437 }
3438 }
3439
3440 public void tryOpenWorkshop(boolean isDwarven)
3441 {
3442 if (canOpenPrivateStore())
3443 {
3444 if (isInStoreMode())
3445 setStoreType(StoreType.NONE);
3446
3447 if (getStoreType() == StoreType.NONE)
3448 {
3449 standUp();
3450
3451 if (getCreateList() == null)
3452 setCreateList(new ManufactureList());
3453
3454 sendPacket(new RecipeShopManageList(this, isDwarven));
3455 }
3456 }
3457 else
3458 {
3459 if (!isInsideZone(ZoneId.STORE))
3460 sendPacket(SystemMessageId.NO_PRIVATE_WORKSHOP_HERE);
3461
3462 sendPacket(ActionFailed.STATIC_PACKET);
3463 }
3464 }
3465
3466 public final PreparedListContainer getMultiSell()
3467 {
3468 return _currentMultiSell;
3469 }
3470
3471 public final void setMultiSell(PreparedListContainer list)
3472 {
3473 _currentMultiSell = list;
3474 }
3475
3476 @Override
3477 public void setTarget(WorldObject newTarget)
3478 {
3479 // Check if the new target is visible.
3480 if (newTarget != null && !newTarget.isVisible() && !(newTarget instanceof Player && isInParty() && _party.containsPlayer(newTarget)))
3481 newTarget = null;
3482
3483 // Can't target and attack festival monsters if not participant
3484 if ((newTarget instanceof FestivalMonster) && !isFestivalParticipant())
3485 newTarget = null;
3486 // Can't target and attack rift invaders if not in the same room
3487 else if (isInParty() && getParty().isInDimensionalRift())
3488 {
3489 byte riftType = getParty().getDimensionalRift().getType();
3490 byte riftRoom = getParty().getDimensionalRift().getCurrentRoom();
3491
3492 if (newTarget != null && !DimensionalRiftManager.getInstance().getRoom(riftType, riftRoom).checkIfInZone(newTarget.getX(), newTarget.getY(), newTarget.getZ()))
3493 newTarget = null;
3494 }
3495
3496 // Get the current target
3497 WorldObject oldTarget = getTarget();
3498
3499 if (oldTarget != null)
3500 {
3501 if (oldTarget.equals(newTarget))
3502 return; // no target change
3503
3504 // Remove the Player from the _statusListener of the old target if it was a Creature
3505 if (oldTarget instanceof Creature)
3506 ((Creature) oldTarget).removeStatusListener(this);
3507 }
3508
3509 // Verify if it's a static object.
3510 if (newTarget instanceof StaticObject)
3511 {
3512 sendPacket(new MyTargetSelected(newTarget.getObjectId(), 0));
3513 sendPacket(new StaticObjectInfo((StaticObject) newTarget));
3514 }
3515 // Add the Player to the _statusListener of the new target if it's a Creature
3516 else if (newTarget instanceof Creature)
3517 {
3518 final Creature target = (Creature) newTarget;
3519
3520 // Validate location of the new target.
3521 if (newTarget.getObjectId() != getObjectId())
3522 sendPacket(new ValidateLocation(target));
3523
3524 // Show the client his new target.
3525 sendPacket(new MyTargetSelected(target.getObjectId(), (target.isAutoAttackable(this) || target instanceof Summon) ? getLevel() - target.getLevel() : 0));
3526
3527 target.addStatusListener(this);
3528
3529 // Send max/current hp.
3530 final StatusUpdate su = new StatusUpdate(target);
3531 su.addAttribute(StatusUpdate.MAX_HP, target.getMaxHp());
3532 su.addAttribute(StatusUpdate.CUR_HP, (int) target.getCurrentHp());
3533 sendPacket(su);
3534
3535 Broadcast.toKnownPlayers(this, new TargetSelected(getObjectId(), newTarget.getObjectId(), getX(), getY(), getZ()));
3536 }
3537
3538 if (newTarget instanceof Folk)
3539 setCurrentFolk((Folk) newTarget);
3540 else if (newTarget == null)
3541 {
3542 sendPacket(ActionFailed.STATIC_PACKET);
3543
3544 if (getTarget() != null)
3545 {
3546 broadcastPacket(new TargetUnselected(this));
3547 setCurrentFolk(null);
3548 }
3549 }
3550
3551 // Target the new WorldObject
3552 super.setTarget(newTarget);
3553 }
3554
3555 /**
3556 * Return the active weapon instance (always equipped in the right hand).
3557 */
3558 @Override
3559 public ItemInstance getActiveWeaponInstance()
3560 {
3561 return getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
3562 }
3563
3564 /**
3565 * Return the active weapon item (always equipped in the right hand).
3566 */
3567 @Override
3568 public Weapon getActiveWeaponItem()
3569 {
3570 final ItemInstance weapon = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
3571 return (weapon == null) ? getTemplate().getFists() : (Weapon) weapon.getItem();
3572 }
3573
3574 /**
3575 * @return the type of attack, depending of the worn weapon.
3576 */
3577 @Override
3578 public WeaponType getAttackType()
3579 {
3580 return getActiveWeaponItem().getItemType();
3581 }
3582
3583 /**
3584 * @param type : The ArmorType to check. It supports NONE, SHIELD, MAGIC, LIGHT and HEAVY.
3585 * @return true if the given ArmorType is used by the chest of the player, false otherwise.
3586 */
3587 public boolean isWearingArmorType(ArmorType type)
3588 {
3589 // Retrieve either the shield or the chest, following ArmorType to check.
3590 final ItemInstance armor = getInventory().getPaperdollItem((type == ArmorType.SHIELD) ? Inventory.PAPERDOLL_LHAND : Inventory.PAPERDOLL_CHEST);
3591 if (armor == null)
3592 return type == ArmorType.NONE; // Return true if not equipped and the check was based on NONE ArmorType.
3593
3594 // Test if the equipped item is an armor, then finally compare both ArmorType.
3595 return armor.getItemType() instanceof ArmorType && armor.getItemType() == type;
3596 }
3597
3598 public boolean isUnderMarryRequest()
3599 {
3600 return _isUnderMarryRequest;
3601 }
3602
3603 public void setUnderMarryRequest(boolean state)
3604 {
3605 _isUnderMarryRequest = state;
3606 }
3607
3608 public int getCoupleId()
3609 {
3610 return _coupleId;
3611 }
3612
3613 public void setCoupleId(int coupleId)
3614 {
3615 _coupleId = coupleId;
3616 }
3617
3618 public void setRequesterId(int requesterId)
3619 {
3620 _requesterId = requesterId;
3621 }
3622
3623 public void engageAnswer(int answer)
3624 {
3625 if (!_isUnderMarryRequest || _requesterId == 0)
3626 return;
3627
3628 final Player requester = World.getInstance().getPlayer(_requesterId);
3629 if (requester != null)
3630 {
3631 if (answer == 1)
3632 {
3633 // Create the couple
3634 CoupleManager.getInstance().addCouple(requester, this);
3635
3636 // Then "finish the job"
3637 WeddingManagerNpc.justMarried(requester, this);
3638 }
3639 else
3640 {
3641 setUnderMarryRequest(false);
3642 sendMessage("You declined your partner's marriage request.");
3643
3644 requester.setUnderMarryRequest(false);
3645 requester.sendMessage("Your partner declined your marriage request.");
3646 }
3647 }
3648 }
3649
3650 /**
3651 * Return the secondary weapon instance (always equipped in the left hand).
3652 */
3653 @Override
3654 public ItemInstance getSecondaryWeaponInstance()
3655 {
3656 return getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
3657 }
3658
3659 /**
3660 * Return the secondary L2Item item (always equiped in the left hand).
3661 */
3662 @Override
3663 public Item getSecondaryWeaponItem()
3664 {
3665 ItemInstance item = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
3666 if (item != null)
3667 return item.getItem();
3668
3669 return null;
3670 }
3671
3672 /**
3673 * Kill the Creature, Apply Death Penalty, Manage gain/loss Karma and Item Drop.
3674 * <ul>
3675 * <li>Reduce the Experience of the Player in function of the calculated Death Penalty</li>
3676 * <li>If necessary, unsummon the Pet of the killed Player</li>
3677 * <li>Manage Karma gain for attacker and Karam loss for the killed Player</li>
3678 * <li>If the killed Player has Karma, manage Drop Item</li>
3679 * <li>Kill the Player</li>
3680 * </ul>
3681 * @param killer The Creature who attacks
3682 */
3683 @Override
3684 public boolean doDie(Creature killer)
3685 {
3686 // Kill the Player
3687 if (!super.doDie(killer))
3688 return false;
3689
3690 if (isMounted())
3691 stopFeed();
3692
3693 _killCount = 0;
3694 _tvtkills = 0;
3695
3696 // Icons update in order to get retained buffs list
3697 updateEffectIcons();
3698
3699 synchronized (this)
3700 {
3701 if (isFakeDeath())
3702 stopFakeDeath(true);
3703 }
3704
3705 if (killer != null)
3706 {
3707 Player pk = killer.getActingPlayer();
3708
3709 // Clear resurrect xp calculation
3710 setExpBeforeDeath(0);
3711
3712 if (isCursedWeaponEquipped())
3713 CursedWeaponManager.getInstance().drop(_cursedWeaponEquippedId, killer);
3714 else
3715 {
3716 if (pk == null || !pk.isCursedWeaponEquipped())
3717 {
3718 if (EventManager.getInstance().isRunning() && EventManager.getInstance().isRegistered(this))
3719 {
3720 if (killer.isRaid() || killer.isRaidMinion())
3721 EventManager.getInstance().getCurrentEvent().onDie(this, killer);
3722 else if (pk != null && EventManager.getInstance().isRegistered(pk))
3723 {
3724 EventManager.getInstance().getCurrentEvent().onKill(this, pk);
3725 EventManager.getInstance().getCurrentEvent().onDie(this, pk);
3726 }
3727 }
3728
3729 onDieDropItem(killer); // Check if any item should be dropped
3730
3731 // if the area isn't an arena
3732 if (!isInArena())
3733 {
3734 // if both victim and attacker got clans & aren't academicians
3735 if (pk != null && pk.getClan() != null && getClan() != null && !isAcademyMember() && !pk.isAcademyMember())
3736 {
3737 // if clans got mutual war, then use the reputation calcul
3738 if (_clan.isAtWarWith(pk.getClanId()) && pk.getClan().isAtWarWith(_clan.getClanId()))
3739 {
3740 // when your reputation score is 0 or below, the other clan cannot acquire any reputation points
3741 if (getClan().getReputationScore() > 0)
3742 pk.getClan().addReputationScore(1);
3743 // when the opposing sides reputation score is 0 or below, your clans reputation score doesn't decrease
3744 if (pk.getClan().getReputationScore() > 0)
3745 _clan.takeReputationScore(1);
3746 }
3747 }
3748 }
3749
3750 // Reduce player's xp and karma.
3751 if (Config.ALT_GAME_DELEVEL && (!hasSkill(L2Skill.SKILL_LUCKY) || getStat().getLevel() > 9))
3752 deathPenalty(pk != null && getClan() != null && pk.getClan() != null && (getClan().isAtWarWith(pk.getClanId()) || pk.getClan().isAtWarWith(getClanId())), pk != null, killer instanceof SiegeGuard);
3753 }
3754 }
3755 }
3756
3757 // Unsummon Cubics
3758 if (!_cubics.isEmpty())
3759 {
3760 for (Cubic cubic : _cubics.values())
3761 {
3762 cubic.stopAction();
3763 cubic.cancelDisappear();
3764 }
3765
3766 _cubics.clear();
3767 }
3768
3769 if (_fusionSkill != null)
3770 abortCast();
3771
3772 for (Creature character : getKnownType(Creature.class))
3773 if (character.getFusionSkill() != null && character.getFusionSkill().getTarget() == this)
3774 character.abortCast();
3775
3776 // calculate death penalty buff
3777 calculateDeathPenaltyBuffLevel(killer);
3778
3779 WaterTaskManager.getInstance().remove(this);
3780
3781 if (isPhoenixBlessed() || (isAffected(L2EffectFlag.CHARM_OF_COURAGE) && isInSiege()))
3782 reviveRequest(this, null, false);
3783
3784 return true;
3785 }
3786
3787 private void onDieDropItem(Creature killer)
3788 {
3789 if (killer == null)
3790 return;
3791
3792 Player pk = killer.getActingPlayer();
3793 if (getKarma() <= 0 && pk != null && pk.getClan() != null && getClan() != null && pk.getClan().isAtWarWith(getClanId()))
3794 return;
3795
3796 if ((!isInsideZone(ZoneId.PVP) || pk == null) && (!isGM() || Config.KARMA_DROP_GM))
3797 {
3798 boolean isKillerNpc = (killer instanceof Npc);
3799 int pkLimit = Config.KARMA_PK_LIMIT;
3800
3801 int dropEquip = 0;
3802 int dropEquipWeapon = 0;
3803 int dropItem = 0;
3804 int dropLimit = 0;
3805 int dropPercent = 0;
3806
3807 if (getKarma() > 0 && getPkKills() >= pkLimit)
3808 {
3809 dropPercent = Config.KARMA_RATE_DROP;
3810 dropEquip = Config.KARMA_RATE_DROP_EQUIP;
3811 dropEquipWeapon = Config.KARMA_RATE_DROP_EQUIP_WEAPON;
3812 dropItem = Config.KARMA_RATE_DROP_ITEM;
3813 dropLimit = Config.KARMA_DROP_LIMIT;
3814 }
3815 else if (isKillerNpc && getLevel() > 4 && !isFestivalParticipant())
3816 {
3817 dropPercent = Config.PLAYER_RATE_DROP;
3818 dropEquip = Config.PLAYER_RATE_DROP_EQUIP;
3819 dropEquipWeapon = Config.PLAYER_RATE_DROP_EQUIP_WEAPON;
3820 dropItem = Config.PLAYER_RATE_DROP_ITEM;
3821 dropLimit = Config.PLAYER_DROP_LIMIT;
3822 }
3823
3824 if (dropPercent > 0 && Rnd.get(100) < dropPercent)
3825 {
3826 int dropCount = 0;
3827 int itemDropPercent = 0;
3828
3829 for (ItemInstance itemDrop : getInventory().getItems())
3830 {
3831 // Don't drop those following things
3832 if (!itemDrop.isDropable() || itemDrop.isShadowItem() || itemDrop.getItemId() == 57 || itemDrop.getItem().getType2() == Item.TYPE2_QUEST || getPet() != null && getPet().getControlItemId() == itemDrop.getItemId() || Arrays.binarySearch(Config.KARMA_LIST_NONDROPPABLE_ITEMS, itemDrop.getItemId()) >= 0 || Arrays.binarySearch(Config.KARMA_LIST_NONDROPPABLE_PET_ITEMS, itemDrop.getItemId()) >= 0)
3833 continue;
3834
3835 if (itemDrop.isEquipped())
3836 {
3837 // Set proper chance according to Item type of equipped Item
3838 itemDropPercent = itemDrop.getItem().getType2() == Item.TYPE2_WEAPON ? dropEquipWeapon : dropEquip;
3839 getInventory().unEquipItemInSlot(itemDrop.getLocationSlot());
3840 }
3841 else
3842 itemDropPercent = dropItem; // Item in inventory
3843
3844 // NOTE: Each time an item is dropped, the chance of another item being dropped gets lesser (dropCount * 2)
3845 if (Rnd.get(100) < itemDropPercent)
3846 {
3847 dropItem("DieDrop", itemDrop, killer, true);
3848
3849 if (++dropCount >= dropLimit)
3850 break;
3851 }
3852 }
3853 }
3854 }
3855 }
3856
3857 public void updateKarmaLoss(long exp)
3858 {
3859 if (!isCursedWeaponEquipped() && getKarma() > 0)
3860 {
3861 int karmaLost = Formulas.calculateKarmaLost(getLevel(), exp);
3862 if (karmaLost > 0)
3863 setKarma(getKarma() - karmaLost);
3864 }
3865 }
3866
3867 /**
3868 * Check anti farm.
3869 *
3870 * @param targetPlayer the target player
3871 * @return true, if successful
3872 */
3873 private boolean checkAntiFarm(Player targetPlayer)
3874 {
3875
3876 if(Config.ANTI_FARM_ENABLED)
3877 {
3878
3879 //Anti FARM Clan - Ally
3880 if(Config.ANTI_FARM_CLAN_ALLY_ENABLED && !isInsideZone(ZoneId.MULTI_FUNCTION) && (getClanId() > 0 && targetPlayer.getClanId() > 0 && getClanId() == targetPlayer.getClanId()) || (getAllyId() > 0 && !isInsideZone(ZoneId.MULTI_FUNCTION) && targetPlayer.getAllyId() > 0 && getAllyId() == targetPlayer.getAllyId()))
3881 {
3882 this.sendMessage("Farm PvP is punishable!");
3883 _log.warning("PVP POINT FARM ATTEMPT, " + this.getName() + " and " + targetPlayer.getName() +". CLAN or ALLY.");
3884 return false;
3885 }
3886
3887 //Anti FARM Party
3888 if(Config.ANTI_FARM_PARTY_ENABLED && this.getParty() != null
3889 && targetPlayer.getParty() != null
3890 && this.getParty().equals(targetPlayer.getParty()))
3891 {
3892 this.sendMessage("Farm PvP is punishable!");
3893 _log.warning("PVP POINT FARM ATTEMPT, " + this.getName() + " and " + targetPlayer.getName() +". SAME PARTY.");
3894 return false;
3895 }
3896
3897 //Anti FARM same Ip
3898 if(Config.ANTI_FARM_IP_ENABLED)
3899 {
3900 if(this.getClient() != null && targetPlayer.getClient() != null)
3901 {
3902 String ip1 = this.getClient().getConnection().getInetAddress().getHostAddress();
3903 String ip2 = targetPlayer.getClient().getConnection().getInetAddress().getHostAddress();
3904
3905 if (ip1.equals(ip2))
3906 {
3907 this.sendMessage("Farm PvP is punishable!");
3908 _log.warning("PVP POINT FARM ATTEMPT: " + this.getName() + " and " + targetPlayer.getName() +". SAME IP.");
3909 return false;
3910 }
3911 }
3912 }
3913 return true;
3914 }
3915 return true;
3916 }
3917
3918 /**
3919 * This method is used to update PvP counter, or PK counter / add Karma if necessary.<br>
3920 * It also updates clan kills/deaths counters on siege.
3921 * @param target The L2Playable victim.
3922 */
3923 public void onKillUpdatePvPKarma(Playable target)
3924 {
3925 if (target == null)
3926 return;
3927
3928 final Player targetPlayer = target.getActingPlayer();
3929 if (targetPlayer == null || targetPlayer == this)
3930 return;
3931
3932 // Don't rank up the CW if it was a summon.
3933 if (isCursedWeaponEquipped() && target instanceof Player)
3934 {
3935 CursedWeaponManager.getInstance().increaseKills(_cursedWeaponEquippedId);
3936 return;
3937 }
3938
3939 // If in duel and you kill (only can kill l2summon), do nothing
3940 if (isInDuel() && targetPlayer.isInDuel())
3941 return;
3942
3943 if (EventManager.getInstance().isRunning() && EventManager.getInstance().isRegistered(this) && EventManager.getInstance().isRegistered(targetPlayer))
3944 {
3945 if (!(target instanceof Summon))
3946 {
3947 getPvpKills();
3948 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_S2);
3949 sm.addZoneName(targetPlayer.getPosition());
3950 sm.addString(" " + getName() + " killed " + targetPlayer.getName() + ".");
3951 Broadcast.toAllOnlinePlayers(sm);
3952 }
3953
3954 return;
3955 }
3956
3957 //check anti-farm
3958 if(!checkAntiFarm(targetPlayer))
3959 return;
3960
3961 // If in duel and you kill (only can kill l2summon), do nothing
3962 if (isInDuel() && targetPlayer.isInDuel())
3963 return;
3964
3965 // If in pvp zone, do nothing.
3966 if (isInsideZone(ZoneId.PVP) && targetPlayer.isInsideZone(ZoneId.PVP))
3967 {
3968 // Until the zone was a siege zone. Check also if victim was a player. Randomers aren't counted.
3969 if (target instanceof Player && getSiegeState() > 0 && targetPlayer.getSiegeState() > 0 && getSiegeState() != targetPlayer.getSiegeState())
3970 {
3971 // Now check clan relations.
3972 final Clan killerClan = getClan();
3973 if (killerClan != null)
3974 killerClan.setSiegeKills(killerClan.getSiegeKills() + 1);
3975
3976 final Clan targetClan = targetPlayer.getClan();
3977 if (targetClan != null)
3978 targetClan.setSiegeDeaths(targetClan.getSiegeDeaths() + 1);
3979 }
3980 return;
3981 }
3982
3983 // Check if it's pvp (cases : regular, wars, victim is PKer)
3984 if (checkIfPvP(target) || (targetPlayer.getClan() != null && getClan() != null && getClan().isAtWarWith(targetPlayer.getClanId()) && targetPlayer.getClan().isAtWarWith(getClanId()) && targetPlayer.getPledgeType() != Clan.SUBUNIT_ACADEMY && getPledgeType() != Clan.SUBUNIT_ACADEMY) || (targetPlayer.getKarma() > 0 && Config.KARMA_AWARD_PK_KILL))
3985 {
3986 if (target instanceof Player)
3987 {
3988 // Add PvP point to attacker.
3989 setPvpKills(getPvpKills() + 1);
3990
3991 MultiFunctionZone.givereward(this);
3992
3993 if (Config.DAILY_LORD_ENABLED) {
3994 DailyLord.addZonePvp(this);
3995 sendMessage("You got " + DailyLord.getZonePvp(this) + " daily pvp.");
3996 }
3997
3998 //if(Config.ALLOW_PVP_REWARD_MULTI_FUNCTION)
3999 //{
4000 // if (isInsideZone(ZoneId.MULTI_FUNCTION))
4001 // addItem("Loot", Config.PVP_REWARD_ITEM_MULTI_FUNCTION, Config.PVP_REWARD_COUNT_MULTI_FUNCTION, this, true);
4002 //}
4003
4004 if(Config.ALLOW_PVP_REWARD)
4005 {
4006 addItem("Loot", Config.PVP_REWARD_ITEM, Config.PVP_REWARD_COUNT, this, true);
4007 }
4008
4009 if (Config.PVP_COUNT_SYSTEM)
4010 {
4011 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 16, "[PvP]Player",target.getName()+" Killed by " +getName()));
4012
4013 // Count the kill
4014 _killCount++;
4015
4016 switch (_killCount)
4017 {
4018
4019 case 3:
4020 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", is Triple kill! with 3 kills in row."));
4021 break;
4022 case 6:
4023 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", is Good killer! with 6 kills in row."));
4024 break;
4025 case 9:
4026 break;
4027 case 12:
4028 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", is Mega kill! with 12 kills in row."));
4029 break;
4030 case 15:
4031 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+ ", have no Mercy! with 15 kills in row."));
4032 break;
4033 case 20:
4034 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", is in Killing Spree! with 20 kills in row."));
4035 break;
4036 case 25:
4037 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", is in Rampage! with 25 kills in row."));
4038 break;
4039 case 30:
4040 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", is in Dominating! with 30 kills in row."));
4041 break;
4042 case 35:
4043 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", is in Ultra Kill! with 35 kills in row."));
4044 break;
4045 case 40:
4046 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", is in Ownage! with 40 kills in row."));
4047 break;
4048 case 45:
4049 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", is in Wicked Sick! with 45 kills in row."));
4050 break;
4051 case 46:
4052 Broadcast.toAllOnlinePlayers(new CreatureSay(0, 15, "[PvP]",getName()+", SOME ONE KILL HIM!!!."));
4053 break;
4054 }
4055 }
4056
4057 // Send UserInfo packet to attacker with its Karma and PK Counter
4058 sendPacket(new UserInfo(this));
4059 }
4060 }
4061 // Otherwise, killer is considered as a PKer.
4062 else if (targetPlayer.getKarma() == 0 && targetPlayer.getPvpFlag() == 0)
4063 {
4064 // PK Points are increased only if you kill a player.
4065 if (target instanceof Player)
4066 setPkKills(getPkKills() + 1);
4067
4068 if(Config.ALLOW_PK_REWARD)
4069 {
4070 // Item Reward system
4071 addItem("Loot", Config.PK_REWARD_ITEM, Config.PK_REWARD_COUNT, this, true);
4072 }
4073
4074 // Calculate new karma.
4075 setKarma(getKarma() + Formulas.calculateKarmaGain(getPkKills(), target instanceof Summon));
4076
4077 // Send UserInfo packet to attacker with its Karma and PK Counter
4078 sendPacket(new UserInfo(this));
4079 }
4080 }
4081
4082 public void updatePvPStatus()
4083 {
4084 if (isInsideZone(ZoneId.PVP) || isInsideZone(ZoneId.MULTI_FUNCTION) || isInsideZone(ZoneId.PVP_FLAG))
4085 return;
4086
4087 if (EventManager.getInstance().isRegistered(this) && EventManager.getInstance().isRunning())
4088 return;
4089
4090 PvpFlagTaskManager.getInstance().add(this, Config.PVP_NORMAL_TIME);
4091
4092 if (getPvpFlag() == 0)
4093 updatePvPFlag(1);
4094 }
4095
4096 public void updatePvPStatus(Creature target)
4097 {
4098 final Player player = target.getActingPlayer();
4099 if (player == null)
4100 return;
4101
4102 if (EventManager.getInstance().isRegistered(this) && EventManager.getInstance().isRunning())
4103 return;
4104
4105 if (isInDuel() && player.getDuelId() == getDuelId())
4106 return;
4107
4108 if (isInsideZone(ZoneId.PVP_FLAG) || isInsideZone(ZoneId.MULTI_FUNCTION))
4109 return;
4110
4111 if (isInOlympiadMode() && isOlympiadStart()) {
4112 return;
4113 }
4114
4115 if ((!isInsideZone(ZoneId.PVP) || !target.isInsideZone(ZoneId.PVP)) && player.getKarma() == 0)
4116 {
4117 PvpFlagTaskManager.getInstance().add(this, checkIfPvP(player) ? Config.PVP_PVP_TIME : Config.PVP_NORMAL_TIME);
4118
4119 if (getPvpFlag() == 0)
4120 updatePvPFlag(1);
4121 }
4122 }
4123
4124 // Custom PVP Color System - Start
4125 public void updatePvPColor(int pvpKillAmount)
4126 {
4127 if(Config.PVP_COLOR_SYSTEM_ENABLED)
4128 {
4129 //Check if the character has GM access and if so, let them be.
4130 if(isGM())
4131 return;
4132
4133 if(pvpKillAmount >= Config.PVP_AMOUNT1 && pvpKillAmount < Config.PVP_AMOUNT2)
4134 {
4135 getAppearance().setNameColor(Config.NAME_COLOR_FOR_PVP_AMOUNT1);
4136 }
4137 else if(pvpKillAmount >= Config.PVP_AMOUNT2 && pvpKillAmount < Config.PVP_AMOUNT3)
4138 {
4139 getAppearance().setNameColor(Config.NAME_COLOR_FOR_PVP_AMOUNT2);
4140 }
4141 else if(pvpKillAmount >= Config.PVP_AMOUNT3 && pvpKillAmount < Config.PVP_AMOUNT4)
4142 {
4143 getAppearance().setNameColor(Config.NAME_COLOR_FOR_PVP_AMOUNT3);
4144 }
4145 else if(pvpKillAmount >= Config.PVP_AMOUNT4 && pvpKillAmount < Config.PVP_AMOUNT5)
4146 {
4147 getAppearance().setNameColor(Config.NAME_COLOR_FOR_PVP_AMOUNT4);
4148 }
4149 else if(pvpKillAmount >= Config.PVP_AMOUNT5 && pvpKillAmount < Config.PVP_AMOUNT6)
4150 {
4151 getAppearance().setNameColor(Config.NAME_COLOR_FOR_PVP_AMOUNT5);
4152 }
4153 else if(pvpKillAmount >= Config.PVP_AMOUNT6 && pvpKillAmount < Config.PVP_AMOUNT7)
4154 {
4155 getAppearance().setNameColor(Config.NAME_COLOR_FOR_PVP_AMOUNT6);
4156 }
4157 else if(pvpKillAmount >= Config.PVP_AMOUNT7 && pvpKillAmount < Config.PVP_AMOUNT8)
4158 {
4159 getAppearance().setNameColor(Config.NAME_COLOR_FOR_PVP_AMOUNT7);
4160 }
4161 else if(pvpKillAmount >= Config.PVP_AMOUNT8)
4162 {
4163 getAppearance().setNameColor(Config.NAME_COLOR_FOR_PVP_AMOUNT8);
4164 }
4165 }
4166 }
4167 /**
4168 * Restore the experience this Player has lost and sends StatusUpdate packet.
4169 * @param restorePercent The specified % of restored experience.
4170 */
4171 public void restoreExp(double restorePercent)
4172 {
4173 if (getExpBeforeDeath() > 0)
4174 {
4175 getStat().addExp((int) Math.round((getExpBeforeDeath() - getExp()) * restorePercent / 100));
4176 setExpBeforeDeath(0);
4177 }
4178 }
4179
4180 /**
4181 * Reduce the Experience (and level if necessary) of the Player in function of the calculated Death Penalty.
4182 * <ul>
4183 * <li>Calculate the Experience loss</li>
4184 * <li>Set the value of _expBeforeDeath</li>
4185 * <li>Set the new Experience value of the Player and Decrease its level if necessary</li>
4186 * <li>Send StatusUpdate packet with its new Experience</li>
4187 * </ul>
4188 * @param atWar If true, use clan war penalty system instead of regular system.
4189 * @param killedByPlayable Used to see if victim loses XP or not.
4190 * @param killedBySiegeNpc Used to see if victim loses XP or not.
4191 */
4192 public void deathPenalty(boolean atWar, boolean killedByPlayable, boolean killedBySiegeNpc)
4193 {
4194 if (EventManager.getInstance().isRegistered(this) && EventManager.getInstance().isRunning())
4195 return;
4196
4197 // No xp loss inside pvp zone unless
4198 // - it's a siege zone and you're NOT participating
4199 // - you're killed by a non-pc whose not belong to the siege
4200 if (isInsideZone(ZoneId.PVP))
4201 {
4202 // No xp loss for siege participants inside siege zone.
4203 if (isInsideZone(ZoneId.SIEGE))
4204 {
4205 if (isInSiege() && (killedByPlayable || killedBySiegeNpc))
4206 return;
4207 }
4208 // No xp loss for arenas participants killed by playable.
4209 else if (killedByPlayable)
4210 return;
4211 }
4212
4213 // Get the level of the Player
4214 final int lvl = getLevel();
4215
4216 // The death steal you some Exp
4217 double percentLost = 7.0;
4218 if (getLevel() >= 76)
4219 percentLost = 2.0;
4220 else if (getLevel() >= 40)
4221 percentLost = 4.0;
4222
4223 if (getKarma() > 0)
4224 percentLost *= Config.RATE_KARMA_EXP_LOST;
4225
4226 if (isFestivalParticipant() || atWar || isInsideZone(ZoneId.SIEGE))
4227 percentLost /= 4.0;
4228
4229 // Calculate the Experience loss
4230 long lostExp = 0;
4231
4232 if (lvl < Experience.MAX_LEVEL)
4233 lostExp = Math.round((getStat().getExpForLevel(lvl + 1) - getStat().getExpForLevel(lvl)) * percentLost / 100);
4234 else
4235 lostExp = Math.round((getStat().getExpForLevel(Experience.MAX_LEVEL) - getStat().getExpForLevel(Experience.MAX_LEVEL - 1)) * percentLost / 100);
4236
4237 // Get the Experience before applying penalty
4238 setExpBeforeDeath(getExp());
4239
4240 // Set new karma
4241 updateKarmaLoss(lostExp);
4242
4243 // Set the new Experience value of the Player
4244 getStat().addExp(-lostExp);
4245 }
4246
4247 public int getPartyRoom()
4248 {
4249 return _partyroom;
4250 }
4251
4252 public boolean isInPartyMatchRoom()
4253 {
4254 return _partyroom > 0;
4255 }
4256
4257 public void setPartyRoom(int id)
4258 {
4259 _partyroom = id;
4260 }
4261
4262 /**
4263 * Remove the player from both waiting list and any potential room.
4264 */
4265 public void removeMeFromPartyMatch()
4266 {
4267 PartyMatchWaitingList.getInstance().removePlayer(this);
4268 if (_partyroom != 0)
4269 {
4270 PartyMatchRoom room = PartyMatchRoomList.getInstance().getRoom(_partyroom);
4271 if (room != null)
4272 room.deleteMember(this);
4273 }
4274 }
4275
4276 /**
4277 * Stop all timers related to that Player.
4278 */
4279 public void stopAllTimers()
4280 {
4281 stopHpMpRegeneration();
4282 WaterTaskManager.getInstance().remove(this);
4283 stopFeed();
4284
4285 _petTemplate = null;
4286 _petData = null;
4287
4288 storePetFood(_mountNpcId);
4289 stopPunishTask(true);
4290 stopChargeTask();
4291
4292 AttackStanceTaskManager.getInstance().remove(this);
4293 PvpFlagTaskManager.getInstance().remove(this);
4294 GameTimeTaskManager.getInstance().remove(this);
4295 ShadowItemTaskManager.getInstance().remove(this);
4296 AioTaskManager.getInstance().remove(this);
4297 if (isVipStatus())
4298 VipTimeTaskManager.getInstance().remove(this);
4299 }
4300
4301 /**
4302 * Return the L2Summon of the Player or null.
4303 */
4304 @Override
4305 public Summon getPet()
4306 {
4307 return _summon;
4308 }
4309
4310 /**
4311 * @return {@code true} if the player has a pet, {@code false} otherwise
4312 */
4313 public boolean hasPet()
4314 {
4315 return _summon instanceof Pet;
4316 }
4317
4318 /**
4319 * @return {@code true} if the player has a summon, {@code false} otherwise
4320 */
4321 public boolean hasServitor()
4322 {
4323 return _summon instanceof Servitor;
4324 }
4325
4326 /**
4327 * Set the L2Summon of the Player.
4328 * @param summon The Object.
4329 */
4330 public void setPet(Summon summon)
4331 {
4332 _summon = summon;
4333 }
4334
4335 /**
4336 * @return the L2TamedBeast of the Player or null.
4337 */
4338 public TamedBeast getTrainedBeast()
4339 {
4340 return _tamedBeast;
4341 }
4342
4343 /**
4344 * Set the L2TamedBeast of the Player.
4345 * @param tamedBeast The Object.
4346 */
4347 public void setTrainedBeast(TamedBeast tamedBeast)
4348 {
4349 _tamedBeast = tamedBeast;
4350 }
4351
4352 /**
4353 * @return the current {@link Request}.
4354 */
4355 public Request getRequest()
4356 {
4357 return _request;
4358 }
4359
4360 /**
4361 * Set the Player requester of a transaction (ex : FriendInvite, JoinAlly, JoinParty...).
4362 * @param requester
4363 */
4364 public void setActiveRequester(Player requester)
4365 {
4366 _activeRequester = requester;
4367 }
4368
4369 /**
4370 * @return the Player requester of a transaction (ex : FriendInvite, JoinAlly, JoinParty...).
4371 */
4372 public Player getActiveRequester()
4373 {
4374 if (_activeRequester != null && _activeRequester.isRequestExpired() && _activeTradeList == null)
4375 _activeRequester = null;
4376
4377 return _activeRequester;
4378 }
4379
4380 /**
4381 * @return True if a request is in progress.
4382 */
4383 public boolean isProcessingRequest()
4384 {
4385 return getActiveRequester() != null || _requestExpireTime > System.currentTimeMillis();
4386 }
4387
4388 /**
4389 * @return True if a transaction <B>(trade OR request)</B> is in progress.
4390 */
4391 public boolean isProcessingTransaction()
4392 {
4393 return getActiveRequester() != null || _activeTradeList != null || _requestExpireTime > System.currentTimeMillis();
4394 }
4395
4396 /**
4397 * Set the _requestExpireTime of that Player, and set his partner as the active requester.
4398 * @param partner The partner to make checks on.
4399 */
4400 public void onTransactionRequest(Player partner)
4401 {
4402 _requestExpireTime = System.currentTimeMillis() + REQUEST_TIMEOUT * 1000;
4403 partner.setActiveRequester(this);
4404 }
4405
4406 /**
4407 * @return true if last request is expired.
4408 */
4409 public boolean isRequestExpired()
4410 {
4411 return _requestExpireTime <= System.currentTimeMillis();
4412 }
4413
4414 /**
4415 * Select the Warehouse to be used in next activity.
4416 */
4417 public void onTransactionResponse()
4418 {
4419 _requestExpireTime = 0;
4420 }
4421
4422 /**
4423 * Select the Warehouse to be used in next activity.
4424 * @param warehouse An active warehouse.
4425 */
4426 public void setActiveWarehouse(ItemContainer warehouse)
4427 {
4428 _activeWarehouse = warehouse;
4429 }
4430
4431 /**
4432 * @return The active Warehouse.
4433 */
4434 public ItemContainer getActiveWarehouse()
4435 {
4436 return _activeWarehouse;
4437 }
4438
4439 /**
4440 * Set the TradeList to be used in next activity.
4441 * @param tradeList The TradeList to be used.
4442 */
4443 public void setActiveTradeList(TradeList tradeList)
4444 {
4445 _activeTradeList = tradeList;
4446 }
4447
4448 /**
4449 * @return The active TradeList.
4450 */
4451 public TradeList getActiveTradeList()
4452 {
4453 return _activeTradeList;
4454 }
4455
4456 public void onTradeStart(Player partner)
4457 {
4458 _activeTradeList = new TradeList(this);
4459 _activeTradeList.setPartner(partner);
4460
4461 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.BEGIN_TRADE_WITH_S1).addString(partner.getName()));
4462 sendPacket(new TradeStart(this));
4463 }
4464
4465 public void onTradeConfirm(Player partner)
4466 {
4467 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_CONFIRMED_TRADE).addString(partner.getName()));
4468
4469 partner.sendPacket(TradePressOwnOk.STATIC_PACKET);
4470 sendPacket(TradePressOtherOk.STATIC_PACKET);
4471 }
4472
4473 public void onTradeCancel(Player partner)
4474 {
4475 if (_activeTradeList == null)
4476 return;
4477
4478 _activeTradeList.lock();
4479 _activeTradeList = null;
4480
4481 sendPacket(new SendTradeDone(0));
4482 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_CANCELED_TRADE).addString(partner.getName()));
4483 }
4484
4485 public void onTradeFinish(boolean successfull)
4486 {
4487 _activeTradeList = null;
4488 sendPacket(new SendTradeDone(1));
4489 if (successfull)
4490 sendPacket(SystemMessageId.TRADE_SUCCESSFUL);
4491 }
4492
4493 public void startTrade(Player partner)
4494 {
4495 onTradeStart(partner);
4496 partner.onTradeStart(this);
4497 }
4498
4499 public void cancelActiveTrade()
4500 {
4501 if (_activeTradeList == null)
4502 return;
4503
4504 Player partner = _activeTradeList.getPartner();
4505 if (partner != null)
4506 partner.onTradeCancel(this);
4507
4508 onTradeCancel(this);
4509 }
4510
4511 /**
4512 * @return The _createList object of the Player.
4513 */
4514 public ManufactureList getCreateList()
4515 {
4516 return _createList;
4517 }
4518
4519 /**
4520 * Set the _createList object of the Player.
4521 * @param list
4522 */
4523 public void setCreateList(ManufactureList list)
4524 {
4525 _createList = list;
4526 }
4527
4528 /**
4529 * @return The _sellList object of the Player.
4530 */
4531 public TradeList getSellList()
4532 {
4533 if (_sellList == null)
4534 _sellList = new TradeList(this);
4535
4536 return _sellList;
4537 }
4538
4539 /**
4540 * @return the _buyList object of the Player.
4541 */
4542 public TradeList getBuyList()
4543 {
4544 if (_buyList == null)
4545 _buyList = new TradeList(this);
4546
4547 return _buyList;
4548 }
4549
4550 /**
4551 * Set the Store type of the Player.
4552 * @param type : 0 = none, 1 = sell, 2 = sellmanage, 3 = buy, 4 = buymanage, 5 = manufacture.
4553 */
4554 public void setStoreType(StoreType type)
4555 {
4556 _storeType = type;
4557
4558 if (Config.OFFLINE_DISCONNECT_FINISHED && type == StoreType.NONE && (getClient() == null || getClient().isDetached()))
4559 {
4560 deleteMe();
4561 logout();
4562 }
4563 }
4564
4565 /**
4566 * @return The Store type of the Player.
4567 */
4568 public StoreType getStoreType()
4569 {
4570 return _storeType;
4571 }
4572
4573 /**
4574 * @return true if the {@link Player} can use dwarven recipes.
4575 */
4576 public boolean hasDwarvenCraft()
4577 {
4578 return hasSkill(L2Skill.SKILL_CREATE_DWARVEN);
4579 }
4580
4581 /**
4582 * @return true if the {@link Player} can use common recipes.
4583 */
4584 public boolean hasCommonCraft()
4585 {
4586 return hasSkill(L2Skill.SKILL_CREATE_COMMON);
4587 }
4588
4589 /**
4590 * Method used by regular leveling system.<br>
4591 * Reward the {@link Player} with autoGet skills only, or if Config.AUTO_LEARN_SKILLS is activated, with all available skills.
4592 */
4593 public void giveSkills()
4594 {
4595 if (Config.AUTO_LEARN_SKILLS && !isAio())
4596 rewardSkills();
4597 else
4598 {
4599 for (GeneralSkillNode skill : getAvailableAutoGetSkills())
4600 addSkill(skill.getSkill(), false);
4601
4602 // Remove the Lucky skill if level superior to 10.
4603 if (getLevel() >= 10 && hasSkill(L2Skill.SKILL_LUCKY))
4604 removeSkill(L2Skill.SKILL_LUCKY, false);
4605
4606 // Remove invalid skills.
4607 removeInvalidSkills();
4608
4609 sendSkillList();
4610 }
4611 }
4612
4613 /**
4614 * Method used by admin commands, Config.AUTO_LEARN_SKILLS or class master.<br>
4615 * Reward the {@link Player} with all available skills, being autoGet or general skills.
4616 */
4617 public void rewardSkills()
4618 {
4619 // We reward all skills to the players, but don't store autoGet skills on the database.
4620 for (GeneralSkillNode skill : getAllAvailableSkills())
4621 addSkill(skill.getSkill(), skill.getCost() != 0);
4622
4623 // Remove the Lucky skill if level superior to 10.
4624 if (getLevel() >= 10 && hasSkill(L2Skill.SKILL_LUCKY))
4625 removeSkill(L2Skill.SKILL_LUCKY, false);
4626
4627 // Remove invalid skills.
4628 removeInvalidSkills();
4629
4630 sendSkillList();
4631 }
4632
4633 /**
4634 * + * Delete all invalid {@link L2Skill}s for this {@link Player}.<br>
4635 * <br>
4636 * A skill is considered invalid when the level of obtention of the skill is superior to 9 compared to player level (expertise skill obtention level is compared to player level without any penalty).<br>
4637 * <br>
4638 * It is then either deleted, or level is refreshed.
4639 */
4640 private void removeInvalidSkills()
4641 {
4642 if (getSkills().isEmpty())
4643 return;
4644
4645 // Retrieve the player template skills, based on actual level (+9 for regular skills, unchanged for expertise).
4646 final Map<Integer, Optional<GeneralSkillNode>> availableSkills = getTemplate().getSkills().stream().filter(s -> s.getMinLvl() <= getLevel() + ((s.getId() == L2Skill.SKILL_EXPERTISE) ? 0 : 9)).collect(Collectors.groupingBy(s -> s.getId(), Collectors.maxBy(COMPARE_SKILLS_BY_LVL)));
4647
4648 for (L2Skill skill : getSkills().values())
4649 {
4650 // Bother only with skills existing on template (spare temporary skills, items skills, etc).
4651 if (getTemplate().getSkills().stream().filter(s -> s.getId() == skill.getId()).count() == 0)
4652 continue;
4653
4654 // The known skill doesn't exist on available skills ; we drop existing skill.
4655 final Optional<GeneralSkillNode> tempSkill = availableSkills.get(skill.getId());
4656 if (tempSkill == null)
4657 {
4658 removeSkill(skill.getId(), true);
4659 continue;
4660 }
4661
4662 // Retrieve the skill and max level for enchant scenario.
4663 final GeneralSkillNode availableSkill = tempSkill.get();
4664 final int maxLevel = SkillTable.getInstance().getMaxLevel(skill.getId());
4665
4666 // Case of enchanted skills.
4667 if (skill.getLevel() > maxLevel)
4668 {
4669 // Player level is inferior to 76, or available skill is a good candidate.
4670 if ((getLevel() < 76 || availableSkill.getValue() < maxLevel) && skill.getLevel() > availableSkill.getValue())
4671 addSkill(availableSkill.getSkill(), true);
4672 }
4673 // We check if current known skill level is bigger than available skill level. If it's true, we override current skill with available skill.
4674 else if (skill.getLevel() > availableSkill.getValue())
4675 addSkill(availableSkill.getSkill(), true);
4676 }
4677 }
4678
4679 /**
4680 * Regive all skills which aren't saved to database, like Noble, Hero, Clan Skills.<br>
4681 * <b>Do not call this on enterworld or char load.</b>.
4682 */
4683 private void regiveTemporarySkills()
4684 {
4685 // Add noble skills if noble.
4686 if (isNoble())
4687 setNoble(true, false);
4688
4689 // Add Hero skills if hero.
4690 if (isHero())
4691 setHero(true);
4692
4693 // Add clan skills.
4694 if (getClan() != null)
4695 {
4696 getClan().addSkillEffects(this);
4697
4698 if (getClan().getLevel() >= Config.MINIMUM_CLAN_LEVEL && isClanLeader())
4699 addSiegeSkills();
4700 }
4701
4702 // Reload passive skills from armors / jewels / weapons
4703 getInventory().reloadEquippedItems();
4704
4705 // Add Death Penalty Buff Level
4706 restoreDeathPenaltyBuffLevel();
4707 }
4708
4709 public void addSiegeSkills()
4710 {
4711 for (L2Skill sk : SkillTable.getInstance().getSiegeSkills(isNoble()))
4712 addSkill(sk, false);
4713 }
4714
4715 public void removeSiegeSkills()
4716 {
4717 for (L2Skill sk : SkillTable.getInstance().getSiegeSkills(isNoble()))
4718 removeSkill(sk.getId(), false);
4719 }
4720
4721 /**
4722 * @return a {@link List} of all available autoGet {@link GeneralSkillNode}s <b>of maximal level</b> for this {@link Player}.
4723 */
4724 public List<GeneralSkillNode> getAvailableAutoGetSkills()
4725 {
4726 final List<GeneralSkillNode> result = new ArrayList<>();
4727
4728 getTemplate().getSkills().stream().filter(s -> s.getMinLvl() <= getLevel() && s.getCost() == 0).collect(Collectors.groupingBy(s -> s.getId(), Collectors.maxBy(COMPARE_SKILLS_BY_LVL))).forEach((i, s) ->
4729 {
4730 if (getSkillLevel(i) < s.get().getValue())
4731 result.add(s.get());
4732 });
4733 return result;
4734 }
4735
4736 /**
4737 * @return a {@link List} of available {@link GeneralSkillNode}s (only general) for this {@link Player}.
4738 */
4739 public List<GeneralSkillNode> getAvailableSkills()
4740 {
4741 final List<GeneralSkillNode> result = new ArrayList<>();
4742
4743 getTemplate().getSkills().stream().filter(s -> s.getMinLvl() <= getLevel() && s.getCost() != 0).forEach(s ->
4744 {
4745 if (getSkillLevel(s.getId()) == s.getValue() - 1)
4746 result.add(s);
4747 });
4748 return result;
4749 }
4750
4751 /**
4752 * @return a {@link List} of all available {@link GeneralSkillNode}s (being general or autoGet) <b>of maximal level</b> for this {@link Player}.
4753 */
4754 public List<GeneralSkillNode> getAllAvailableSkills()
4755 {
4756 final List<GeneralSkillNode> result = new ArrayList<>();
4757
4758 getTemplate().getSkills().stream().filter(s -> s.getMinLvl() <= getLevel()).collect(Collectors.groupingBy(s -> s.getId(), Collectors.maxBy(COMPARE_SKILLS_BY_LVL))).forEach((i, s) ->
4759 {
4760 if (getSkillLevel(i) < s.get().getValue())
4761 result.add(s.get());
4762 });
4763 return result;
4764 }
4765
4766 /**
4767 * Retrieve next lowest level skill to learn, based on current player level and skill sp cost.
4768 * @return the required level for next {@link GeneralSkillNode} to learn for this {@link Player}.
4769 */
4770 public int getRequiredLevelForNextSkill()
4771 {
4772 return getTemplate().getSkills().stream().filter(s -> s.getMinLvl() > getLevel() && s.getCost() != 0).min(COMPARE_SKILLS_BY_MIN_LVL).map(s -> s.getMinLvl()).orElse(0);
4773 }
4774
4775 /**
4776 * Set the _clan object, _clanId, _clanLeader Flag and title of the Player.
4777 * @param clan The Clan object which is used to feed Player values.
4778 */
4779 public void setClan(Clan clan)
4780 {
4781 _clan = clan;
4782 setTitle("");
4783
4784 if (clan == null)
4785 {
4786 _clanId = 0;
4787 _clanPrivileges = 0;
4788 _pledgeType = 0;
4789 _powerGrade = 0;
4790 _lvlJoinedAcademy = 0;
4791 _apprentice = 0;
4792 _sponsor = 0;
4793 return;
4794 }
4795
4796 if (!clan.isMember(getObjectId()))
4797 {
4798 // char has been kicked from clan
4799 setClan(null);
4800 return;
4801 }
4802
4803 _clanId = clan.getClanId();
4804 }
4805
4806 /**
4807 * @return The _clan object of the Player.
4808 */
4809 public Clan getClan()
4810 {
4811 return _clan;
4812 }
4813
4814 /**
4815 * @return True if the Player is the leader of its clan.
4816 */
4817 public boolean isClanLeader()
4818 {
4819 return _clan != null && getObjectId() == _clan.getLeaderId();
4820 }
4821
4822 /**
4823 * Reduce the number of arrows owned by the Player and send InventoryUpdate or ItemList (to unequip if the last arrow was consummed).
4824 */
4825 @Override
4826 protected void reduceArrowCount() // TODO: replace with a simple player.destroyItem...
4827 {
4828 final ItemInstance arrows = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
4829 if (arrows == null)
4830 return;
4831
4832 final InventoryUpdate iu = new InventoryUpdate();
4833
4834 if (arrows.getCount() > 1)
4835 {
4836 synchronized (arrows)
4837 {
4838 arrows.changeCount(null, -1, this, null);
4839 arrows.setLastChange(ItemState.MODIFIED);
4840
4841 iu.addModifiedItem(arrows);
4842
4843 // could do also without saving, but let's save approx 1 of 10
4844 if (Rnd.get(10) < 1)
4845 arrows.updateDatabase();
4846
4847 _inventory.refreshWeight();
4848 }
4849 }
4850 else
4851 {
4852 iu.addRemovedItem(arrows);
4853
4854 // Destroy entire item and save to database
4855 _inventory.destroyItem("Consume", arrows, this, null);
4856 }
4857 sendPacket(iu);
4858 }
4859
4860 /**
4861 * Check if the arrow item exists on inventory and is already slotted ; if not, equip it.
4862 */
4863 @Override
4864 protected boolean checkAndEquipArrows()
4865 {
4866 // Retrieve arrows instance on player inventory.
4867 final ItemInstance arrows = getInventory().findArrowForBow(getActiveWeaponItem());
4868 if (arrows == null)
4869 return false;
4870
4871 // Arrows are already equiped, don't bother.
4872 if (arrows.getLocation() == ItemLocation.PAPERDOLL)
4873 return true;
4874
4875 // Equip arrows in left hand.
4876 getInventory().setPaperdollItem(Inventory.PAPERDOLL_LHAND, arrows);
4877
4878 // Send ItemList to this player to update left hand equipement
4879 sendPacket(new ItemList(this, false));
4880
4881 return true;
4882 }
4883
4884 /**
4885 * Disarm the player's weapon and shield.
4886 * @return true if successful, false otherwise.
4887 */
4888 public boolean disarmWeapons()
4889 {
4890 // Don't allow disarming a cursed weapon
4891 if (isCursedWeaponEquipped())
4892 return false;
4893
4894 // Unequip the weapon
4895 ItemInstance wpn = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
4896 if (wpn != null)
4897 {
4898 if (wpn.getItemId() == 9999)
4899 return false;
4900
4901 ItemInstance[] unequipped = getInventory().unEquipItemInBodySlotAndRecord(wpn);
4902 InventoryUpdate iu = new InventoryUpdate();
4903 for (ItemInstance itm : unequipped)
4904 iu.addModifiedItem(itm);
4905 sendPacket(iu);
4906
4907 abortAttack();
4908 broadcastUserInfo();
4909
4910 // this can be 0 if the user pressed the right mousebutton twice very fast
4911 if (unequipped.length > 0)
4912 {
4913 SystemMessage sm;
4914 if (unequipped[0].getEnchantLevel() > 0)
4915 sm = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED).addNumber(unequipped[0].getEnchantLevel()).addItemName(unequipped[0]);
4916 else
4917 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISARMED).addItemName(unequipped[0]);
4918
4919 sendPacket(sm);
4920 }
4921 }
4922
4923 // Unequip the shield
4924 ItemInstance sld = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
4925 if (sld != null)
4926 {
4927 if (sld.getItemId() == 17 && EventManager.getInstance().isRegistered(this))
4928 return false;
4929
4930 ItemInstance[] unequipped = getInventory().unEquipItemInBodySlotAndRecord(sld);
4931 InventoryUpdate iu = new InventoryUpdate();
4932 for (ItemInstance itm : unequipped)
4933 iu.addModifiedItem(itm);
4934 sendPacket(iu);
4935
4936 abortAttack();
4937 broadcastUserInfo();
4938
4939 // this can be 0 if the user pressed the right mousebutton twice very fast
4940 if (unequipped.length > 0)
4941 {
4942 SystemMessage sm;
4943 if (unequipped[0].getEnchantLevel() > 0)
4944 sm = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED).addNumber(unequipped[0].getEnchantLevel()).addItemName(unequipped[0]);
4945 else
4946 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISARMED).addItemName(unequipped[0]);
4947
4948 sendPacket(sm);
4949 }
4950 }
4951 return true;
4952 }
4953
4954 public boolean mount(Summon pet)
4955 {
4956 if (!disarmWeapons())
4957 return false;
4958
4959 setRunning();
4960 stopAllToggles();
4961
4962 Ride mount = new Ride(getObjectId(), Ride.ACTION_MOUNT, pet.getTemplate().getNpcId());
4963 setMount(pet.getNpcId(), pet.getLevel(), mount.getMountType());
4964
4965 _petTemplate = (PetTemplate) pet.getTemplate();
4966 _petData = _petTemplate.getPetDataEntry(pet.getLevel());
4967 _mountObjectId = pet.getControlItemId();
4968
4969 startFeed(pet.getNpcId());
4970 broadcastPacket(mount);
4971
4972 // Notify self and others about speed change
4973 broadcastUserInfo();
4974
4975 pet.unSummon(this);
4976 return true;
4977 }
4978
4979 public boolean mount(int npcId, int controlItemId, boolean useFood)
4980 {
4981 if (!disarmWeapons())
4982 return false;
4983
4984 setRunning();
4985 stopAllToggles();
4986
4987 Ride mount = new Ride(getObjectId(), Ride.ACTION_MOUNT, npcId);
4988 if (setMount(npcId, getLevel(), mount.getMountType()))
4989 {
4990 _petTemplate = (PetTemplate) NpcData.getInstance().getTemplate(npcId);
4991 _petData = _petTemplate.getPetDataEntry(getLevel());
4992 _mountObjectId = controlItemId;
4993
4994 broadcastPacket(mount);
4995
4996 // Notify self and others about speed change
4997 broadcastUserInfo();
4998
4999 if (useFood)
5000 startFeed(npcId);
5001
5002 return true;
5003 }
5004 return false;
5005 }
5006
5007 public boolean mountPlayer(Summon summon)
5008 {
5009 if (summon instanceof Pet && summon.isMountable() && !isMounted() && !isBetrayed())
5010 {
5011 if (isDead()) // A strider cannot be ridden when dead.
5012 {
5013 sendPacket(SystemMessageId.STRIDER_CANT_BE_RIDDEN_WHILE_DEAD);
5014 return false;
5015 }
5016
5017 if (summon.isDead()) // A dead strider cannot be ridden.
5018 {
5019 sendPacket(SystemMessageId.DEAD_STRIDER_CANT_BE_RIDDEN);
5020 return false;
5021 }
5022
5023 if (summon.isInCombat() || summon.isRooted()) // A strider in battle cannot be ridden.
5024 {
5025 sendPacket(SystemMessageId.STRIDER_IN_BATLLE_CANT_BE_RIDDEN);
5026 return false;
5027 }
5028
5029 if (isInCombat()) // A strider cannot be ridden while in battle
5030 {
5031 sendPacket(SystemMessageId.STRIDER_CANT_BE_RIDDEN_WHILE_IN_BATTLE);
5032 return false;
5033 }
5034
5035 if (isSitting()) // A strider can be ridden only when standing
5036 {
5037 sendPacket(SystemMessageId.STRIDER_CAN_BE_RIDDEN_ONLY_WHILE_STANDING);
5038 return false;
5039 }
5040
5041 if (isFishing()) // You can't mount, dismount, break and drop items while fishing
5042 {
5043 sendPacket(SystemMessageId.CANNOT_DO_WHILE_FISHING_2);
5044 return false;
5045 }
5046
5047 if (isCursedWeaponEquipped()) // You can't mount, dismount, break and drop items while weilding a cursed weapon
5048 {
5049 sendPacket(SystemMessageId.STRIDER_CANT_BE_RIDDEN_WHILE_IN_BATTLE);
5050 return false;
5051 }
5052
5053 if (!MathUtil.checkIfInRange(200, this, summon, true))
5054 {
5055 sendPacket(SystemMessageId.TOO_FAR_AWAY_FROM_STRIDER_TO_MOUNT);
5056 return false;
5057 }
5058
5059 if (((Pet) summon).checkHungryState())
5060 {
5061 sendPacket(SystemMessageId.HUNGRY_STRIDER_NOT_MOUNT);
5062 return false;
5063 }
5064
5065 if (!summon.isDead() && !isMounted())
5066 mount(summon);
5067 }
5068 else if (isMounted())
5069 {
5070 if (getMountType() == 2 && isInsideZone(ZoneId.NO_LANDING))
5071 {
5072 sendPacket(SystemMessageId.NO_DISMOUNT_HERE);
5073 return false;
5074 }
5075
5076 if (checkFoodState(_petTemplate.getHungryLimit()))
5077 {
5078 sendPacket(SystemMessageId.HUNGRY_STRIDER_NOT_MOUNT);
5079 return false;
5080 }
5081
5082 dismount();
5083 }
5084 return true;
5085 }
5086
5087 public boolean dismount()
5088 {
5089 sendPacket(new SetupGauge(GaugeColor.GREEN, 0));
5090
5091 int petId = _mountNpcId;
5092 if (setMount(0, 0, 0))
5093 {
5094 stopFeed();
5095
5096 broadcastPacket(new Ride(getObjectId(), Ride.ACTION_DISMOUNT, 0));
5097
5098 _petTemplate = null;
5099 _petData = null;
5100 _mountObjectId = 0;
5101
5102 storePetFood(petId);
5103
5104 // Notify self and others about speed change
5105 broadcastUserInfo();
5106 return true;
5107 }
5108 return false;
5109 }
5110
5111 public void storePetFood(int petId)
5112 {
5113 if (_controlItemId != 0 && petId != 0)
5114 {
5115 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
5116 {
5117 PreparedStatement statement = con.prepareStatement("UPDATE pets SET fed=? WHERE item_obj_id = ?");
5118 statement.setInt(1, getCurrentFeed());
5119 statement.setInt(2, _controlItemId);
5120 statement.executeUpdate();
5121 statement.close();
5122 _controlItemId = 0;
5123 }
5124 catch (Exception e)
5125 {
5126 _log.log(Level.SEVERE, "Failed to store Pet [NpcId: " + petId + "] data", e);
5127 }
5128 }
5129 }
5130
5131 protected class FeedTask implements Runnable
5132 {
5133 @Override
5134 public void run()
5135 {
5136 if (!isMounted())
5137 {
5138 stopFeed();
5139 return;
5140 }
5141
5142 // Eat or return to pet control item.
5143 if (getCurrentFeed() > getFeedConsume())
5144 setCurrentFeed(getCurrentFeed() - getFeedConsume());
5145 else
5146 {
5147 setCurrentFeed(0);
5148 stopFeed();
5149 dismount();
5150 sendPacket(SystemMessageId.OUT_OF_FEED_MOUNT_CANCELED);
5151 return;
5152 }
5153
5154 ItemInstance food = getInventory().getItemByItemId(_petTemplate.getFood1());
5155 if (food == null)
5156 food = getInventory().getItemByItemId(_petTemplate.getFood2());
5157
5158 if (food != null && checkFoodState(_petTemplate.getAutoFeedLimit()))
5159 {
5160 IItemHandler handler = ItemHandler.getInstance().getHandler(food.getEtcItem());
5161 if (handler != null)
5162 {
5163 handler.useItem(Player.this, food, false);
5164 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.PET_TOOK_S1_BECAUSE_HE_WAS_HUNGRY).addItemName(food));
5165 }
5166 }
5167 }
5168 }
5169
5170 protected synchronized void startFeed(int npcId)
5171 {
5172 _canFeed = npcId > 0;
5173 if (!isMounted())
5174 return;
5175
5176 if (getPet() != null)
5177 {
5178 setCurrentFeed(((Pet) getPet()).getCurrentFed());
5179 _controlItemId = getPet().getControlItemId();
5180 sendPacket(new SetupGauge(GaugeColor.GREEN, getCurrentFeed() * 10000 / getFeedConsume(), _petData.getMaxMeal() * 10000 / getFeedConsume()));
5181 if (!isDead())
5182 _mountFeedTask = ThreadPool.scheduleAtFixedRate(new FeedTask(), 10000, 10000);
5183 }
5184 else if (_canFeed)
5185 {
5186 setCurrentFeed(_petData.getMaxMeal());
5187 sendPacket(new SetupGauge(GaugeColor.GREEN, getCurrentFeed() * 10000 / getFeedConsume(), _petData.getMaxMeal() * 10000 / getFeedConsume()));
5188 if (!isDead())
5189 _mountFeedTask = ThreadPool.scheduleAtFixedRate(new FeedTask(), 10000, 10000);
5190 }
5191 }
5192
5193 protected synchronized void stopFeed()
5194 {
5195 if (_mountFeedTask != null)
5196 {
5197 _mountFeedTask.cancel(false);
5198 _mountFeedTask = null;
5199 }
5200 }
5201
5202 public PetTemplate getPetTemplate()
5203 {
5204 return _petTemplate;
5205 }
5206
5207 public PetDataEntry getPetDataEntry()
5208 {
5209 return _petData;
5210 }
5211
5212 public int getCurrentFeed()
5213 {
5214 return _curFeed;
5215 }
5216
5217 protected int getFeedConsume()
5218 {
5219 return (isAttackingNow()) ? _petData.getMountMealInBattle() : _petData.getMountMealInNormal();
5220 }
5221
5222 public void setCurrentFeed(int num)
5223 {
5224 _curFeed = Math.min(num, _petData.getMaxMeal());
5225
5226 sendPacket(new SetupGauge(GaugeColor.GREEN, getCurrentFeed() * 10000 / getFeedConsume(), _petData.getMaxMeal() * 10000 / getFeedConsume()));
5227 }
5228
5229 /**
5230 * @param state : The state to check (can be autofeed, hungry or unsummon).
5231 * @return true if the limit is reached, false otherwise or if there is no need to feed.
5232 */
5233 public boolean checkFoodState(double state)
5234 {
5235 return (_canFeed) ? getCurrentFeed() < (_petData.getMaxMeal() * state) : false;
5236 }
5237
5238 public void setUptime(long time)
5239 {
5240 _uptime = time;
5241 }
5242
5243 public long getUptime()
5244 {
5245 return System.currentTimeMillis() - _uptime;
5246 }
5247
5248 /**
5249 * Return True if the Player is invulnerable.
5250 */
5251 @Override
5252 public boolean isInvul()
5253 {
5254 return super.isInvul() || isSpawnProtected();
5255 }
5256
5257 /**
5258 * Return True if the Player has a Party in progress.
5259 */
5260 @Override
5261 public boolean isInParty()
5262 {
5263 return _party != null;
5264 }
5265
5266 /**
5267 * Set the _party object of the Player (without joining it).
5268 * @param party The object.
5269 */
5270 public void setParty(Party party)
5271 {
5272 _party = party;
5273 }
5274
5275 /**
5276 * Return the _party object of the Player.
5277 */
5278 @Override
5279 public Party getParty()
5280 {
5281 return _party;
5282 }
5283
5284 public LootRule getLootRule()
5285 {
5286 return _lootRule;
5287 }
5288
5289 /**
5290 * Manage the Leave Party task of the L2PcInstance.
5291 */
5292 public void leaveParty()
5293 {
5294 if (isInParty())
5295 {
5296 _party.removePartyMember(this, MessageType.DISCONNECTED);
5297 _party = null;
5298 }
5299 }
5300
5301 public void setLootRule(LootRule lootRule)
5302 {
5303 _lootRule = lootRule;
5304 }
5305
5306 /**
5307 * Return True if the Player is a GM.
5308 */
5309 @Override
5310 public boolean isGM()
5311 {
5312 return getAccessLevel().isGm();
5313 }
5314
5315 /**
5316 * Set the _accessLevel of the Player.
5317 * @param level
5318 */
5319 public void setAccessLevel(int level)
5320 {
5321 // Retrieve the AccessLevel. Even if not existing, it returns user level.
5322 AccessLevel accessLevel = AdminData.getInstance().getAccessLevel(level);
5323 if (accessLevel == null)
5324 {
5325 _log.warning("Can't find access level " + level + " for " + toString());
5326 accessLevel = AdminData.getInstance().getAccessLevel(0);
5327 }
5328
5329 _accessLevel = accessLevel;
5330
5331 if (level > 0)
5332 {
5333 // For level lower or equal to user, we don't apply AccessLevel name as title.
5334 setTitle(accessLevel.getName());
5335
5336 // We log master access.
5337 if (level == AdminData.getInstance().getMasterAccessLevel().getLevel())
5338 _log.info(getName() + " has logged in with Master access level.");
5339 }
5340
5341 // We refresh GMList if the access level is GM.
5342 if (accessLevel.isGm())
5343 {
5344 // A little hack to avoid Enterworld config to be replaced.
5345 if (!AdminData.getInstance().isRegisteredAsGM(this))
5346 AdminData.getInstance().addGm(this, false);
5347 }
5348 else
5349 AdminData.getInstance().deleteGm(this);
5350
5351 getAppearance().setNameColor(accessLevel.getNameColor());
5352 getAppearance().setTitleColor(accessLevel.getTitleColor());
5353 broadcastUserInfo();
5354
5355 PlayerInfoTable.getInstance().updatePlayerData(this, true);
5356 }
5357
5358 public void setAccountAccesslevel(int level)
5359 {
5360 LoginServerThread.getInstance().sendAccessLevel(getAccountName(), level);
5361 }
5362
5363 /**
5364 * @return the _accessLevel of the Player.
5365 */
5366 public AccessLevel getAccessLevel()
5367 {
5368 return _accessLevel;
5369 }
5370
5371 /**
5372 * Update Stats of the Player client side by sending UserInfo/StatusUpdate to this Player and CharInfo/StatusUpdate to all Player in its _KnownPlayers (broadcast).
5373 * @param broadcastType
5374 */
5375 public void updateAndBroadcastStatus(int broadcastType)
5376 {
5377 refreshOverloaded();
5378 refreshExpertisePenalty();
5379
5380 if (broadcastType == 1)
5381 sendPacket(new UserInfo(this));
5382 else if (broadcastType == 2)
5383 broadcastUserInfo();
5384 }
5385
5386 /**
5387 * Send StatusUpdate packet with Karma to the Player and all Player to inform (broadcast).
5388 */
5389 public void broadcastKarma()
5390 {
5391 final StatusUpdate su = new StatusUpdate(this);
5392 su.addAttribute(StatusUpdate.KARMA, getKarma());
5393 sendPacket(su);
5394
5395 if (getPet() != null)
5396 sendPacket(new RelationChanged(getPet(), getRelation(this), false));
5397
5398 broadcastRelationsChanges();
5399 }
5400
5401 /**
5402 * Set the online Flag to True or False and update the characters table of the database with online status and lastAccess (called when login and logout).
5403 * @param isOnline
5404 * @param updateInDb
5405 */
5406 public void setOnlineStatus(boolean isOnline, boolean updateInDb)
5407 {
5408 if (_isOnline != isOnline)
5409 _isOnline = isOnline;
5410
5411 // Update the characters table of the database with online status and lastAccess (called when login and logout)
5412 if (updateInDb)
5413 updateOnlineStatus();
5414 }
5415
5416 public void setIsIn7sDungeon(boolean isIn7sDungeon)
5417 {
5418 _isIn7sDungeon = isIn7sDungeon;
5419 }
5420
5421 /**
5422 * Update the characters table of the database with online status and lastAccess of this Player (called when login and logout).
5423 */
5424 public void updateOnlineStatus()
5425 {
5426 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
5427 {
5428 PreparedStatement statement = con.prepareStatement("UPDATE characters SET online=?, lastAccess=? WHERE obj_id=?");
5429 statement.setInt(1, isOnlineInt());
5430 statement.setLong(2, System.currentTimeMillis());
5431 statement.setInt(3, getObjectId());
5432 statement.execute();
5433 statement.close();
5434 }
5435 catch (Exception e)
5436 {
5437 _log.warning("could not set char online status:" + e);
5438 }
5439 }
5440
5441 /**
5442 * Retrieve a Player from the characters table of the database.
5443 * <ul>
5444 * <li>Retrieve the Player from the characters table of the database</li>
5445 * <li>Set the x,y,z position of the Player and make it invisible</li>
5446 * <li>Update the overloaded status of the Player</li>
5447 * </ul>
5448 * @param objectId Identifier of the object to initialized
5449 * @return The Player loaded from the database
5450 */
5451 public static Player restore(int objectId)
5452 {
5453 Player player = null;
5454
5455 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
5456 {
5457 PreparedStatement statement = con.prepareStatement(RESTORE_CHARACTER);
5458 statement.setInt(1, objectId);
5459
5460 ResultSet rset = statement.executeQuery();
5461
5462 while (rset.next())
5463 {
5464 final int activeClassId = rset.getInt("classid");
5465 final PlayerTemplate template = PlayerData.getInstance().getTemplate(activeClassId);
5466 final PcAppearance app = new PcAppearance(rset.getByte("face"), rset.getByte("hairColor"), rset.getByte("hairStyle"), Sex.values()[rset.getInt("sex")]);
5467
5468 player = new Player(objectId, template, rset.getString("account_name"), app);
5469 player.setName(rset.getString("char_name"));
5470 player._lastAccess = rset.getLong("lastAccess");
5471
5472 player.getStat().setExp(rset.getLong("exp"));
5473 player.getStat().setLevel(rset.getByte("level"));
5474 player.getStat().setSp(rset.getInt("sp"));
5475
5476 player.setExpBeforeDeath(rset.getLong("expBeforeDeath"));
5477 player.setWantsPeace(rset.getInt("wantspeace") == 1);
5478
5479 player.setHeading(rset.getInt("heading"));
5480
5481 player.setKarma(rset.getInt("karma"));
5482 player.setPvpKills(rset.getInt("pvpkills"));
5483 player.setPkKills(rset.getInt("pkkills"));
5484 player.setOnlineTime(rset.getLong("onlinetime"));
5485 player.setNoble(rset.getInt("nobless") == 1, false);
5486
5487 player.setClanJoinExpiryTime(rset.getLong("clan_join_expiry_time"));
5488 if (player.getClanJoinExpiryTime() < System.currentTimeMillis())
5489 player.setClanJoinExpiryTime(0);
5490
5491 player.setClanCreateExpiryTime(rset.getLong("clan_create_expiry_time"));
5492 if (player.getClanCreateExpiryTime() < System.currentTimeMillis())
5493 player.setClanCreateExpiryTime(0);
5494
5495 player.setPowerGrade(rset.getInt("power_grade"));
5496 player.setPledgeType(rset.getInt("subpledge"));
5497
5498 int clanId = rset.getInt("clanid");
5499 if (clanId > 0)
5500 player.setClan(ClanTable.getInstance().getClan(clanId));
5501
5502 if (player.getClan() != null)
5503 {
5504 if (player.getClan().getLeaderId() != player.getObjectId())
5505 {
5506 if (player.getPowerGrade() == 0)
5507 player.setPowerGrade(5);
5508
5509 player.setClanPrivileges(player.getClan().getPriviledgesByRank(player.getPowerGrade()));
5510 }
5511 else
5512 {
5513 player.setClanPrivileges(Clan.CP_ALL);
5514 player.setPowerGrade(1);
5515 }
5516 }
5517 else
5518 player.setClanPrivileges(Clan.CP_NOTHING);
5519
5520 player.setDeleteTimer(rset.getLong("deletetime"));
5521
5522 player.setTitle(rset.getString("title"));
5523 player.setAccessLevel(rset.getInt("accesslevel"));
5524 player.setUptime(System.currentTimeMillis());
5525 player.setRecomHave(rset.getInt("rec_have"));
5526 player.setRecomLeft(rset.getInt("rec_left"));
5527
5528 player._classIndex = 0;
5529 try
5530 {
5531 player.setBaseClass(rset.getInt("base_class"));
5532 }
5533 catch (Exception e)
5534 {
5535 player.setBaseClass(activeClassId);
5536 }
5537
5538 // Restore Subclass Data (cannot be done earlier in function)
5539 if (restoreSubClassData(player))
5540 {
5541 if (activeClassId != player.getBaseClass())
5542 {
5543 for (SubClass subClass : player.getSubClasses().values())
5544 if (subClass.getClassId() == activeClassId)
5545 player._classIndex = subClass.getClassIndex();
5546 }
5547 }
5548 if (player.getClassIndex() == 0 && activeClassId != player.getBaseClass())
5549 {
5550 // Subclass in use but doesn't exist in DB -
5551 // a possible restart-while-modifysubclass cheat has been attempted.
5552 // Switching to use base class
5553 player.setClassId(player.getBaseClass());
5554 _log.warning("Player " + player.getName() + " reverted to base class. Possibly has tried a relogin exploit while subclassing.");
5555 }
5556 else
5557 player._activeClass = activeClassId;
5558
5559 player.setApprentice(rset.getInt("apprentice"));
5560 player.setSponsor(rset.getInt("sponsor"));
5561 player.setLvlJoinedAcademy(rset.getInt("lvl_joined_academy"));
5562 player.setIsIn7sDungeon(rset.getInt("isin7sdungeon") == 1);
5563 player.setPunishLevel(rset.getInt("punish_level"));
5564 if (player.getPunishLevel() != PunishLevel.NONE)
5565 player.setPunishTimer(rset.getLong("punish_timer"));
5566 else
5567 player.setPunishTimer(0);
5568
5569 CursedWeaponManager.getInstance().checkPlayer(player);
5570
5571 player.setAllianceWithVarkaKetra(rset.getInt("varka_ketra_ally"));
5572
5573 player.setDeathPenaltyBuffLevel(rset.getInt("death_penalty_level"));
5574
5575 player.pcBangPoint = rset.getInt("pc_point");
5576
5577 player.setLastHopVote(rset.getLong("last_hop_vote"));
5578 player.setLastTopVote(rset.getLong("last_top_vote"));
5579 player.setLastNetVote(rset.getLong("last_net_vote"));
5580
5581 player.setlastInstance(rset.getInt("lastInstance"));
5582
5583 // Set the x,y,z position of the Player and make it invisible
5584 player.getPosition().set(rset.getInt("x"), rset.getInt("y"), rset.getInt("z"));
5585
5586 // Set Hero status if it applies
5587 if (Hero.getInstance().isActiveHero(objectId))
5588 player.setHero(true);
5589
5590 // Set pledge class rank.
5591 player.setPledgeClass(ClanMember.calculatePledgeClass(player));
5592
5593 // Retrieve from the database all secondary data of this Player and reward expertise/lucky skills if necessary.
5594 // Note that Clan, Noblesse and Hero skills are given separately and not here.
5595 player.restoreCharData();
5596 player.giveSkills();
5597
5598 // buff and status icons
5599 if (Config.STORE_SKILL_COOLTIME)
5600 player.restoreEffects();
5601
5602 // Restore current CP, HP and MP values
5603 final double currentHp = rset.getDouble("curHp");
5604
5605 player.setCurrentCp(rset.getDouble("curCp"));
5606 player.setCurrentHp(currentHp);
5607 player.setCurrentMp(rset.getDouble("curMp"));
5608
5609 if (currentHp < 0.5)
5610 {
5611 player.setIsDead(true);
5612 player.stopHpMpRegeneration();
5613 }
5614
5615 // Restore pet if it exists in the world.
5616 final Pet pet = World.getInstance().getPet(player.getObjectId());
5617 if (pet != null)
5618 {
5619 player.setPet(pet);
5620 pet.setOwner(player);
5621 }
5622
5623 player.refreshOverloaded();
5624 player.refreshExpertisePenalty();
5625
5626 player.restoreFriendList();
5627
5628 // Retrieve the name and ID of the other characters assigned to this account.
5629 PreparedStatement stmt = con.prepareStatement("SELECT obj_Id, char_name FROM characters WHERE account_name=? AND obj_Id<>?");
5630 stmt.setString(1, player._accountName);
5631 stmt.setInt(2, objectId);
5632 ResultSet chars = stmt.executeQuery();
5633
5634 while (chars.next())
5635 player.getAccountChars().put(chars.getInt("obj_Id"), chars.getString("char_name"));
5636
5637 chars.close();
5638 stmt.close();
5639 break;
5640 }
5641
5642 rset.close();
5643 statement.close();
5644 }
5645 catch (Exception e)
5646 {
5647 _log.severe("Could not restore char data: " + e);
5648 }
5649
5650 return player;
5651 }
5652
5653 public Forum getMemo()
5654 {
5655 if (_forumMemo == null)
5656 {
5657 final Forum forum = ForumsBBSManager.getInstance().getForumByName("MemoRoot");
5658 if (forum != null)
5659 {
5660 _forumMemo = forum.getChildByName(_accountName);
5661 if (_forumMemo == null)
5662 _forumMemo = ForumsBBSManager.getInstance().createNewForum(_accountName, forum, Forum.MEMO, Forum.OWNERONLY, getObjectId()); }
5663 }
5664 return _forumMemo;
5665 }
5666
5667 /**
5668 * Restores sub-class data for the Player, used to check the current class index for the character.
5669 * @param player The player to make checks on.
5670 * @return true if successful.
5671 */
5672 private static boolean restoreSubClassData(Player player)
5673 {
5674 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
5675 {
5676 PreparedStatement statement = con.prepareStatement(RESTORE_CHAR_SUBCLASSES);
5677 statement.setInt(1, player.getObjectId());
5678
5679 ResultSet rset = statement.executeQuery();
5680
5681 while (rset.next())
5682 {
5683 SubClass subClass = new SubClass(rset.getInt("class_id"), rset.getInt("class_index"), rset.getLong("exp"), rset.getInt("sp"), rset.getByte("level"));
5684
5685 // Enforce the correct indexing of _subClasses against their class indexes.
5686 player.getSubClasses().put(subClass.getClassIndex(), subClass);
5687 }
5688 rset.close();
5689 statement.close();
5690 }
5691 catch (Exception e)
5692 {
5693 _log.warning("Could not restore classes for " + player.getName() + ": " + e);
5694 e.printStackTrace();
5695 }
5696
5697 return true;
5698 }
5699
5700 /**
5701 * Restores secondary data for the Player, based on the current class index.
5702 */
5703 private void restoreCharData()
5704 {
5705 // Retrieve from the database all skills of this Player and add them to _skills.
5706 restoreSkills();
5707
5708 // Retrieve from the database all macroses of this Player and add them to _macroses.
5709 _macroses.restore();
5710
5711 // Retrieve from the database all shortCuts of this Player and add them to _shortCuts.
5712 _shortCuts.restore();
5713
5714 // Retrieve from the database all henna of this Player and add them to _henna.
5715 restoreHenna();
5716
5717 // Retrieve from the database all recom data of this Player and add to _recomChars.
5718 restoreRecom();
5719
5720 // Retrieve from the database the recipe book of this Player.
5721 if (!isSubClassActive())
5722 restoreRecipeBook();
5723 }
5724
5725 /**
5726 * Store {@link Recipe} book data for this {@link Player}, if he isn't on an active subclass.
5727 */
5728 private void storeRecipeBook()
5729 {
5730 // If the player is on a sub-class don't even attempt to store a recipe book.
5731 if (isSubClassActive())
5732 return;
5733
5734 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
5735 {
5736 PreparedStatement ps = con.prepareStatement("DELETE FROM character_recipebook WHERE charId=?");
5737 ps.setInt(1, getObjectId());
5738 ps.execute();
5739 ps.close();
5740
5741 ps = con.prepareStatement("INSERT INTO character_recipebook (charId, recipeId) values(?,?)");
5742
5743 for (Recipe recipe : getCommonRecipeBook())
5744 {
5745 ps.setInt(1, getObjectId());
5746 ps.setInt(2, recipe.getId());
5747 ps.addBatch();
5748 }
5749
5750 for (Recipe recipe : getDwarvenRecipeBook())
5751 {
5752 ps.setInt(1, getObjectId());
5753 ps.setInt(2, recipe.getId());
5754 ps.addBatch();
5755 }
5756
5757 ps.executeBatch();
5758 ps.close();
5759 }
5760 catch (Exception e)
5761 {
5762 _log.log(Level.SEVERE, "Could not store recipe book data.", e);
5763 }
5764 }
5765
5766 /**
5767 * Restore {@link Recipe} book data for this {@link Player}.
5768 */
5769 private void restoreRecipeBook()
5770 {
5771 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
5772 {
5773 PreparedStatement ps = con.prepareStatement("SELECT recipeId FROM character_recipebook WHERE charId=?");
5774 ps.setInt(1, getObjectId());
5775
5776 ResultSet rs = ps.executeQuery();
5777 while (rs.next())
5778 {
5779 final Recipe recipe = RecipeData.getInstance().getRecipeList(rs.getInt("recipeId"));
5780 if (recipe.isDwarven())
5781 registerDwarvenRecipeList(recipe);
5782 else
5783 registerCommonRecipeList(recipe);
5784 }
5785
5786 rs.close();
5787 ps.close();
5788 }
5789 catch (Exception e)
5790 {
5791 _log.log(Level.SEVERE, "Could not restore recipe book data.", e);
5792 }
5793 }
5794
5795 /**
5796 * Update Player stats in the characters table of the database.
5797 * @param storeActiveEffects
5798 */
5799 public synchronized void store(boolean storeActiveEffects)
5800 {
5801 // update client coords, if these look like true
5802 if (isInsideRadius(getClientX(), getClientY(), 1000, true))
5803 setXYZ(getClientX(), getClientY(), getClientZ());
5804
5805 storeCharBase();
5806 storeCharSub();
5807 storeEffect(storeActiveEffects);
5808 storeRecipeBook();
5809
5810 _vars.storeMe();
5811 }
5812
5813 public void store()
5814 {
5815 store(true);
5816 }
5817
5818 private void storeCharBase()
5819 {
5820 // Get the exp, level, and sp of base class to store in base table
5821 final int currentClassIndex = getClassIndex();
5822
5823 _classIndex = 0;
5824
5825 final long exp = getStat().getExp();
5826 final int level = getStat().getLevel();
5827 final int sp = getStat().getSp();
5828
5829 _classIndex = currentClassIndex;
5830
5831 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
5832 PreparedStatement ps = con.prepareStatement(UPDATE_CHARACTER))
5833 {
5834 ps.setInt(1, level);
5835 ps.setInt(2, getMaxHp());
5836 ps.setDouble(3, getCurrentHp());
5837 ps.setInt(4, getMaxCp());
5838 ps.setDouble(5, getCurrentCp());
5839 ps.setInt(6, getMaxMp());
5840 ps.setDouble(7, getCurrentMp());
5841 ps.setInt(8, getAppearance().getFace());
5842 ps.setInt(9, getAppearance().getHairStyle());
5843 ps.setInt(10, getAppearance().getHairColor());
5844 ps.setInt(11, getAppearance().getSex().ordinal());
5845 ps.setInt(12, getHeading());
5846
5847 if (!isInObserverMode())
5848 {
5849 ps.setInt(13, getX());
5850 ps.setInt(14, getY());
5851 ps.setInt(15, getZ());
5852 }
5853 else
5854 {
5855 ps.setInt(13, _savedLocation.getX());
5856 ps.setInt(14, _savedLocation.getY());
5857 ps.setInt(15, _savedLocation.getZ());
5858 }
5859
5860 ps.setLong(16, exp);
5861 ps.setLong(17, getExpBeforeDeath());
5862 ps.setInt(18, sp);
5863 ps.setInt(19, getKarma());
5864 ps.setInt(20, getPvpKills());
5865 ps.setInt(21, getPkKills());
5866 ps.setInt(22, getClanId());
5867 ps.setInt(23, getRace().ordinal());
5868 ps.setInt(24, getClassId().getId());
5869 ps.setLong(25, getDeleteTimer());
5870 ps.setString(26, getTitle());
5871 ps.setInt(27, getAccessLevel().getLevel());
5872 ps.setInt(28, isOnlineInt());
5873 ps.setInt(29, isIn7sDungeon() ? 1 : 0);
5874 ps.setInt(30, getClanPrivileges());
5875 ps.setInt(31, wantsPeace() ? 1 : 0);
5876 ps.setInt(32, getBaseClass());
5877
5878 long totalOnlineTime = _onlineTime;
5879 if (_onlineBeginTime > 0)
5880 totalOnlineTime += (System.currentTimeMillis() - _onlineBeginTime) / 1000;
5881
5882 ps.setLong(33, totalOnlineTime);
5883 ps.setInt(34, getPunishLevel().value());
5884 ps.setLong(35, getPunishTimer());
5885 ps.setInt(36, isNoble() ? 1 : 0);
5886 ps.setLong(37, getPowerGrade());
5887 ps.setInt(38, getPledgeType());
5888 ps.setInt(39, getLvlJoinedAcademy());
5889 ps.setLong(40, getApprentice());
5890 ps.setLong(41, getSponsor());
5891 ps.setInt(42, getAllianceWithVarkaKetra());
5892 ps.setLong(43, getClanJoinExpiryTime());
5893 ps.setLong(44, getClanCreateExpiryTime());
5894 ps.setString(45, getName());
5895 ps.setLong(46, getDeathPenaltyBuffLevel());
5896 ps.setInt(47, getPcBangScore());
5897 ps.setInt(48, getLastInstance());
5898 ps.setInt(49, getObjectId());
5899
5900 ps.execute();
5901 }
5902 catch (Exception e)
5903 {
5904 _log.warning("Could not store char base data: " + e);
5905 }
5906 }
5907
5908 private void storeCharSub()
5909 {
5910 if (_subClasses.isEmpty())
5911 return;
5912
5913 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
5914 {
5915 PreparedStatement statement = con.prepareStatement(UPDATE_CHAR_SUBCLASS);
5916 for (SubClass subClass : _subClasses.values())
5917 {
5918 statement.setLong(1, subClass.getExp());
5919 statement.setInt(2, subClass.getSp());
5920 statement.setInt(3, subClass.getLevel());
5921 statement.setInt(4, subClass.getClassId());
5922 statement.setInt(5, getObjectId());
5923 statement.setInt(6, subClass.getClassIndex());
5924 statement.execute();
5925 statement.clearParameters();
5926 }
5927 statement.close();
5928 }
5929 catch (Exception e)
5930 {
5931 _log.warning("Could not store sub class data for " + getName() + ": " + e);
5932 }
5933 }
5934
5935 private void storeEffect(boolean storeEffects)
5936 {
5937 if (!Config.STORE_SKILL_COOLTIME)
5938 return;
5939
5940 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
5941 {
5942 // Delete all current stored effects for char to avoid dupe
5943 try (PreparedStatement ps = con.prepareStatement(DELETE_SKILL_SAVE))
5944 {
5945 ps.setInt(1, getObjectId());
5946 ps.setInt(2, getClassIndex());
5947 ps.executeUpdate();
5948 }
5949
5950 int buff_index = 0;
5951 final List<Integer> storedSkills = new ArrayList<>();
5952
5953 try (PreparedStatement ps = con.prepareStatement(ADD_SKILL_SAVE))
5954 {
5955 // Store all effect data along with calulated remaining reuse delays for matching skills. 'restore_type'= 0.
5956 if (storeEffects)
5957 {
5958 for (L2Effect effect : getAllEffects())
5959 {
5960 if (effect == null)
5961 continue;
5962
5963 switch (effect.getEffectType())
5964 {
5965 case HEAL_OVER_TIME:
5966 case COMBAT_POINT_HEAL_OVER_TIME:
5967 continue;
5968 default:
5969 break;
5970 }
5971
5972 final L2Skill skill = effect.getSkill();
5973 if (storedSkills.contains(skill.getReuseHashCode()))
5974 continue;
5975
5976 storedSkills.add(skill.getReuseHashCode());
5977 if (!effect.isHerbEffect() && effect.getInUse() && !skill.isToggle())
5978 {
5979 ps.setInt(1, getObjectId());
5980 ps.setInt(2, skill.getId());
5981 ps.setInt(3, skill.getLevel());
5982 ps.setInt(4, effect.getCount());
5983 ps.setInt(5, effect.getTime());
5984
5985 final TimeStamp t = _reuseTimeStamps.get(skill.getReuseHashCode());
5986 if (t != null && t.hasNotPassed())
5987 {
5988 ps.setLong(6, t.getReuse());
5989 ps.setDouble(7, t.getStamp());
5990 }
5991 else
5992 {
5993 ps.setLong(6, 0);
5994 ps.setDouble(7, 0);
5995 }
5996
5997 ps.setInt(8, 0);
5998 ps.setInt(9, getClassIndex());
5999 ps.setInt(10, ++buff_index);
6000 ps.addBatch(); // Add SQL
6001 }
6002 }
6003 }
6004
6005 // Store the reuse delays of remaining skills which lost effect but still under reuse delay. 'restore_type' 1.
6006 for (Map.Entry<Integer, TimeStamp> entry : _reuseTimeStamps.entrySet())
6007 {
6008 final int hash = entry.getKey();
6009 if (storedSkills.contains(hash))
6010 continue;
6011
6012 final TimeStamp t = entry.getValue();
6013 if (t != null && t.hasNotPassed())
6014 {
6015 storedSkills.add(hash);
6016
6017 ps.setInt(1, getObjectId());
6018 ps.setInt(2, t.getSkillId());
6019 ps.setInt(3, t.getSkillLvl());
6020 ps.setInt(4, -1);
6021 ps.setInt(5, -1);
6022 ps.setLong(6, t.getReuse());
6023 ps.setDouble(7, t.getStamp());
6024 ps.setInt(8, 1);
6025 ps.setInt(9, getClassIndex());
6026 ps.setInt(10, ++buff_index);
6027 ps.addBatch(); // Add SQL
6028 }
6029 }
6030
6031 ps.executeBatch(); // Execute SQLs
6032 }
6033 }
6034 catch (Exception e)
6035 {
6036 _log.log(Level.WARNING, "Could not store char effect data: ", e);
6037 }
6038 }
6039
6040 /**
6041 * @return True if the Player is online.
6042 */
6043 public boolean isOnline()
6044 {
6045 return _isOnline;
6046 }
6047
6048 /**
6049 * @return an int interpretation of online status.
6050 */
6051 public int isOnlineInt()
6052 {
6053 if (_isOnline && getClient() != null)
6054 return getClient().isDetached() ? 2 : 1;
6055
6056 return 0;
6057 }
6058
6059 public boolean isIn7sDungeon()
6060 {
6061 return _isIn7sDungeon;
6062 }
6063
6064 /**
6065 * Add a {@link L2Skill} and its Func objects to the calculator set of the {@link Player}.<BR>
6066 * <ul>
6067 * <li>Replace or add oldSkill by newSkill (only if oldSkill is different than newSkill)</li>
6068 * <li>If an old skill has been replaced, remove all its Func objects of Creature calculator set</li>
6069 * <li>Add Func objects of newSkill to the calculator set of the Creature</li>
6070 * </ul>
6071 * @param newSkill : The skill to add.
6072 * @param store : If true, we save the skill on database.
6073 * @return true if the skill has been successfully added.
6074 */
6075 public boolean addSkill(L2Skill newSkill, boolean store)
6076 {
6077 // New skill is null, abort.
6078 if (newSkill == null)
6079 return false;
6080
6081 // Search the old skill. We test if it's different than the new one. If yes, we abort the operation.
6082 final L2Skill oldSkill = getSkills().get(newSkill.getId());
6083 if (oldSkill != null && oldSkill.equals(newSkill))
6084 return false;
6085
6086 // The 2 skills were different (or old wasn't existing). We can refresh the map.
6087 getSkills().put(newSkill.getId(), newSkill);
6088
6089 // If an old skill has been replaced, remove all its Func objects
6090 if (oldSkill != null)
6091 {
6092 // if skill came with another one, we should delete the other one too.
6093 if (oldSkill.triggerAnotherSkill())
6094 removeSkill(oldSkill.getTriggeredId(), false);
6095
6096 removeStatsByOwner(oldSkill);
6097 }
6098
6099 // Add Func objects of newSkill to the calculator set of the Creature
6100 addStatFuncs(newSkill.getStatFuncs(this));
6101
6102 // Test and delete chance skill if found.
6103 if (oldSkill != null && getChanceSkills() != null)
6104 removeChanceSkill(oldSkill.getId());
6105
6106 // If new skill got a chance, trigger it.
6107 if (newSkill.isChance())
6108 addChanceTrigger(newSkill);
6109
6110 // Add or update the skill in the database.
6111 if (store)
6112 storeSkill(newSkill, -1);
6113
6114 return true;
6115 }
6116
6117 /**
6118 * Remove a {@link L2Skill} from this {@link Player}. If parameter store is true, we also remove it from database and update shortcuts.
6119 * @param skillId : The skill identifier to remove.
6120 * @param store : If true, we delete the skill from database.
6121 */
6122 public L2Skill removeSkill(int skillId, boolean store)
6123 {
6124 return removeSkill(skillId, store, true);
6125 }
6126
6127 /**
6128 * Remove a {@link L2Skill} from this {@link Player}. If parameter store is true, we also remove it from database and update shortcuts.
6129 * @param skillId : The skill identifier to remove.
6130 * @param store : If true, we delete the skill from database.
6131 * @param removeEffect : If true, we remove the associated effect if existing.
6132 * @return the L2Skill removed or null if it couldn't be removed.
6133 */
6134 public L2Skill removeSkill(int skillId, boolean store, boolean removeEffect)
6135 {
6136 // Remove the skill from the Creature _skills
6137 final L2Skill oldSkill = getSkills().remove(skillId);
6138 if (oldSkill == null)
6139 return null;
6140
6141 // this is just a fail-safe againts buggers and gm dummies...
6142 if (oldSkill.triggerAnotherSkill() && oldSkill.getTriggeredId() > 0)
6143 removeSkill(oldSkill.getTriggeredId(), false);
6144
6145 // Stop casting if this skill is used right now
6146 if (getLastSkillCast() != null && isCastingNow() && skillId == getLastSkillCast().getId())
6147 abortCast();
6148
6149 if (getLastSimultaneousSkillCast() != null && isCastingSimultaneouslyNow() && skillId == getLastSimultaneousSkillCast().getId())
6150 abortCast();
6151
6152 // Remove all its Func objects from the Creature calculator set
6153 if (removeEffect)
6154 {
6155 removeStatsByOwner(oldSkill);
6156 stopSkillEffects(skillId);
6157 }
6158
6159 if (oldSkill.isChance() && getChanceSkills() != null)
6160 removeChanceSkill(skillId);
6161
6162 if (store)
6163 {
6164 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
6165 PreparedStatement ps = con.prepareStatement(DELETE_SKILL_FROM_CHAR))
6166 {
6167 ps.setInt(1, skillId);
6168 ps.setInt(2, getObjectId());
6169 ps.setInt(3, getClassIndex());
6170 ps.execute();
6171 }
6172 catch (Exception e)
6173 {
6174 _log.log(Level.SEVERE, "Couldn't delete player skill.", e);
6175 }
6176
6177 // Don't busy with shortcuts if skill was a passive skill.
6178 if (!oldSkill.isPassive())
6179 {
6180 for (L2ShortCut sc : getAllShortCuts())
6181 {
6182 if (sc != null && sc.getId() == skillId && sc.getType() == L2ShortCut.TYPE_SKILL)
6183 deleteShortCut(sc.getSlot(), sc.getPage());
6184 }
6185 }
6186 }
6187
6188 return oldSkill;
6189 }
6190
6191 /**
6192 * Insert or update a {@link Player} skill in the database.<br>
6193 * If newClassIndex > -1, the skill will be stored with that class index, not the current one.
6194 * @param skill : The skill to add or update (if updated, only the level is refreshed).
6195 * @param classIndex : The current class index to set, or current if none is found.
6196 */
6197 private void storeSkill(L2Skill skill, int classIndex)
6198 {
6199 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
6200 PreparedStatement ps = con.prepareStatement(ADD_OR_UPDATE_SKILL))
6201 {
6202 ps.setInt(1, getObjectId());
6203 ps.setInt(2, skill.getId());
6204 ps.setInt(3, skill.getLevel());
6205 ps.setInt(4, (classIndex > -1) ? classIndex : _classIndex);
6206 ps.executeUpdate();
6207 }
6208 catch (Exception e)
6209 {
6210 _log.log(Level.SEVERE, "Couldn't store player skill.", e);
6211 }
6212 }
6213
6214 /**
6215 * Restore all skills from database for this {@link Player} and feed getSkills().
6216 */
6217 private void restoreSkills()
6218 {
6219 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
6220 PreparedStatement ps = con.prepareStatement(RESTORE_SKILLS_FOR_CHAR))
6221 {
6222 ps.setInt(1, getObjectId());
6223 ps.setInt(2, getClassIndex());
6224
6225 final ResultSet rs = ps.executeQuery();
6226 while (rs.next())
6227 addSkill(SkillTable.getInstance().getInfo(rs.getInt("skill_id"), rs.getInt("skill_level")), false);
6228
6229 rs.close();
6230 }
6231 catch (Exception e)
6232 {
6233 _log.log(Level.SEVERE, "Couldn't restore player skills.", e);
6234 }
6235 }
6236
6237 /**
6238 * Retrieve from the database all skill effects of this Player and add them to the player.
6239 */
6240 public void restoreEffects()
6241 {
6242 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
6243 {
6244 PreparedStatement statement = con.prepareStatement(RESTORE_SKILL_SAVE);
6245 statement.setInt(1, getObjectId());
6246 statement.setInt(2, getClassIndex());
6247 ResultSet rset = statement.executeQuery();
6248
6249 while (rset.next())
6250 {
6251 int effectCount = rset.getInt("effect_count");
6252 int effectCurTime = rset.getInt("effect_cur_time");
6253 long reuseDelay = rset.getLong("reuse_delay");
6254 long systime = rset.getLong("systime");
6255 int restoreType = rset.getInt("restore_type");
6256
6257 final L2Skill skill = SkillTable.getInstance().getInfo(rset.getInt("skill_id"), rset.getInt("skill_level"));
6258 if (skill == null)
6259 continue;
6260
6261 final long remainingTime = systime - System.currentTimeMillis();
6262 if (remainingTime > 10)
6263 {
6264 disableSkill(skill, remainingTime);
6265 addTimeStamp(skill, reuseDelay, systime);
6266 }
6267
6268 /**
6269 * Restore Type 1 The remaning skills lost effect upon logout but were still under a high reuse delay.
6270 */
6271 if (restoreType > 0)
6272 continue;
6273
6274 /**
6275 * Restore Type 0 These skills were still in effect on the character upon logout. Some of which were self casted and might still have a long reuse delay which also is restored.
6276 */
6277 if (skill.hasEffects())
6278 {
6279 final Env env = new Env();
6280 env.setCharacter(this);
6281 env.setTarget(this);
6282 env.setSkill(skill);
6283
6284 for (EffectTemplate et : skill.getEffectTemplates())
6285 {
6286 final L2Effect ef = et.getEffect(env);
6287 if (ef != null)
6288 {
6289 ef.setCount(effectCount);
6290 ef.setFirstTime(effectCurTime);
6291 ef.scheduleEffect();
6292 }
6293 }
6294 }
6295 }
6296
6297 rset.close();
6298 statement.close();
6299
6300 statement = con.prepareStatement(DELETE_SKILL_SAVE);
6301 statement.setInt(1, getObjectId());
6302 statement.setInt(2, getClassIndex());
6303 statement.executeUpdate();
6304 statement.close();
6305 }
6306 catch (Exception e)
6307 {
6308 _log.log(Level.WARNING, "Could not restore " + this + " active effect data: " + e.getMessage(), e);
6309 }
6310 }
6311
6312 /**
6313 * Retrieve from the database all Henna of this Player, add them to _henna and calculate stats of the Player.
6314 */
6315 private void restoreHenna()
6316 {
6317 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
6318 {
6319 PreparedStatement statement = con.prepareStatement(RESTORE_CHAR_HENNAS);
6320 statement.setInt(1, getObjectId());
6321 statement.setInt(2, getClassIndex());
6322 ResultSet rset = statement.executeQuery();
6323
6324 for (int i = 0; i < 3; i++)
6325 _henna[i] = null;
6326
6327 while (rset.next())
6328 {
6329 int slot = rset.getInt("slot");
6330
6331 if (slot < 1 || slot > 3)
6332 continue;
6333
6334 int symbolId = rset.getInt("symbol_id");
6335 if (symbolId != 0)
6336 {
6337 Henna tpl = HennaData.getInstance().getHenna(symbolId);
6338 if (tpl != null)
6339 _henna[slot - 1] = tpl;
6340 }
6341 }
6342
6343 rset.close();
6344 statement.close();
6345 }
6346 catch (Exception e)
6347 {
6348 _log.warning("could not restore henna: " + e);
6349 }
6350
6351 // Calculate Henna modifiers of this Player
6352 recalcHennaStats();
6353 }
6354
6355 /**
6356 * Retrieve from the database all Recommendation data of this Player, add to _recomChars and calculate stats of the Player.
6357 */
6358 private void restoreRecom()
6359 {
6360 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
6361 {
6362 PreparedStatement statement = con.prepareStatement(RESTORE_CHAR_RECOMS);
6363 statement.setInt(1, getObjectId());
6364
6365 ResultSet rset = statement.executeQuery();
6366 while (rset.next())
6367 _recomChars.add(rset.getInt("target_id"));
6368
6369 rset.close();
6370 statement.close();
6371 }
6372 catch (Exception e)
6373 {
6374 _log.warning("could not restore recommendations: " + e);
6375 }
6376 }
6377
6378 /**
6379 * @return the number of Henna empty slot of the Player.
6380 */
6381 public int getHennaEmptySlots()
6382 {
6383 int totalSlots = 0;
6384 if (getClassId().level() == 1)
6385 totalSlots = 2;
6386 else
6387 totalSlots = 3;
6388
6389 for (int i = 0; i < 3; i++)
6390 {
6391 if (_henna[i] != null)
6392 totalSlots--;
6393 }
6394
6395 if (totalSlots <= 0)
6396 return 0;
6397
6398 return totalSlots;
6399 }
6400
6401 /**
6402 * Remove a Henna of the Player, save update in the character_hennas table of the database and send HennaInfo/UserInfo packet to this Player.
6403 * @param slot The slot number to make checks on.
6404 * @return true if successful.
6405 */
6406 public boolean removeHenna(int slot)
6407 {
6408 if (slot < 1 || slot > 3)
6409 return false;
6410
6411 slot--;
6412
6413 if (_henna[slot] == null)
6414 return false;
6415
6416 Henna henna = _henna[slot];
6417 _henna[slot] = null;
6418
6419 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
6420 {
6421 PreparedStatement statement = con.prepareStatement(DELETE_CHAR_HENNA);
6422
6423 statement.setInt(1, getObjectId());
6424 statement.setInt(2, slot + 1);
6425 statement.setInt(3, getClassIndex());
6426
6427 statement.execute();
6428 statement.close();
6429 }
6430 catch (Exception e)
6431 {
6432 _log.warning("could not remove char henna: " + e);
6433 }
6434
6435 // Calculate Henna modifiers of this Player
6436 recalcHennaStats();
6437
6438 // Send HennaInfo packet to this Player
6439 sendPacket(new HennaInfo(this));
6440
6441 // Send UserInfo packet to this Player
6442 sendPacket(new UserInfo(this));
6443
6444 reduceAdena("Henna", henna.getPrice() / 5, this, false);
6445
6446 // Add the recovered dyes to the player's inventory and notify them.
6447 addItem("Henna", henna.getDyeId(), Henna.getRequiredDyeAmount() / 2, this, true);
6448 sendPacket(SystemMessageId.SYMBOL_DELETED);
6449 return true;
6450 }
6451
6452 /**
6453 * Add a Henna to the Player, save update in the character_hennas table of the database and send Server->Client HennaInfo/UserInfo packet to this Player.
6454 * @param henna The Henna template to add.
6455 */
6456 public void addHenna(Henna henna)
6457 {
6458 for (int i = 0; i < 3; i++)
6459 {
6460 if (_henna[i] == null)
6461 {
6462 _henna[i] = henna;
6463
6464 // Calculate Henna modifiers of this Player
6465 recalcHennaStats();
6466
6467 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
6468 {
6469 PreparedStatement statement = con.prepareStatement(ADD_CHAR_HENNA);
6470
6471 statement.setInt(1, getObjectId());
6472 statement.setInt(2, henna.getSymbolId());
6473 statement.setInt(3, i + 1);
6474 statement.setInt(4, getClassIndex());
6475
6476 statement.execute();
6477 statement.close();
6478 }
6479 catch (Exception e)
6480 {
6481 _log.warning("could not save char henna: " + e);
6482 }
6483
6484 sendPacket(new HennaInfo(this));
6485 sendPacket(new UserInfo(this));
6486 sendPacket(SystemMessageId.SYMBOL_ADDED);
6487 return;
6488 }
6489 }
6490 }
6491
6492 /**
6493 * Calculate Henna modifiers of this Player.
6494 */
6495 private void recalcHennaStats()
6496 {
6497 _hennaINT = 0;
6498 _hennaSTR = 0;
6499 _hennaCON = 0;
6500 _hennaMEN = 0;
6501 _hennaWIT = 0;
6502 _hennaDEX = 0;
6503
6504 for (int i = 0; i < 3; i++)
6505 {
6506 if (_henna[i] == null)
6507 continue;
6508
6509 _hennaINT += _henna[i].getINT();
6510 _hennaSTR += _henna[i].getSTR();
6511 _hennaMEN += _henna[i].getMEN();
6512 _hennaCON += _henna[i].getCON();
6513 _hennaWIT += _henna[i].getWIT();
6514 _hennaDEX += _henna[i].getDEX();
6515 }
6516
6517 if (_hennaINT > 5)
6518 _hennaINT = 5;
6519
6520 if (_hennaSTR > 5)
6521 _hennaSTR = 5;
6522
6523 if (_hennaMEN > 5)
6524 _hennaMEN = 5;
6525
6526 if (_hennaCON > 5)
6527 _hennaCON = 5;
6528
6529 if (_hennaWIT > 5)
6530 _hennaWIT = 5;
6531
6532 if (_hennaDEX > 5)
6533 _hennaDEX = 5;
6534 }
6535
6536 /**
6537 * @param slot A slot to check.
6538 * @return the Henna of this Player corresponding to the selected slot.
6539 */
6540 public Henna getHenna(int slot)
6541 {
6542 if (slot < 1 || slot > 3)
6543 return null;
6544
6545 return _henna[slot - 1];
6546 }
6547
6548 public int getHennaStatINT()
6549 {
6550 return _hennaINT;
6551 }
6552
6553 public int getHennaStatSTR()
6554 {
6555 return _hennaSTR;
6556 }
6557
6558 public int getHennaStatCON()
6559 {
6560 return _hennaCON;
6561 }
6562
6563 public int getHennaStatMEN()
6564 {
6565 return _hennaMEN;
6566 }
6567
6568 public int getHennaStatWIT()
6569 {
6570 return _hennaWIT;
6571 }
6572
6573 public int getHennaStatDEX()
6574 {
6575 return _hennaDEX;
6576 }
6577
6578 /**
6579 * Return True if the Player is autoAttackable.
6580 * <ul>
6581 * <li>Check if the attacker isn't the Player Pet</li>
6582 * <li>Check if the attacker is L2MonsterInstance</li>
6583 * <li>If the attacker is a Player, check if it is not in the same party</li>
6584 * <li>Check if the Player has Karma</li>
6585 * <li>If the attacker is a Player, check if it is not in the same siege clan (Attacker, Defender)</li>
6586 * </ul>
6587 */
6588 @Override
6589 public boolean isAutoAttackable(Creature attacker)
6590 {
6591 // Check if the attacker isn't the Player Pet
6592 if (attacker == this || attacker == getPet())
6593 return false;
6594
6595 // Check if the attacker is a L2MonsterInstance
6596 if (attacker instanceof Monster)
6597 return true;
6598
6599 // Check if the attacker is not in the same party
6600 if (_party != null && _party.containsPlayer(attacker))
6601 return false;
6602
6603 // Check if the attacker is a L2Playable
6604 if (attacker instanceof Playable)
6605 {
6606 if (isInsideZone(ZoneId.PEACE))
6607 return false;
6608
6609 // Get Player
6610 final Player cha = attacker.getActingPlayer();
6611
6612 // Check if the attacker is in olympiad and olympiad start
6613 if (attacker instanceof Player && cha.isInOlympiadMode())
6614 {
6615 if (isInOlympiadMode() && isOlympiadStart() && cha.getOlympiadGameId() == getOlympiadGameId())
6616 return true;
6617
6618 return false;
6619 }
6620
6621 if(cha.isInsideZone(ZoneId.PVP_FLAG))
6622 {
6623 cha.updatePvPFlag(1);
6624 }
6625
6626 // is AutoAttackable if both players are in the same duel and the duel is still going on
6627 if (getDuelState() == DuelState.DUELLING && getDuelId() == cha.getDuelId())
6628 return true;
6629
6630 if (getClan() != null)
6631 {
6632 final Siege siege = CastleManager.getInstance().getActiveSiege(this);
6633 if (siege != null)
6634 {
6635 // Check if a siege is in progress and if attacker and the Player aren't in the Defender clan
6636 if (siege.checkSides(cha.getClan(), SiegeSide.DEFENDER, SiegeSide.OWNER) && siege.checkSides(getClan(), SiegeSide.DEFENDER, SiegeSide.OWNER))
6637 return false;
6638
6639 // Check if a siege is in progress and if attacker and the Player aren't in the Attacker clan
6640 // Default : false; change to true for Attacket can fight with out ctr.
6641 if (siege.checkSide(cha.getClan(), SiegeSide.ATTACKER) && siege.checkSide(getClan(), SiegeSide.ATTACKER))
6642 return true;
6643 }
6644
6645 // Check if clan is at war
6646 if (getClan().isAtWarWith(cha.getClanId()) && cha.getClan().isAtWarWith(getClanId()) && !wantsPeace() && !cha.wantsPeace() && !isAcademyMember())
6647 return true;
6648
6649 if (cha.isInsideZone(ZoneId.MULTI_FUNCTION) && getAllyId() != 0 && getAllyId() == cha.getAllyId())
6650 return true;
6651
6652 if (cha.isInsideZone(ZoneId.MULTI_FUNCTION) && getClan() != null && getClan().isMember(cha.getObjectId()))
6653 return true;
6654 }
6655
6656 // Check if the Player is in an arena.
6657 if (isInArena() && attacker.isInArena())
6658 return true;
6659
6660 // Check if the attacker is not in the same ally.
6661 if (getAllyId() != 0 && getAllyId() == cha.getAllyId())
6662 return false;
6663
6664 // Check if the attacker is not in the same clan.
6665 if (getClan() != null && getClan().isMember(cha.getObjectId()))
6666 return false;
6667
6668 // Now check again if the Player is in pvp zone (as arenas check was made before, it ends with sieges).
6669 if (isInsideZone(ZoneId.PVP) && attacker.isInsideZone(ZoneId.PVP))
6670 return true;
6671
6672 if (EventManager.getInstance().isRunning() && EventManager.getInstance().isRegistered(this) && EventManager.getInstance().isRegistered(attacker))
6673 return true;
6674 }
6675 else if (attacker instanceof SiegeGuard)
6676 {
6677 if (getClan() != null)
6678 {
6679 final Siege siege = CastleManager.getInstance().getActiveSiege(this);
6680 return (siege != null && siege.checkSide(getClan(), SiegeSide.ATTACKER));
6681 }
6682 }
6683
6684 // Check if the Player has Karma
6685 if (getKarma() > 0 || getPvpFlag() > 0)
6686 return true;
6687
6688 return false;
6689 }
6690
6691 /**
6692 * Check if the active L2Skill can be casted.
6693 * <ul>
6694 * <li>Check if the skill isn't toggle and is offensive</li>
6695 * <li>Check if the target is in the skill cast range</li>
6696 * <li>Check if the skill is Spoil type and if the target isn't already spoiled</li>
6697 * <li>Check if the caster owns enought consummed Item, enough HP and MP to cast the skill</li>
6698 * <li>Check if the caster isn't sitting</li>
6699 * <li>Check if all skills are enabled and this skill is enabled</li>
6700 * <li>Check if the caster own the weapon needed</li>
6701 * <li>Check if the skill is active</li>
6702 * <li>Check if all casting conditions are completed</li>
6703 * <li>Notify the AI with CAST and target</li>
6704 * </ul>
6705 * @param skill The L2Skill to use
6706 * @param forceUse used to force ATTACK on players
6707 * @param dontMove used to prevent movement, if not in range
6708 */
6709 @Override
6710 public boolean useMagic(L2Skill skill, boolean forceUse, boolean dontMove)
6711 {
6712
6713 if (EventManager.getInstance().isRunning() && EventManager.getInstance().isRegistered(this))
6714 {
6715 if (!EventManager.getInstance().getCurrentEvent().getBoolean("allowUseMagic"))
6716 {
6717 sendPacket(ActionFailed.STATIC_PACKET);
6718 return false;
6719 }
6720
6721 if (!EventManager.getInstance().getCurrentEvent().onUseMagic(skill))
6722 {
6723 sendPacket(ActionFailed.STATIC_PACKET);
6724 return false;
6725 }
6726 }
6727
6728 // Check if the skill is active
6729 if (skill.isPassive())
6730 {
6731 sendPacket(ActionFailed.STATIC_PACKET);
6732 return false;
6733 }
6734
6735 // Check if this skill is enabled (ex : reuse time)
6736// if (isSkillDisabled(skill))
6737// {
6738// sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_PREPARED_FOR_REUSE).addSkillName(skill));
6739// return false;
6740// }
6741
6742 if (isAio() && !isGM() && !isInsideZone(ZoneId.TOWN))
6743 {
6744 sendPacket(ActionFailed.STATIC_PACKET);
6745 return false;
6746 }
6747
6748 // Cancels the use of skills when player uses a cursed weapon or is flying.
6749 if ((isCursedWeaponEquipped() && !skill.isDemonicSkill()) // If CW, allow ONLY demonic skills.
6750 || (getMountType() == 1 && !skill.isStriderSkill()) // If mounted, allow ONLY Strider skills.
6751 || (getMountType() == 2 && !skill.isFlyingSkill())) // If flying, allow ONLY Wyvern skills.
6752 {
6753 sendPacket(ActionFailed.STATIC_PACKET);
6754 return false;
6755 }
6756
6757 // Players wearing Formal Wear cannot use skills.
6758 final ItemInstance formal = getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST);
6759 if (formal != null && formal.getItem().getBodyPart() == Item.SLOT_ALLDRESS)
6760 {
6761 sendPacket(SystemMessageId.CANNOT_USE_ITEMS_SKILLS_WITH_FORMALWEAR);
6762 sendPacket(ActionFailed.STATIC_PACKET);
6763 return false;
6764 }
6765
6766 // ************************************* Check Casting in Progress *******************************************
6767
6768 // If a skill is currently being used, queue this one if this is not the same
6769 if (isCastingNow())
6770 {
6771 // Check if new skill different from current skill in progress ; queue it in the player _queuedSkill
6772 if (_currentSkill.getSkill() != null && skill.getId() != _currentSkill.getSkillId())
6773 setQueuedSkill(skill, forceUse, dontMove);
6774
6775 sendPacket(ActionFailed.STATIC_PACKET);
6776 return false;
6777 }
6778
6779 setIsCastingNow(true);
6780
6781 // Set the player _currentSkill.
6782 setCurrentSkill(skill, forceUse, dontMove);
6783
6784 // Wipe queued skill.
6785 if (_queuedSkill.getSkill() != null)
6786 setQueuedSkill(null, false, false);
6787
6788 if (!checkUseMagicConditions(skill, forceUse, dontMove))
6789 {
6790 setIsCastingNow(false);
6791 return false;
6792 }
6793
6794 // Check if the target is correct and Notify the AI with CAST and target
6795 WorldObject target = null;
6796
6797 switch (skill.getTargetType())
6798 {
6799 case TARGET_AURA:
6800 case TARGET_FRONT_AURA:
6801 case TARGET_BEHIND_AURA:
6802 case TARGET_GROUND:
6803 case TARGET_SELF:
6804 case TARGET_CORPSE_ALLY:
6805 case TARGET_AURA_UNDEAD:
6806 target = this;
6807 break;
6808
6809 default: // Get the first target of the list
6810 target = skill.getFirstOfTargetList(this);
6811 break;
6812 }
6813
6814 // Notify the AI with CAST and target
6815 getAI().setIntention(CtrlIntention.CAST, skill, target);
6816 return true;
6817 }
6818
6819 private boolean checkUseMagicConditions(L2Skill skill, boolean forceUse, boolean dontMove)
6820 {
6821 // ************************************* Check Player State *******************************************
6822
6823 // Check if the player is dead or out of control.
6824 if (isDead() || isOutOfControl())
6825 {
6826 sendPacket(ActionFailed.STATIC_PACKET);
6827 return false;
6828 }
6829
6830 L2SkillType sklType = skill.getSkillType();
6831
6832 if (isFishing() && (sklType != L2SkillType.PUMPING && sklType != L2SkillType.REELING && sklType != L2SkillType.FISHING))
6833 {
6834 // Only fishing skills are available
6835 sendPacket(SystemMessageId.ONLY_FISHING_SKILLS_NOW);
6836 return false;
6837 }
6838
6839 if (isInObserverMode())
6840 {
6841 sendPacket(SystemMessageId.OBSERVERS_CANNOT_PARTICIPATE);
6842 abortCast();
6843 sendPacket(ActionFailed.STATIC_PACKET);
6844 return false;
6845 }
6846
6847 // Check if the caster is sitted.
6848 if (isSitting())
6849 {
6850
6851 // Send a System Message to the caster
6852 sendPacket(SystemMessageId.CANT_MOVE_SITTING);
6853
6854 // Send ActionFailed to the Player
6855 sendPacket(ActionFailed.STATIC_PACKET);
6856 return false;
6857 }
6858
6859 // Check if the skill type is TOGGLE
6860 if (skill.isToggle())
6861 {
6862 // Get effects of the skill
6863 L2Effect effect = getFirstEffect(skill.getId());
6864
6865 if (effect != null)
6866 {
6867 // If the toggle is different of FakeDeath, you can de-activate it clicking on it.
6868 if (skill.getId() != 60)
6869 effect.exit();
6870
6871 // Send ActionFailed to the Player
6872 sendPacket(ActionFailed.STATIC_PACKET);
6873 return false;
6874 }
6875 }
6876
6877 // Check if the player uses "Fake Death" skill
6878 if (isFakeDeath())
6879 {
6880 // Send ActionFailed to the Player
6881 sendPacket(ActionFailed.STATIC_PACKET);
6882 return false;
6883 }
6884
6885 // ************************************* Check Target *******************************************
6886 // Create and set a WorldObject containing the target of the skill
6887 WorldObject target = null;
6888 SkillTargetType sklTargetType = skill.getTargetType();
6889 Location worldPosition = getCurrentSkillWorldPosition();
6890
6891 if (sklTargetType == SkillTargetType.TARGET_GROUND && worldPosition == null)
6892 {
6893 _log.info("WorldPosition is null for skill: " + skill.getName() + ", player: " + getName() + ".");
6894 sendPacket(ActionFailed.STATIC_PACKET);
6895 return false;
6896 }
6897
6898 switch (sklTargetType)
6899 {
6900 // Target the player if skill type is AURA, PARTY, CLAN or SELF
6901 case TARGET_AURA:
6902 case TARGET_FRONT_AURA:
6903 case TARGET_BEHIND_AURA:
6904 case TARGET_AURA_UNDEAD:
6905 case TARGET_PARTY:
6906 case TARGET_ALLY:
6907 case TARGET_CLAN:
6908 case TARGET_GROUND:
6909 case TARGET_SELF:
6910 case TARGET_CORPSE_ALLY:
6911 case TARGET_AREA_SUMMON:
6912 target = this;
6913 break;
6914 case TARGET_PET:
6915 case TARGET_SUMMON:
6916 target = getPet();
6917 break;
6918 default:
6919 target = getTarget();
6920 break;
6921 }
6922
6923 // Check the validity of the target
6924 if (target == null)
6925 {
6926 sendPacket(ActionFailed.STATIC_PACKET);
6927 return false;
6928 }
6929
6930 if (target instanceof Door)
6931 {
6932 if (!((Door) target).isAutoAttackable(this) // Siege doors only hittable during siege
6933 || (((Door) target).isUnlockable() && skill.getSkillType() != L2SkillType.UNLOCK)) // unlockable doors
6934 {
6935 sendPacket(SystemMessageId.INCORRECT_TARGET);
6936 sendPacket(ActionFailed.STATIC_PACKET);
6937 return false;
6938 }
6939 }
6940
6941 // Are the target and the player in the same duel?
6942 if (isInDuel())
6943 {
6944 if (target instanceof Playable)
6945 {
6946 // Get Player
6947 Player cha = target.getActingPlayer();
6948 if (cha.getDuelId() != getDuelId())
6949 {
6950 sendPacket(SystemMessageId.INCORRECT_TARGET);
6951 sendPacket(ActionFailed.STATIC_PACKET);
6952 return false;
6953 }
6954 }
6955 }
6956
6957 // ************************************* Check skill availability *******************************************
6958
6959 // Siege summon checks. Both checks send a message to the player if it return false.
6960 if (skill.isSiegeSummonSkill())
6961 {
6962 final Siege siege = CastleManager.getInstance().getActiveSiege(this);
6963 if (siege == null || !siege.checkSide(getClan(), SiegeSide.ATTACKER) || (isInSiege() && isInsideZone(ZoneId.CASTLE)))
6964 {
6965 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.NOT_CALL_PET_FROM_THIS_LOCATION));
6966 return false;
6967 }
6968
6969 if (SevenSigns.getInstance().isSealValidationPeriod() && SevenSigns.getInstance().getSealOwner(SealType.STRIFE) == CabalType.DAWN && SevenSigns.getInstance().getPlayerCabal(getObjectId()) == CabalType.DUSK)
6970 {
6971 sendPacket(SystemMessageId.SEAL_OF_STRIFE_FORBIDS_SUMMONING);
6972 return false;
6973 }
6974 }
6975
6976 // Check if this skill is enabled (ex : reuse time)
6977 if (isSkillDisabled(skill)) {
6978 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_PREPARED_FOR_REUSE).addSkillName(skill));
6979 return false;
6980 }
6981
6982 // ************************************* Check casting conditions *******************************************
6983
6984 // Check if all casting conditions are completed
6985 if (!skill.checkCondition(this, target, false))
6986 {
6987 // Send ActionFailed to the Player
6988 sendPacket(ActionFailed.STATIC_PACKET);
6989 return false;
6990 }
6991
6992 // ************************************* Check Skill Type *******************************************
6993
6994 // Check if this is offensive magic skill
6995 if (skill.isOffensive())
6996 {
6997 if (isInsidePeaceZone(this, target))
6998 {
6999 // If Creature or target is in a peace zone, send a system message TARGET_IN_PEACEZONE ActionFailed
7000 sendPacket(SystemMessageId.TARGET_IN_PEACEZONE);
7001 sendPacket(ActionFailed.STATIC_PACKET);
7002 return false;
7003 }
7004
7005 if (isInOlympiadMode() && !isOlympiadStart() && skill.getId() != 347)
7006 {
7007 // if Player is in Olympia and the match isn't already start, send ActionFailed
7008 sendPacket(ActionFailed.STATIC_PACKET);
7009 return false;
7010 }
7011
7012 // Check if the target is attackable
7013 if (!target.isAttackable() && !getAccessLevel().allowPeaceAttack())
7014 {
7015 // If target is not attackable, send ActionFailed
7016 sendPacket(ActionFailed.STATIC_PACKET);
7017 return false;
7018 }
7019
7020 // Check if a Forced ATTACK is in progress on non-attackable target
7021 if (!target.isAutoAttackable(this) && !forceUse)
7022 {
7023 switch (sklTargetType)
7024 {
7025 case TARGET_AURA:
7026 case TARGET_FRONT_AURA:
7027 case TARGET_BEHIND_AURA:
7028 case TARGET_AURA_UNDEAD:
7029 case TARGET_CLAN:
7030 case TARGET_ALLY:
7031 case TARGET_PARTY:
7032 case TARGET_SELF:
7033 case TARGET_GROUND:
7034 case TARGET_CORPSE_ALLY:
7035 case TARGET_AREA_SUMMON:
7036 break;
7037 default: // Send ActionFailed to the Player
7038 sendPacket(ActionFailed.STATIC_PACKET);
7039 return false;
7040 }
7041 }
7042
7043 // Check if the target is in the skill cast range
7044 if (dontMove)
7045 {
7046 // Calculate the distance between the Player and the target
7047 if (sklTargetType == SkillTargetType.TARGET_GROUND)
7048 {
7049 if (!isInsideRadius(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), (int) (skill.getCastRange() + getCollisionRadius()), false, false))
7050 {
7051 // Send a System Message to the caster
7052 sendPacket(SystemMessageId.TARGET_TOO_FAR);
7053
7054 // Send ActionFailed to the Player
7055 sendPacket(ActionFailed.STATIC_PACKET);
7056 return false;
7057 }
7058 }
7059 else if (skill.getCastRange() > 0 && !isInsideRadius(target, (int) (skill.getCastRange() + getCollisionRadius()), false, false))
7060 {
7061 // Send a System Message to the caster
7062 sendPacket(SystemMessageId.TARGET_TOO_FAR);
7063
7064 // Send ActionFailed to the Player
7065 sendPacket(ActionFailed.STATIC_PACKET);
7066 return false;
7067 }
7068 }
7069 }
7070
7071 // Check if the skill is defensive
7072 if (!skill.isOffensive() && target instanceof Monster && !forceUse)
7073 {
7074 // check if the target is a monster and if force attack is set.. if not then we don't want to cast.
7075 switch (sklTargetType)
7076 {
7077 case TARGET_PET:
7078 case TARGET_SUMMON:
7079 case TARGET_AURA:
7080 case TARGET_FRONT_AURA:
7081 case TARGET_BEHIND_AURA:
7082 case TARGET_AURA_UNDEAD:
7083 case TARGET_CLAN:
7084 case TARGET_SELF:
7085 case TARGET_CORPSE_ALLY:
7086 case TARGET_PARTY:
7087 case TARGET_ALLY:
7088 case TARGET_CORPSE_MOB:
7089 case TARGET_AREA_CORPSE_MOB:
7090 case TARGET_GROUND:
7091 break;
7092 default:
7093 {
7094 switch (sklType)
7095 {
7096 case BEAST_FEED:
7097 case DELUXE_KEY_UNLOCK:
7098 case UNLOCK:
7099 break;
7100 default:
7101 sendPacket(ActionFailed.STATIC_PACKET);
7102 return false;
7103 }
7104 break;
7105 }
7106 }
7107 }
7108
7109 // Check if the skill is Spoil type and if the target isn't already spoiled
7110 if (sklType == L2SkillType.SPOIL)
7111 {
7112 if (!(target instanceof Monster))
7113 {
7114 // Send a System Message to the Player
7115 sendPacket(SystemMessageId.INCORRECT_TARGET);
7116
7117 // Send ActionFailed to the Player
7118 sendPacket(ActionFailed.STATIC_PACKET);
7119 return false;
7120 }
7121 }
7122
7123 // Check if the skill is Sweep type and if conditions not apply
7124 if (sklType == L2SkillType.SWEEP && target instanceof Attackable)
7125 {
7126 if (((Attackable) target).isDead())
7127 {
7128 final int spoilerId = ((Attackable) target).getSpoilerId();
7129 if (spoilerId == 0)
7130 {
7131 // Send a System Message to the Player
7132 sendPacket(SystemMessageId.SWEEPER_FAILED_TARGET_NOT_SPOILED);
7133
7134 // Send ActionFailed to the Player
7135 sendPacket(ActionFailed.STATIC_PACKET);
7136 return false;
7137 }
7138
7139 if (!isLooterOrInLooterParty(spoilerId))
7140 {
7141 // Send a System Message to the Player
7142 sendPacket(SystemMessageId.SWEEP_NOT_ALLOWED);
7143
7144 // Send ActionFailed to the Player
7145 sendPacket(ActionFailed.STATIC_PACKET);
7146 return false;
7147 }
7148 }
7149 }
7150
7151 // Check if the skill is Drain Soul (Soul Crystals) and if the target is a MOB
7152 if (sklType == L2SkillType.DRAIN_SOUL)
7153 {
7154 if (!(target instanceof Monster))
7155 {
7156 // Send a System Message to the Player
7157 sendPacket(SystemMessageId.INCORRECT_TARGET);
7158
7159 // Send ActionFailed to the Player
7160 sendPacket(ActionFailed.STATIC_PACKET);
7161 return false;
7162 }
7163 }
7164
7165 // Check if this is a Pvp skill and target isn't a non-flagged/non-karma player
7166 switch (sklTargetType)
7167 {
7168 case TARGET_PARTY:
7169 case TARGET_ALLY: // For such skills, checkPvpSkill() is called from L2Skill.getTargetList()
7170 case TARGET_CLAN: // For such skills, checkPvpSkill() is called from L2Skill.getTargetList()
7171 case TARGET_AURA:
7172 case TARGET_FRONT_AURA:
7173 case TARGET_BEHIND_AURA:
7174 case TARGET_AURA_UNDEAD:
7175 case TARGET_GROUND:
7176 case TARGET_SELF:
7177 case TARGET_CORPSE_ALLY:
7178 case TARGET_AREA_SUMMON:
7179 break;
7180 default:
7181 if (!checkPvpSkill(target, skill) && !getAccessLevel().allowPeaceAttack())
7182 {
7183 // Send a System Message to the Player
7184 sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
7185
7186 // Send ActionFailed to the Player
7187 sendPacket(ActionFailed.STATIC_PACKET);
7188 return false;
7189 }
7190 }
7191
7192 if ((sklTargetType == SkillTargetType.TARGET_HOLY && !checkIfOkToCastSealOfRule(CastleManager.getInstance().getCastle(this), false, skill, target)) || (sklType == L2SkillType.SIEGEFLAG && !L2SkillSiegeFlag.checkIfOkToPlaceFlag(this, false)) || (sklType == L2SkillType.STRSIEGEASSAULT && !checkIfOkToUseStriderSiegeAssault(skill)) || (sklType == L2SkillType.SUMMON_FRIEND && !(checkSummonerStatus(this) && checkSummonTargetStatus(target, this))))
7193 {
7194 sendPacket(ActionFailed.STATIC_PACKET);
7195 abortCast();
7196 return false;
7197 }
7198
7199 // GeoData Los Check here
7200 if (skill.getCastRange() > 0)
7201 {
7202 if (sklTargetType == SkillTargetType.TARGET_GROUND)
7203 {
7204 if (!GeoEngine.getInstance().canSeeTarget(this, worldPosition))
7205 {
7206 sendPacket(SystemMessageId.CANT_SEE_TARGET);
7207 sendPacket(ActionFailed.STATIC_PACKET);
7208 return false;
7209 }
7210 }
7211 else if (!GeoEngine.getInstance().canSeeTarget(this, target))
7212 {
7213 sendPacket(SystemMessageId.CANT_SEE_TARGET);
7214 sendPacket(ActionFailed.STATIC_PACKET);
7215 return false;
7216 }
7217 }
7218 // finally, after passing all conditions
7219 return true;
7220 }
7221
7222 public void dodiepanel(Creature killer)
7223 {
7224
7225
7226 if(Config.SHOW_HP_PVP)
7227 {
7228 NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
7229 StringBuilder replyMSG = new StringBuilder("<html><body><title>Euro-Gold.net</title>");
7230 replyMSG.append("<center>He Kill you</center><br>");
7231 final Player player = killer.getActingPlayer();
7232// int RNAND = player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND).getItemId();
7233 replyMSG.append("<center>-----><font color=\"ffe700\">" + player.getName() + "</font><-----</center><br>");
7234 replyMSG.append("<center>-----><font color=\"ffe700\">" + player.getClassId() + "</font><-----</center><br>");
7235 replyMSG.append("<table border=0 width=\"100%\">");
7236 replyMSG.append("<tr><td><center>CP: <font color=\"ffe700\">"+ player.getCurrentShowCPPvp() + "</font> / <font color=\"ffe700\">"+ player.getMaxCp() + "</font></center></td></tr>");
7237 replyMSG.append("<br>");
7238 replyMSG.append("<tr><td><center>HP: <font color=\"ff0000\">"+ player.getCurrentShowHpPvp() + "</font> / <font color=\"ff0000\">"+ player.getMaxHp() + "</font></center></td></tr>");
7239 replyMSG.append("<br>");
7240 replyMSG.append("<tr><td><center>MP: <font color=\"00abff\">"+ player.getCurrentShowMpPvp() + "</font> / <font color=\"00abff\">"+ player.getMaxMp() + "</font></center></td></tr>");
7241 replyMSG.append("</table>");
7242 replyMSG.append("<tr><td><center>==================================</center></tr></td>");
7243 //Weapon
7244 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND) != null)
7245 {
7246 replyMSG.append("<table border=0 width=\"100%\">");
7247 replyMSG.append("<tr><td><center>Weapon <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND).getEnchantLevel() + "</font></center></tr></td></table>");
7248 replyMSG.append("<br>");
7249 }
7250 else
7251 {
7252 replyMSG.append("<table border=0 width=\"100%\">");
7253 replyMSG.append("<tr><td><center>Weapon :<font color=\"FF0000\"> The player doesn't have weapon.</font></center></tr></td></table>");
7254 replyMSG.append("<br>");
7255 }
7256 //helmet
7257 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_HEAD) != null)
7258 {
7259 replyMSG.append("<table border=0 width=\"100%\">");
7260 replyMSG.append("<tr><td><center>Helmet <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_HEAD).getName()+"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_HEAD).getEnchantLevel() + "</font></center></tr></td></table>");
7261 replyMSG.append("<br>");
7262 }
7263 else
7264 {
7265 replyMSG.append("<table border=0 width=\"100%\">");
7266 replyMSG.append("<tr><td><center>Helmet :<font color=\"FF0000\"> The player doesn't have helmet.</font></center></tr></td></table>");
7267 replyMSG.append("<br>");
7268 }
7269 //chest
7270 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST) != null)
7271 {
7272 replyMSG.append("<table border=0 width=\"100%\">");
7273 replyMSG.append("<tr><td><center>Chest <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST).getEnchantLevel() + "</font></center></tr></td></table>");
7274 replyMSG.append("<br>");
7275 }
7276 else
7277 {
7278 replyMSG.append("<table border=0 width=\"100%\">");
7279 replyMSG.append("<tr><td><center>Chest :<font color=\"FF0000\"> The player doesn't have chest.</font></center></tr></td></table>");
7280 replyMSG.append("<br>");
7281 }
7282 //Legs
7283 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LEGS) != null)
7284 {
7285 replyMSG.append("<table border=0 width=\"100%\">");
7286 replyMSG.append("<tr><td><center>Legs <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LEGS).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LEGS).getEnchantLevel() + "</font></center></tr></td></table>");
7287 replyMSG.append("<br>");
7288 }
7289 else
7290 {
7291 replyMSG.append("<table border=0 width=\"100%\">");
7292 replyMSG.append("<tr><td><center>Legs :<font color=\"FF0000\"> The player doesn't have legs.</font></center></tr></td></table>");
7293 replyMSG.append("<br>");
7294 }
7295 //Gloves
7296 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_GLOVES) != null)
7297 {
7298 replyMSG.append("<table border=0 width=\"100%\">");
7299 replyMSG.append("<tr><td><center>Gloves <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_GLOVES).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_GLOVES).getEnchantLevel() + "</font></center></tr></td></table>");
7300 replyMSG.append("<br>");
7301 }
7302 else
7303 {
7304 replyMSG.append("<table border=0 width=\"100%\">");
7305 replyMSG.append("<tr><td><center>Gloves :<font color=\"FF0000\"> The player doesn't have gloves.</font></center></tr></td></table>");
7306 replyMSG.append("<br>");
7307 }
7308 //Boots
7309 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_FEET) != null)
7310 {
7311 replyMSG.append("<table border=0 width=\"100%\">");
7312 replyMSG.append("<tr><td><center>Boots <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_FEET).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_FEET).getEnchantLevel() + "</font></center></tr></td></table>");
7313 replyMSG.append("<br>");
7314 }
7315 else
7316 {
7317 replyMSG.append("<table border=0 width=\"100%\">");
7318 replyMSG.append("<tr><td><center>Boots :<font color=\"FF0000\"> The player doesn't have boots.</font></center></tr></td></table>");
7319 replyMSG.append("<br>");
7320 }
7321 //Necklace
7322 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_NECK) != null)
7323 {
7324 replyMSG.append("<table border=0 width=\"100%\">");
7325 replyMSG.append("<tr><td><center> <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_NECK).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_NECK).getEnchantLevel() + "</font></center></tr></td></table>");
7326 replyMSG.append("<br>");
7327 }
7328 else
7329 {
7330 replyMSG.append("<table border=0 width=\"100%\">");
7331 replyMSG.append("<tr><td><center>Necklace :<font color=\"FF0000\"> The player doesn't have necklace.</font></center></tr></td></table>");
7332 replyMSG.append("<br>");
7333 }
7334 //L-Earring
7335 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LEAR) != null)
7336 {
7337 replyMSG.append("<table border=0 width=\"100%\">");
7338 replyMSG.append("<tr><td><center>L- <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LEAR).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LEAR).getEnchantLevel() + "</font></center></tr></td></table>");
7339 replyMSG.append("<br>");
7340 }
7341 else
7342 {
7343 replyMSG.append("<table border=0 width=\"100%\">");
7344 replyMSG.append("<tr><td><center>L-Earring :<font color=\"FF0000\"> The player doesn't have l-earring.</font></center></tr></td></table>");
7345 replyMSG.append("<br>");
7346 }
7347 //R-Earring
7348 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_REAR) != null)
7349 {
7350 replyMSG.append("<table border=0 width=\"100%\">");
7351 replyMSG.append("<tr><td><center>R- <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_REAR).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_REAR).getEnchantLevel() + "</font></center></tr></td></table>");
7352 replyMSG.append("<br>");
7353 }
7354 else
7355 {
7356 replyMSG.append("<table border=0 width=\"100%\">");
7357 replyMSG.append("<tr><td><center>R-Earring :<font color=\"FF0000\"> The player doesn't have r-earring.</font></center></tr></td></table>");
7358 replyMSG.append("<br>");
7359 }
7360 //L-Ring
7361 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LFINGER) != null)
7362 {
7363 replyMSG.append("<table border=0 width=\"100%\">");
7364 replyMSG.append("<tr><td><center>L- <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LFINGER).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LFINGER).getEnchantLevel() + "</font></center></tr></td></table>");
7365 replyMSG.append("<br>");
7366 }
7367 else
7368 {
7369 replyMSG.append("<table border=0 width=\"100%\">");
7370 replyMSG.append("<tr><td><center>L-Ring :<font color=\"FF0000\"> The player doesn't have l-ring.</font></center></tr></td></table>");
7371 replyMSG.append("<br>");
7372 }
7373 //R-Ring
7374 if(player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_RFINGER) != null)
7375 {
7376 replyMSG.append("<table border=0 width=\"100%\">");
7377 replyMSG.append("<tr><td><center>R- <font color=\"00ccbe\">"+ player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_RFINGER).getName() +"</font>:<font color=\"FFE700\"> +" + player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_RFINGER).getEnchantLevel() + "</font></center></tr></td></table>");
7378 replyMSG.append("<br>");
7379 }
7380 else
7381 {
7382 replyMSG.append("<table border=0 width=\"100%\">");
7383 replyMSG.append("<tr><td><center>R-Ring :<font color=\"FF0000\"> The player doesn't have r-ring.</font></center></tr></td></table>");
7384 replyMSG.append("<br>");
7385 }
7386 replyMSG.append("</body></html>");
7387
7388 adminReply.setHtml(replyMSG.toString());
7389 sendPacket(adminReply);
7390
7391 adminReply = null;
7392 replyMSG = null;
7393 }
7394 }
7395 public boolean checkIfOkToUseStriderSiegeAssault(L2Skill skill)
7396 {
7397 final Siege siege = CastleManager.getInstance().getActiveSiege(this);
7398
7399 SystemMessage sm;
7400
7401 if (!isRiding())
7402 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED).addSkillName(skill);
7403 else if (!(getTarget() instanceof Door))
7404 sm = SystemMessage.getSystemMessage(SystemMessageId.INCORRECT_TARGET);
7405 else if (siege == null || !siege.checkSide(getClan(), SiegeSide.ATTACKER))
7406 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED).addSkillName(skill);
7407 else
7408 return true;
7409
7410 sendPacket(sm);
7411 return false;
7412 }
7413
7414 public boolean checkIfOkToCastSealOfRule(Castle castle, boolean isCheckOnly, L2Skill skill, WorldObject target)
7415 {
7416 SystemMessage sm;
7417
7418 if (castle == null || castle.getCastleId() <= 0)
7419 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED).addSkillName(skill);
7420 else if (!castle.isGoodArtifact(target))
7421 sm = SystemMessage.getSystemMessage(SystemMessageId.INCORRECT_TARGET);
7422 else if (!castle.getSiege().isInProgress())
7423 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED).addSkillName(skill);
7424 else if (!MathUtil.checkIfInRange(200, this, target, true))
7425 sm = SystemMessage.getSystemMessage(SystemMessageId.DIST_TOO_FAR_CASTING_STOPPED);
7426 else if (!isInsideZone(ZoneId.CAST_ON_ARTIFACT))
7427 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED).addSkillName(skill);
7428 else if (!castle.getSiege().checkSide(getClan(), SiegeSide.ATTACKER))
7429 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED).addSkillName(skill);
7430 else
7431 {
7432 if (!isCheckOnly)
7433 {
7434 sm = SystemMessage.getSystemMessage(SystemMessageId.OPPONENT_STARTED_ENGRAVING);
7435 castle.getSiege().announceToPlayers(sm, false);
7436 }
7437 return true;
7438 }
7439 sendPacket(sm);
7440 return false;
7441 }
7442
7443 /**
7444 * @param objectId : The looter object to make checks on.
7445 * @return true if the active player is the looter or in the same party or command channel than looter objectId.
7446 */
7447 public boolean isLooterOrInLooterParty(int objectId)
7448 {
7449 if (objectId == getObjectId())
7450 return true;
7451
7452 final Player looter = World.getInstance().getPlayer(objectId);
7453 if (looter == null)
7454 return false;
7455
7456 if (_party == null)
7457 return false;
7458
7459 final CommandChannel channel = _party.getCommandChannel();
7460 return (channel != null) ? channel.containsPlayer(looter) : _party.containsPlayer(looter);
7461 }
7462
7463 /**
7464 * Check if the requested casting is a Pc->Pc skill cast and if it's a valid pvp condition
7465 * @param target WorldObject instance containing the target
7466 * @param skill L2Skill instance with the skill being casted
7467 * @return {@code false} if the skill is a pvpSkill and target is not a valid pvp target, {@code true} otherwise.
7468 */
7469 public boolean checkPvpSkill(WorldObject target, L2Skill skill)
7470 {
7471 if (isInOlympiadMode() && !isOlympiadStart() && skill.getId() == 347)
7472 {
7473 // if Player is in Olympiad and the match isn't already start, send ActionFailed
7474 // sendPacket(ActionFailed.STATIC_PACKET);
7475 return false;
7476 }
7477
7478 if (skill == null || target == null)
7479 return false;
7480
7481 if (!(target instanceof Playable))
7482 return true;
7483
7484 if (EventManager.getInstance().isRunning() && EventManager.getInstance().isRegistered(this) && EventManager.getInstance().isRegistered((Player) target))
7485 return true;
7486
7487 if (skill.isDebuff() || skill.isOffensive())
7488 {
7489 final Player targetPlayer = target.getActingPlayer();
7490 if (targetPlayer == null || this == target)
7491 return false;
7492
7493 // Peace Zone
7494 if (target.isInsideZone(ZoneId.PEACE))
7495 return false;
7496
7497 // Duel
7498 if (isInDuel() && targetPlayer.isInDuel() && getDuelId() == targetPlayer.getDuelId())
7499 return true;
7500
7501 final boolean isCtrlPressed = getCurrentSkill() != null && getCurrentSkill().isCtrlPressed();
7502
7503 // Party
7504 if (isInParty() && targetPlayer.isInParty())
7505 {
7506 // Same Party
7507 if (getParty().getLeader() == targetPlayer.getParty().getLeader())
7508 {
7509 if (skill.getEffectRange() > 0 && isCtrlPressed && getTarget() == target && skill.isDamage())
7510 return true;
7511
7512 return false;
7513 }
7514 else if (getParty().getCommandChannel() != null && getParty().getCommandChannel().containsPlayer(targetPlayer))
7515 {
7516 if (skill.getEffectRange() > 0 && isCtrlPressed && getTarget() == target && skill.isDamage())
7517 return true;
7518
7519 return false;
7520 }
7521 }
7522
7523 // You can debuff anyone except party members while in an arena...
7524 if (isInsideZone(ZoneId.PVP) && targetPlayer.isInsideZone(ZoneId.PVP))
7525 return true;
7526
7527 // Olympiad
7528 if (isInOlympiadMode() && targetPlayer.isInOlympiadMode() && getOlympiadGameId() == targetPlayer.getOlympiadGameId())
7529 return true;
7530
7531 if (EventManager.getInstance().isRunning() && EventManager.getInstance().isRegistered(this) && EventManager.getInstance().isRegistered((Player) target))
7532 return true;
7533
7534 final Clan aClan = getClan();
7535 final Clan tClan = targetPlayer.getClan();
7536
7537// if (EventManager.getInstance().isRunning() && EventManager.getInstance().isRegistered(this)
7538// && EventManager.getInstance().isRegistered((Player) target))
7539// return true;
7540
7541 if (aClan != null && tClan != null)
7542 {
7543 if (aClan.isAtWarWith(tClan.getClanId()) && tClan.isAtWarWith(aClan.getClanId()))
7544 {
7545 // Check if skill can do dmg
7546 // if (skill.getEffectRange() > 0 && isCtrlPressed && getTarget() == target && skill.isAOE())
7547 return true;
7548
7549 // return isCtrlPressed;
7550 }
7551 else if (!isInsideZone(ZoneId.MULTI_FUNCTION) && getClanId() == targetPlayer.getClanId() || (!isInsideZone(ZoneId.MULTI_FUNCTION) && getAllyId() > 0 && getAllyId() == targetPlayer.getAllyId())) {
7552 // Check if skill can do dmg
7553 if (skill.getEffectRange() > 0 && isCtrlPressed && getTarget() == target && skill.isDamage())
7554 return true;
7555
7556 return false;
7557 }
7558 }
7559
7560 // On retail, it is impossible to debuff a "peaceful" player.
7561 if (targetPlayer.getPvpFlag() == 0 && targetPlayer.getKarma() == 0)
7562 {
7563 // Check if skill can do dmg
7564 if (skill.getEffectRange() > 0 && isCtrlPressed && getTarget() == target && skill.isDamage())
7565 return true;
7566
7567 return false;
7568 }
7569
7570 if (targetPlayer.getPvpFlag() > 0 || targetPlayer.getKarma() > 0)
7571 return true;
7572
7573 return false;
7574 }
7575 return true;
7576 }
7577
7578 /**
7579 * @return True if the Player is a Mage (based on class templates).
7580 */
7581 public boolean isMageClass()
7582 {
7583 return getClassId().getType() != ClassType.FIGHTER;
7584 }
7585
7586 public boolean isMounted()
7587 {
7588 return _mountType > 0;
7589 }
7590
7591 /**
7592 * This method allows to :
7593 * <ul>
7594 * <li>change isRiding/isFlying flags</li>
7595 * <li>gift player with Wyvern Breath skill if mount is a wyvern</li>
7596 * <li>send the skillList (faded icons update)</li>
7597 * </ul>
7598 * @param npcId the npcId of the mount
7599 * @param npcLevel The level of the mount
7600 * @param mountType 0, 1 or 2 (dismount, strider or wyvern).
7601 * @return always true.
7602 */
7603 public boolean setMount(int npcId, int npcLevel, int mountType)
7604 {
7605 switch (mountType)
7606 {
7607 case 0: // Dismounted
7608 if (isFlying())
7609 removeSkill(FrequentSkill.WYVERN_BREATH.getSkill().getId(), false);
7610 break;
7611
7612 case 2: // Flying Wyvern
7613 addSkill(FrequentSkill.WYVERN_BREATH.getSkill(), false);
7614 break;
7615 }
7616
7617 _mountNpcId = npcId;
7618 _mountType = mountType;
7619 _mountLevel = npcLevel;
7620
7621 sendSkillList(); // Update faded icons && eventual added skills.
7622 return true;
7623 }
7624
7625 @Override
7626 public boolean isSeated()
7627 {
7628 return _throneId > 0;
7629 }
7630
7631 @Override
7632 public boolean isRiding()
7633 {
7634 return _mountType == 1;
7635 }
7636
7637 @Override
7638 public boolean isFlying()
7639 {
7640 return _mountType == 2;
7641 }
7642
7643 /**
7644 * @return the type of Pet mounted (0 : none, 1 : Strider, 2 : Wyvern).
7645 */
7646 public int getMountType()
7647 {
7648 return _mountType;
7649 }
7650
7651 @Override
7652 public final void stopAllEffects()
7653 {
7654 super.stopAllEffects();
7655 updateAndBroadcastStatus(2);
7656 }
7657
7658 @Override
7659 public final void stopAllEffectsExceptThoseThatLastThroughDeath()
7660 {
7661 super.stopAllEffectsExceptThoseThatLastThroughDeath();
7662 updateAndBroadcastStatus(2);
7663 }
7664
7665 /**
7666 * Stop all toggle-type effects
7667 */
7668 public final void stopAllToggles()
7669 {
7670 _effects.stopAllToggles();
7671 }
7672
7673 public final void stopCubics()
7674 {
7675 if (getCubics() != null)
7676 {
7677 boolean removed = false;
7678 for (Cubic cubic : getCubics().values())
7679 {
7680 cubic.stopAction();
7681 delCubic(cubic.getId());
7682 removed = true;
7683 }
7684 if (removed)
7685 broadcastUserInfo();
7686 }
7687 }
7688
7689 public final void stopCubicsByOthers()
7690 {
7691 if (getCubics() != null)
7692 {
7693 boolean removed = false;
7694 for (Cubic cubic : getCubics().values())
7695 {
7696 if (cubic.givenByOther())
7697 {
7698 cubic.stopAction();
7699 delCubic(cubic.getId());
7700 removed = true;
7701 }
7702 }
7703 if (removed)
7704 broadcastUserInfo();
7705 }
7706 }
7707
7708 /**
7709 * Send UserInfo to this Player and CharInfo to all Player in its _KnownPlayers.<BR>
7710 * <ul>
7711 * <li>Send UserInfo to this Player (Public and Private Data)</li>
7712 * <li>Send CharInfo to all Player in _KnownPlayers of the Player (Public data only)</li>
7713 * </ul>
7714 * <FONT COLOR=#FF0000><B> <U>Caution</U> : DON'T SEND UserInfo packet to other players instead of CharInfo packet. Indeed, UserInfo packet contains PRIVATE DATA as MaxHP, STR, DEX...</B></FONT><BR>
7715 * <BR>
7716 */
7717 @Override
7718 public void updateAbnormalEffect()
7719 {
7720 broadcastUserInfo();
7721 }
7722
7723 /**
7724 * Disable the Inventory and create a new task to enable it after 1.5s.
7725 */
7726 public void tempInventoryDisable()
7727 {
7728 _inventoryDisable = true;
7729
7730 ThreadPool.schedule(() -> _inventoryDisable = false, 1500);
7731 }
7732
7733 /**
7734 * @return True if the Inventory is disabled.
7735 */
7736 public boolean isInventoryDisabled()
7737 {
7738 return _inventoryDisable;
7739 }
7740
7741 public Map<Integer, Cubic> getCubics()
7742 {
7743 return _cubics;
7744 }
7745
7746 /**
7747 * Add a L2CubicInstance to the Player _cubics.
7748 * @param id
7749 * @param level
7750 * @param matk
7751 * @param activationtime
7752 * @param activationchance
7753 * @param totalLifetime
7754 * @param givenByOther
7755 */
7756 public void addCubic(int id, int level, double matk, int activationtime, int activationchance, int totalLifetime, boolean givenByOther)
7757 {
7758 _cubics.put(id, new Cubic(this, id, level, (int) matk, activationtime, activationchance, totalLifetime, givenByOther));
7759 }
7760
7761 /**
7762 * Remove a L2CubicInstance from the Player _cubics.
7763 * @param id
7764 */
7765 public void delCubic(int id)
7766 {
7767 _cubics.remove(id);
7768 }
7769
7770 /**
7771 * @param id
7772 * @return the L2CubicInstance corresponding to the Identifier of the Player _cubics.
7773 */
7774 public Cubic getCubic(int id)
7775 {
7776 return _cubics.get(id);
7777 }
7778
7779 @Override
7780 public String toString()
7781 {
7782 return "player " + getName();
7783 }
7784
7785 /**
7786 * @return the modifier corresponding to the Enchant Effect of the Active Weapon (Min : 127).
7787 */
7788 public int getEnchantEffect()
7789 {
7790 final ItemInstance wpn = getActiveWeaponInstance();
7791 return (wpn == null) ? 0 : Math.min(127, wpn.getEnchantLevel());
7792 }
7793
7794 /**
7795 * Remember the current {@link Folk} of the {@link Player}, used notably for integrity check.
7796 * @param folk : The Folk to remember.
7797 */
7798 public void setCurrentFolk(Folk folk)
7799 {
7800 _currentFolk = folk;
7801 }
7802
7803 /**
7804 * @return the current {@link Folk} of the {@link Player}.
7805 */
7806 public Folk getCurrentFolk()
7807 {
7808 return _currentFolk;
7809 }
7810
7811 /**
7812 * @return True if Player is a participant in the Festival of Darkness.
7813 */
7814 public boolean isFestivalParticipant()
7815 {
7816 return SevenSignsFestival.getInstance().isParticipant(this);
7817 }
7818
7819 public void addAutoSoulShot(int itemId)
7820 {
7821 _activeSoulShots.add(itemId);
7822 }
7823
7824 public boolean removeAutoSoulShot(int itemId)
7825 {
7826 return _activeSoulShots.remove(itemId);
7827 }
7828
7829 public Set<Integer> getAutoSoulShot()
7830 {
7831 return _activeSoulShots;
7832 }
7833
7834 @Override
7835 public boolean isChargedShot(ShotType type)
7836 {
7837 ItemInstance weapon = getActiveWeaponInstance();
7838 return weapon != null && weapon.isChargedShot(type);
7839 }
7840
7841 @Override
7842 public void setChargedShot(ShotType type, boolean charged)
7843 {
7844 ItemInstance weapon = getActiveWeaponInstance();
7845 if (weapon != null)
7846 weapon.setChargedShot(type, charged);
7847 }
7848
7849 @Override
7850 public void rechargeShots(boolean physical, boolean magic)
7851 {
7852 if (_activeSoulShots.isEmpty())
7853 return;
7854
7855 for (int itemId : _activeSoulShots)
7856 {
7857 ItemInstance item = getInventory().getItemByItemId(itemId);
7858 if (item != null)
7859 {
7860 if (magic && item.getItem().getDefaultAction() == ActionType.spiritshot)
7861 {
7862 IItemHandler handler = ItemHandler.getInstance().getHandler(item.getEtcItem());
7863 if (handler != null)
7864 handler.useItem(this, item, false);
7865 }
7866
7867 if (physical && item.getItem().getDefaultAction() == ActionType.soulshot)
7868 {
7869 IItemHandler handler = ItemHandler.getInstance().getHandler(item.getEtcItem());
7870 if (handler != null)
7871 handler.useItem(this, item, false);
7872 }
7873 }
7874 else
7875 removeAutoSoulShot(itemId);
7876 }
7877 }
7878
7879 /**
7880 * Cancel autoshot use for shot itemId
7881 * @param itemId int id to disable
7882 * @return true if canceled.
7883 */
7884 public boolean disableAutoShot(int itemId)
7885 {
7886 if (_activeSoulShots.contains(itemId))
7887 {
7888 removeAutoSoulShot(itemId);
7889 sendPacket(new ExAutoSoulShot(itemId, 0));
7890 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.AUTO_USE_OF_S1_CANCELLED).addItemName(itemId));
7891 return true;
7892 }
7893
7894 return false;
7895 }
7896
7897 /**
7898 * Cancel all autoshots for player
7899 */
7900 public void disableAutoShotsAll()
7901 {
7902 for (int itemId : _activeSoulShots)
7903 {
7904 sendPacket(new ExAutoSoulShot(itemId, 0));
7905 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.AUTO_USE_OF_S1_CANCELLED).addItemName(itemId));
7906 }
7907 _activeSoulShots.clear();
7908 }
7909
7910 class LookingForFishTask implements Runnable
7911 {
7912 boolean _isNoob, _isUpperGrade;
7913 int _fishType, _fishGutsCheck;
7914 long _endTaskTime;
7915
7916 protected LookingForFishTask(int fishWaitTime, int fishGutsCheck, int fishType, boolean isNoob, boolean isUpperGrade)
7917 {
7918 _fishGutsCheck = fishGutsCheck;
7919 _endTaskTime = System.currentTimeMillis() + fishWaitTime + 10000;
7920 _fishType = fishType;
7921 _isNoob = isNoob;
7922 _isUpperGrade = isUpperGrade;
7923 }
7924
7925 @Override
7926 public void run()
7927 {
7928 if (System.currentTimeMillis() >= _endTaskTime)
7929 {
7930 endFishing(false);
7931 return;
7932 }
7933
7934 if (_fishType == -1)
7935 return;
7936
7937 int check = Rnd.get(1000);
7938 if (_fishGutsCheck > check)
7939 {
7940 stopLookingForFishTask();
7941 startFishCombat(_isNoob, _isUpperGrade);
7942 }
7943 }
7944 }
7945
7946 public int getClanPrivileges()
7947 {
7948 return _clanPrivileges;
7949 }
7950
7951 public void setClanPrivileges(int n)
7952 {
7953 _clanPrivileges = n;
7954 }
7955
7956 public int getPledgeClass()
7957 {
7958 return _pledgeClass;
7959 }
7960
7961 public void setPledgeClass(int classId)
7962 {
7963 _pledgeClass = classId;
7964 }
7965
7966 public int getPledgeType()
7967 {
7968 return _pledgeType;
7969 }
7970
7971 public void setPledgeType(int typeId)
7972 {
7973 _pledgeType = typeId;
7974 }
7975
7976 public int getApprentice()
7977 {
7978 return _apprentice;
7979 }
7980
7981 public void setApprentice(int id)
7982 {
7983 _apprentice = id;
7984 }
7985
7986 public int getSponsor()
7987 {
7988 return _sponsor;
7989 }
7990
7991 public void setSponsor(int id)
7992 {
7993 _sponsor = id;
7994 }
7995
7996 @Override
7997 public void sendMessage(String message)
7998 {
7999 sendPacket(SystemMessage.sendString(message));
8000 }
8001
8002 /**
8003 * Unsummon all types of summons : pets, cubics, normal summons and trained beasts.
8004 */
8005 public void dropAllSummons()
8006 {
8007 // Delete summons and pets
8008 if (getPet() != null)
8009 getPet().unSummon(this);
8010
8011 // Delete trained beasts
8012 if (getTrainedBeast() != null)
8013 getTrainedBeast().deleteMe();
8014
8015 // Delete any form of cubics
8016 stopCubics();
8017 }
8018
8019 public void enterObserverMode(int x, int y, int z)
8020 {
8021 dropAllSummons();
8022
8023 if (getParty() != null)
8024 getParty().removePartyMember(this, MessageType.EXPELLED);
8025
8026 standUp();
8027
8028 _savedLocation.set(getPosition());
8029
8030 setTarget(null);
8031 setIsInvul(true);
8032 getAppearance().setInvisible();
8033 setIsParalyzed(true);
8034 startParalyze();
8035
8036 teleToLocation(x, y, z, 0, 0);
8037 sendPacket(new ObservationMode(x, y, z));
8038 }
8039
8040 public void enterOlympiadObserverMode(int id)
8041 {
8042 final OlympiadGameTask task = OlympiadGameManager.getInstance().getOlympiadTask(id);
8043 final Location loc = task.getZone().getSpawns().get(2);
8044 if (task == null)
8045 return;
8046
8047 dropAllSummons();
8048
8049 if (getParty() != null)
8050 getParty().removePartyMember(this, MessageType.EXPELLED);
8051
8052 _olympiadGameId = id;
8053
8054 standUp();
8055
8056 // Don't override saved location if we jump from stadium to stadium.
8057 if (!isInObserverMode())
8058 _savedLocation.set(getPosition());
8059
8060 setTarget(null);
8061 setIsInvul(true);
8062 getAppearance().setInvisible();
8063 loc.setInstanceId(OlympiadGameManager.getInstance().getOlympiadTask(id).getZone().getInstanceId());
8064 teleToLocation(loc, 0);
8065 sendPacket(new ExOlympiadMode(3));
8066 }
8067
8068 public long getOfflineStartTime()
8069 {
8070 return _offlineShopStart;
8071 }
8072
8073 public void setOfflineStartTime(long time)
8074 {
8075 _offlineShopStart = time;
8076 }
8077
8078 public void leaveObserverMode()
8079 {
8080 if (hasAI())
8081 getAI().setIntention(CtrlIntention.IDLE);
8082
8083 setTarget(null);
8084 getAppearance().setVisible();
8085 setIsInvul(false);
8086 setIsParalyzed(false);
8087 stopParalyze(false);
8088
8089 sendPacket(new ObservationReturn(_savedLocation));
8090 teleToLocation(_savedLocation, 0);
8091
8092 // Clear the location.
8093 _savedLocation.clean();
8094 }
8095
8096 public void leaveOlympiadObserverMode()
8097 {
8098 if (_olympiadGameId == -1)
8099 return;
8100
8101 _olympiadGameId = -1;
8102
8103 if (hasAI())
8104 getAI().setIntention(CtrlIntention.IDLE);
8105
8106 setTarget(null);
8107 if (!isGM())
8108 getAppearance().setVisible();
8109 setIsInvul(false);
8110
8111 sendPacket(new ExOlympiadMode(0));
8112 teleToLocation(_savedLocation, 0);
8113
8114 // Clear the location.
8115 _savedLocation.clean();
8116 }
8117
8118 public int getOlympiadSide()
8119 {
8120 return _olympiadSide;
8121 }
8122
8123 public void setOlympiadSide(int i)
8124 {
8125 _olympiadSide = i;
8126 }
8127
8128 public int getOlympiadGameId()
8129 {
8130 return _olympiadGameId;
8131 }
8132
8133 public void setOlympiadGameId(int id)
8134 {
8135 _olympiadGameId = id;
8136 }
8137
8138 public Location getSavedLocation()
8139 {
8140 return _savedLocation;
8141 }
8142
8143 public boolean isInObserverMode()
8144 {
8145 return !_isInOlympiadMode && !_savedLocation.equals(Location.DUMMY_LOC);
8146 }
8147
8148 public int getTeleMode()
8149 {
8150 return _teleMode;
8151 }
8152
8153 public void setTeleMode(int mode)
8154 {
8155 _teleMode = mode;
8156 }
8157
8158 public int getLoto(int i)
8159 {
8160 return _loto[i];
8161 }
8162
8163 public void setLoto(int i, int val)
8164 {
8165 _loto[i] = val;
8166 }
8167
8168 public int getRace(int i)
8169 {
8170 return _race[i];
8171 }
8172
8173 public void setRace(int i, int val)
8174 {
8175 _race[i] = val;
8176 }
8177
8178 public boolean isInRefusalMode()
8179 {
8180 return _messageRefusal;
8181 }
8182
8183 public void setInRefusalMode(boolean mode)
8184 {
8185 _messageRefusal = mode;
8186 sendPacket(new EtcStatusUpdate(this));
8187 }
8188
8189 public void setTradeRefusal(boolean mode)
8190 {
8191 _tradeRefusal = mode;
8192 }
8193
8194 public boolean getTradeRefusal()
8195 {
8196 return _tradeRefusal;
8197 }
8198
8199 public void setExchangeRefusal(boolean mode)
8200 {
8201 _exchangeRefusal = mode;
8202 }
8203
8204 public boolean getExchangeRefusal()
8205 {
8206 return _exchangeRefusal;
8207 }
8208
8209 public BlockList getBlockList()
8210 {
8211 return _blockList;
8212 }
8213
8214 public boolean isHero()
8215 {
8216 return _isHero;
8217 }
8218
8219 public void setHero(boolean hero)
8220 {
8221 if (hero && _baseClass == _activeClass)
8222 {
8223 for (L2Skill skill : SkillTable.getHeroSkills())
8224 addSkill(skill, false);
8225 }
8226 else
8227 {
8228 for (L2Skill skill : SkillTable.getHeroSkills())
8229 removeSkill(skill.getId(), false);
8230 }
8231 _isHero = hero;
8232
8233 sendSkillList();
8234 }
8235
8236 public boolean isOlympiadStart()
8237 {
8238 return _isInOlympiadStart;
8239 }
8240
8241 public void setOlympiadStart(boolean b)
8242 {
8243 _isInOlympiadStart = b;
8244 }
8245
8246 public boolean isInOlympiadMode()
8247 {
8248 return _isInOlympiadMode;
8249 }
8250
8251 public void setOlympiadMode(boolean b)
8252 {
8253 _isInOlympiadMode = b;
8254 }
8255
8256 public boolean isInDuel()
8257 {
8258 return _duelId > 0;
8259 }
8260
8261 public int getDuelId()
8262 {
8263 return _duelId;
8264 }
8265
8266 public void setDuelState(DuelState state)
8267 {
8268 _duelState = state;
8269 }
8270
8271 public DuelState getDuelState()
8272 {
8273 return _duelState;
8274 }
8275
8276 /**
8277 * Sets up the duel state using a non 0 duelId.
8278 * @param duelId 0=not in a duel
8279 */
8280 public void setInDuel(int duelId)
8281 {
8282 if (duelId > 0)
8283 {
8284 _duelState = DuelState.ON_COUNTDOWN;
8285 _duelId = duelId;
8286 }
8287 else
8288 {
8289 if (_duelState == DuelState.DEAD)
8290 {
8291 enableAllSkills();
8292 getStatus().startHpMpRegeneration();
8293 }
8294 _duelState = DuelState.NO_DUEL;
8295 _duelId = 0;
8296 }
8297 }
8298
8299 /**
8300 * This returns a SystemMessage stating why the player is not available for duelling.
8301 * @return S1_CANNOT_DUEL... message
8302 */
8303 public SystemMessage getNoDuelReason()
8304 {
8305 // Prepare the message with the good reason.
8306 final SystemMessage sm = SystemMessage.getSystemMessage(_noDuelReason).addCharName(this);
8307
8308 // Reinitialize the reason.
8309 _noDuelReason = SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL;
8310
8311 // Send stored reason.
8312 return sm;
8313 }
8314
8315 /**
8316 * Checks if this player might join / start a duel. To get the reason use getNoDuelReason() after calling this function.
8317 * @return true if the player might join/start a duel.
8318 */
8319 public boolean canDuel()
8320 {
8321 if (isInCombat() || getPunishLevel() == PunishLevel.JAIL)
8322 _noDuelReason = SystemMessageId.S1_CANNOT_DUEL_BECAUSE_S1_IS_CURRENTLY_ENGAGED_IN_BATTLE;
8323 else if (isDead() || isAlikeDead() || (getCurrentHp() < getMaxHp() / 2 || getCurrentMp() < getMaxMp() / 2))
8324 _noDuelReason = SystemMessageId.S1_CANNOT_DUEL_BECAUSE_S1_HP_OR_MP_IS_BELOW_50_PERCENT;
8325 else if (isInDuel())
8326 _noDuelReason = SystemMessageId.S1_CANNOT_DUEL_BECAUSE_S1_IS_ALREADY_ENGAGED_IN_A_DUEL;
8327 else if (isInOlympiadMode())
8328 _noDuelReason = SystemMessageId.S1_CANNOT_DUEL_BECAUSE_S1_IS_PARTICIPATING_IN_THE_OLYMPIAD;
8329 else if (isCursedWeaponEquipped() || getKarma() != 0)
8330 _noDuelReason = SystemMessageId.S1_CANNOT_DUEL_BECAUSE_S1_IS_IN_A_CHAOTIC_STATE;
8331 else if (isInStoreMode())
8332 _noDuelReason = SystemMessageId.S1_CANNOT_DUEL_BECAUSE_S1_IS_CURRENTLY_ENGAGED_IN_A_PRIVATE_STORE_OR_MANUFACTURE;
8333 else if (isMounted() || isInBoat())
8334 _noDuelReason = SystemMessageId.S1_CANNOT_DUEL_BECAUSE_S1_IS_CURRENTLY_RIDING_A_BOAT_WYVERN_OR_STRIDER;
8335 else if (isFishing())
8336 _noDuelReason = SystemMessageId.S1_CANNOT_DUEL_BECAUSE_S1_IS_CURRENTLY_FISHING;
8337 else if (isInsideZone(ZoneId.PVP) || isInsideZone(ZoneId.PEACE) || isInsideZone(ZoneId.SIEGE))
8338 _noDuelReason = SystemMessageId.S1_CANNOT_MAKE_A_CHALLANGE_TO_A_DUEL_BECAUSE_S1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA;
8339 else
8340 return true;
8341
8342 return false;
8343 }
8344
8345 public boolean isNoble()
8346 {
8347 return _isNoble;
8348 }
8349
8350 /**
8351 * Set Noblesse Status, and reward with nobles' skills.
8352 * @param val Add skills if setted to true, else remove skills.
8353 * @param store Store the status directly in the db if setted to true.
8354 */
8355 public void setNoble(boolean val, boolean store)
8356 {
8357 if (val)
8358 for (L2Skill skill : SkillTable.getNobleSkills())
8359 addSkill(skill, false);
8360 else
8361 for (L2Skill skill : SkillTable.getNobleSkills())
8362 removeSkill(skill.getId(), false);
8363
8364 _isNoble = val;
8365
8366 sendSkillList();
8367
8368 if (store)
8369 {
8370 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
8371 {
8372 PreparedStatement statement = con.prepareStatement(UPDATE_NOBLESS);
8373 statement.setBoolean(1, val);
8374 statement.setInt(2, getObjectId());
8375 statement.executeUpdate();
8376 statement.close();
8377 }
8378 catch (Exception e)
8379 {
8380 _log.log(Level.WARNING, "Could not update " + getName() + " nobless status: " + e.getMessage(), e);
8381 }
8382 }
8383 }
8384
8385 public void setLvlJoinedAcademy(int lvl)
8386 {
8387 _lvlJoinedAcademy = lvl;
8388 }
8389
8390 public int getLvlJoinedAcademy()
8391 {
8392 return _lvlJoinedAcademy;
8393 }
8394
8395 public boolean isAcademyMember()
8396 {
8397 return _lvlJoinedAcademy > 0;
8398 }
8399
8400 public void setTeam(int team)
8401 {
8402 _team = team;
8403 }
8404
8405 public int getTeam()
8406 {
8407 return _team;
8408 }
8409
8410 public void setWantsPeace(boolean wantsPeace)
8411 {
8412 _wantsPeace = wantsPeace;
8413 }
8414
8415 public boolean wantsPeace()
8416 {
8417 return _wantsPeace;
8418 }
8419
8420 public boolean isFishing()
8421 {
8422 return _fishingLoc != null;
8423 }
8424
8425 public void setAllianceWithVarkaKetra(int sideAndLvlOfAlliance)
8426 {
8427 _alliedVarkaKetra = sideAndLvlOfAlliance;
8428 }
8429
8430 /**
8431 * [-5,-1] varka, 0 neutral, [1,5] ketra
8432 * @return the side faction.
8433 */
8434 public int getAllianceWithVarkaKetra()
8435 {
8436 return _alliedVarkaKetra;
8437 }
8438
8439 public boolean isAlliedWithVarka()
8440 {
8441 return _alliedVarkaKetra < 0;
8442 }
8443
8444 public boolean isAlliedWithKetra()
8445 {
8446 return _alliedVarkaKetra > 0;
8447 }
8448
8449 public void sendSkillList()
8450 {
8451 final ItemInstance formal = getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST);
8452 final boolean isWearingFormalWear = formal != null && formal.getItem().getBodyPart() == Item.SLOT_ALLDRESS;
8453 final SkillList sl = new SkillList();
8454
8455 for (L2Skill s : getSkills().values())
8456 {
8457 if (isWearingFormalWear)
8458 sl.addSkill(s.getId(), s.getLevel(), s.isPassive(), true);
8459 else
8460 {
8461 boolean isDisabled = false;
8462 if (getClan() != null)
8463 isDisabled = s.isClanSkill() && getClan().getReputationScore() < 0;
8464
8465 if (isCursedWeaponEquipped()) // Only Demonic skills are available
8466 isDisabled = !s.isDemonicSkill();
8467 else if (isMounted()) // else if, because only ONE state is possible
8468 {
8469 if (getMountType() == 1) // Only Strider skills are available
8470 isDisabled = !s.isStriderSkill();
8471 else if (getMountType() == 2) // Only Wyvern skills are available
8472 isDisabled = !s.isFlyingSkill();
8473 }
8474 if (isAio() && !isGM() && !isInsideZone(ZoneId.TOWN))
8475 isDisabled = true;
8476 sl.addSkill(s.getId(), s.getLevel(), s.isPassive(), isDisabled);
8477 }
8478 }
8479 sendPacket(sl);
8480 }
8481
8482 /**
8483 * 1. Add the specified class ID as a subclass (up to the maximum number of <b>three</b>) for this character.<BR>
8484 * 2. This method no longer changes the active _classIndex of the player. This is only done by the calling of setActiveClass() method as that should be the only way to do so.
8485 * @param classId
8486 * @param classIndex
8487 * @return boolean subclassAdded
8488 */
8489 public boolean addSubClass(int classId, int classIndex)
8490 {
8491 if (!_subclassLock.tryLock())
8492 return false;
8493
8494 if (EventManager.getInstance().players.contains(this))
8495 return false;
8496
8497 try
8498 {
8499 if (_subClasses.size() == 3 || classIndex == 0 || _subClasses.containsKey(classIndex))
8500 return false;
8501
8502 final SubClass subclass = new SubClass(classId, classIndex);
8503
8504 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
8505 PreparedStatement ps = con.prepareStatement(ADD_CHAR_SUBCLASS))
8506 {
8507 ps.setInt(1, getObjectId());
8508 ps.setInt(2, subclass.getClassId());
8509 ps.setLong(3, subclass.getExp());
8510 ps.setInt(4, subclass.getSp());
8511 ps.setInt(5, subclass.getLevel());
8512 ps.setInt(6, subclass.getClassIndex());
8513 ps.execute();
8514 }
8515 catch (Exception e)
8516 {
8517 _log.log(Level.SEVERE, "Couldn't add subclass for " + getName(), e);
8518 return false;
8519 }
8520
8521 _subClasses.put(subclass.getClassIndex(), subclass);
8522
8523 PlayerData.getInstance().getTemplate(classId).getSkills().stream().filter(s -> s.getMinLvl() <= 40).collect(Collectors.groupingBy(s -> s.getId(), Collectors.maxBy(COMPARE_SKILLS_BY_LVL))).forEach((i, s) ->
8524 {
8525 storeSkill(s.get().getSkill(), classIndex);
8526 });
8527
8528 return true;
8529 }
8530 finally
8531 {
8532 _subclassLock.unlock();
8533 }
8534 }
8535
8536 /**
8537 * 1. Completely erase all existance of the subClass linked to the classIndex.<BR>
8538 * 2. Send over the newClassId to addSubClass()to create a new instance on this classIndex.<BR>
8539 * 3. Upon Exception, revert the player to their BaseClass to avoid further problems.<BR>
8540 * @param classIndex
8541 * @param newClassId
8542 * @return boolean subclassAdded
8543 */
8544 public boolean modifySubClass(int classIndex, int newClassId)
8545 {
8546 if (!_subclassLock.tryLock())
8547 return false;
8548
8549 if (EventManager.getInstance().players.contains(this))
8550 return false;
8551
8552 try
8553 {
8554 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
8555 {
8556 // Remove all henna info stored for this sub-class.
8557 PreparedStatement statement = con.prepareStatement(DELETE_CHAR_HENNAS);
8558 statement.setInt(1, getObjectId());
8559 statement.setInt(2, classIndex);
8560 statement.execute();
8561 statement.close();
8562
8563 // Remove all shortcuts info stored for this sub-class.
8564 statement = con.prepareStatement(DELETE_CHAR_SHORTCUTS);
8565 statement.setInt(1, getObjectId());
8566 statement.setInt(2, classIndex);
8567 statement.execute();
8568 statement.close();
8569
8570 // Remove all effects info stored for this sub-class.
8571 statement = con.prepareStatement(DELETE_SKILL_SAVE);
8572 statement.setInt(1, getObjectId());
8573 statement.setInt(2, classIndex);
8574 statement.execute();
8575 statement.close();
8576
8577 // Remove all skill info stored for this sub-class.
8578 statement = con.prepareStatement(DELETE_CHAR_SKILLS);
8579 statement.setInt(1, getObjectId());
8580 statement.setInt(2, classIndex);
8581 statement.execute();
8582 statement.close();
8583
8584 // Remove all basic info stored about this sub-class.
8585 statement = con.prepareStatement(DELETE_CHAR_SUBCLASS);
8586 statement.setInt(1, getObjectId());
8587 statement.setInt(2, classIndex);
8588 statement.execute();
8589 statement.close();
8590 }
8591 catch (Exception e)
8592 {
8593 _log.warning("Could not modify subclass for " + getName() + " to class index " + classIndex + ": " + e);
8594
8595 // This must be done in order to maintain data consistency.
8596 _subClasses.remove(classIndex);
8597 return false;
8598 }
8599
8600 _subClasses.remove(classIndex);
8601 }
8602 finally
8603 {
8604 _subclassLock.unlock();
8605 }
8606
8607 return addSubClass(newClassId, classIndex);
8608 }
8609
8610 public boolean isSubClassActive()
8611 {
8612 return _classIndex > 0;
8613 }
8614
8615 public Map<Integer, SubClass> getSubClasses()
8616 {
8617 return _subClasses;
8618 }
8619
8620 public int getBaseClass()
8621 {
8622 return _baseClass;
8623 }
8624
8625 public int getActiveClass()
8626 {
8627 return _activeClass;
8628 }
8629
8630 public int getClassIndex()
8631 {
8632 return _classIndex;
8633 }
8634
8635 private void setClassTemplate(int classId)
8636 {
8637 _activeClass = classId;
8638
8639 // Set the template of the Player
8640 setTemplate(PlayerData.getInstance().getTemplate(classId));
8641 }
8642
8643 /**
8644 * Changes the character's class based on the given class index. <BR>
8645 * <BR>
8646 * An index of zero specifies the character's original (base) class, while indexes 1-3 specifies the character's sub-classes respectively.
8647 * @param classIndex
8648 * @return true if successful.
8649 */
8650 public boolean setActiveClass(int classIndex)
8651 {
8652 if (!_subclassLock.tryLock())
8653 return false;
8654
8655 if (EventManager.getInstance().players.contains(this))
8656 return false;
8657
8658 try
8659 {
8660 // Remove active item skills before saving char to database because next time when choosing this class, worn items can be different
8661 for (ItemInstance item : getInventory().getAugmentedItems())
8662 {
8663 if (item != null && item.isEquipped())
8664 item.getAugmentation().removeBonus(this);
8665 }
8666
8667 // abort any kind of cast.
8668 abortCast();
8669
8670 // Stop casting for any player that may be casting a force buff on this l2pcinstance.
8671 for (Creature character : getKnownType(Creature.class))
8672 if (character.getFusionSkill() != null && character.getFusionSkill().getTarget() == this)
8673 character.abortCast();
8674
8675 store();
8676 _reuseTimeStamps.clear();
8677
8678 // clear charges
8679 _charges.set(0);
8680 stopChargeTask();
8681
8682 if (classIndex == 0)
8683 setClassTemplate(getBaseClass());
8684 else
8685 {
8686 try
8687 {
8688 setClassTemplate(_subClasses.get(classIndex).getClassId());
8689 }
8690 catch (Exception e)
8691 {
8692 _log.info("Could not switch " + getName() + "'s sub class to class index " + classIndex + ": " + e);
8693 return false;
8694 }
8695 }
8696 _classIndex = classIndex;
8697
8698 if (_party != null)
8699 _party.recalculateLevel();
8700
8701 if (getPet() instanceof Servitor)
8702 getPet().unSummon(this);
8703
8704 for (L2Skill skill : getSkills().values())
8705 removeSkill(skill.getId(), false);
8706
8707 stopAllEffectsExceptThoseThatLastThroughDeath();
8708 stopCubics();
8709
8710 if (isSubClassActive())
8711 {
8712 _dwarvenRecipeBook.clear();
8713 _commonRecipeBook.clear();
8714 }
8715 else
8716 restoreRecipeBook();
8717
8718 restoreSkills();
8719 giveSkills();
8720 regiveTemporarySkills();
8721
8722 // Prevents some issues when changing between subclases that shares skills
8723 getDisabledSkills().clear();
8724
8725 restoreEffects();
8726 updateEffectIcons();
8727 sendPacket(new EtcStatusUpdate(this));
8728
8729 // If player has quest "Repent Your Sins", remove it
8730 QuestState st = getQuestState("Q422_RepentYourSins");
8731 if (st != null)
8732 st.exitQuest(true);
8733
8734 for (int i = 0; i < 3; i++)
8735 _henna[i] = null;
8736
8737 restoreHenna();
8738 sendPacket(new HennaInfo(this));
8739
8740 if (getCurrentHp() > getMaxHp())
8741 setCurrentHp(getMaxHp());
8742 if (getCurrentMp() > getMaxMp())
8743 setCurrentMp(getMaxMp());
8744 if (getCurrentCp() > getMaxCp())
8745 setCurrentCp(getMaxCp());
8746
8747 refreshOverloaded();
8748 refreshExpertisePenalty();
8749 broadcastUserInfo();
8750
8751 // Clear resurrect xp calculation
8752 setExpBeforeDeath(0);
8753
8754 // Remove shot automation
8755 disableAutoShotsAll();
8756
8757 // Discharge any active shots
8758 ItemInstance item = getActiveWeaponInstance();
8759 if (item != null)
8760 item.unChargeAllShots();
8761
8762 _shortCuts.restore();
8763 sendPacket(new ShortCutInit(this));
8764
8765 broadcastPacket(new SocialAction(this, 15));
8766 sendPacket(new SkillCoolTime(this));
8767 return true;
8768 }
8769 finally
8770 {
8771 _subclassLock.unlock();
8772 }
8773 }
8774
8775 public boolean isLocked()
8776 {
8777 return _subclassLock.isLocked();
8778 }
8779
8780 public void onPlayerEnter()
8781 {
8782 if (isCursedWeaponEquipped())
8783 CursedWeaponManager.getInstance().getCursedWeapon(getCursedWeaponEquippedId()).cursedOnLogin();
8784
8785 if (isAio())
8786 AioTaskManager.getInstance().add(this);
8787
8788 // Add to the GameTimeTask to keep inform about activity time.
8789 GameTimeTaskManager.getInstance().add(this);
8790 if (isVipStatus())
8791 VipTimeTaskManager.getInstance().add(this);
8792
8793 // Teleport player if the Seven Signs period isn't the good one, or if the player isn't in a cabal.
8794 if (isIn7sDungeon() && !isGM())
8795 {
8796 if (SevenSigns.getInstance().isSealValidationPeriod() || SevenSigns.getInstance().isCompResultsPeriod())
8797 {
8798 if (SevenSigns.getInstance().getPlayerCabal(getObjectId()) != SevenSigns.getInstance().getCabalHighestScore())
8799 {
8800 teleToLocation(TeleportType.TOWN);
8801 setIsIn7sDungeon(false);
8802 }
8803 }
8804 else if (SevenSigns.getInstance().getPlayerCabal(getObjectId()) == CabalType.NORMAL)
8805 {
8806 teleToLocation(TeleportType.TOWN);
8807 setIsIn7sDungeon(false);
8808 }
8809 }
8810
8811 // Jail task
8812 updatePunishState();
8813
8814 if (isGM())
8815 {
8816 if (isInvul())
8817 sendMessage("Entering world in Invulnerable mode.");
8818 if (getAppearance().getInvisible())
8819 sendMessage("Entering world in Invisible mode.");
8820 if (isInRefusalMode())
8821 sendMessage("Entering world in Message Refusal mode.");
8822 }
8823
8824 revalidateZone(true);
8825 notifyFriends(true);
8826 }
8827
8828 public long getLastAccess()
8829 {
8830 return _lastAccess;
8831 }
8832
8833 public long getLastHopVote()
8834 {
8835 return _lastHopVote;
8836 }
8837
8838 public long getLastTopVote()
8839 {
8840 return _lastTopVote;
8841 }
8842
8843 public long getLastNetVote()
8844 {
8845 return _lastNetVote;
8846 }
8847
8848 public void setLastHopVote(long val)
8849 {
8850 _lastHopVote = val;
8851 }
8852
8853 public void setLastTopVote(long val)
8854 {
8855 _lastTopVote = val;
8856 }
8857
8858 public void setLastNetVote(long val)
8859 {
8860 _lastNetVote = val;
8861 }
8862
8863 @Override
8864 public void doRevive()
8865 {
8866 super.doRevive();
8867
8868 stopEffects(L2EffectType.CHARMOFCOURAGE);
8869 sendPacket(new EtcStatusUpdate(this));
8870
8871 _reviveRequested = 0;
8872 _revivePower = 0;
8873
8874 if (isMounted())
8875 startFeed(_mountNpcId);
8876
8877 if (getInstanceId() > 0)
8878 {
8879 final Instance instance = InstanceManager.getInstance().getInstance(getInstanceId());
8880 if (instance != null)
8881 instance.cancelEjectDeadPlayer(this);
8882 }
8883
8884
8885 // Schedule a paralyzed task to wait for the animation to finish
8886 ThreadPool.schedule(() -> setIsParalyzed(false), (int) (2000 / getStat().getMovementSpeedMultiplier()));
8887 setIsParalyzed(true);
8888 }
8889
8890 @Override
8891 public void doRevive(double revivePower)
8892 {
8893 // Restore the player's lost experience, depending on the % return of the skill used (based on its power).
8894 restoreExp(revivePower);
8895 doRevive();
8896 }
8897
8898 public void reviveRequest(Player Reviver, L2Skill skill, boolean Pet)
8899 {
8900 if (_reviveRequested == 1)
8901 {
8902 // Resurrection has already been proposed.
8903 if (_revivePet == Pet)
8904 Reviver.sendPacket(SystemMessageId.RES_HAS_ALREADY_BEEN_PROPOSED);
8905 else
8906 {
8907 if (Pet)
8908 // A pet cannot be resurrected while it's owner is in the process of resurrecting.
8909 Reviver.sendPacket(SystemMessageId.CANNOT_RES_PET2);
8910 else
8911 // While a pet is attempting to resurrect, it cannot help in resurrecting its master.
8912 Reviver.sendPacket(SystemMessageId.MASTER_CANNOT_RES);
8913 }
8914 return;
8915 }
8916
8917 if ((Pet && getPet() != null && getPet().isDead()) || (!Pet && isDead()))
8918 {
8919 _reviveRequested = 1;
8920
8921 if (isPhoenixBlessed())
8922 _revivePower = 100;
8923 else if (isAffected(L2EffectFlag.CHARM_OF_COURAGE))
8924 _revivePower = 0;
8925 else
8926 _revivePower = Formulas.calculateSkillResurrectRestorePercent(skill.getPower(), Reviver);
8927
8928 _revivePet = Pet;
8929
8930 if (isAffected(L2EffectFlag.CHARM_OF_COURAGE))
8931 {
8932 sendPacket(new ConfirmDlg(SystemMessageId.DO_YOU_WANT_TO_BE_RESTORED).addTime(60000));
8933 return;
8934 }
8935
8936 sendPacket(new ConfirmDlg(SystemMessageId.RESSURECTION_REQUEST_BY_S1).addCharName(Reviver));
8937 }
8938 }
8939
8940 public void reviveAnswer(int answer)
8941 {
8942 if (_reviveRequested != 1 || (!isDead() && !_revivePet) || (_revivePet && getPet() != null && !getPet().isDead()))
8943 return;
8944
8945 if (answer == 0 && isPhoenixBlessed())
8946 stopPhoenixBlessing(null);
8947 else if (answer == 1)
8948 {
8949 if (!_revivePet)
8950 {
8951 if (_revivePower != 0)
8952 doRevive(_revivePower);
8953 else
8954 doRevive();
8955 }
8956 else if (getPet() != null)
8957 {
8958 if (_revivePower != 0)
8959 getPet().doRevive(_revivePower);
8960 else
8961 getPet().doRevive();
8962 }
8963 }
8964 _reviveRequested = 0;
8965 _revivePower = 0;
8966 }
8967
8968 public boolean isReviveRequested()
8969 {
8970 return (_reviveRequested == 1);
8971 }
8972
8973 public boolean isRevivingPet()
8974 {
8975 return _revivePet;
8976 }
8977
8978 public void removeReviving()
8979 {
8980 _reviveRequested = 0;
8981 _revivePower = 0;
8982 }
8983
8984 public void onActionRequest()
8985 {
8986 if (isSpawnProtected())
8987 {
8988 sendMessage("As you acted, you are no longer under spawn protection.");
8989 setSpawnProtection(false);
8990 }
8991 }
8992
8993 @Override
8994 public final void onTeleported()
8995 {
8996 super.onTeleported();
8997
8998 // Force a revalidation
8999 revalidateZone(true);
9000
9001 if (!(!this.isAio() || this.isGM() || this.isInsideZone(ZoneId.TOWN)
9002 || EventManager.getInstance().isRegistered(this))) {
9003 sendPacket(new CreatureSay(0, Say2.SHOUT, "System",
9004 "You can only teleport to another town while being an AIO!"));
9005 teleToLocation(MapRegionData.TeleportType.TOWN);
9006 }
9007
9008 if (Config.PLAYER_SPAWN_PROTECTION > 0)
9009 {
9010 sendMessage("You have " + Config.PLAYER_SPAWN_PROTECTION + " sec's spawn protection.");
9011 setSpawnProtection(true);
9012 }
9013 // Stop toggles upon teleport.
9014 if (!isGM())
9015 stopAllToggles();
9016
9017 // Modify the position of the tamed beast if necessary
9018 if (getTrainedBeast() != null)
9019 {
9020 getTrainedBeast().getAI().stopFollow();
9021 getTrainedBeast().teleToLocation(getPosition().getX(), getPosition().getY(), getPosition().getZ(), getTrainedBeast().getInstanceId(), 0);
9022 getTrainedBeast().getAI().startFollow(this);
9023 }
9024
9025 // Modify the position of the pet if necessary
9026 Summon pet = getPet();
9027 if (pet != null)
9028 {
9029 pet.setFollowStatus(false);
9030 pet.teleToLocation(getPosition().getX(), getPosition().getY(), getPosition().getZ(), getInstanceId(), 0);
9031 ((SummonAI) pet.getAI()).setStartFollowController(true);
9032 pet.setFollowStatus(true);
9033 }
9034 }
9035
9036 @Override
9037 public void addExpAndSp(long addToExp, int addToSp)
9038 {
9039 getStat().addExpAndSp(addToExp, addToSp);
9040 }
9041
9042 public void addExpAndSp(long addToExp, int addToSp, Map<Creature, RewardInfo> rewards)
9043 {
9044 getStat().addExpAndSp(addToExp, addToSp, rewards);
9045 }
9046
9047 public void removeExpAndSp(long removeExp, int removeSp)
9048 {
9049 getStat().removeExpAndSp(removeExp, removeSp);
9050 }
9051
9052 @Override
9053 public void reduceCurrentHp(double value, Creature attacker, boolean awake, boolean isDOT, L2Skill skill)
9054 {
9055 if (skill != null)
9056 getStatus().reduceHp(value, attacker, awake, isDOT, skill.isToggle(), skill.getDmgDirectlyToHP());
9057 else
9058 getStatus().reduceHp(value, attacker, awake, isDOT, false, false);
9059
9060 // notify the tamed beast of attacks
9061 if (getTrainedBeast() != null)
9062 getTrainedBeast().onOwnerGotAttacked(attacker);
9063 }
9064
9065 public synchronized void addBypass(String bypass)
9066 {
9067 if (bypass == null)
9068 return;
9069
9070 _validBypass.add(bypass);
9071 }
9072
9073 public synchronized void addBypass2(String bypass)
9074 {
9075 if (bypass == null)
9076 return;
9077
9078 _validBypass2.add(bypass);
9079 }
9080
9081 public synchronized boolean validateBypass(String cmd)
9082 {
9083 for (String bp : _validBypass)
9084 {
9085 if (bp == null)
9086 continue;
9087
9088 if (bp.equals(cmd))
9089 return true;
9090 }
9091
9092 for (String bp : _validBypass2)
9093 {
9094 if (bp == null)
9095 continue;
9096
9097 if (cmd.startsWith(bp))
9098 return true;
9099 }
9100
9101 return false;
9102 }
9103
9104 /**
9105 * Test cases (player drop, trade item) where the item shouldn't be able to manipulate.
9106 * @param objectId : The item objectId.
9107 * @return true if it the item can be manipulated, false ovtherwise.
9108 */
9109 public ItemInstance validateItemManipulation(int objectId)
9110 {
9111 final ItemInstance item = getInventory().getItemByObjectId(objectId);
9112
9113 // You don't own the item, or item is null.
9114 if (item == null || item.getOwnerId() != getObjectId())
9115 return null;
9116
9117 // Pet whom item you try to manipulate is summoned/mounted.
9118 if (getPet() != null && getPet().getControlItemId() == objectId || _mountObjectId == objectId)
9119 return null;
9120
9121 // Item is under enchant process.
9122 if (getActiveEnchantItem() != null && getActiveEnchantItem().getObjectId() == objectId)
9123 return null;
9124
9125 // Can't trade a cursed weapon.
9126 if (CursedWeaponManager.getInstance().isCursed(item.getItemId()))
9127 return null;
9128
9129 return item;
9130 }
9131
9132 public synchronized void clearBypass()
9133 {
9134 _validBypass.clear();
9135 _validBypass2.clear();
9136 }
9137
9138 /**
9139 * @return Returns the inBoat.
9140 */
9141 public boolean isInBoat()
9142 {
9143 return _boat != null;
9144 }
9145
9146 public Boat getBoat()
9147 {
9148 return _boat;
9149 }
9150
9151 public void setBoat(Boat v)
9152 {
9153 if (v == null && _boat != null)
9154 _boat.removePassenger(this);
9155
9156 _boat = v;
9157 }
9158
9159 public void setCrystallizing(boolean mode)
9160 {
9161 _isCrystallizing = mode;
9162 }
9163
9164 public boolean isCrystallizing()
9165 {
9166 return _isCrystallizing;
9167 }
9168
9169 public SpawnLocation getBoatPosition()
9170 {
9171 return _boatPosition;
9172 }
9173
9174 /**
9175 * Manage the delete task of a Player (Leave Party, Unsummon pet, Save its inventory in the database, Remove it from the world...).
9176 * <ul>
9177 * <li>If the Player is in observer mode, set its position to its position before entering in observer mode</li>
9178 * <li>Set the online Flag to True or False and update the characters table of the database with online status and lastAccess</li>
9179 * <li>Stop the HP/MP/CP Regeneration task</li>
9180 * <li>Cancel Crafting, Attak or Cast</li>
9181 * <li>Remove the Player from the world</li>
9182 * <li>Stop Party and Unsummon Pet</li>
9183 * <li>Update database with items in its inventory and remove them from the world</li>
9184 * <li>Remove the object from region</li>
9185 * <li>Close the connection with the client</li>
9186 * </ul>
9187 */
9188 @Override
9189 public void deleteMe()
9190 {
9191 EventManager.getInstance().onLogout(this);
9192 if (EventManager.getInstance().isRegistered(this))
9193 EventManager.getInstance().getCurrentEvent().onLogout(this);
9194
9195 cleanup();
9196 store();
9197 super.deleteMe();
9198 }
9199
9200 private synchronized void cleanup()
9201 {
9202 try
9203 {
9204 // Put the online status to false
9205 setOnlineStatus(false, true);
9206
9207 // abort cast & attack and remove the target. Cancels movement aswell.
9208 abortAttack();
9209 abortCast();
9210 stopMove(null);
9211 setTarget(null);
9212
9213 removeMeFromPartyMatch();
9214
9215 if (isFlying())
9216 removeSkill(FrequentSkill.WYVERN_BREATH.getSkill().getId(), false);
9217
9218 // Stop all scheduled tasks
9219 stopAllTimers();
9220
9221 // Cancel the cast of eventual fusion skill users on this target.
9222 for (Creature character : getKnownType(Creature.class))
9223 if (character.getFusionSkill() != null && character.getFusionSkill().getTarget() == this)
9224 character.abortCast();
9225
9226 // Stop signets & toggles effects.
9227 for (L2Effect effect : getAllEffects())
9228 {
9229 if (effect.getSkill().isToggle())
9230 {
9231 effect.exit();
9232 continue;
9233 }
9234
9235 switch (effect.getEffectType())
9236 {
9237 case SIGNET_GROUND:
9238 case SIGNET_EFFECT:
9239 effect.exit();
9240 break;
9241 default:
9242 break;
9243 }
9244 }
9245
9246 // Remove the Player from the world
9247 decayMe();
9248
9249 // If a party is in progress, leave it
9250 if (_party != null)
9251 {
9252 if (_party.isLeader(this) && _party.getMembersCount() >= 3)
9253 {
9254 Player member_1 = this.getParty().getMembers().get(1);
9255 if (member_1 != null)
9256 _party.changePartyLeader(member_1.getName());
9257 else
9258 {
9259 Player member_2 = this.getParty().getMembers().get(2);
9260 if (member_2 != null)
9261 _party.changePartyLeader(member_2.getName());
9262 }
9263 }
9264 _party.removePartyMember(this, MessageType.DISCONNECTED);
9265 }
9266 // If the Player has Pet, unsummon it
9267 if (getPet() != null)
9268 getPet().unSummon(this);
9269
9270 // Handle removal from olympiad game
9271 if (OlympiadManager.getInstance().isRegistered(this) || getOlympiadGameId() != -1)
9272 OlympiadManager.getInstance().removeDisconnectedCompetitor(this);
9273
9274 // set the status for pledge member list to OFFLINE
9275 if (getClan() != null)
9276 {
9277 ClanMember clanMember = getClan().getClanMember(getObjectId());
9278 if (clanMember != null)
9279 clanMember.setPlayerInstance(null);
9280 }
9281
9282 // deals with sudden exit in the middle of transaction
9283 if (getActiveRequester() != null)
9284 {
9285 setActiveRequester(null);
9286 cancelActiveTrade();
9287 }
9288
9289 // If the Player is a GM, remove it from the GM List
9290 if (isGM())
9291 AdminData.getInstance().deleteGm(this);
9292
9293 // remove player from instance and set spawn location if any
9294 final int instanceId = getInstanceId();
9295 if (instanceId > 0)
9296 {
9297 final Instance inst = InstanceManager.getInstance().getInstance(instanceId);
9298 if (inst != null)
9299 {
9300 inst.removePlayer(this);
9301 final Location spawn = inst.getSpawnLoc();
9302 if (spawn.getX() != 0 && spawn.getY() != 0 && spawn.getZ() != 0)
9303 {
9304 setXYZ(spawn.getX() + Rnd.get(-30, 30), spawn.getY() + Rnd.get(-30, 30), spawn.getZ());
9305
9306 if (getPet() != null) // dead pet
9307 getPet().teleToLocation(spawn.getX(), spawn.getY(), spawn.getZ(), 0, 0);
9308 }
9309 }
9310 }
9311
9312 // Check if the Player is in observer mode to set its position to its position before entering in observer mode
9313 if (isInObserverMode())
9314 setXYZInvisible(_savedLocation);
9315
9316 // Oust player from boat
9317 if (getBoat() != null)
9318 getBoat().oustPlayer(this, true, Location.DUMMY_LOC);
9319
9320 // Update inventory and remove them from the world
9321 getInventory().deleteMe();
9322
9323 // Update warehouse and remove them from the world
9324 clearWarehouse();
9325
9326 // Update freight and remove them from the world
9327 clearFreight();
9328 clearDepositedFreight();
9329
9330 if (isCursedWeaponEquipped())
9331 CursedWeaponManager.getInstance().getCursedWeapon(_cursedWeaponEquippedId).setPlayer(null);
9332
9333 if (getClanId() > 0)
9334 getClan().broadcastToOtherOnlineMembers(new PledgeShowMemberListUpdate(this), this);
9335
9336 if (isSeated())
9337 {
9338 final WorldObject object = World.getInstance().getObject(_throneId);
9339 if (object instanceof StaticObject)
9340 ((StaticObject) object).setBusy(false);
9341 }
9342
9343 if (getInstanceId() != 0 && !Config.RESTORE_PLAYER_INSTANCE)
9344 {
9345 final Instance inst = InstanceManager.getInstance().getInstance(getInstanceId());
9346 if (inst != null)
9347 {
9348 inst.removePlayer(this);
9349
9350 final Location loc = inst.getSpawnLoc();
9351 if (loc != null)
9352 {
9353 final int x = loc.getX() + Rnd.get(-30, 30);
9354 final int y = loc.getY() + Rnd.get(-30, 30);
9355
9356 setXYZInvisible(x, y, loc.getZ());
9357
9358 if (hasPet())
9359 {
9360 getPet().teleToLocation(loc, 50);
9361 getPet().setInstanceId(0);
9362 }
9363 }
9364 }
9365 }
9366
9367 World.getInstance().removePlayer(this); // force remove in case of crash during teleport
9368
9369 // friends & blocklist update
9370 notifyFriends(false);
9371 getBlockList().playerLogout();
9372 }
9373 catch (Exception e)
9374 {
9375 _log.log(Level.WARNING, "Exception on deleteMe()" + e.getMessage(), e);
9376 }
9377 }
9378
9379 public void startFishing(Location loc)
9380 {
9381 stopMove(null);
9382 setIsImmobilized(true);
9383
9384 _fishingLoc = loc;
9385
9386 // Starts fishing
9387 int group = getRandomGroup();
9388
9389 _fish = FishData.getInstance().getFish(getRandomFishLvl(), getRandomFishType(group), group);
9390 if (_fish == null)
9391 {
9392 endFishing(false);
9393 return;
9394 }
9395
9396 sendPacket(SystemMessageId.CAST_LINE_AND_START_FISHING);
9397
9398 broadcastPacket(new ExFishingStart(this, _fish.getType(_lure.isNightLure()), loc, _lure.isNightLure()));
9399 sendPacket(new PlaySound(1, "SF_P_01"));
9400 startLookingForFishTask();
9401 }
9402
9403 public void stopLookingForFishTask()
9404 {
9405 if (_fishingTask != null)
9406 {
9407 _fishingTask.cancel(false);
9408 _fishingTask = null;
9409 }
9410 }
9411
9412 public void startLookingForFishTask()
9413 {
9414 if (!isDead() && _fishingTask == null)
9415 {
9416 int checkDelay = 0;
9417 boolean isNoob = false;
9418 boolean isUpperGrade = false;
9419
9420 if (_lure != null)
9421 {
9422 int lureid = _lure.getItemId();
9423 isNoob = _fish.getGroup() == 0;
9424 isUpperGrade = _fish.getGroup() == 2;
9425 if (lureid == 6519 || lureid == 6522 || lureid == 6525 || lureid == 8505 || lureid == 8508 || lureid == 8511) // low grade
9426 checkDelay = Math.round((float) (_fish.getGutsCheckTime() * (1.33)));
9427 else if (lureid == 6520 || lureid == 6523 || lureid == 6526 || (lureid >= 8505 && lureid <= 8513) || (lureid >= 7610 && lureid <= 7613) || (lureid >= 7807 && lureid <= 7809) || (lureid >= 8484 && lureid <= 8486)) // medium grade, beginner, prize-winning & quest special bait
9428 checkDelay = Math.round((float) (_fish.getGutsCheckTime() * (1.00)));
9429 else if (lureid == 6521 || lureid == 6524 || lureid == 6527 || lureid == 8507 || lureid == 8510 || lureid == 8513) // high grade
9430 checkDelay = Math.round((float) (_fish.getGutsCheckTime() * (0.66)));
9431 }
9432 _fishingTask = ThreadPool.scheduleAtFixedRate(new LookingForFishTask(_fish.getWaitTime(), _fish.getGuts(), _fish.getType(_lure.isNightLure()), isNoob, isUpperGrade), 10000, checkDelay);
9433 }
9434 }
9435
9436 private int getRandomGroup()
9437 {
9438 switch (_lure.getItemId())
9439 {
9440 case 7807: // green for beginners
9441 case 7808: // purple for beginners
9442 case 7809: // yellow for beginners
9443 case 8486: // prize-winning for beginners
9444 return 0;
9445
9446 case 8485: // prize-winning luminous
9447 case 8506: // green luminous
9448 case 8509: // purple luminous
9449 case 8512: // yellow luminous
9450 return 2;
9451
9452 default:
9453 return 1;
9454 }
9455 }
9456
9457 private int getRandomFishType(int group)
9458 {
9459 int check = Rnd.get(100);
9460 int type = 1;
9461 switch (group)
9462 {
9463 case 0: // fish for novices
9464 switch (_lure.getItemId())
9465 {
9466 case 7807: // green lure, preferred by fast-moving (nimble) fish (type 5)
9467 if (check <= 54)
9468 type = 5;
9469 else if (check <= 77)
9470 type = 4;
9471 else
9472 type = 6;
9473 break;
9474
9475 case 7808: // purple lure, preferred by fat fish (type 4)
9476 if (check <= 54)
9477 type = 4;
9478 else if (check <= 77)
9479 type = 6;
9480 else
9481 type = 5;
9482 break;
9483
9484 case 7809: // yellow lure, preferred by ugly fish (type 6)
9485 if (check <= 54)
9486 type = 6;
9487 else if (check <= 77)
9488 type = 5;
9489 else
9490 type = 4;
9491 break;
9492
9493 case 8486: // prize-winning fishing lure for beginners
9494 if (check <= 33)
9495 type = 4;
9496 else if (check <= 66)
9497 type = 5;
9498 else
9499 type = 6;
9500 break;
9501 }
9502 break;
9503
9504 case 1: // normal fish
9505 switch (_lure.getItemId())
9506 {
9507 case 7610:
9508 case 7611:
9509 case 7612:
9510 case 7613:
9511 type = 3;
9512 break;
9513
9514 case 6519: // all theese lures (green) are prefered by fast-moving (nimble) fish (type 1)
9515 case 8505:
9516 case 6520:
9517 case 6521:
9518 case 8507:
9519 if (check <= 54)
9520 type = 1;
9521 else if (check <= 74)
9522 type = 0;
9523 else if (check <= 94)
9524 type = 2;
9525 else
9526 type = 3;
9527 break;
9528
9529 case 6522: // all theese lures (purple) are prefered by fat fish (type 0)
9530 case 8508:
9531 case 6523:
9532 case 6524:
9533 case 8510:
9534 if (check <= 54)
9535 type = 0;
9536 else if (check <= 74)
9537 type = 1;
9538 else if (check <= 94)
9539 type = 2;
9540 else
9541 type = 3;
9542 break;
9543
9544 case 6525: // all theese lures (yellow) are prefered by ugly fish (type 2)
9545 case 8511:
9546 case 6526:
9547 case 6527:
9548 case 8513:
9549 if (check <= 55)
9550 type = 2;
9551 else if (check <= 74)
9552 type = 1;
9553 else if (check <= 94)
9554 type = 0;
9555 else
9556 type = 3;
9557 break;
9558 case 8484: // prize-winning fishing lure
9559 if (check <= 33)
9560 type = 0;
9561 else if (check <= 66)
9562 type = 1;
9563 else
9564 type = 2;
9565 break;
9566 }
9567 break;
9568
9569 case 2: // upper grade fish, luminous lure
9570 switch (_lure.getItemId())
9571 {
9572 case 8506: // green lure, preferred by fast-moving (nimble) fish (type 8)
9573 if (check <= 54)
9574 type = 8;
9575 else if (check <= 77)
9576 type = 7;
9577 else
9578 type = 9;
9579 break;
9580
9581 case 8509: // purple lure, preferred by fat fish (type 7)
9582 if (check <= 54)
9583 type = 7;
9584 else if (check <= 77)
9585 type = 9;
9586 else
9587 type = 8;
9588 break;
9589
9590 case 8512: // yellow lure, preferred by ugly fish (type 9)
9591 if (check <= 54)
9592 type = 9;
9593 else if (check <= 77)
9594 type = 8;
9595 else
9596 type = 7;
9597 break;
9598
9599 case 8485: // prize-winning fishing lure
9600 if (check <= 33)
9601 type = 7;
9602 else if (check <= 66)
9603 type = 8;
9604 else
9605 type = 9;
9606 break;
9607 }
9608 }
9609 return type;
9610 }
9611
9612 private int getRandomFishLvl()
9613 {
9614 int skilllvl = getSkillLevel(1315);
9615
9616 final L2Effect e = getFirstEffect(2274);
9617 if (e != null)
9618 skilllvl = (int) e.getSkill().getPower();
9619
9620 if (skilllvl <= 0)
9621 return 1;
9622
9623 int randomlvl;
9624
9625 final int check = Rnd.get(100);
9626 if (check <= 50)
9627 randomlvl = skilllvl;
9628 else if (check <= 85)
9629 {
9630 randomlvl = skilllvl - 1;
9631 if (randomlvl <= 0)
9632 randomlvl = 1;
9633 }
9634 else
9635 {
9636 randomlvl = skilllvl + 1;
9637 if (randomlvl > 27)
9638 randomlvl = 27;
9639 }
9640 return randomlvl;
9641 }
9642
9643 public void startFishCombat(boolean isNoob, boolean isUpperGrade)
9644 {
9645 _fishCombat = new L2Fishing(this, _fish, isNoob, isUpperGrade, _lure.getItemId());
9646 }
9647
9648 public void endFishing(boolean win)
9649 {
9650 if (_fishCombat == null)
9651 sendPacket(SystemMessageId.BAIT_LOST_FISH_GOT_AWAY);
9652 else
9653 _fishCombat = null;
9654
9655 _lure = null;
9656 _fishingLoc = null;
9657
9658 // Ends fishing
9659 broadcastPacket(new ExFishingEnd(win, getObjectId()));
9660 sendPacket(SystemMessageId.REEL_LINE_AND_STOP_FISHING);
9661 setIsImmobilized(false);
9662 stopLookingForFishTask();
9663 }
9664
9665 public L2Fishing getFishCombat()
9666 {
9667 return _fishCombat;
9668 }
9669
9670 public Location getFishingLoc()
9671 {
9672 return _fishingLoc;
9673 }
9674
9675 public void setLure(ItemInstance lure)
9676 {
9677 _lure = lure;
9678 }
9679
9680 public ItemInstance getLure()
9681 {
9682 return _lure;
9683 }
9684
9685 public int getInventoryLimit()
9686 {
9687 return ((getRace() == ClassRace.DWARF) ? Config.INVENTORY_MAXIMUM_DWARF : Config.INVENTORY_MAXIMUM_NO_DWARF) + (int) getStat().calcStat(Stats.INV_LIM, 0, null, null);
9688 }
9689
9690 public static int getQuestInventoryLimit()
9691 {
9692 return Config.INVENTORY_MAXIMUM_QUEST_ITEMS;
9693 }
9694
9695 public int getWareHouseLimit()
9696 {
9697 return ((getRace() == ClassRace.DWARF) ? Config.WAREHOUSE_SLOTS_DWARF : Config.WAREHOUSE_SLOTS_NO_DWARF) + (int) getStat().calcStat(Stats.WH_LIM, 0, null, null);
9698 }
9699
9700 public int getPrivateSellStoreLimit()
9701 {
9702 return ((getRace() == ClassRace.DWARF) ? Config.MAX_PVTSTORE_SLOTS_DWARF : Config.MAX_PVTSTORE_SLOTS_OTHER) + (int) getStat().calcStat(Stats.P_SELL_LIM, 0, null, null);
9703 }
9704
9705 public int getPrivateBuyStoreLimit()
9706 {
9707 return ((getRace() == ClassRace.DWARF) ? Config.MAX_PVTSTORE_SLOTS_DWARF : Config.MAX_PVTSTORE_SLOTS_OTHER) + (int) getStat().calcStat(Stats.P_BUY_LIM, 0, null, null);
9708 }
9709
9710 public int getFreightLimit()
9711 {
9712 return Config.FREIGHT_SLOTS + (int) getStat().calcStat(Stats.FREIGHT_LIM, 0, null, null);
9713 }
9714
9715 public int getDwarfRecipeLimit()
9716 {
9717 return Config.DWARF_RECIPE_LIMIT + (int) getStat().calcStat(Stats.REC_D_LIM, 0, null, null);
9718 }
9719
9720 public int getCommonRecipeLimit()
9721 {
9722 return Config.COMMON_RECIPE_LIMIT + (int) getStat().calcStat(Stats.REC_C_LIM, 0, null, null);
9723 }
9724
9725 public int getMountNpcId()
9726 {
9727 return _mountNpcId;
9728 }
9729
9730 public int getMountLevel()
9731 {
9732 return _mountLevel;
9733 }
9734
9735 public void setMountObjectId(int id)
9736 {
9737 _mountObjectId = id;
9738 }
9739
9740 public int getMountObjectId()
9741 {
9742 return _mountObjectId;
9743 }
9744
9745 /**
9746 * This method is overidden on Player, L2Summon and L2Npc.
9747 * @return the skills list of this Creature.
9748 */
9749 @Override
9750 public Map<Integer, L2Skill> getSkills()
9751 {
9752 return _skills;
9753 }
9754
9755 /**
9756 * @return the current player skill in use.
9757 */
9758 public SkillUseHolder getCurrentSkill()
9759 {
9760 return _currentSkill;
9761 }
9762
9763 /**
9764 * Update the _currentSkill holder.
9765 * @param skill : The skill to update for (or null)
9766 * @param ctrlPressed : The boolean information regarding ctrl key.
9767 * @param shiftPressed : The boolean information regarding shift key.
9768 */
9769 public void setCurrentSkill(L2Skill skill, boolean ctrlPressed, boolean shiftPressed)
9770 {
9771 _currentSkill.setSkill(skill);
9772 _currentSkill.setCtrlPressed(ctrlPressed);
9773 _currentSkill.setShiftPressed(shiftPressed);
9774 }
9775
9776 /**
9777 * @return the current pet skill in use.
9778 */
9779 public SkillUseHolder getCurrentPetSkill()
9780 {
9781 return _currentPetSkill;
9782 }
9783
9784 /**
9785 * Update the _currentPetSkill holder.
9786 * @param skill : The skill to update for (or null)
9787 * @param ctrlPressed : The boolean information regarding ctrl key.
9788 * @param shiftPressed : The boolean information regarding shift key.
9789 */
9790 public void setCurrentPetSkill(L2Skill skill, boolean ctrlPressed, boolean shiftPressed)
9791 {
9792 _currentPetSkill.setSkill(skill);
9793 _currentPetSkill.setCtrlPressed(ctrlPressed);
9794 _currentPetSkill.setShiftPressed(shiftPressed);
9795 }
9796
9797 /**
9798 * @return the current queued skill in use.
9799 */
9800 public SkillUseHolder getQueuedSkill()
9801 {
9802 return _queuedSkill;
9803 }
9804
9805 /**
9806 * Update the _queuedSkill holder.
9807 * @param skill : The skill to update for (or null)
9808 * @param ctrlPressed : The boolean information regarding ctrl key.
9809 * @param shiftPressed : The boolean information regarding shift key.
9810 */
9811 public void setQueuedSkill(L2Skill skill, boolean ctrlPressed, boolean shiftPressed)
9812 {
9813 _queuedSkill.setSkill(skill);
9814 _queuedSkill.setCtrlPressed(ctrlPressed);
9815 _queuedSkill.setShiftPressed(shiftPressed);
9816 }
9817
9818 /**
9819 * @return punishment level of player
9820 */
9821 public PunishLevel getPunishLevel()
9822 {
9823 return _punishLevel;
9824 }
9825
9826 /**
9827 * @return True if player is jailed
9828 */
9829 public boolean isInJail()
9830 {
9831 return _punishLevel == PunishLevel.JAIL;
9832 }
9833
9834 /**
9835 * @return True if player is chat banned
9836 */
9837 public boolean isChatBanned()
9838 {
9839 return _punishLevel == PunishLevel.CHAT;
9840 }
9841
9842 public void setPunishLevel(int state)
9843 {
9844 switch (state)
9845 {
9846 case 0:
9847 _punishLevel = PunishLevel.NONE;
9848 break;
9849 case 1:
9850 _punishLevel = PunishLevel.CHAT;
9851 break;
9852 case 2:
9853 _punishLevel = PunishLevel.JAIL;
9854 break;
9855 case 3:
9856 _punishLevel = PunishLevel.CHAR;
9857 break;
9858 case 4:
9859 _punishLevel = PunishLevel.ACC;
9860 break;
9861 }
9862 }
9863
9864 /**
9865 * Sets punish level for player based on delay
9866 * @param state
9867 * @param delayInMinutes -- 0 for infinite
9868 */
9869 public void setPunishLevel(PunishLevel state, int delayInMinutes)
9870 {
9871 long delayInMilliseconds = delayInMinutes * 60000L;
9872 switch (state)
9873 {
9874 case NONE: // Remove Punishments
9875 {
9876 switch (_punishLevel)
9877 {
9878 case CHAT:
9879 {
9880 _punishLevel = state;
9881 stopPunishTask(true);
9882 sendPacket(new EtcStatusUpdate(this));
9883 sendMessage("Chatting is now available.");
9884 sendPacket(new PlaySound("systemmsg_e.345"));
9885 break;
9886 }
9887 case JAIL:
9888 {
9889 _punishLevel = state;
9890
9891 // Open a Html message to inform the player
9892 final NpcHtmlMessage html = new NpcHtmlMessage(0);
9893 html.setFile("data/html/jail_out.htm");
9894 sendPacket(html);
9895
9896 stopPunishTask(true);
9897 teleToLocation(17836, 170178, -3507, 0, 20); // Floran village
9898 break;
9899 }
9900 default:
9901 break;
9902 }
9903 break;
9904 }
9905 case CHAT: // Chat ban
9906 {
9907 // not allow player to escape jail using chat ban
9908 if (_punishLevel == PunishLevel.JAIL)
9909 break;
9910
9911 _punishLevel = state;
9912 _punishTimer = 0;
9913 sendPacket(new EtcStatusUpdate(this));
9914
9915 // Remove the task if any
9916 stopPunishTask(false);
9917
9918 if (delayInMinutes > 0)
9919 {
9920 _punishTimer = delayInMilliseconds;
9921
9922 // start the countdown
9923 _punishTask = ThreadPool.schedule(() -> setPunishLevel(PunishLevel.NONE, 0), _punishTimer);
9924 sendMessage("Chatting has been suspended for " + delayInMinutes + " minute(s).");
9925 }
9926 else
9927 sendMessage("Chatting has been suspended.");
9928
9929 // Send same sound packet in both "delay" cases.
9930 sendPacket(new PlaySound("systemmsg_e.346"));
9931 break;
9932
9933 }
9934 case JAIL: // Jail Player
9935 {
9936 _punishLevel = state;
9937 _punishTimer = 0;
9938
9939 // Remove the task if any
9940 stopPunishTask(false);
9941
9942 if (delayInMinutes > 0)
9943 {
9944 _punishTimer = delayInMilliseconds;
9945
9946 // start the countdown
9947 _punishTask = ThreadPool.schedule(() -> setPunishLevel(PunishLevel.NONE, 0), _punishTimer);
9948 sendMessage("You are jailed for " + delayInMinutes + " minutes.");
9949 }
9950
9951 if (OlympiadManager.getInstance().isRegisteredInComp(this))
9952 OlympiadManager.getInstance().removeDisconnectedCompetitor(this);
9953
9954 // Open a Html message to inform the player
9955 final NpcHtmlMessage html = new NpcHtmlMessage(0);
9956 html.setFile("data/html/jail_in.htm");
9957 sendPacket(html);
9958
9959 setIsIn7sDungeon(false);
9960 teleToLocation(-114356, -249645, -2984, 0, 0); // Jail
9961 break;
9962 }
9963 case CHAR: // Ban Character
9964 {
9965 setAccessLevel(-1);
9966 logout();
9967 break;
9968 }
9969 case ACC: // Ban Account
9970 {
9971 setAccountAccesslevel(-100);
9972 logout();
9973 break;
9974 }
9975 default:
9976 {
9977 _punishLevel = state;
9978 break;
9979 }
9980 }
9981
9982 // store in database
9983 storeCharBase();
9984 }
9985
9986 public long getPunishTimer()
9987 {
9988 return _punishTimer;
9989 }
9990
9991 public void setPunishTimer(long time)
9992 {
9993 _punishTimer = time;
9994 }
9995
9996 private void updatePunishState()
9997 {
9998 if (getPunishLevel() != PunishLevel.NONE)
9999 {
10000 // If punish timer exists, restart punishtask.
10001 if (_punishTimer > 0)
10002 {
10003 _punishTask = ThreadPool.schedule(() -> setPunishLevel(PunishLevel.NONE, 0), _punishTimer);
10004 sendMessage("You are still " + getPunishLevel().string() + " for " + Math.round(_punishTimer / 60000f) + " minutes.");
10005 }
10006
10007 if (getPunishLevel() == PunishLevel.JAIL)
10008 {
10009 // If player escaped, put him back in jail
10010 if (!isInsideZone(ZoneId.JAIL))
10011 teleToLocation(-114356, -249645, -2984, 0, 20);
10012 }
10013 }
10014 }
10015
10016 public void stopPunishTask(boolean save)
10017 {
10018 if (_punishTask != null)
10019 {
10020 if (save)
10021 {
10022 long delay = _punishTask.getDelay(TimeUnit.MILLISECONDS);
10023 if (delay < 0)
10024 delay = 0;
10025 setPunishTimer(delay);
10026 }
10027 _punishTask.cancel(false);
10028 _punishTask = null;
10029 }
10030 }
10031
10032 public int getPowerGrade()
10033 {
10034 return _powerGrade;
10035 }
10036
10037 public void setPowerGrade(int power)
10038 {
10039 _powerGrade = power;
10040 }
10041
10042 public boolean isCursedWeaponEquipped()
10043 {
10044 return _cursedWeaponEquippedId != 0;
10045 }
10046
10047 public void setCursedWeaponEquippedId(int value)
10048 {
10049 _cursedWeaponEquippedId = value;
10050 }
10051
10052 public int getCursedWeaponEquippedId()
10053 {
10054 return _cursedWeaponEquippedId;
10055 }
10056
10057 public void shortBuffStatusUpdate(int magicId, int level, int time)
10058 {
10059 if (_shortBuffTask != null)
10060 {
10061 _shortBuffTask.cancel(false);
10062 _shortBuffTask = null;
10063 }
10064
10065 _shortBuffTask = ThreadPool.schedule(() ->
10066 {
10067 sendPacket(new ShortBuffStatusUpdate(0, 0, 0));
10068 setShortBuffTaskSkillId(0);
10069 }, time * 1000);
10070 setShortBuffTaskSkillId(magicId);
10071
10072 sendPacket(new ShortBuffStatusUpdate(magicId, level, time));
10073 }
10074
10075 public int getShortBuffTaskSkillId()
10076 {
10077 return _shortBuffTaskSkillId;
10078 }
10079
10080 public void setShortBuffTaskSkillId(int id)
10081 {
10082 _shortBuffTaskSkillId = id;
10083 }
10084
10085 public int getDeathPenaltyBuffLevel()
10086 {
10087 return _deathPenaltyBuffLevel;
10088 }
10089
10090 public void setDeathPenaltyBuffLevel(int level)
10091 {
10092 _deathPenaltyBuffLevel = level;
10093 }
10094
10095 public void calculateDeathPenaltyBuffLevel(Creature killer)
10096 {
10097 if (_deathPenaltyBuffLevel >= 15) // maximum level reached
10098 return;
10099
10100 if (EventManager.getInstance().isRegistered(this) && EventManager.getInstance().isRunning())
10101 return;
10102
10103 if ((getKarma() > 0 || Rnd.get(1, 100) <= Config.DEATH_PENALTY_CHANCE) && !(killer instanceof Player) && !isGM() && !(getCharmOfLuck() && (killer == null || killer.isRaid())) && !isPhoenixBlessed() && !(isInsideZone(ZoneId.PVP) || isInsideZone(ZoneId.SIEGE)))
10104 {
10105 if (_deathPenaltyBuffLevel != 0)
10106 removeSkill(5076, false);
10107
10108 _deathPenaltyBuffLevel++;
10109
10110 addSkill(SkillTable.getInstance().getInfo(5076, _deathPenaltyBuffLevel), false);
10111 sendPacket(new EtcStatusUpdate(this));
10112 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.DEATH_PENALTY_LEVEL_S1_ADDED).addNumber(_deathPenaltyBuffLevel));
10113 }
10114 }
10115
10116 public void reduceDeathPenaltyBuffLevel()
10117 {
10118 if (_deathPenaltyBuffLevel <= 0)
10119 return;
10120
10121 removeSkill(5076, false);
10122
10123 _deathPenaltyBuffLevel--;
10124
10125 if (_deathPenaltyBuffLevel > 0)
10126 {
10127 addSkill(SkillTable.getInstance().getInfo(5076, _deathPenaltyBuffLevel), false);
10128 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.DEATH_PENALTY_LEVEL_S1_ADDED).addNumber(_deathPenaltyBuffLevel));
10129 }
10130 else
10131 sendPacket(SystemMessageId.DEATH_PENALTY_LIFTED);
10132
10133 sendPacket(new EtcStatusUpdate(this));
10134 }
10135
10136 public void restoreDeathPenaltyBuffLevel()
10137 {
10138 if (_deathPenaltyBuffLevel > 0)
10139 addSkill(SkillTable.getInstance().getInfo(5076, _deathPenaltyBuffLevel), false);
10140 }
10141
10142 private final Map<Integer, TimeStamp> _reuseTimeStamps = new ConcurrentHashMap<>();
10143
10144 public Collection<TimeStamp> getReuseTimeStamps()
10145 {
10146 return _reuseTimeStamps.values();
10147 }
10148
10149 public Map<Integer, TimeStamp> getReuseTimeStamp()
10150 {
10151 return _reuseTimeStamps;
10152 }
10153
10154 /**
10155 * Simple class containing all neccessary information to maintain valid timestamps and reuse for skills upon relog. Filter this carefully as it becomes redundant to store reuse for small delays.
10156 * @author Yesod
10157 */
10158 public static class TimeStamp
10159 {
10160 private final int _skillId;
10161 private final int _skillLvl;
10162 private final long _reuse;
10163 private final long _stamp;
10164
10165 public TimeStamp(L2Skill skill, long reuse)
10166 {
10167 _skillId = skill.getId();
10168 _skillLvl = skill.getLevel();
10169 _reuse = reuse;
10170 _stamp = System.currentTimeMillis() + reuse;
10171 }
10172
10173 public TimeStamp(L2Skill skill, long reuse, long systime)
10174 {
10175 _skillId = skill.getId();
10176 _skillLvl = skill.getLevel();
10177 _reuse = reuse;
10178 _stamp = systime;
10179 }
10180
10181 public long getStamp()
10182 {
10183 return _stamp;
10184 }
10185
10186 public int getSkillId()
10187 {
10188 return _skillId;
10189 }
10190
10191 public int getSkillLvl()
10192 {
10193 return _skillLvl;
10194 }
10195
10196 public long getReuse()
10197 {
10198 return _reuse;
10199 }
10200
10201 public long getRemaining()
10202 {
10203 return Math.max(_stamp - System.currentTimeMillis(), 0);
10204 }
10205
10206 public boolean hasNotPassed()
10207 {
10208 return System.currentTimeMillis() < _stamp;
10209 }
10210 }
10211
10212 /**
10213 * Index according to skill id the current timestamp of use.
10214 * @param skill
10215 * @param reuse delay
10216 */
10217 @Override
10218 public void addTimeStamp(L2Skill skill, long reuse)
10219 {
10220 _reuseTimeStamps.put(skill.getReuseHashCode(), new TimeStamp(skill, reuse));
10221 }
10222
10223 /**
10224 * Index according to skill this TimeStamp instance for restoration purposes only.
10225 * @param skill
10226 * @param reuse
10227 * @param systime
10228 */
10229 public void addTimeStamp(L2Skill skill, long reuse, long systime)
10230 {
10231 _reuseTimeStamps.put(skill.getReuseHashCode(), new TimeStamp(skill, reuse, systime));
10232 }
10233
10234 @Override
10235 public Player getActingPlayer()
10236 {
10237 return this;
10238 }
10239
10240 @Override
10241 public final void sendDamageMessage(Creature target, int damage, boolean mcrit, boolean pcrit, boolean miss)
10242 {
10243 // Check if hit is missed
10244 if (miss)
10245 {
10246 sendPacket(SystemMessageId.MISSED_TARGET);
10247 return;
10248 }
10249
10250 // Check if hit is critical
10251 if (pcrit)
10252 sendPacket(SystemMessageId.CRITICAL_HIT);
10253 if (mcrit)
10254 sendPacket(SystemMessageId.CRITICAL_HIT_MAGIC);
10255
10256 if (target.isInvul())
10257 {
10258 if (target.isParalyzed())
10259 sendPacket(SystemMessageId.OPPONENT_PETRIFIED);
10260 else
10261 sendPacket(SystemMessageId.ATTACK_WAS_BLOCKED);
10262 }
10263 else
10264 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_DID_S1_DMG).addNumber(damage));
10265
10266 if (isInOlympiadMode() && target instanceof Player && ((Player) target).isInOlympiadMode() && ((Player) target).getOlympiadGameId() == getOlympiadGameId())
10267 OlympiadGameManager.getInstance().notifyCompetitorDamage(this, damage);
10268 }
10269
10270 public void checkItemRestriction()
10271 {
10272 for (ItemInstance equippedItem : getInventory().getPaperdollItems())
10273 {
10274 if (equippedItem.getItem().checkCondition(this, this, false))
10275 continue;
10276
10277 useEquippableItem(equippedItem, equippedItem.isWeapon());
10278 }
10279 }
10280
10281 /**
10282 * A method used to test player entrance on no landing zone.<br>
10283 * <br>
10284 * If a player is mounted on a Wyvern, it launches a dismount task after 5 seconds, and a warning message.
10285 */
10286 public void enterOnNoLandingZone()
10287 {
10288 if (getMountType() == 2)
10289 {
10290 if (_dismountTask == null)
10291 _dismountTask = ThreadPool.schedule(() -> dismount(), 5000);
10292
10293 sendPacket(SystemMessageId.AREA_CANNOT_BE_ENTERED_WHILE_MOUNTED_WYVERN);
10294 }
10295 }
10296
10297 /**
10298 * A method used to test player leave on no landing zone.<br>
10299 * <br>
10300 * If a player is mounted on a Wyvern, it cancels the dismount task, if existing.
10301 */
10302 public void exitOnNoLandingZone()
10303 {
10304 if (getMountType() == 2 && _dismountTask != null)
10305 {
10306 _dismountTask.cancel(true);
10307 _dismountTask = null;
10308 }
10309 }
10310
10311 public void setIsInSiege(boolean b)
10312 {
10313 _isInSiege = b;
10314 }
10315
10316 public boolean isInSiege()
10317 {
10318 return _isInSiege;
10319 }
10320
10321 /**
10322 * Remove player from BossZones (used on char logout/exit)
10323 */
10324 public void removeFromBossZone()
10325 {
10326 for (BossZone zone : ZoneManager.getInstance().getAllZones(BossZone.class))
10327 zone.removePlayer(this);
10328 }
10329
10330 /**
10331 * @return the number of charges this Player got.
10332 */
10333 public int getCharges()
10334 {
10335 return _charges.get();
10336 }
10337
10338 public void increaseCharges(int count, int max)
10339 {
10340 if (_charges.get() >= max)
10341 {
10342 sendPacket(SystemMessageId.FORCE_MAXLEVEL_REACHED);
10343 return;
10344 }
10345
10346 restartChargeTask();
10347
10348 if (_charges.addAndGet(count) >= max)
10349 {
10350 _charges.set(max);
10351 sendPacket(SystemMessageId.FORCE_MAXLEVEL_REACHED);
10352 }
10353 else
10354 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.FORCE_INCREASED_TO_S1).addNumber(_charges.get()));
10355
10356 sendPacket(new EtcStatusUpdate(this));
10357 }
10358
10359 public boolean decreaseCharges(int count)
10360 {
10361 if (_charges.get() < count)
10362 return false;
10363
10364 if (_charges.addAndGet(-count) == 0)
10365 stopChargeTask();
10366 else
10367 restartChargeTask();
10368
10369 sendPacket(new EtcStatusUpdate(this));
10370 return true;
10371 }
10372
10373 public void clearCharges()
10374 {
10375 _charges.set(0);
10376 sendPacket(new EtcStatusUpdate(this));
10377 }
10378
10379 /**
10380 * Starts/Restarts the ChargeTask to Clear Charges after 10 Mins.
10381 */
10382 private void restartChargeTask()
10383 {
10384 if (_chargeTask != null)
10385 {
10386 _chargeTask.cancel(false);
10387 _chargeTask = null;
10388 }
10389
10390 _chargeTask = ThreadPool.schedule(() -> clearCharges(), 600000);
10391 }
10392
10393 /**
10394 * Stops the Charges Clearing Task.
10395 */
10396 public void stopChargeTask()
10397 {
10398 if (_chargeTask != null)
10399 {
10400 _chargeTask.cancel(false);
10401 _chargeTask = null;
10402 }
10403 }
10404
10405 /**
10406 * Signets check used to valid who is affected when he entered in the aoe effect.
10407 * @param cha The target to make checks on.
10408 * @return true if player can attack the target.
10409 */
10410 public boolean canAttackCharacter(Creature cha)
10411 {
10412 if (cha instanceof Attackable)
10413 return true;
10414
10415 if (cha instanceof Playable)
10416 {
10417 if (cha.isInArena())
10418 return true;
10419
10420 final Player target = cha.getActingPlayer();
10421
10422 if (isInDuel() && target.isInDuel() && target.getDuelId() == getDuelId())
10423 return true;
10424
10425 if (isInParty() && target.isInParty())
10426 {
10427 if (getParty() == target.getParty())
10428 return false;
10429
10430 if ((getParty().getCommandChannel() != null || target.getParty().getCommandChannel() != null) && (getParty().getCommandChannel() == target.getParty().getCommandChannel()))
10431 return false;
10432 }
10433
10434 if (EventManager.getInstance().isRunning() && EventManager.getInstance().isRegistered(this) && EventManager.getInstance().isRegistered((Player) target))
10435 return true;
10436
10437 if (getClan() != null && target.getClan() != null)
10438 {
10439 if (getClanId() == target.getClanId())
10440 return false;
10441
10442 if ((getAllyId() > 0 || target.getAllyId() > 0) && getAllyId() == target.getAllyId())
10443 return false;
10444
10445 if (getClan().isAtWarWith(target.getClanId()))
10446 return true;
10447 }
10448 else
10449 {
10450 if (target.getPvpFlag() == 0 && target.getKarma() == 0)
10451 return false;
10452 }
10453 }
10454 return true;
10455 }
10456
10457 public static void teleToTarget(Player targetChar, Player summonerChar, L2Skill summonSkill)
10458 {
10459 if (targetChar == null || summonerChar == null || summonSkill == null)
10460 return;
10461
10462 if (!checkSummonerStatus(summonerChar))
10463 return;
10464
10465 if (!checkSummonTargetStatus(targetChar, summonerChar))
10466 return;
10467
10468 if (summonerChar.getInstanceId() != targetChar.getInstanceId())
10469 return;
10470
10471 final int itemConsumeId = summonSkill.getTargetConsumeId();
10472 final int itemConsumeCount = summonSkill.getTargetConsume();
10473
10474 if (itemConsumeId != 0 && itemConsumeCount != 0)
10475 {
10476 if (targetChar.getInventory().getInventoryItemCount(itemConsumeId, -1) < itemConsumeCount)
10477 {
10478 targetChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_REQUIRED_FOR_SUMMONING).addItemName(summonSkill.getTargetConsumeId()));
10479 return;
10480 }
10481
10482 targetChar.destroyItemByItemId("Consume", itemConsumeId, itemConsumeCount, targetChar, true);
10483 }
10484
10485 targetChar.teleToLocation(summonerChar.getX(), summonerChar.getY(), summonerChar.getZ(), targetChar.getInstanceId(), 20);
10486 }
10487
10488 public static boolean checkSummonerStatus(Player summonerChar)
10489 {
10490 if (summonerChar == null)
10491 return false;
10492
10493 if (summonerChar.isInOlympiadMode() || summonerChar.isInObserverMode() || summonerChar.isInsideZone(ZoneId.NO_SUMMON_FRIEND) || summonerChar.isMounted() || EventManager.getInstance().isRegistered(summonerChar))
10494 return false;
10495
10496 return true;
10497 }
10498
10499 public static boolean checkSummonTargetStatus(WorldObject target, Player summonerChar)
10500 {
10501 if (target == null || !(target instanceof Player))
10502 return false;
10503
10504 Player targetChar = (Player) target;
10505
10506 if (targetChar.isAlikeDead())
10507 {
10508 summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_IS_DEAD_AT_THE_MOMENT_AND_CANNOT_BE_SUMMONED).addCharName(targetChar));
10509 return false;
10510 }
10511
10512 if (targetChar.isInStoreMode())
10513 {
10514 summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_CURRENTLY_TRADING_OR_OPERATING_PRIVATE_STORE_AND_CANNOT_BE_SUMMONED).addCharName(targetChar));
10515 return false;
10516 }
10517
10518 if (targetChar.isRooted() || targetChar.isInCombat())
10519 {
10520 summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_IS_ENGAGED_IN_COMBAT_AND_CANNOT_BE_SUMMONED).addCharName(targetChar));
10521 return false;
10522 }
10523
10524 if (targetChar.isInOlympiadMode())
10525 {
10526 summonerChar.sendPacket(SystemMessageId.YOU_CANNOT_SUMMON_PLAYERS_WHO_ARE_IN_OLYMPIAD);
10527 return false;
10528 }
10529
10530 if (targetChar.isFestivalParticipant() || targetChar.isMounted())
10531 {
10532 summonerChar.sendPacket(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING);
10533 return false;
10534 }
10535
10536 if (targetChar.isInObserverMode() || targetChar.isInsideZone(ZoneId.NO_SUMMON_FRIEND))
10537 {
10538 summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_IN_SUMMON_BLOCKING_AREA).addCharName(targetChar));
10539 return false;
10540 }
10541
10542 if (EventManager.getInstance().isRegistered(targetChar))
10543 {
10544 summonerChar.sendMessage("Your cannot summon a player while in event.");
10545 return false;
10546 }
10547
10548 if (summonerChar.getInstanceId() != targetChar.getInstanceId())
10549 {
10550 summonerChar.sendMessage("You can't summon a player to instance zone.");
10551 return false;
10552 }
10553
10554 return true;
10555 }
10556
10557 public final int getClientX()
10558 {
10559 return _clientX;
10560 }
10561
10562 public final int getClientY()
10563 {
10564 return _clientY;
10565 }
10566
10567 public final int getClientZ()
10568 {
10569 return _clientZ;
10570 }
10571
10572 public boolean isVipStatus()
10573 {
10574 return _isVipStatus;
10575 }
10576
10577 public void setVipStatus(boolean vip)
10578 {
10579 _isVipStatus = vip;
10580 }
10581
10582 public final int getClientHeading()
10583 {
10584 return _clientHeading;
10585 }
10586
10587 public final void setClientX(int val)
10588 {
10589 _clientX = val;
10590 }
10591
10592 public final void setClientY(int val)
10593 {
10594 _clientY = val;
10595 }
10596
10597 public final void setClientZ(int val)
10598 {
10599 _clientZ = val;
10600 }
10601
10602 public final void setClientHeading(int val)
10603 {
10604 _clientHeading = val;
10605 }
10606
10607 /**
10608 * @return the mailPosition.
10609 */
10610 public int getMailPosition()
10611 {
10612 return _mailPosition;
10613 }
10614
10615 /**
10616 * @param mailPosition The mailPosition to set.
10617 */
10618 public void setMailPosition(int mailPosition)
10619 {
10620 _mailPosition = mailPosition;
10621 }
10622
10623 /**
10624 * @param z
10625 * @return true if character falling now On the start of fall return false for correct coord sync !
10626 */
10627 public final boolean isFalling(int z)
10628 {
10629 if (isDead() || isFlying() || isInsideZone(ZoneId.WATER))
10630 return false;
10631
10632 if (System.currentTimeMillis() < _fallingTimestamp)
10633 return true;
10634
10635 final int deltaZ = getZ() - z;
10636 if (deltaZ <= getBaseTemplate().getFallHeight())
10637 return false;
10638
10639 final int damage = (int) Formulas.calcFallDam(this, deltaZ);
10640 if (damage > 0)
10641 {
10642 reduceCurrentHp(Math.min(damage, getCurrentHp() - 1), null, false, true, null);
10643 sendPacket(SystemMessage.getSystemMessage(SystemMessageId.FALL_DAMAGE_S1).addNumber(damage));
10644 }
10645
10646 setFalling();
10647
10648 return false;
10649 }
10650
10651 /**
10652 * Set falling timestamp
10653 */
10654 public final void setFalling()
10655 {
10656 _fallingTimestamp = System.currentTimeMillis() + FALLING_VALIDATION_DELAY;
10657 }
10658
10659 public boolean isAllowedToEnchantSkills()
10660 {
10661 if (isLocked())
10662 return false;
10663
10664 if (AttackStanceTaskManager.getInstance().isInAttackStance(this))
10665 return false;
10666
10667 if (isCastingNow() || isCastingSimultaneouslyNow())
10668 return false;
10669
10670 if (isInBoat())
10671 return false;
10672
10673 return true;
10674 }
10675
10676 public List<Integer> getFriendList()
10677 {
10678 return _friendList;
10679 }
10680
10681 public void selectFriend(Integer friendId)
10682 {
10683 if (!_selectedFriendList.contains(friendId))
10684 _selectedFriendList.add(friendId);
10685 }
10686
10687 public void deselectFriend(Integer friendId)
10688 {
10689 if (_selectedFriendList.contains(friendId))
10690 _selectedFriendList.remove(friendId);
10691 }
10692
10693 public List<Integer> getSelectedFriendList()
10694 {
10695 return _selectedFriendList;
10696 }
10697
10698 private void restoreFriendList()
10699 {
10700 _friendList.clear();
10701
10702 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
10703 {
10704 PreparedStatement statement = con.prepareStatement("SELECT friend_id FROM character_friends WHERE char_id = ? AND relation = 0");
10705 statement.setInt(1, getObjectId());
10706 ResultSet rset = statement.executeQuery();
10707
10708 int friendId;
10709 while (rset.next())
10710 {
10711 friendId = rset.getInt("friend_id");
10712 if (friendId == getObjectId())
10713 continue;
10714
10715 _friendList.add(friendId);
10716 }
10717
10718 rset.close();
10719 statement.close();
10720 }
10721 catch (Exception e)
10722 {
10723 _log.log(Level.WARNING, "Error found in " + getName() + "'s friendlist: " + e.getMessage(), e);
10724 }
10725 }
10726
10727 protected void notifyFriends(boolean login)
10728 {
10729 for (int id : _friendList)
10730 {
10731 Player friend = World.getInstance().getPlayer(id);
10732 if (friend != null)
10733 {
10734 friend.sendPacket(new FriendList(friend));
10735
10736 if (login)
10737 friend.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.FRIEND_S1_HAS_LOGGED_IN).addCharName(this));
10738 }
10739 }
10740 }
10741
10742 public void selectBlock(Integer friendId)
10743 {
10744 if (!_selectedBlocksList.contains(friendId))
10745 _selectedBlocksList.add(friendId);
10746 }
10747
10748 public void deselectBlock(Integer friendId)
10749 {
10750 if (_selectedBlocksList.contains(friendId))
10751 _selectedBlocksList.remove(friendId);
10752 }
10753
10754 public List<Integer> getSelectedBlocksList()
10755 {
10756 return _selectedBlocksList;
10757 }
10758
10759 @Override
10760 public void broadcastRelationsChanges()
10761 {
10762 for (Player player : getKnownType(Player.class))
10763 {
10764 if (getInstanceId() != player.getInstanceId())
10765 continue;
10766
10767 final int relation = getRelation(player);
10768 final boolean isAutoAttackable = isAutoAttackable(player);
10769
10770 player.sendPacket(new RelationChanged(this, relation, isAutoAttackable));
10771 if (getPet() != null)
10772 player.sendPacket(new RelationChanged(getPet(), relation, isAutoAttackable));
10773 }
10774 }
10775
10776 @Override
10777 public void sendInfo(Player activeChar)
10778 {
10779 if (isInBoat())
10780 getPosition().set(getBoat().getPosition());
10781
10782 if (getPolyType() == PolyType.NPC)
10783 activeChar.sendPacket(new AbstractNpcInfo.PcMorphInfo(this, getPolyTemplate()));
10784 else
10785 {
10786 activeChar.sendPacket(new CharInfo(this));
10787
10788 if (isSeated())
10789 {
10790 final WorldObject object = World.getInstance().getObject(_throneId);
10791 if (object instanceof StaticObject)
10792 activeChar.sendPacket(new ChairSit(getObjectId(), ((StaticObject) object).getStaticObjectId()));
10793 }
10794 }
10795
10796 int relation = getRelation(activeChar);
10797 boolean isAutoAttackable = isAutoAttackable(activeChar);
10798
10799 activeChar.sendPacket(new RelationChanged(this, relation, isAutoAttackable));
10800 if (getPet() != null)
10801 activeChar.sendPacket(new RelationChanged(getPet(), relation, isAutoAttackable));
10802
10803 relation = activeChar.getRelation(this);
10804 isAutoAttackable = activeChar.isAutoAttackable(this);
10805
10806 sendPacket(new RelationChanged(activeChar, relation, isAutoAttackable));
10807 if (activeChar.getPet() != null)
10808 sendPacket(new RelationChanged(activeChar.getPet(), relation, isAutoAttackable));
10809
10810 if (isInBoat())
10811 activeChar.sendPacket(new GetOnVehicle(getObjectId(), getBoat().getObjectId(), getBoatPosition()));
10812
10813 switch (getStoreType())
10814 {
10815 case SELL:
10816 case PACKAGE_SELL:
10817 activeChar.sendPacket(new PrivateStoreMsgSell(this));
10818 break;
10819
10820 case BUY:
10821 activeChar.sendPacket(new PrivateStoreMsgBuy(this));
10822 break;
10823
10824 case MANUFACTURE:
10825 activeChar.sendPacket(new RecipeShopMsg(this));
10826 break;
10827 default:
10828 break;
10829 }
10830 }
10831
10832 @Override
10833 public double getCollisionRadius()
10834 {
10835 return getBaseTemplate().getCollisionRadiusBySex(getAppearance().getSex());
10836 }
10837
10838 @Override
10839 public double getCollisionHeight()
10840 {
10841 return getBaseTemplate().getCollisionHeightBySex(getAppearance().getSex());
10842 }
10843
10844 public boolean teleportRequest(Player requester, L2Skill skill)
10845 {
10846 if (_summonTargetRequest != null && requester != null)
10847 return false;
10848
10849 _summonTargetRequest = requester;
10850 _summonSkillRequest = skill;
10851 return true;
10852 }
10853
10854 public void teleportAnswer(int answer, int requesterId)
10855 {
10856 if (_summonTargetRequest == null)
10857 return;
10858
10859 if (answer == 1 && _summonTargetRequest.getObjectId() == requesterId)
10860 teleToTarget(this, _summonTargetRequest, _summonSkillRequest);
10861
10862 _summonTargetRequest = null;
10863 _summonSkillRequest = null;
10864 }
10865
10866 public void activateGate(int answer, int type)
10867 {
10868 if (_requestedGate == null)
10869 return;
10870
10871 if (answer == 1 && getTarget() == _requestedGate)
10872 {
10873 if (type == 1)
10874 _requestedGate.openMe();
10875 else if (type == 0)
10876 _requestedGate.closeMe();
10877 }
10878
10879 _requestedGate = null;
10880 }
10881
10882 public void setRequestedGate(Door door)
10883 {
10884 _requestedGate = door;
10885 }
10886
10887 @Override
10888 public boolean polymorph(PolyType type, int npcId)
10889 {
10890 if (super.polymorph(type, npcId))
10891 {
10892 sendPacket(new UserInfo(this));
10893 return true;
10894 }
10895 return false;
10896 }
10897
10898 @Override
10899 public void unpolymorph()
10900 {
10901 super.unpolymorph();
10902 sendPacket(new UserInfo(this));
10903 }
10904
10905 @Override
10906 public void addKnownObject(WorldObject object)
10907 {
10908 if (!_knownObjects.contains(object))
10909 {
10910 _knownObjects.add(object);
10911 sendInfoFrom(object);
10912 }
10913 }
10914
10915 @Override
10916 public void removeKnownObject(WorldObject object)
10917 {
10918 super.removeKnownObject(object);
10919
10920 if (_knownObjects.contains(object))
10921 {
10922 _knownObjects.remove(object);
10923
10924 // send Server-Client Packet DeleteObject to the L2PcInstance
10925 sendPacket(new DeleteObject(object, (object instanceof Player) && ((Player) object).isSeated()));
10926 }
10927 }
10928
10929 public final void refreshInfos()
10930 {
10931 for (WorldObject object : getKnownType(WorldObject.class))
10932 {
10933 if (object instanceof Player && ((Player) object).isInObserverMode())
10934 continue;
10935
10936 sendInfoFrom(object);
10937 }
10938 }
10939
10940 private final void sendInfoFrom(WorldObject object)
10941 {
10942 if (object.getPolyType() == PolyType.ITEM)
10943 sendPacket(new SpawnItem(object));
10944 else
10945 {
10946 // send object info to player
10947 object.sendInfo(this);
10948
10949 if (object instanceof Creature)
10950 {
10951 // Update the state of the Creature object client side by sending Server->Client packet MoveToPawn/MoveToLocation and AutoAttackStart to the Player
10952 Creature obj = (Creature) object;
10953 if (obj.hasAI())
10954 obj.getAI().describeStateToPlayer(this);
10955 }
10956 }
10957 }
10958
10959 public int getLastInstance() {
10960 return _lastInstance;
10961 }
10962
10963 public void setlastInstance(int _lastInstance) {
10964 this._lastInstance = _lastInstance;
10965 }
10966
10967 public boolean isAio()
10968 {
10969 return _isAio;
10970 }
10971
10972 public void setAio(boolean b)
10973 {
10974 _isAio = b;
10975 }
10976
10977 public void addAioSkills()
10978 {
10979 for (int skillid : Config.AIO_SKILLS.keySet())
10980 {
10981 final L2Skill skill = SkillTable.getInstance().getInfo(skillid, Config.AIO_SKILLS.get(skillid));
10982
10983 if (skill != null)
10984 addSkill(skill, true);
10985 }
10986 sendSkillList();
10987 }
10988
10989 public int getPcBangScore()
10990 {
10991 return pcBangPoint;
10992 }
10993
10994 public void reducePcBangScore(int to)
10995 {
10996 pcBangPoint -= to;
10997 updatePcBangWnd(to, false, false);
10998 }
10999
11000 public void addPcBangScore(int to)
11001 {
11002 pcBangPoint += to;
11003 }
11004
11005 public void updatePcBangWnd(int score, boolean add, boolean duble)
11006 {
11007 sendPacket(new ExPCCafePointInfo(this, score, add, 24, duble));
11008 }
11009
11010 public void showPcBangWindow()
11011 {
11012 sendPacket(new ExPCCafePointInfo(this, 0, false, 24, false));
11013 }
11014
11015
11016 public int getAntiAfk()
11017 {
11018 return antiAfkTime;
11019 }
11020
11021 public void setAntiAfk(int antiAfk)
11022 {
11023 antiAfkTime = antiAfk;
11024 }
11025
11026 public void disableAutoPot()
11027 {
11028 if (isAutoPot(728))
11029 {
11030 sendPacket(new ExAutoSoulShot(728, 0));
11031 setAutoPot(728, null, false);
11032 }
11033 if (isAutoPot(1539))
11034 {
11035 sendPacket(new ExAutoSoulShot(1539, 0));
11036 setAutoPot(1539, null, false);
11037 }
11038 if (isAutoPot(5592))
11039 {
11040 sendPacket(new ExAutoSoulShot(5592, 0));
11041 setAutoPot(5592, null, false);
11042 }
11043 }
11044
11045 public boolean eligibleToVoteHop()
11046 {
11047 return (getLastHopVote() + 43200000) < System.currentTimeMillis();
11048 }
11049
11050 public boolean eligibleToVoteTop()
11051 {
11052 return (getLastTopVote() + 43200000) < System.currentTimeMillis();
11053 }
11054
11055 public boolean eligibleToVoteNet()
11056 {
11057 return (getLastNetVote() + 43200000) < System.currentTimeMillis();
11058 }
11059
11060 public String getVoteCountdownHop()
11061 {
11062 long youCanVote = getLastHopVote() - (System.currentTimeMillis() - 43200000);
11063 return convertLongToCountdown(youCanVote);
11064 }
11065
11066 public String getVoteCountdownTop()
11067 {
11068 long youCanVote = getLastTopVote() - (System.currentTimeMillis() - 43200000);
11069 return convertLongToCountdown(youCanVote);
11070 }
11071
11072 public String getVoteCountdownNet()
11073 {
11074 long youCanVote = getLastNetVote() - (System.currentTimeMillis() - 43200000);
11075 return convertLongToCountdown(youCanVote);
11076 }
11077
11078 public static String convertLongToCountdown(long youCanVote)
11079 {
11080 String formattedCountdown = String.format("%d hours %d mins %d secs",
11081 TimeUnit.MILLISECONDS.toHours(youCanVote),
11082 TimeUnit.MILLISECONDS.toMinutes(youCanVote) -
11083 TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(youCanVote)),
11084 TimeUnit.MILLISECONDS.toSeconds(youCanVote) -
11085 TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(youCanVote))
11086 );
11087 return formattedCountdown;
11088 }
11089
11090 public final boolean isVoting()
11091 {
11092 return _isVoting;
11093 }
11094
11095 public final void setIsVoting(boolean value)
11096 {
11097 _isVoting = value;
11098 }
11099
11100 Player GMInventoryView = null;
11101
11102 public void setGMInventoryView(Player player) {
11103 GMInventoryView = player;
11104 }
11105
11106 public Player getGMInventoryView() {
11107 return GMInventoryView;
11108 }
11109
11110 // remove rebs
11111 public L2Skill removeSkillReb(L2Skill skill)
11112 {
11113 // Remove a skill from the L2Character and its Func objects from calculator set of the L2Character
11114 L2Skill oldSkill = removeSkill(skill.getId(), false);
11115
11116 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
11117 {
11118 PreparedStatement statement = con.prepareStatement("DELETE FROM character_skills WHERE skill_id=? AND char_obj_id=?");
11119
11120 if (oldSkill != null)
11121 {
11122 statement.setInt(1, skill.getId());
11123 statement.setInt(2, getObjectId());
11124 statement.execute();
11125 }
11126 statement.close();
11127 }
11128 catch (Exception e)
11129 {
11130 _log.warning("Error could not delete skill: " + e);
11131 }
11132
11133 // Don't busy with shortcuts if skill was a passive skill.
11134 if (skill != null && !skill.isPassive())
11135 {
11136 L2ShortCut[] allShortCuts = getAllShortCuts();
11137
11138 for (L2ShortCut sc : allShortCuts)
11139 {
11140 if (sc != null && sc.getId() == skill.getId() && sc.getType() == L2ShortCut.TYPE_SKILL)
11141 deleteShortCut(sc.getSlot(), sc.getPage());
11142 }
11143 }
11144
11145 return oldSkill;
11146 }
11147 public void removerebs(){
11148
11149 int[] rebai = new int[] {549,550,551,552,553,554,555,556,557,558,559,560};
11150 int leveliai = 0;
11151 for (L2Skill skill : getSkills().values()) {
11152 int skillid = skill.getId();
11153
11154 for (int i = 0; i < rebai.length; i++) {
11155 if (rebai[i] == skillid){
11156 removeSkillReb(skill);
11157 leveliai=leveliai+skill.getLevel();
11158 }
11159 }
11160 }
11161
11162 if(leveliai==0){
11163 sendMessage("You don't have any rebirth skill.");
11164
11165 }else{
11166 restoreSkills();
11167 sendMessage("All rebirth skills removed. Now you can learn new rebirth skills.");
11168 final ItemInstance item = this.getInventory().addItem("Quest", 2822, leveliai, this, this);
11169 if (item == null)
11170 return;
11171
11172 // Send message to the client.
11173
11174 SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S).addItemName(2822).addNumber(leveliai);
11175 this.sendPacket(smsg);
11176 }
11177 }
11178
11179 public List<Player> getWatchers() {
11180 return _watchers;
11181 }
11182
11183 public void setAfk(boolean _isAfk) {
11184 this._Afk = _isAfk;
11185 }
11186
11187 public boolean isAfk(){
11188 return _Afk;
11189 }
11190}