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