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