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