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