· 5 years ago · Mar 12, 2020, 11:06 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 com.l2jserver.gameserver.model.actor.instance;
16
17import java.sql.Connection;
18import java.sql.Date;
19import java.sql.PreparedStatement;
20import java.sql.ResultSet;
21import java.sql.SQLException;
22import java.util.Arrays;
23import java.util.Calendar;
24import java.util.Collection;
25import java.util.HashMap;
26import java.util.Iterator;
27import java.util.List;
28import java.util.Map;
29import java.util.Map.Entry;
30import java.util.Set;
31import java.util.concurrent.Future;
32import java.util.concurrent.ScheduledFuture;
33import java.util.concurrent.TimeUnit;
34import java.util.concurrent.atomic.AtomicInteger;
35import java.util.concurrent.locks.ReentrantLock;
36import java.util.logging.Level;
37
38import javolution.util.FastList;
39import javolution.util.FastMap;
40import javolution.util.FastSet;
41
42import com.l2jserver.Config;
43import com.l2jserver.L2DatabaseFactory;
44import com.l2jserver.gameserver.Announcements;
45import com.l2jserver.gameserver.GameTimeController;
46import com.l2jserver.gameserver.GeoData;
47import com.l2jserver.gameserver.ItemsAutoDestroy;
48import com.l2jserver.gameserver.LoginServerThread;
49import com.l2jserver.gameserver.RecipeController;
50import com.l2jserver.gameserver.SevenSigns;
51import com.l2jserver.gameserver.SevenSignsFestival;
52import com.l2jserver.gameserver.ThreadPoolManager;
53import com.l2jserver.gameserver.ai.CtrlIntention;
54import com.l2jserver.gameserver.ai.L2CharacterAI;
55import com.l2jserver.gameserver.ai.L2PlayerAI;
56import com.l2jserver.gameserver.ai.L2SummonAI;
57import com.l2jserver.gameserver.cache.HtmCache;
58import com.l2jserver.gameserver.cache.WarehouseCacheManager;
59import com.l2jserver.gameserver.communitybbs.BB.Forum;
60import com.l2jserver.gameserver.communitybbs.Manager.ForumsBBSManager;
61import com.l2jserver.gameserver.communitybbs.Manager.RegionBBSManager;
62import com.l2jserver.gameserver.custom.PvPColorSystem;
63import com.l2jserver.gameserver.datatables.AdminTable;
64import com.l2jserver.gameserver.datatables.CharNameTable;
65import com.l2jserver.gameserver.datatables.CharSummonTable;
66import com.l2jserver.gameserver.datatables.CharTemplateTable;
67import com.l2jserver.gameserver.datatables.ClanTable;
68import com.l2jserver.gameserver.datatables.ClassListData;
69import com.l2jserver.gameserver.datatables.EnchantGroupsData;
70import com.l2jserver.gameserver.datatables.ExperienceTable;
71import com.l2jserver.gameserver.datatables.FishData;
72import com.l2jserver.gameserver.datatables.HennaData;
73import com.l2jserver.gameserver.datatables.ItemTable;
74import com.l2jserver.gameserver.datatables.LovecTable;
75import com.l2jserver.gameserver.datatables.NpcTable;
76import com.l2jserver.gameserver.datatables.PetDataTable;
77import com.l2jserver.gameserver.datatables.PremiumTable;
78import com.l2jserver.gameserver.datatables.RecipeData;
79import com.l2jserver.gameserver.datatables.SkillTable;
80import com.l2jserver.gameserver.datatables.SkillTable.FrequentSkill;
81import com.l2jserver.gameserver.datatables.SkillTreesData;
82import com.l2jserver.gameserver.handler.IItemHandler;
83import com.l2jserver.gameserver.handler.ItemHandler;
84import com.l2jserver.gameserver.idfactory.IdFactory;
85import com.l2jserver.gameserver.instancemanager.AntiFeedManager;
86import com.l2jserver.gameserver.instancemanager.BotManager;
87import com.l2jserver.gameserver.instancemanager.CastleManager;
88import com.l2jserver.gameserver.instancemanager.CoupleManager;
89import com.l2jserver.gameserver.instancemanager.CursedWeaponsManager;
90import com.l2jserver.gameserver.instancemanager.DimensionalRiftManager;
91import com.l2jserver.gameserver.instancemanager.DuelManager;
92import com.l2jserver.gameserver.instancemanager.ExpirableServicesManager;
93import com.l2jserver.gameserver.instancemanager.ExpirableServicesManager.ServiceType;
94import com.l2jserver.gameserver.instancemanager.FortManager;
95import com.l2jserver.gameserver.instancemanager.FortSiegeManager;
96import com.l2jserver.gameserver.instancemanager.GlobalVariablesManager;
97import com.l2jserver.gameserver.instancemanager.GrandBossManager;
98import com.l2jserver.gameserver.instancemanager.HandysBlockCheckerManager;
99import com.l2jserver.gameserver.instancemanager.InstanceManager;
100import com.l2jserver.gameserver.instancemanager.ItemsOnGroundManager;
101import com.l2jserver.gameserver.instancemanager.MapRegionManager;
102import com.l2jserver.gameserver.instancemanager.QuestManager;
103import com.l2jserver.gameserver.instancemanager.SiegeManager;
104import com.l2jserver.gameserver.instancemanager.TerritoryWarManager;
105import com.l2jserver.gameserver.instancemanager.ZoneManager;
106import com.l2jserver.gameserver.instancemanager.leaderboards.ArenaLeaderboard;
107import com.l2jserver.gameserver.instancemanager.leaderboards.TvTLeaderboard;
108import com.l2jserver.gameserver.model.BlockList;
109import com.l2jserver.gameserver.model.CharEffectList;
110import com.l2jserver.gameserver.model.L2AccessLevel;
111import com.l2jserver.gameserver.model.L2Account;
112import com.l2jserver.gameserver.model.L2Clan;
113import com.l2jserver.gameserver.model.L2ClanMember;
114import com.l2jserver.gameserver.model.L2ContactList;
115import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
116import com.l2jserver.gameserver.model.L2Macro;
117import com.l2jserver.gameserver.model.L2ManufactureItem;
118import com.l2jserver.gameserver.model.L2ManufactureList;
119import com.l2jserver.gameserver.model.L2Object;
120import com.l2jserver.gameserver.model.L2Party;
121import com.l2jserver.gameserver.model.L2Party.messageType;
122import com.l2jserver.gameserver.model.L2PetData;
123import com.l2jserver.gameserver.model.L2PetLevelData;
124import com.l2jserver.gameserver.model.L2PremiumItem;
125import com.l2jserver.gameserver.model.L2Radar;
126import com.l2jserver.gameserver.model.L2RecipeList;
127import com.l2jserver.gameserver.model.L2Request;
128import com.l2jserver.gameserver.model.L2ShortCut;
129import com.l2jserver.gameserver.model.L2SkillLearn;
130import com.l2jserver.gameserver.model.L2Transformation;
131import com.l2jserver.gameserver.model.L2UIKeysSettings;
132import com.l2jserver.gameserver.model.L2World;
133import com.l2jserver.gameserver.model.L2WorldRegion;
134import com.l2jserver.gameserver.model.Location;
135import com.l2jserver.gameserver.model.MacroList;
136import com.l2jserver.gameserver.model.PartyMatchRoom;
137import com.l2jserver.gameserver.model.PartyMatchRoomList;
138import com.l2jserver.gameserver.model.PartyMatchWaitingList;
139import com.l2jserver.gameserver.model.PcCondOverride;
140import com.l2jserver.gameserver.model.ShortCuts;
141import com.l2jserver.gameserver.model.ShotType;
142import com.l2jserver.gameserver.model.TerritoryWard;
143import com.l2jserver.gameserver.model.TimeStamp;
144import com.l2jserver.gameserver.model.TradeList;
145import com.l2jserver.gameserver.model.actor.L2Attackable;
146import com.l2jserver.gameserver.model.actor.L2Character;
147import com.l2jserver.gameserver.model.actor.L2Decoy;
148import com.l2jserver.gameserver.model.actor.L2Npc;
149import com.l2jserver.gameserver.model.actor.L2Playable;
150import com.l2jserver.gameserver.model.actor.L2Summon;
151import com.l2jserver.gameserver.model.actor.L2Trap;
152import com.l2jserver.gameserver.model.actor.L2Vehicle;
153import com.l2jserver.gameserver.model.actor.appearance.PcAppearance;
154import com.l2jserver.gameserver.model.actor.knownlist.PcKnownList;
155import com.l2jserver.gameserver.model.actor.position.PcPosition;
156import com.l2jserver.gameserver.model.actor.stat.PcStat;
157import com.l2jserver.gameserver.model.actor.status.PcStatus;
158import com.l2jserver.gameserver.model.actor.templates.L2PcTemplate;
159import com.l2jserver.gameserver.model.base.ClassId;
160import com.l2jserver.gameserver.model.base.ClassLevel;
161import com.l2jserver.gameserver.model.base.PlayerClass;
162import com.l2jserver.gameserver.model.base.Race;
163import com.l2jserver.gameserver.model.base.Sex;
164import com.l2jserver.gameserver.model.base.SubClass;
165import com.l2jserver.gameserver.model.effects.AbnormalEffect;
166import com.l2jserver.gameserver.model.effects.EffectTemplate;
167import com.l2jserver.gameserver.model.effects.L2Effect;
168import com.l2jserver.gameserver.model.effects.L2EffectType;
169import com.l2jserver.gameserver.model.entity.Castle;
170import com.l2jserver.gameserver.model.entity.Duel;
171import com.l2jserver.gameserver.model.entity.Fort;
172import com.l2jserver.gameserver.model.entity.Hero;
173import com.l2jserver.gameserver.model.entity.Hitman;
174import com.l2jserver.gameserver.model.entity.Instance;
175import com.l2jserver.gameserver.model.entity.L2Event;
176import com.l2jserver.gameserver.model.entity.Siege;
177import com.l2jserver.gameserver.model.entity.TvTEvent;
178import com.l2jserver.gameserver.model.entity.TvTRoundEvent;
179import com.l2jserver.gameserver.model.fishing.L2Fish;
180import com.l2jserver.gameserver.model.fishing.L2Fishing;
181import com.l2jserver.gameserver.model.itemcontainer.Inventory;
182import com.l2jserver.gameserver.model.itemcontainer.ItemContainer;
183import com.l2jserver.gameserver.model.itemcontainer.PcFreight;
184import com.l2jserver.gameserver.model.itemcontainer.PcInventory;
185import com.l2jserver.gameserver.model.itemcontainer.PcRefund;
186import com.l2jserver.gameserver.model.itemcontainer.PcWarehouse;
187import com.l2jserver.gameserver.model.itemcontainer.PetInventory;
188import com.l2jserver.gameserver.model.items.L2Armor;
189import com.l2jserver.gameserver.model.items.L2EtcItem;
190import com.l2jserver.gameserver.model.items.L2Henna;
191import com.l2jserver.gameserver.model.items.L2Item;
192import com.l2jserver.gameserver.model.items.L2Weapon;
193import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
194import com.l2jserver.gameserver.model.items.type.L2ActionType;
195import com.l2jserver.gameserver.model.items.type.L2ArmorType;
196import com.l2jserver.gameserver.model.items.type.L2EtcItemType;
197import com.l2jserver.gameserver.model.items.type.L2WeaponType;
198import com.l2jserver.gameserver.model.multisell.PreparedListContainer;
199import com.l2jserver.gameserver.model.olympiad.OlympiadGameManager;
200import com.l2jserver.gameserver.model.olympiad.OlympiadGameTask;
201import com.l2jserver.gameserver.model.olympiad.OlympiadManager;
202import com.l2jserver.gameserver.model.quest.Quest;
203import com.l2jserver.gameserver.model.quest.Quest.QuestEventType;
204import com.l2jserver.gameserver.model.quest.QuestState;
205import com.l2jserver.gameserver.model.quest.State;
206import com.l2jserver.gameserver.model.skills.L2Skill;
207import com.l2jserver.gameserver.model.skills.L2SkillType;
208import com.l2jserver.gameserver.model.skills.l2skills.L2SkillSiegeFlag;
209import com.l2jserver.gameserver.model.skills.l2skills.L2SkillSummon;
210import com.l2jserver.gameserver.model.skills.l2skills.L2SkillTrap;
211import com.l2jserver.gameserver.model.skills.targets.L2TargetType;
212import com.l2jserver.gameserver.model.stats.Env;
213import com.l2jserver.gameserver.model.stats.Formulas;
214import com.l2jserver.gameserver.model.stats.Rates;
215import com.l2jserver.gameserver.model.stats.Stats;
216import com.l2jserver.gameserver.model.zone.L2ZoneType;
217import com.l2jserver.gameserver.model.zone.ZoneId;
218import com.l2jserver.gameserver.model.zone.type.L2BossZone;
219import com.l2jserver.gameserver.model.zone.type.L2NoRestartZone;
220import com.l2jserver.gameserver.network.DialogId;
221import com.l2jserver.gameserver.network.L2GameClient;
222import com.l2jserver.gameserver.network.SystemMessageId;
223import com.l2jserver.gameserver.network.communityserver.CommunityServerThread;
224import com.l2jserver.gameserver.network.communityserver.writepackets.WorldInfo;
225import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
226import com.l2jserver.gameserver.network.serverpackets.ChangeWaitType;
227import com.l2jserver.gameserver.network.serverpackets.CharInfo;
228import com.l2jserver.gameserver.network.serverpackets.ConfirmDlg;
229import com.l2jserver.gameserver.network.serverpackets.EtcStatusUpdate;
230import com.l2jserver.gameserver.network.serverpackets.ExAutoSoulShot;
231import com.l2jserver.gameserver.network.serverpackets.ExBasicActionList;
232import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
233import com.l2jserver.gameserver.network.serverpackets.ExDominionWarStart;
234import com.l2jserver.gameserver.network.serverpackets.ExDuelUpdateUserInfo;
235import com.l2jserver.gameserver.network.serverpackets.ExFishingEnd;
236import com.l2jserver.gameserver.network.serverpackets.ExFishingStart;
237import com.l2jserver.gameserver.network.serverpackets.ExGetBookMarkInfoPacket;
238import com.l2jserver.gameserver.network.serverpackets.ExGetOnAirShip;
239import com.l2jserver.gameserver.network.serverpackets.ExNevitAdventEffect;
240import com.l2jserver.gameserver.network.serverpackets.ExNevitAdventPointInfoPacket;
241import com.l2jserver.gameserver.network.serverpackets.ExNevitAdventTimeChange;
242import com.l2jserver.gameserver.network.serverpackets.ExOlympiadMode;
243import com.l2jserver.gameserver.network.serverpackets.ExPrivateStoreSetWholeMsg;
244import com.l2jserver.gameserver.network.serverpackets.ExSetCompassZoneCode;
245import com.l2jserver.gameserver.network.serverpackets.ExSpawnEmitter;
246import com.l2jserver.gameserver.network.serverpackets.ExStartScenePlayer;
247import com.l2jserver.gameserver.network.serverpackets.ExStorageMaxCount;
248import com.l2jserver.gameserver.network.serverpackets.ExUseSharedGroupItem;
249import com.l2jserver.gameserver.network.serverpackets.ExVitalityPointInfo;
250import com.l2jserver.gameserver.network.serverpackets.ExVoteSystemInfo;
251import com.l2jserver.gameserver.network.serverpackets.FriendStatusPacket;
252import com.l2jserver.gameserver.network.serverpackets.GameGuardQuery;
253import com.l2jserver.gameserver.network.serverpackets.GetOnVehicle;
254import com.l2jserver.gameserver.network.serverpackets.HennaInfo;
255import com.l2jserver.gameserver.network.serverpackets.InventoryUpdate;
256import com.l2jserver.gameserver.network.serverpackets.ItemList;
257import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
258import com.l2jserver.gameserver.network.serverpackets.LeaveWorld;
259import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
260import com.l2jserver.gameserver.network.serverpackets.NicknameChanged;
261import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
262import com.l2jserver.gameserver.network.serverpackets.ObservationMode;
263import com.l2jserver.gameserver.network.serverpackets.ObservationReturn;
264import com.l2jserver.gameserver.network.serverpackets.PartySmallWindowUpdate;
265import com.l2jserver.gameserver.network.serverpackets.PetInventoryUpdate;
266import com.l2jserver.gameserver.network.serverpackets.PlaySound;
267import com.l2jserver.gameserver.network.serverpackets.PledgeShowMemberListDelete;
268import com.l2jserver.gameserver.network.serverpackets.PledgeShowMemberListUpdate;
269import com.l2jserver.gameserver.network.serverpackets.PrivateStoreListBuy;
270import com.l2jserver.gameserver.network.serverpackets.PrivateStoreListSell;
271import com.l2jserver.gameserver.network.serverpackets.PrivateStoreManageListBuy;
272import com.l2jserver.gameserver.network.serverpackets.PrivateStoreManageListSell;
273import com.l2jserver.gameserver.network.serverpackets.PrivateStoreMsgBuy;
274import com.l2jserver.gameserver.network.serverpackets.PrivateStoreMsgSell;
275import com.l2jserver.gameserver.network.serverpackets.RecipeShopMsg;
276import com.l2jserver.gameserver.network.serverpackets.RecipeShopSellList;
277import com.l2jserver.gameserver.network.serverpackets.RelationChanged;
278import com.l2jserver.gameserver.network.serverpackets.Ride;
279import com.l2jserver.gameserver.network.serverpackets.ServerClose;
280import com.l2jserver.gameserver.network.serverpackets.SetupGauge;
281import com.l2jserver.gameserver.network.serverpackets.ShortBuffStatusUpdate;
282import com.l2jserver.gameserver.network.serverpackets.ShortCutInit;
283import com.l2jserver.gameserver.network.serverpackets.SkillCoolTime;
284import com.l2jserver.gameserver.network.serverpackets.SkillList;
285import com.l2jserver.gameserver.network.serverpackets.Snoop;
286import com.l2jserver.gameserver.network.serverpackets.SocialAction;
287import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
288import com.l2jserver.gameserver.network.serverpackets.StopMove;
289import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
290import com.l2jserver.gameserver.network.serverpackets.TargetSelected;
291import com.l2jserver.gameserver.network.serverpackets.TargetUnselected;
292import com.l2jserver.gameserver.network.serverpackets.TradeDone;
293import com.l2jserver.gameserver.network.serverpackets.TradeOtherDone;
294import com.l2jserver.gameserver.network.serverpackets.TradeStart;
295import com.l2jserver.gameserver.network.serverpackets.UserInfo;
296import com.l2jserver.gameserver.scripting.scriptengine.events.EquipmentEvent;
297import com.l2jserver.gameserver.scripting.scriptengine.events.HennaEvent;
298import com.l2jserver.gameserver.scripting.scriptengine.events.ProfessionChangeEvent;
299import com.l2jserver.gameserver.scripting.scriptengine.events.TransformEvent;
300import com.l2jserver.gameserver.scripting.scriptengine.listeners.player.EquipmentListener;
301import com.l2jserver.gameserver.scripting.scriptengine.listeners.player.HennaListener;
302import com.l2jserver.gameserver.scripting.scriptengine.listeners.player.PlayerDespawnListener;
303import com.l2jserver.gameserver.scripting.scriptengine.listeners.player.ProfessionChangeListener;
304import com.l2jserver.gameserver.scripting.scriptengine.listeners.player.TransformListener;
305import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager;
306import com.l2jserver.gameserver.util.BotPunish;
307import com.l2jserver.gameserver.util.FloodProtectors;
308import com.l2jserver.gameserver.util.PlayerEventStatus;
309import com.l2jserver.gameserver.util.Point3D;
310import com.l2jserver.gameserver.util.Util;
311import com.l2jserver.util.L2FastList;
312import com.l2jserver.util.Rnd;
313import com.l2jserver.util.TimeConstant;
314
315import gnu.trove.list.array.TIntArrayList;
316
317/**
318 * This class represents all player characters in the world.<br>
319 * There is always a client-thread connected to this (except if a player-store is activated upon logout).
320 */
321public final class L2PcInstance extends L2Playable
322{
323 // Character Skill SQL String Definitions:
324 private static final String RESTORE_SKILLS_FOR_CHAR = "SELECT skill_id,skill_level FROM character_skills WHERE charId=? AND class_index=?";
325 private static final String ADD_NEW_SKILL = "INSERT INTO character_skills (charId,skill_id,skill_level,class_index) VALUES (?,?,?,?)";
326 private static final String UPDATE_CHARACTER_SKILL_LEVEL = "UPDATE character_skills SET skill_level=? WHERE skill_id=? AND charId=? AND class_index=?";
327 private static final String DELETE_SKILL_FROM_CHAR = "DELETE FROM character_skills WHERE skill_id=? AND charId=? AND class_index=?";
328 private static final String DELETE_CHAR_SKILLS = "DELETE FROM character_skills WHERE charId=? AND class_index=?";
329
330 // Character Skill Save SQL String Definitions:
331 private static final String ADD_SKILL_SAVE = "INSERT INTO character_skills_save (charId,skill_id,skill_level,effect_count,effect_cur_time,reuse_delay,systime,restore_type,class_index,buff_index) VALUES (?,?,?,?,?,?,?,?,?,?)";
332 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 charId=? AND class_index=? ORDER BY buff_index ASC";
333 private static final String DELETE_SKILL_SAVE = "DELETE FROM character_skills_save WHERE charId=? AND class_index=?";
334
335 // Character Item Reuse Time String Definition:
336 private static final String ADD_ITEM_REUSE_SAVE = "INSERT INTO character_item_reuse_save (charId,itemId,itemObjId,reuseDelay,systime) VALUES (?,?,?,?,?)";
337 private static final String RESTORE_ITEM_REUSE_SAVE = "SELECT charId,itemId,itemObjId,reuseDelay,systime FROM character_item_reuse_save WHERE charId=?";
338 private static final String DELETE_ITEM_REUSE_SAVE = "DELETE FROM character_item_reuse_save WHERE charId=?";
339
340 // Character Character SQL String Definitions:
341 private static final String INSERT_CHARACTER = "INSERT INTO characters (account_name,charId,char_name,level,maxHp,curHp,maxCp,curCp,maxMp,curMp,face,hairStyle,hairColor,sex,exp,sp,karma,fame,pvpkills,pkkills,clanid,race,classid,deletetime,cancraft,title,title_color,accesslevel,online,isin7sdungeon,clan_privs,wantspeace,base_class,newbie,nobless,power_grade,createDate) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
342 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=?,fame=?,pvpkills=?,pkkills=?,clanid=?,race=?,classid=?,deletetime=?,title=?,title_color=?,accesslevel=?,online=?,isin7sdungeon=?,clan_privs=?,wantspeace=?,base_class=?,onlinetime=?,punish_level=?,punish_timer=?,newbie=?,nobless=?,power_grade=?,subpledge=?,lvl_joined_academy=?,apprentice=?,sponsor=?,varka_ketra_ally=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=?,bookmarkslot=?,vitality_points=?,pccafe_points=?,language=?,game_points=?,hitman_target=? WHERE charId=?";
343 private static final String RESTORE_CHARACTER = "SELECT account_name, charId, char_name, level, maxHp, curHp, maxCp, curCp, maxMp, curMp, face, hairStyle, hairColor, sex, heading, x, y, z, exp, expBeforeDeath, sp, karma, fame, pvpkills, pkkills, clanid, race, classid, deletetime, cancraft, title, title_color, accesslevel, online, char_slot, lastAccess, clan_privs, wantspeace, base_class, onlinetime, isin7sdungeon, punish_level, punish_timer, newbie, nobless, power_grade, subpledge, lvl_joined_academy, apprentice, sponsor, varka_ketra_ally,clan_join_expiry_time,clan_create_expiry_time,death_penalty_level,bookmarkslot,vitality_points,pccafe_points,createDate,language,game_points,hitman_target FROM characters WHERE charId=?";
344
345 // Character Teleport Bookmark:
346 private static final String INSERT_TP_BOOKMARK = "INSERT INTO character_tpbookmark (charId,Id,x,y,z,icon,tag,name) values (?,?,?,?,?,?,?,?)";
347 private static final String UPDATE_TP_BOOKMARK = "UPDATE character_tpbookmark SET icon=?,tag=?,name=? where charId=? AND Id=?";
348 private static final String RESTORE_TP_BOOKMARK = "SELECT Id,x,y,z,icon,tag,name FROM character_tpbookmark WHERE charId=?";
349 private static final String DELETE_TP_BOOKMARK = "DELETE FROM character_tpbookmark WHERE charId=? AND Id=?";
350
351 // Character Subclass SQL String Definitions:
352 private static final String RESTORE_CHAR_SUBCLASSES = "SELECT class_id,exp,sp,level,class_index FROM character_subclasses WHERE charId=? ORDER BY class_index ASC";
353 private static final String ADD_CHAR_SUBCLASS = "INSERT INTO character_subclasses (charId,class_id,exp,sp,level,class_index) VALUES (?,?,?,?,?,?)";
354 private static final String UPDATE_CHAR_SUBCLASS = "UPDATE character_subclasses SET exp=?,sp=?,level=?,class_id=? WHERE charId=? AND class_index =?";
355 private static final String DELETE_CHAR_SUBCLASS = "DELETE FROM character_subclasses WHERE charId=? AND class_index=?";
356
357 // Character Henna SQL String Definitions:
358 private static final String RESTORE_CHAR_HENNAS = "SELECT slot,symbol_id FROM character_hennas WHERE charId=? AND class_index=?";
359 private static final String ADD_CHAR_HENNA = "INSERT INTO character_hennas (charId,symbol_id,slot,class_index) VALUES (?,?,?,?)";
360 private static final String DELETE_CHAR_HENNA = "DELETE FROM character_hennas WHERE charId=? AND slot=? AND class_index=?";
361 private static final String DELETE_CHAR_HENNAS = "DELETE FROM character_hennas WHERE charId=? AND class_index=?";
362
363 // Character Shortcut SQL String Definitions:
364 private static final String DELETE_CHAR_SHORTCUTS = "DELETE FROM character_shortcuts WHERE charId=? AND class_index=?";
365
366 // Character Transformation SQL String Definitions:
367 private static final String SELECT_CHAR_TRANSFORM = "SELECT transform_id FROM characters WHERE charId=?";
368 private static final String UPDATE_CHAR_TRANSFORM = "UPDATE characters SET transform_id=? WHERE charId=?";
369
370 // Character zone restart time SQL String Definitions - L2Master mod
371 private static final String DELETE_ZONE_RESTART_LIMIT = "DELETE FROM character_norestart_zone_time WHERE charId = ?";
372 private static final String LOAD_ZONE_RESTART_LIMIT = "SELECT time_limit FROM character_norestart_zone_time WHERE charId = ?";
373 private static final String UPDATE_ZONE_RESTART_LIMIT = "REPLACE INTO character_norestart_zone_time (charId, time_limit) VALUES (?,?)";
374
375 public static final int REQUEST_TIMEOUT = 15;
376 public static final int STORE_PRIVATE_NONE = 0;
377 public static final int STORE_PRIVATE_SELL = 1;
378 public static final int STORE_PRIVATE_BUY = 3;
379 public static final int STORE_PRIVATE_MANUFACTURE = 5;
380 public static final int STORE_PRIVATE_PACKAGE_SELL = 8;
381 private int _pcBangPoints = 0;
382
383 public static FastList<PlayerDespawnListener> despawnListeners = new FastList<PlayerDespawnListener>().shared();
384 public static FastList<HennaListener> hennaListeners = new FastList<HennaListener>().shared();
385 public FastList<EquipmentListener> equipmentListeners = new FastList<EquipmentListener>().shared();
386 public static FastList<EquipmentListener> globalEquipmentListeners = new FastList<EquipmentListener>().shared();
387 public FastList<TransformListener> transformListeners = new FastList<TransformListener>().shared();
388 public FastList<ProfessionChangeListener> professionChangeListeners = new FastList<ProfessionChangeListener>().shared();
389 public static FastList<ProfessionChangeListener> globalProfessionChangeListeners = new FastList<ProfessionChangeListener>().shared();
390
391 public class AIAccessor extends L2Character.AIAccessor
392 {
393 protected AIAccessor()
394 {
395
396 }
397
398 public L2PcInstance getPlayer()
399 {
400 return L2PcInstance.this;
401 }
402
403 public void doPickupItem(L2Object object)
404 {
405 L2PcInstance.this.doPickupItem(object);
406 }
407
408 public void doInteract(L2Character target)
409 {
410 L2PcInstance.this.doInteract(target);
411 }
412
413 @Override
414 public void doAttack(L2Character target)
415 {
416 super.doAttack(target);
417
418 // cancel the recent fake-death protection instantly if the player attacks or casts spells
419 getPlayer().setRecentFakeDeath(false);
420 }
421
422 @Override
423 public void doCast(L2Skill skill)
424 {
425 super.doCast(skill);
426
427 // cancel the recent fake-death protection instantly if the player attacks or casts spells
428 getPlayer().setRecentFakeDeath(false);
429 }
430 }
431
432 private L2GameClient _client;
433
434 private String _accountName;
435 private long _deleteTimer;
436 private Calendar _createDate = Calendar.getInstance();
437
438 private String _lang = null;
439 private String _htmlPrefix = null;
440
441 private volatile boolean _isOnline = false;
442 private long _onlineTime;
443 private long _onlineBeginTime;
444 private long _lastAccess;
445 private long _uptime;
446 private long _zoneRestartLimitTime = 0;
447
448 private final ReentrantLock _subclassLock = new ReentrantLock();
449 protected int _baseClass;
450 protected int _activeClass;
451 protected int _classIndex = 0;
452
453 /** data for mounted pets */
454 private int _controlItemId;
455 private L2PetData _data;
456 private L2PetLevelData _leveldata;
457 private int _curFeed;
458 protected Future<?> _mountFeedTask;
459 private ScheduledFuture<?> _dismountTask;
460 private boolean _petItems = false;
461
462 /** The list of sub-classes this character has. */
463 private Map<Integer, SubClass> _subClasses;
464
465 private PcAppearance _appearance;
466
467 /** The Identifier of the L2PcInstance */
468 @Deprecated
469 private int _charId = 0x00030b7a;
470
471 /** The Experience of the L2PcInstance before the last Death Penalty */
472 private long _expBeforeDeath;
473
474 /** The Karma of the L2PcInstance (if higher than 0, the name of the L2PcInstance appears in red) */
475 private int _karma;
476
477 /** The number of player killed during a PvP (the player killed was PvP Flagged) */
478 private int _pvpKills;
479
480 /** The PK counter of the L2PcInstance (= Number of non PvP Flagged player killed) */
481 private int _pkKills;
482
483 /** The player's bot punishment */
484 private BotPunish _botPunish = null;
485 public L2Account _account = null;
486
487 /** The PvP Flag state of the L2PcInstance (0=White, 1=Purple) */
488 private byte _pvpFlag;
489
490 /** The Fame of this L2PcInstance */
491 private int _fame;
492 private ScheduledFuture<?> _fameTask;
493
494 /** Vitality recovery task */
495 private ScheduledFuture<?> _vitalityTask;
496
497 private volatile ScheduledFuture<?> _teleportWatchdog;
498
499 /** The Siege state of the L2PcInstance */
500 private byte _siegeState = 0;
501
502 /** The id of castle/fort which the L2PcInstance is registered for siege */
503 private int _siegeSide = 0;
504
505 private int _curWeightPenalty = 0;
506
507 private int _lastCompassZone; // the last compass zone update send to the client
508
509 private boolean _isIn7sDungeon = false;
510
511 private final L2ContactList _contactList = new L2ContactList(this);
512
513 private int _bookmarkslot = 0; // The Teleport Bookmark Slot
514
515 private List<TeleportBookmark> tpbookmark = new FastList<>();
516
517 private PunishLevel _punishLevel = PunishLevel.NONE;
518 private long _punishTimer = 0;
519 private ScheduledFuture<?> _punishTask;
520
521 private boolean _canFeed;
522 private int _eventEffectId = 0;
523 private boolean _isInSiege;
524 private boolean _isInHideoutSiege = false;
525
526 public enum PunishLevel
527 {
528 NONE(0, ""),
529 CHAT(1, "chat banned"),
530 JAIL(2, "jailed"),
531 CHAR(3, "banned"),
532 ACC(4, "banned");
533
534 private final int punValue;
535 private final String punString;
536
537 PunishLevel(int value, String string)
538 {
539 punValue = value;
540 punString = string;
541 }
542
543 public int value()
544 {
545 return punValue;
546 }
547
548 public String string()
549 {
550 return punString;
551 }
552 }
553
554 /** Olympiad */
555 private boolean _inOlympiadMode = false;
556 private boolean _OlympiadStart = false;
557 private int _olympiadGameId = -1;
558 private int _olympiadSide = -1;
559 public int olyBuff = 0;
560
561 /** Duel */
562 private boolean _isInDuel = false;
563 private int _duelState = Duel.DUELSTATE_NODUEL;
564 private int _duelId = 0;
565 private SystemMessageId _noDuelReason = SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL;
566
567 /** Boat and AirShip */
568 private L2Vehicle _vehicle = null;
569 private Point3D _inVehiclePosition;
570
571 public ScheduledFuture<?> _taskforfish;
572 private int _mountType;
573 private int _mountNpcId;
574 private int _mountLevel;
575 /** Store object used to summon the strider you are mounting **/
576 private int _mountObjectID = 0;
577
578 public int _telemode = 0;
579
580 private boolean _inCrystallize;
581 private boolean _inCraftMode;
582
583 private long _offlineShopStart = 0;
584
585 private L2Transformation _transformation;
586 private int _transformationId = 0;
587
588 /** The table containing all L2RecipeList of the L2PcInstance */
589 private final Map<Integer, L2RecipeList> _dwarvenRecipeBook = new FastMap<>();
590 private final Map<Integer, L2RecipeList> _commonRecipeBook = new FastMap<>();
591
592 /** Premium Items */
593 private final Map<Integer, L2PremiumItem> _premiumItems = new FastMap<>();
594
595 /** True if the L2PcInstance is sitting */
596 private boolean _waitTypeSitting;
597
598 /** Location before entering Observer Mode */
599 private int _lastX;
600 private int _lastY;
601 private int _lastZ;
602 private boolean _observerMode = false;
603
604 /** Stored from last ValidatePosition **/
605 private final Point3D _lastServerPosition = new Point3D(0, 0, 0);
606
607 /** The number of recommendation obtained by the L2PcInstance */
608 private int _recomHave; // how much I was recommended by others
609 /** The number of recommendation that the L2PcInstance can give */
610 private int _recomLeft; // how many recommendations I can give to others
611 /** Recommendation Bonus task **/
612 private ScheduledFuture<?> _recoBonusTask;
613 private boolean _isRecoBonusActive = false;
614 private int _recoBonusMode = 0;
615 /** Recommendation task **/
616 private ScheduledFuture<?> _recoGiveTask;
617 /** Recommendation Two Hours bonus **/
618 protected boolean _recoTwoHoursGiven = false;
619
620 private final PcInventory _inventory = new PcInventory(this);
621 private final PcFreight _freight = new PcFreight(this);
622 private PcWarehouse _warehouse;
623 private PcRefund _refund;
624
625 /** The Private Store type of the L2PcInstance (STORE_PRIVATE_NONE=0, STORE_PRIVATE_SELL=1, sellmanage=2, STORE_PRIVATE_BUY=3, buymanage=4, STORE_PRIVATE_MANUFACTURE=5) */
626 private int _privatestore;
627
628 private TradeList _activeTradeList;
629 private ItemContainer _activeWarehouse;
630 private L2ManufactureList _createList;
631 private TradeList _sellList;
632 private TradeList _buyList;
633
634 // Multisell
635 private PreparedListContainer _currentMultiSell = null;
636
637 /** Bitmask used to keep track of one-time/newbie quest rewards */
638 private int _newbie;
639
640 private boolean _noble = false;
641 private boolean _hero = false;
642
643 /** The L2FolkInstance corresponding to the last Folk wich one the player talked. */
644 private L2Npc _lastFolkNpc = null;
645
646 /** Last NPC Id talked on a quest */
647 private int _questNpcObject = 0;
648
649 /** The table containing all Quests began by the L2PcInstance */
650 private final Map<String, QuestState> _quests = new FastMap<>();
651
652 /** The list containing all shortCuts of this L2PcInstance */
653 private final ShortCuts _shortCuts = new ShortCuts(this);
654
655 /**
656 * The list containing all macros of this L2PcInstance.
657 */
658 private final MacroList _macros = new MacroList(this);
659
660 private final List<L2PcInstance> _snoopListener = new FastList<>();
661 private final List<L2PcInstance> _snoopedPlayer = new FastList<>();
662
663 // hennas
664 private final L2Henna[] _henna = new L2Henna[3];
665 private int _hennaSTR;
666 private int _hennaINT;
667 private int _hennaDEX;
668 private int _hennaMEN;
669 private int _hennaWIT;
670 private int _hennaCON;
671
672 /** The L2Summon of the L2PcInstance */
673 private L2Summon _summon = null;
674 /** The L2Decoy of the L2PcInstance */
675 private L2Decoy _decoy = null;
676 /** The L2Trap of the L2PcInstance */
677 private L2Trap _trap = null;
678 /** The L2Agathion of the L2PcInstance */
679 private int _agathionId = 0;
680 // apparently, a L2PcInstance CAN have both a summon AND a tamed beast at the same time!!
681 // after Freya players can control more than one tamed beast
682 private List<L2TamedBeastInstance> _tamedBeast = null;
683
684 private boolean _minimapAllowed = false;
685
686 // client radar
687 // TODO: This needs to be better integrated and saved/loaded
688 private L2Radar _radar;
689
690 // Party matching
691 // private int _partymatching = 0;
692 private int _partyroom = 0;
693 // private int _partywait = 0;
694
695 // Clan related attributes
696 /** The Clan Identifier of the L2PcInstance */
697 private int _clanId;
698
699 /** The Clan object of the L2PcInstance */
700 private L2Clan _clan;
701
702 /** Apprentice and Sponsor IDs */
703 private int _apprentice = 0;
704 private int _sponsor = 0;
705
706 private long _clanJoinExpiryTime;
707 private long _clanCreateExpiryTime;
708
709 private int _powerGrade = 0;
710 private int _clanPrivileges = 0;
711
712 /** L2PcInstance's pledge class (knight, Baron, etc.) */
713 private int _pledgeClass = 0;
714 private int _pledgeType = 0;
715
716 /** Level at which the player joined the clan as an academy member */
717 private int _lvlJoinedAcademy = 0;
718
719 private int _wantsPeace = 0;
720
721 // Death Penalty Buff Level
722 private int _deathPenaltyBuffLevel = 0;
723
724 // charges
725 private final AtomicInteger _charges = new AtomicInteger();
726 private ScheduledFuture<?> _chargeTask = null;
727
728 // Absorbed Souls
729 private int _souls = 0;
730 private ScheduledFuture<?> _soulTask = null;
731
732 // WorldPosition used by TARGET_SIGNET_GROUND
733 private Point3D _currentSkillWorldPosition;
734
735 private L2AccessLevel _accessLevel;
736
737 private boolean _addXpSp = true;
738
739 private boolean _messageRefusal = false; // message refusal mode
740
741 private boolean _silenceMode = false; // silence mode
742 private final TIntArrayList _silenceModeExcluded = new TIntArrayList(); // silence mode
743 private boolean _dietMode = false; // ignore weight penalty
744 private boolean _tradeRefusal = false; // Trade refusal
745 private boolean _exchangeRefusal = false; // Exchange refusal
746
747 private L2Party _party;
748
749 // this is needed to find the inviting player for Party response
750 // there can only be one active party request at once
751 private L2PcInstance _activeRequester;
752 private long _requestExpireTime = 0;
753 private final L2Request _request = new L2Request(this);
754 private L2ItemInstance _arrowItem;
755 private L2ItemInstance _boltItem;
756
757 // Used for protection after teleport
758 private long _protectEndTime = 0;
759
760 public boolean isSpawnProtected()
761 {
762 return _protectEndTime > GameTimeController.getGameTicks();
763 }
764
765 private long _teleportProtectEndTime = 0;
766
767 public boolean isTeleportProtected()
768 {
769 return _teleportProtectEndTime > GameTimeController.getGameTicks();
770 }
771
772 // protects a char from agro mobs when getting up from fake death
773 private long _recentFakeDeathEndTime = 0;
774 private boolean _isFakeDeath;
775
776 /** The fists L2Weapon of the L2PcInstance (used when no weapon is equiped) */
777 private L2Weapon _fistsWeaponItem;
778
779 private final Map<Integer, String> _chars = new FastMap<>();
780
781 // private byte _updateKnownCounter = 0;
782
783 private int _expertiseArmorPenalty = 0;
784 private int _expertiseWeaponPenalty = 0;
785 private int _expertisePenaltyBonus = 0;
786
787 private boolean _isEnchanting = false;
788 private L2ItemInstance _activeEnchantItem = null;
789 private L2ItemInstance _activeEnchantSupportItem = null;
790 private L2ItemInstance _activeEnchantAttrItem = null;
791 private long _activeEnchantTimestamp = 0;
792
793 protected boolean _inventoryDisable = false;
794
795 private final FastMap<Integer, L2CubicInstance> _cubics = new FastMap<>();
796
797 /** Active shots. */
798 protected FastSet<Integer> _activeSoulShots = new FastSet<Integer>().shared();
799
800 public final ReentrantLock soulShotLock = new ReentrantLock();
801
802 /** Event parameters */
803 private PlayerEventStatus eventStatus = null;
804
805 private byte _handysBlockCheckerEventArena = -1;
806
807 /** new loto ticket **/
808 private final int _loto[] = new int[5];
809 // public static int _loto_nums[] = {0,1,2,3,4,5,6,7,8,9,};
810 /** new race ticket **/
811 private final int _race[] = new int[2];
812
813 private final BlockList _blockList = new BlockList(this);
814
815 /**
816 * lvl of alliance with ketra orcs or varka silenos, used in quests and aggro checks [-5,-1] varka, 0 neutral, [1,5] ketra
817 */
818 private int _alliedVarkaKetra = 0;
819
820 private L2Fishing _fishCombat;
821 private boolean _fishing = false;
822 private int _fishx = 0;
823 private int _fishy = 0;
824 private int _fishz = 0;
825
826 private short points = 0;
827
828 private int[] _transformAllowedSkills = {};
829 private ScheduledFuture<?> _taskRentPet;
830 private ScheduledFuture<?> _taskWater;
831
832 /** Bypass validations */
833 private final List<String> _validBypass = new L2FastList<>(true);
834 private final List<String> _validBypass2 = new L2FastList<>(true);
835
836 private Forum _forumMail;
837 private Forum _forumMemo;
838
839 /** Current skill in use. Note that L2Character has _lastSkillCast, but this has the button presses */
840 private SkillDat _currentSkill;
841 private SkillDat _currentPetSkill;
842
843 /** Skills queued because a skill is already in progress */
844 private SkillDat _queuedSkill;
845
846 private int _cursedWeaponEquippedId = 0;
847 private boolean _combatFlagEquippedId = false;
848
849 private int _reviveRequested = 0;
850 private double _revivePower = 0;
851 private boolean _revivePet = false;
852
853 private double _cpUpdateIncCheck = .0;
854 private double _cpUpdateDecCheck = .0;
855 private double _cpUpdateInterval = .0;
856 private double _mpUpdateIncCheck = .0;
857 private double _mpUpdateDecCheck = .0;
858 private double _mpUpdateInterval = .0;
859
860 // not used any more
861 // private boolean _isRidingFenrirWolf = false;
862 // private boolean _isRidingWFenrirWolf = false;
863 // private boolean _isRidingGreatSnowWolf = false;
864
865 private boolean _isRidingStrider = false;
866 private boolean _isFlyingMounted = false;
867
868 /** Char Coords from Client */
869 private int _clientX;
870 private int _clientY;
871 private int _clientZ;
872 private int _clientHeading;
873
874 // during fall validations will be disabled for 10 ms.
875 private static final int FALLING_VALIDATION_DELAY = 10000;
876 private volatile long _fallingTimestamp = 0;
877
878 private int _multiSocialTarget = 0;
879 private int _multiSociaAction = 0;
880
881 private long _gamePoints;
882
883 private int _movieId = 0;
884
885 private String _adminConfirmCmd = null;
886
887 private DialogId _currentDialogId = DialogId.NONE;
888
889 private volatile long _lastItemAuctionInfoRequest = 0;
890
891 private Future<?> _PvPRegTask;
892
893 private long _pvpFlagLasts;
894
895 private long _notMoveUntil = 0;
896
897 public void setPvpFlagLasts(long time)
898 {
899 _pvpFlagLasts = time;
900 }
901
902 public long getPvpFlagLasts()
903 {
904 return _pvpFlagLasts;
905 }
906
907 public void startPvPFlag()
908 {
909 updatePvPFlag(1);
910
911 if (_PvPRegTask == null)
912 {
913 _PvPRegTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new PvPFlag(), 1000, 1000);
914 }
915 }
916
917 public void stopPvpRegTask()
918 {
919 if (_PvPRegTask != null)
920 {
921 _PvPRegTask.cancel(true);
922 _PvPRegTask = null;
923 }
924 }
925
926 public void stopPvPFlag()
927 {
928 stopPvpRegTask();
929
930 updatePvPFlag(0);
931
932 _PvPRegTask = null;
933 }
934
935 /** Task lauching the function stopPvPFlag() */
936 private class PvPFlag implements Runnable
937 {
938 public PvPFlag()
939 {
940
941 }
942
943 @Override
944 public void run()
945 {
946 try
947 {
948 if (System.currentTimeMillis() > getPvpFlagLasts())
949 {
950 stopPvPFlag();
951 }
952 else if (System.currentTimeMillis() > (getPvpFlagLasts() - 20000))
953 {
954 updatePvPFlag(2);
955 }
956 else
957 {
958 updatePvPFlag(1);
959 // Start a new PvP timer check
960 // checkPvPFlag();
961 }
962 }
963 catch (Exception e)
964 {
965 _log.log(Level.WARNING, "error in pvp flag task:", e);
966 }
967 }
968 }
969
970 // Character UI
971 private L2UIKeysSettings _uiKeySettings;
972
973 /** Herbs Task Time **/
974 private int _herbstask = 0;
975
976 /** Task for Herbs */
977 private class HerbTask implements Runnable
978 {
979 private final String _process;
980 private final int _itemId;
981 private final long _count;
982 private final L2Object _reference;
983 private final boolean _sendMessage;
984
985 HerbTask(String process, int itemId, long count, L2Object reference, boolean sendMessage)
986 {
987 _process = process;
988 _itemId = itemId;
989 _count = count;
990 _reference = reference;
991 _sendMessage = sendMessage;
992 }
993
994 @Override
995 public void run()
996 {
997 try
998 {
999 addItem(_process, _itemId, _count, _reference, _sendMessage);
1000 }
1001 catch (Exception e)
1002 {
1003 _log.log(Level.WARNING, "", e);
1004 }
1005 }
1006 }
1007
1008 /** ShortBuff clearing Task */
1009 ScheduledFuture<?> _shortBuffTask = null;
1010
1011 protected class ShortBuffTask implements Runnable
1012 {
1013 @Override
1014 public void run()
1015 {
1016 if (L2PcInstance.this == null)
1017 {
1018 return;
1019 }
1020
1021 L2PcInstance.this.sendPacket(new ShortBuffStatusUpdate(0, 0, 0));
1022 setShortBuffTaskSkillId(0);
1023 }
1024 }
1025
1026 // L2JMOD Wedding
1027 private boolean _married = false;
1028 private int _partnerId = 0;
1029 private int _coupleId = 0;
1030 private boolean _engagerequest = false;
1031 private int _engageid = 0;
1032 private boolean _marryrequest = false;
1033 private boolean _marryaccepted = false;
1034
1035 /** Skill casting information (used to queue when several skills are cast in a short time) **/
1036 public static class SkillDat
1037 {
1038 private final L2Skill _skill;
1039 private final boolean _ctrlPressed;
1040 private final boolean _shiftPressed;
1041
1042 protected SkillDat(L2Skill skill, boolean ctrlPressed, boolean shiftPressed)
1043 {
1044 _skill = skill;
1045 _ctrlPressed = ctrlPressed;
1046 _shiftPressed = shiftPressed;
1047 }
1048
1049 public boolean isCtrlPressed()
1050 {
1051 return _ctrlPressed;
1052 }
1053
1054 public boolean isShiftPressed()
1055 {
1056 return _shiftPressed;
1057 }
1058
1059 public L2Skill getSkill()
1060 {
1061 return _skill;
1062 }
1063
1064 public int getSkillId()
1065 {
1066 return (getSkill() != null) ? getSkill().getId() : -1;
1067 }
1068 }
1069
1070 // summon friend
1071 private final SummonRequest _summonRequest = new SummonRequest();
1072
1073 protected static class SummonRequest
1074 {
1075 private L2PcInstance _target = null;
1076 private L2Skill _skill = null;
1077
1078 public void setTarget(L2PcInstance destination, L2Skill skill)
1079 {
1080 _target = destination;
1081 _skill = skill;
1082 }
1083
1084 public L2PcInstance getTarget()
1085 {
1086 return _target;
1087 }
1088
1089 public L2Skill getSkill()
1090 {
1091 return _skill;
1092 }
1093 }
1094
1095 // open/close gates
1096 private final GatesRequest _gatesRequest = new GatesRequest();
1097
1098 protected static class GatesRequest
1099 {
1100 private L2DoorInstance _target = null;
1101
1102 public void setTarget(L2DoorInstance door)
1103 {
1104 _target = door;
1105 }
1106
1107 public L2DoorInstance getDoor()
1108 {
1109 return _target;
1110 }
1111 }
1112
1113 // Save responder name for log it
1114 private String _lastPetitionGmName = null;
1115
1116 /**
1117 * Create a new L2PcInstance and add it in the characters table of the database.<br>
1118 * <B><U> Actions</U> :</B>
1119 * <ul>
1120 * <li>Create a new L2PcInstance with an account name</li>
1121 * <li>Set the name, the Hair Style, the Hair Color and the Face type of the L2PcInstance</li>
1122 * <li>Add the player in the characters table of the database</li>
1123 * </ul>
1124 * @param objectId Identifier of the object to initialized
1125 * @param template The L2PcTemplate to apply to the L2PcInstance
1126 * @param accountName The name of the L2PcInstance
1127 * @param name The name of the L2PcInstance
1128 * @param hairStyle The hair style Identifier of the L2PcInstance
1129 * @param hairColor The hair color Identifier of the L2PcInstance
1130 * @param face The face type Identifier of the L2PcInstance
1131 * @param sex
1132 * @return The L2PcInstance added to the database or null
1133 */
1134 public static L2PcInstance create(int objectId, L2PcTemplate template, String accountName, String name, byte hairStyle, byte hairColor, byte face, boolean sex)
1135 {
1136 // Create a new L2PcInstance with an account name
1137 PcAppearance app = new PcAppearance(face, hairColor, hairStyle, sex);
1138 L2PcInstance player = new L2PcInstance(objectId, template, accountName, app);
1139
1140 // Set the name of the L2PcInstance
1141 player.setName(name);
1142
1143 // Set Character's create time
1144 player.setCreateDate(Calendar.getInstance());
1145
1146 // Set the base class ID to that of the actual class ID.
1147 player.setBaseClass(player.getClassId());
1148 // Kept for backwards compatibility.
1149 player.setNewbie(1);
1150 // Add the player in the characters table of the database
1151 boolean ok = player.createDb();
1152
1153 if (!ok)
1154 {
1155 return null;
1156 }
1157
1158 // Give premium to Newbie, if needed
1159 if (Config.NEWBIES_PREMIUM_PERIOD > 0)
1160 {
1161 PremiumTable.addTime(player, TimeConstant.DAY, Config.NEWBIES_PREMIUM_PERIOD);
1162 }
1163
1164 return player;
1165 }
1166
1167 public static L2PcInstance createDummyPlayer(int objectId, String name)
1168 {
1169 // Create a new L2PcInstance with an account name
1170 L2PcInstance player = new L2PcInstance(objectId);
1171 player.setName(name);
1172
1173 return player;
1174 }
1175
1176 public String getAccountName()
1177 {
1178 if (getClient() == null)
1179 {
1180 return getAccountNamePlayer();
1181 }
1182 return getClient().getAccountName();
1183 }
1184
1185 public String getAccountNamePlayer()
1186 {
1187 return _accountName;
1188 }
1189
1190 public Map<Integer, String> getAccountChars()
1191 {
1192 return _chars;
1193 }
1194
1195 public int getRelation(L2PcInstance target)
1196 {
1197 int result = 0;
1198
1199 if (getClan() != null)
1200 {
1201 result |= RelationChanged.RELATION_CLAN_MEMBER;
1202 if (getClan() == target.getClan())
1203 {
1204 result |= RelationChanged.RELATION_CLAN_MATE;
1205 }
1206 if (getAllyId() != 0)
1207 {
1208 result |= RelationChanged.RELATION_ALLY_MEMBER;
1209 }
1210 }
1211 if (isClanLeader())
1212 {
1213 result |= RelationChanged.RELATION_LEADER;
1214 }
1215 if ((getParty() != null) && (getParty() == target.getParty()))
1216 {
1217 result |= RelationChanged.RELATION_HAS_PARTY;
1218 for (int i = 0; i < getParty().getMembers().size(); i++)
1219 {
1220 if (getParty().getMembers().get(i) != this)
1221 {
1222 continue;
1223 }
1224 switch (i)
1225 {
1226 case 0:
1227 result |= RelationChanged.RELATION_PARTYLEADER; // 0x10
1228 break;
1229 case 1:
1230 result |= RelationChanged.RELATION_PARTY4; // 0x8
1231 break;
1232 case 2:
1233 result |= RelationChanged.RELATION_PARTY3 + RelationChanged.RELATION_PARTY2 + RelationChanged.RELATION_PARTY1; // 0x7
1234 break;
1235 case 3:
1236 result |= RelationChanged.RELATION_PARTY3 + RelationChanged.RELATION_PARTY2; // 0x6
1237 break;
1238 case 4:
1239 result |= RelationChanged.RELATION_PARTY3 + RelationChanged.RELATION_PARTY1; // 0x5
1240 break;
1241 case 5:
1242 result |= RelationChanged.RELATION_PARTY3; // 0x4
1243 break;
1244 case 6:
1245 result |= RelationChanged.RELATION_PARTY2 + RelationChanged.RELATION_PARTY1; // 0x3
1246 break;
1247 case 7:
1248 result |= RelationChanged.RELATION_PARTY2; // 0x2
1249 break;
1250 case 8:
1251 result |= RelationChanged.RELATION_PARTY1; // 0x1
1252 break;
1253 }
1254 }
1255 }
1256 if (getSiegeState() != 0)
1257 {
1258 if (TerritoryWarManager.getInstance().getRegisteredTerritoryId(this) != 0)
1259 {
1260 result |= RelationChanged.RELATION_TERRITORY_WAR;
1261 }
1262 else
1263 {
1264 result |= RelationChanged.RELATION_INSIEGE;
1265 if (getSiegeState() != target.getSiegeState())
1266 {
1267 result |= RelationChanged.RELATION_ENEMY;
1268 }
1269 else
1270 {
1271 result |= RelationChanged.RELATION_ALLY;
1272 }
1273 if (getSiegeState() == 1)
1274 {
1275 result |= RelationChanged.RELATION_ATTACKER;
1276 }
1277 }
1278 }
1279 if ((getClan() != null) && (target.getClan() != null))
1280 {
1281 if ((target.getPledgeType() != L2Clan.SUBUNIT_ACADEMY) && (getPledgeType() != L2Clan.SUBUNIT_ACADEMY) && target.getClan().isAtWarWith(getClan().getClanId()))
1282 {
1283 result |= RelationChanged.RELATION_1SIDED_WAR;
1284 if (getClan().isAtWarWith(target.getClan().getClanId()))
1285 {
1286 result |= RelationChanged.RELATION_MUTUAL_WAR;
1287 }
1288 }
1289 }
1290 if (getBlockCheckerArena() != -1)
1291 {
1292 result |= RelationChanged.RELATION_INSIEGE;
1293 HandysBlockCheckerManager.ArenaParticipantsHolder holder = HandysBlockCheckerManager.getInstance().getHolder(getBlockCheckerArena());
1294 if (holder.getPlayerTeam(this) == 0)
1295 {
1296 result |= RelationChanged.RELATION_ENEMY;
1297 }
1298 else
1299 {
1300 result |= RelationChanged.RELATION_ALLY;
1301 }
1302 result |= RelationChanged.RELATION_ATTACKER;
1303 }
1304 return result;
1305 }
1306
1307 /**
1308 * Retrieve a L2PcInstance from the characters table of the database and add it in _allObjects of the L2world (call restore method).<br>
1309 * <B><U> Actions</U> :</B>
1310 * <ul>
1311 * <li>Retrieve the L2PcInstance from the characters table of the database</li>
1312 * <li>Add the L2PcInstance object in _allObjects</li>
1313 * <li>Set the x,y,z position of the L2PcInstance and make it invisible</li>
1314 * <li>Update the overloaded status of the L2PcInstance</li>
1315 * </ul>
1316 * @param objectId Identifier of the object to initialized
1317 * @return The L2PcInstance loaded from the database
1318 */
1319 public static L2PcInstance load(int objectId)
1320 {
1321 return restore(objectId);
1322 }
1323
1324 private void initPcStatusUpdateValues()
1325 {
1326 _cpUpdateInterval = getMaxCp() / 352.0;
1327 _cpUpdateIncCheck = getMaxCp();
1328 _cpUpdateDecCheck = getMaxCp() - _cpUpdateInterval;
1329 _mpUpdateInterval = getMaxMp() / 352.0;
1330 _mpUpdateIncCheck = getMaxMp();
1331 _mpUpdateDecCheck = getMaxMp() - _mpUpdateInterval;
1332 }
1333
1334 /**
1335 * Constructor of L2PcInstance (use L2Character constructor).<br>
1336 * <B><U> Actions</U> :</B>
1337 * <ul>
1338 * <li>Call the L2Character constructor to create an empty _skills slot and copy basic Calculator set to this L2PcInstance</li>
1339 * <li>Set the name of the L2PcInstance</li>
1340 * </ul>
1341 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method SET the level of the L2PcInstance to 1</B></FONT>
1342 * @param objectId Identifier of the object to initialized
1343 * @param template The L2PcTemplate to apply to the L2PcInstance
1344 * @param accountName The name of the account including this L2PcInstance
1345 * @param app
1346 */
1347 private L2PcInstance(int objectId, L2PcTemplate template, String accountName, PcAppearance app)
1348 {
1349 super(objectId, template);
1350 setInstanceType(InstanceType.L2PcInstance);
1351 super.initCharStatusUpdateValues();
1352 initPcStatusUpdateValues();
1353
1354 _accountName = accountName;
1355 app.setOwner(this);
1356 _appearance = app;
1357
1358 // Create an AI
1359 _ai = new L2PlayerAI(new L2PcInstance.AIAccessor());
1360
1361 // Create a L2Radar object
1362 _radar = new L2Radar(this);
1363
1364 startVitalityTask();
1365
1366 _cubics.shared();
1367 }
1368
1369 private L2PcInstance(int objectId)
1370 {
1371 super(objectId, null);
1372 setInstanceType(InstanceType.L2PcInstance);
1373 super.initCharStatusUpdateValues();
1374 initPcStatusUpdateValues();
1375 }
1376
1377 @Override
1378 public final PcKnownList getKnownList()
1379 {
1380 return (PcKnownList) super.getKnownList();
1381 }
1382
1383 @Override
1384 public void initKnownList()
1385 {
1386 setKnownList(new PcKnownList(this));
1387 }
1388
1389 @Override
1390 public final PcStat getStat()
1391 {
1392 return (PcStat) super.getStat();
1393 }
1394
1395 @Override
1396 public void initCharStat()
1397 {
1398 setStat(new PcStat(this));
1399 }
1400
1401 @Override
1402 public final PcStatus getStatus()
1403 {
1404 return (PcStatus) super.getStatus();
1405 }
1406
1407 @Override
1408 public void initCharStatus()
1409 {
1410 setStatus(new PcStatus(this));
1411 }
1412
1413 @Override
1414 public PcPosition getPosition()
1415 {
1416 return (PcPosition) super.getPosition();
1417 }
1418
1419 @Override
1420 public void initPosition()
1421 {
1422 setObjectPosition(new PcPosition(this));
1423 }
1424
1425 public final PcAppearance getAppearance()
1426 {
1427 return _appearance;
1428 }
1429
1430 /**
1431 * @return the base L2PcTemplate link to the L2PcInstance.
1432 */
1433 public final L2PcTemplate getBaseTemplate()
1434 {
1435 return CharTemplateTable.getInstance().getTemplate(_baseClass);
1436 }
1437
1438 /**
1439 * @return the L2PcTemplate link to the L2PcInstance.
1440 */
1441 @Override
1442 public final L2PcTemplate getTemplate()
1443 {
1444 return (L2PcTemplate) super.getTemplate();
1445 }
1446
1447 /**
1448 * @param newclass
1449 */
1450 public void setTemplate(ClassId newclass)
1451 {
1452 super.setTemplate(CharTemplateTable.getInstance().getTemplate(newclass));
1453 }
1454
1455 /**
1456 * Return the AI of the L2PcInstance (create it if necessary).
1457 */
1458 @Override
1459 public L2CharacterAI getAI()
1460 {
1461 L2CharacterAI ai = _ai; // copy handle
1462 if (ai == null)
1463 {
1464 synchronized (this)
1465 {
1466 if (_ai == null)
1467 {
1468 _ai = new L2PlayerAI(new L2PcInstance.AIAccessor());
1469 }
1470 return _ai;
1471 }
1472 }
1473 return ai;
1474 }
1475
1476 /** Return the Level of the L2PcInstance. */
1477 @Override
1478 public final int getLevel()
1479 {
1480 return getStat().getLevel();
1481 }
1482
1483 /**
1484 * @return the _newbie rewards state of the L2PcInstance.
1485 */
1486 public int getNewbie()
1487 {
1488 return _newbie;
1489 }
1490
1491 /**
1492 * Set the _newbie rewards state of the L2PcInstance.
1493 * @param newbieRewards The Identifier of the _newbie state
1494 */
1495 public void setNewbie(int newbieRewards)
1496 {
1497 _newbie = newbieRewards;
1498 }
1499
1500 public void setBaseClass(int baseClass)
1501 {
1502 _baseClass = baseClass;
1503 }
1504
1505 public void setBaseClass(ClassId classId)
1506 {
1507 _baseClass = classId.ordinal();
1508 }
1509
1510 public boolean isInStoreMode()
1511 {
1512 return (getPrivateStoreType() > L2PcInstance.STORE_PRIVATE_NONE);
1513 }
1514
1515 // public boolean isInCraftMode() { return (getPrivateStoreType() == STORE_PRIVATE_MANUFACTURE); }
1516
1517 public boolean isInCraftMode()
1518 {
1519 return _inCraftMode;
1520 }
1521
1522 public void isInCraftMode(boolean b)
1523 {
1524 _inCraftMode = b;
1525 }
1526
1527 /**
1528 * Manage Logout Task:
1529 * <ul>
1530 * <li>Remove player from world</li>
1531 * <li>Save player data into DB</li>
1532 * </ul>
1533 */
1534 public void logout()
1535 {
1536 for (PlayerDespawnListener listener : despawnListeners)
1537 {
1538 listener.onDespawn(this);
1539 }
1540 logout(true);
1541 }
1542
1543 /**
1544 * Manage Logout Task:
1545 * <ul>
1546 * <li>Remove player from world</li>
1547 * <li>Save player data into DB</li>
1548 * </ul>
1549 * @param closeClient
1550 */
1551 public void logout(boolean closeClient)
1552 {
1553 try
1554 {
1555 closeNetConnection(closeClient);
1556 }
1557 catch (Exception e)
1558 {
1559 _log.log(Level.WARNING, "Exception on logout(): " + e.getMessage(), e);
1560 }
1561 }
1562
1563 /**
1564 * @return a table containing all Common L2RecipeList of the L2PcInstance.
1565 */
1566 public L2RecipeList[] getCommonRecipeBook()
1567 {
1568 return _commonRecipeBook.values().toArray(new L2RecipeList[_commonRecipeBook.values().size()]);
1569 }
1570
1571 /**
1572 * @return a table containing all Dwarf L2RecipeList of the L2PcInstance.
1573 */
1574 public L2RecipeList[] getDwarvenRecipeBook()
1575 {
1576 return _dwarvenRecipeBook.values().toArray(new L2RecipeList[_dwarvenRecipeBook.values().size()]);
1577 }
1578
1579 /**
1580 * Add a new L2RecipList to the table _commonrecipebook containing all L2RecipeList of the L2PcInstance
1581 * @param recipe The L2RecipeList to add to the _recipebook
1582 * @param saveToDb
1583 */
1584 public void registerCommonRecipeList(L2RecipeList recipe, boolean saveToDb)
1585 {
1586 _commonRecipeBook.put(recipe.getId(), recipe);
1587
1588 if (saveToDb)
1589 {
1590 insertNewRecipeData(recipe.getId(), false);
1591 }
1592 }
1593
1594 /**
1595 * Add a new L2RecipList to the table _recipebook containing all L2RecipeList of the L2PcInstance
1596 * @param recipe The L2RecipeList to add to the _recipebook
1597 * @param saveToDb
1598 */
1599 public void registerDwarvenRecipeList(L2RecipeList recipe, boolean saveToDb)
1600 {
1601 _dwarvenRecipeBook.put(recipe.getId(), recipe);
1602
1603 if (saveToDb)
1604 {
1605 insertNewRecipeData(recipe.getId(), true);
1606 }
1607 }
1608
1609 /**
1610 * @param recipeId The Identifier of the L2RecipeList to check in the player's recipe books
1611 * @return {@code true}if player has the recipe on Common or Dwarven Recipe book else returns {@code false}
1612 */
1613 public boolean hasRecipeList(int recipeId)
1614 {
1615 if (_dwarvenRecipeBook.containsKey(recipeId))
1616 {
1617 return true;
1618 }
1619 else if (_commonRecipeBook.containsKey(recipeId))
1620 {
1621 return true;
1622 }
1623 else
1624 {
1625 return false;
1626 }
1627 }
1628
1629 /**
1630 * Tries to remove a L2RecipList from the table _DwarvenRecipeBook or from table _CommonRecipeBook, those table contain all L2RecipeList of the L2PcInstance
1631 * @param recipeId The Identifier of the L2RecipeList to remove from the _recipebook
1632 */
1633 public void unregisterRecipeList(int recipeId)
1634 {
1635 if (_dwarvenRecipeBook.remove(recipeId) != null)
1636 {
1637 deleteRecipeData(recipeId, true);
1638 }
1639 else if (_commonRecipeBook.remove(recipeId) != null)
1640 {
1641 deleteRecipeData(recipeId, false);
1642 }
1643 else
1644 {
1645 _log.warning("Attempted to remove unknown RecipeList: " + recipeId);
1646 }
1647
1648 L2ShortCut[] allShortCuts = getAllShortCuts();
1649
1650 for (L2ShortCut sc : allShortCuts)
1651 {
1652 if ((sc != null) && (sc.getId() == recipeId) && (sc.getType() == L2ShortCut.TYPE_RECIPE))
1653 {
1654 deleteShortCut(sc.getSlot(), sc.getPage());
1655 }
1656 }
1657 }
1658
1659 private void insertNewRecipeData(int recipeId, boolean isDwarf)
1660 {
1661 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
1662 PreparedStatement statement = con.prepareStatement("INSERT INTO character_recipebook (charId, id, classIndex, type) values(?,?,?,?)"))
1663 {
1664 statement.setInt(1, getObjectId());
1665 statement.setInt(2, recipeId);
1666 statement.setInt(3, isDwarf ? _classIndex : 0);
1667 statement.setInt(4, isDwarf ? 1 : 0);
1668 statement.execute();
1669 }
1670 catch (SQLException e)
1671 {
1672 if (_log.isLoggable(Level.SEVERE))
1673 {
1674 _log.log(Level.SEVERE, "SQL exception while inserting recipe: " + recipeId + " from character " + getObjectId(), e);
1675 }
1676 }
1677 }
1678
1679 private void deleteRecipeData(int recipeId, boolean isDwarf)
1680 {
1681 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
1682 PreparedStatement statement = con.prepareStatement("DELETE FROM character_recipebook WHERE charId=? AND id=? AND classIndex=?"))
1683 {
1684 statement.setInt(1, getObjectId());
1685 statement.setInt(2, recipeId);
1686 statement.setInt(3, isDwarf ? _classIndex : 0);
1687 statement.execute();
1688 }
1689 catch (SQLException e)
1690 {
1691 if (_log.isLoggable(Level.SEVERE))
1692 {
1693 _log.log(Level.SEVERE, "SQL exception while deleting recipe: " + recipeId + " from character " + getObjectId(), e);
1694 }
1695 }
1696 }
1697
1698 /**
1699 * @return the Id for the last talked quest NPC.
1700 */
1701 public int getLastQuestNpcObject()
1702 {
1703 return _questNpcObject;
1704 }
1705
1706 public void setLastQuestNpcObject(int npcId)
1707 {
1708 _questNpcObject = npcId;
1709 }
1710
1711 /**
1712 * @param quest The name of the quest
1713 * @return the QuestState object corresponding to the quest name.
1714 */
1715 public QuestState getQuestState(String quest)
1716 {
1717 return _quests.get(quest);
1718 }
1719
1720 /**
1721 * Add a QuestState to the table _quest containing all quests began by the L2PcInstance.
1722 * @param qs The QuestState to add to _quest
1723 */
1724 public void setQuestState(QuestState qs)
1725 {
1726 _quests.put(qs.getQuestName(), qs);
1727 }
1728
1729 /**
1730 * Remove a QuestState from the table _quest containing all quests began by the L2PcInstance.
1731 * @param quest The name of the quest
1732 */
1733 public void delQuestState(String quest)
1734 {
1735 _quests.remove(quest);
1736 }
1737
1738 private QuestState[] addToQuestStateArray(QuestState[] questStateArray, QuestState state)
1739 {
1740 final int len = questStateArray.length;
1741 QuestState[] tmp = new QuestState[len + 1];
1742 System.arraycopy(questStateArray, 0, tmp, 0, len);
1743 tmp[len] = state;
1744 return tmp;
1745 }
1746
1747 /**
1748 * @return a table containing all Quest in progress from the table _quests.
1749 */
1750 public Quest[] getAllActiveQuests()
1751 {
1752 FastList<Quest> quests = new FastList<>();
1753
1754 for (QuestState qs : _quests.values())
1755 {
1756 if (qs == null)
1757 {
1758 continue;
1759 }
1760
1761 if (qs.getQuest() == null)
1762 {
1763 continue;
1764 }
1765
1766 int questId = qs.getQuest().getQuestIntId();
1767 if ((questId > 19999) || (questId < 1))
1768 {
1769 continue;
1770 }
1771
1772 if (!qs.isStarted() && !Config.DEVELOPER)
1773 {
1774 continue;
1775 }
1776
1777 quests.add(qs.getQuest());
1778 }
1779
1780 return quests.toArray(new Quest[quests.size()]);
1781 }
1782
1783 /**
1784 * @param npc
1785 * @return a table containing all QuestState to modify after a L2Attackable killing.
1786 */
1787 public QuestState[] getQuestsForAttacks(L2Npc npc)
1788 {
1789 // Create a QuestState table that will contain all QuestState to modify
1790 QuestState[] states = null;
1791
1792 // Go through the QuestState of the L2PcInstance quests
1793 for (Quest quest : npc.getTemplate().getEventQuests(QuestEventType.ON_ATTACK))
1794 {
1795 // Check if the Identifier of the L2Attackable attck is needed for the current quest
1796 if (getQuestState(quest.getName()) != null)
1797 {
1798 // Copy the current L2PcInstance QuestState in the QuestState table
1799 if (states == null)
1800 {
1801 states = new QuestState[]
1802 {
1803 getQuestState(quest.getName())
1804 };
1805 }
1806 else
1807 {
1808 states = addToQuestStateArray(states, getQuestState(quest.getName()));
1809 }
1810 }
1811 }
1812
1813 // Return a table containing all QuestState to modify
1814 return states;
1815 }
1816
1817 /**
1818 * @param npc
1819 * @return a table containing all QuestState to modify after a L2Attackable killing.
1820 */
1821 public QuestState[] getQuestsForKills(L2Npc npc)
1822 {
1823 // Create a QuestState table that will contain all QuestState to modify
1824 QuestState[] states = null;
1825
1826 // Go through the QuestState of the L2PcInstance quests
1827 for (Quest quest : npc.getTemplate().getEventQuests(QuestEventType.ON_KILL))
1828 {
1829 // Check if the Identifier of the L2Attackable killed is needed for the current quest
1830 if (getQuestState(quest.getName()) != null)
1831 {
1832 // Copy the current L2PcInstance QuestState in the QuestState table
1833 if (states == null)
1834 {
1835 states = new QuestState[]
1836 {
1837 getQuestState(quest.getName())
1838 };
1839 }
1840 else
1841 {
1842 states = addToQuestStateArray(states, getQuestState(quest.getName()));
1843 }
1844 }
1845 }
1846
1847 // Return a table containing all QuestState to modify
1848 return states;
1849 }
1850
1851 /**
1852 * @param npcId The Identifier of the NPC
1853 * @return a table containing all QuestState from the table _quests in which the L2PcInstance must talk to the NPC.
1854 */
1855 public QuestState[] getQuestsForTalk(int npcId)
1856 {
1857 // Create a QuestState table that will contain all QuestState to modify
1858 QuestState[] states = null;
1859
1860 // Go through the QuestState of the L2PcInstance quests
1861 List<Quest> quests = NpcTable.getInstance().getTemplate(npcId).getEventQuests(QuestEventType.ON_TALK);
1862 if (quests != null)
1863 {
1864 for (Quest quest : quests)
1865 {
1866 if (quest != null)
1867 {
1868 // Copy the current L2PcInstance QuestState in the QuestState table
1869 if (getQuestState(quest.getName()) != null)
1870 {
1871 if (states == null)
1872 {
1873 states = new QuestState[]
1874 {
1875 getQuestState(quest.getName())
1876 };
1877 }
1878 else
1879 {
1880 states = addToQuestStateArray(states, getQuestState(quest.getName()));
1881 }
1882 }
1883 }
1884 }
1885 }
1886
1887 // Return a table containing all QuestState to modify
1888 return states;
1889 }
1890
1891 public QuestState processQuestEvent(String quest, String event)
1892 {
1893 QuestState retval = null;
1894 if (event == null)
1895 {
1896 event = "";
1897 }
1898 QuestState qs = getQuestState(quest);
1899 if ((qs == null) && event.isEmpty())
1900 {
1901 return retval;
1902 }
1903 if (qs == null)
1904 {
1905 Quest q = QuestManager.getInstance().getQuest(quest);
1906 if (q == null)
1907 {
1908 return retval;
1909 }
1910 qs = q.newQuestState(this);
1911 }
1912 if (qs != null)
1913 {
1914 if (getLastQuestNpcObject() > 0)
1915 {
1916 L2Object object = L2World.getInstance().findObject(getLastQuestNpcObject());
1917 if ((object instanceof L2Npc) && isInsideRadius(object, L2Npc.INTERACTION_DISTANCE, false, false))
1918 {
1919 L2Npc npc = (L2Npc) object;
1920 QuestState[] states = getQuestsForTalk(npc.getNpcId());
1921
1922 if (states != null)
1923 {
1924 for (QuestState state : states)
1925 {
1926 if (state.getQuest().getName().equals(qs.getQuest().getName()))
1927 {
1928 if (qs.getQuest().notifyEvent(event, npc, this))
1929 {
1930 showQuestWindow(quest, State.getStateName(qs.getState()));
1931 }
1932
1933 retval = qs;
1934 }
1935 }
1936 }
1937 }
1938 }
1939 }
1940
1941 return retval;
1942 }
1943
1944 private void showQuestWindow(String questId, String stateId)
1945 {
1946 String path = "data/scripts/quests/" + questId + "/" + stateId + ".htm";
1947 String content = HtmCache.getInstance().getHtm(getHtmlPrefix(), path); // TODO path for quests html
1948
1949 if (content != null)
1950 {
1951 NpcHtmlMessage npcReply = new NpcHtmlMessage(5);
1952 npcReply.setHtml(content);
1953 sendPacket(npcReply);
1954 }
1955
1956 sendPacket(ActionFailed.STATIC_PACKET);
1957 }
1958
1959 /** List of all QuestState instance that needs to be notified of this L2PcInstance's or its pet's death */
1960 private volatile List<QuestState> _notifyQuestOfDeathList;
1961
1962 /**
1963 * Add QuestState instance that is to be notified of L2PcInstance's death.
1964 * @param qs The QuestState that subscribe to this event
1965 */
1966 public void addNotifyQuestOfDeath(QuestState qs)
1967 {
1968 if (qs == null)
1969 {
1970 return;
1971 }
1972
1973 if (!getNotifyQuestOfDeath().contains(qs))
1974 {
1975 getNotifyQuestOfDeath().add(qs);
1976 }
1977 }
1978
1979 /**
1980 * Remove QuestState instance that is to be notified of L2PcInstance's death.
1981 * @param qs The QuestState that subscribe to this event
1982 */
1983 public void removeNotifyQuestOfDeath(QuestState qs)
1984 {
1985 if ((qs == null) || (_notifyQuestOfDeathList == null))
1986 {
1987 return;
1988 }
1989
1990 _notifyQuestOfDeathList.remove(qs);
1991 }
1992
1993 /**
1994 * @return a list of QuestStates which registered for notify of death of this L2PcInstance.
1995 */
1996 public final List<QuestState> getNotifyQuestOfDeath()
1997 {
1998 if (_notifyQuestOfDeathList == null)
1999 {
2000 synchronized (this)
2001 {
2002 if (_notifyQuestOfDeathList == null)
2003 {
2004 _notifyQuestOfDeathList = new FastList<>();
2005 }
2006 }
2007 }
2008
2009 return _notifyQuestOfDeathList;
2010 }
2011
2012 public final boolean isNotifyQuestOfDeathEmpty()
2013 {
2014 return (_notifyQuestOfDeathList == null) || _notifyQuestOfDeathList.isEmpty();
2015 }
2016
2017 /**
2018 * @return a table containing all L2ShortCut of the L2PcInstance.
2019 */
2020 public L2ShortCut[] getAllShortCuts()
2021 {
2022 return _shortCuts.getAllShortCuts();
2023 }
2024
2025 /**
2026 * @param slot The slot in which the shortCuts is equipped
2027 * @param page The page of shortCuts containing the slot
2028 * @return the L2ShortCut of the L2PcInstance corresponding to the position (page-slot).
2029 */
2030 public L2ShortCut getShortCut(int slot, int page)
2031 {
2032 return _shortCuts.getShortCut(slot, page);
2033 }
2034
2035 /**
2036 * Add a L2shortCut to the L2PcInstance _shortCuts
2037 * @param shortcut
2038 */
2039 public void registerShortCut(L2ShortCut shortcut)
2040 {
2041 _shortCuts.registerShortCut(shortcut);
2042 }
2043
2044 /**
2045 * Updates the shortcut bars with the new skill.
2046 * @param skillId the skill Id to search and update.
2047 * @param skillLevel the skill level to update.
2048 */
2049 public void updateShortCuts(int skillId, int skillLevel)
2050 {
2051 _shortCuts.updateShortCuts(skillId, skillLevel);
2052 }
2053
2054 /**
2055 * Delete the L2ShortCut corresponding to the position (page-slot) from the L2PcInstance _shortCuts.
2056 * @param slot
2057 * @param page
2058 */
2059 public void deleteShortCut(int slot, int page)
2060 {
2061 _shortCuts.deleteShortCut(slot, page);
2062 }
2063
2064 /**
2065 * @param macro the macro to add to this L2PcInstance.
2066 */
2067 public void registerMacro(L2Macro macro)
2068 {
2069 _macros.registerMacro(macro);
2070 }
2071
2072 /**
2073 * @param id the macro Id to delete.
2074 */
2075 public void deleteMacro(int id)
2076 {
2077 _macros.deleteMacro(id);
2078 }
2079
2080 /**
2081 * @return all L2Macro of the L2PcInstance.
2082 */
2083 public MacroList getMacros()
2084 {
2085 return _macros;
2086 }
2087
2088 /**
2089 * Set the siege state of the L2PcInstance.
2090 * @param siegeState 1 = attacker, 2 = defender, 0 = not involved
2091 */
2092 public void setSiegeState(byte siegeState)
2093 {
2094 _siegeState = siegeState;
2095 }
2096
2097 /**
2098 * Get the siege state of the L2PcInstance.
2099 * @return 1 = attacker, 2 = defender, 0 = not involved
2100 */
2101 public byte getSiegeState()
2102 {
2103 return _siegeState;
2104 }
2105
2106 /**
2107 * Set the siege Side of the L2PcInstance.
2108 * @param val
2109 */
2110 public void setSiegeSide(int val)
2111 {
2112 _siegeSide = val;
2113 }
2114
2115 public boolean isRegisteredOnThisSiegeField(int val)
2116 {
2117 if ((_siegeSide != val) && ((_siegeSide < 81) || (_siegeSide > 89)))
2118 {
2119 return false;
2120 }
2121 return true;
2122 }
2123
2124 public int getSiegeSide()
2125 {
2126 return _siegeSide;
2127 }
2128
2129 /**
2130 * Set the PvP Flag of the L2PcInstance.
2131 * @param pvpFlag
2132 */
2133 public void setPvpFlag(int pvpFlag)
2134 {
2135 _pvpFlag = (byte) pvpFlag;
2136 }
2137
2138 @Override
2139 public byte getPvpFlag()
2140 {
2141 return _pvpFlag;
2142 }
2143
2144 @Override
2145 public void updatePvPFlag(int value)
2146 {
2147 if (getPvpFlag() == value)
2148 {
2149 return;
2150 }
2151 setPvpFlag(value);
2152
2153 sendPacket(new UserInfo(this));
2154 sendPacket(new ExBrExtraUserInfo(this));
2155
2156 // If this player has a pet update the pets pvp flag as well
2157 if (hasSummon())
2158 {
2159 sendPacket(new RelationChanged(getSummon(), getRelation(this), false));
2160 }
2161
2162 Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
2163
2164 for (L2PcInstance target : plrs)
2165 {
2166 target.sendPacket(new RelationChanged(this, getRelation(target), isAutoAttackable(target)));
2167 if (hasSummon())
2168 {
2169 target.sendPacket(new RelationChanged(getSummon(), getRelation(target), isAutoAttackable(target)));
2170 }
2171 }
2172 }
2173
2174 @Override
2175 public void revalidateZone(boolean force)
2176 {
2177 // Cannot validate if not in a world region (happens during teleport)
2178 if (getWorldRegion() == null)
2179 {
2180 return;
2181 }
2182
2183 // This function is called too often from movement code
2184 if (force)
2185 {
2186 _zoneValidateCounter = 4;
2187 }
2188 else
2189 {
2190 _zoneValidateCounter--;
2191 if (_zoneValidateCounter < 0)
2192 {
2193 _zoneValidateCounter = 4;
2194 }
2195 else
2196 {
2197 return;
2198 }
2199 }
2200
2201 getWorldRegion().revalidateZones(this);
2202
2203 if (Config.ALLOW_WATER)
2204 {
2205 checkWaterState();
2206 }
2207
2208 if (isInsideZone(ZoneId.ALTERED))
2209 {
2210 if (_lastCompassZone == ExSetCompassZoneCode.ALTEREDZONE)
2211 {
2212 return;
2213 }
2214 _lastCompassZone = ExSetCompassZoneCode.ALTEREDZONE;
2215 ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.ALTEREDZONE);
2216 sendPacket(cz);
2217 }
2218 else if (isInsideZone(ZoneId.SIEGE))
2219 {
2220 if (_lastCompassZone == ExSetCompassZoneCode.SIEGEWARZONE2)
2221 {
2222 return;
2223 }
2224 _lastCompassZone = ExSetCompassZoneCode.SIEGEWARZONE2;
2225 ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.SIEGEWARZONE2);
2226 sendPacket(cz);
2227 }
2228 else if (isInsideZone(ZoneId.PVP))
2229 {
2230 if (_lastCompassZone == ExSetCompassZoneCode.PVPZONE)
2231 {
2232 return;
2233 }
2234 _lastCompassZone = ExSetCompassZoneCode.PVPZONE;
2235 ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.PVPZONE);
2236 sendPacket(cz);
2237 }
2238 else if (isIn7sDungeon())
2239 {
2240 if (_lastCompassZone == ExSetCompassZoneCode.SEVENSIGNSZONE)
2241 {
2242 return;
2243 }
2244 _lastCompassZone = ExSetCompassZoneCode.SEVENSIGNSZONE;
2245 ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.SEVENSIGNSZONE);
2246 sendPacket(cz);
2247 }
2248 else if (isInsideZone(ZoneId.PEACE))
2249 {
2250 if (_lastCompassZone == ExSetCompassZoneCode.PEACEZONE)
2251 {
2252 return;
2253 }
2254 _lastCompassZone = ExSetCompassZoneCode.PEACEZONE;
2255 ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.PEACEZONE);
2256 sendPacket(cz);
2257 }
2258 else
2259 {
2260 if (_lastCompassZone == ExSetCompassZoneCode.GENERALZONE)
2261 {
2262 return;
2263 }
2264 if (_lastCompassZone == ExSetCompassZoneCode.SIEGEWARZONE2)
2265 {
2266 updatePvPStatus();
2267 }
2268 _lastCompassZone = ExSetCompassZoneCode.GENERALZONE;
2269 ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.GENERALZONE);
2270 sendPacket(cz);
2271 }
2272 }
2273
2274 /**
2275 * @return True if the L2PcInstance can Craft Dwarven Recipes.
2276 */
2277 public boolean hasDwarvenCraft()
2278 {
2279 return getSkillLevel(L2Skill.SKILL_CREATE_DWARVEN) >= 1;
2280 }
2281
2282 public int getDwarvenCraft()
2283 {
2284 return getSkillLevel(L2Skill.SKILL_CREATE_DWARVEN);
2285 }
2286
2287 /**
2288 * @return True if the L2PcInstance can Craft Dwarven Recipes.
2289 */
2290 public boolean hasCommonCraft()
2291 {
2292 return getSkillLevel(L2Skill.SKILL_CREATE_COMMON) >= 1;
2293 }
2294
2295 public int getCommonCraft()
2296 {
2297 return getSkillLevel(L2Skill.SKILL_CREATE_COMMON);
2298 }
2299
2300 /**
2301 * @return the PK counter of the L2PcInstance.
2302 */
2303 public int getPkKills()
2304 {
2305 return _pkKills;
2306 }
2307
2308 /**
2309 * Set the PK counter of the L2PcInstance.
2310 * @param pkKills
2311 */
2312 public void setPkKills(int pkKills)
2313 {
2314 _pkKills = pkKills;
2315 }
2316
2317 /**
2318 * @return the _deleteTimer of the L2PcInstance.
2319 */
2320 public long getDeleteTimer()
2321 {
2322 return _deleteTimer;
2323 }
2324
2325 /**
2326 * Set the _deleteTimer of the L2PcInstance.
2327 * @param deleteTimer
2328 */
2329 public void setDeleteTimer(long deleteTimer)
2330 {
2331 _deleteTimer = deleteTimer;
2332 }
2333
2334 /**
2335 * @return the number of recommendation obtained by the L2PcInstance.
2336 */
2337 public int getRecomHave()
2338 {
2339 return _recomHave;
2340 }
2341
2342 /**
2343 * Increment the number of recommendation obtained by the L2PcInstance (Max : 255).
2344 */
2345 protected void incRecomHave()
2346 {
2347 if (_recomHave < 255)
2348 {
2349 _recomHave++;
2350 }
2351 }
2352
2353 /**
2354 * Set the number of recommendation obtained by the L2PcInstance (Max : 255).
2355 * @param value
2356 */
2357 public void setRecomHave(int value)
2358 {
2359 if (value > 255)
2360 {
2361 _recomHave = 255;
2362 }
2363 else if (value < 0)
2364 {
2365 _recomHave = 0;
2366 }
2367 else
2368 {
2369 _recomHave = value;
2370 }
2371 }
2372
2373 /**
2374 * Set the number of recommendation obtained by the L2PcInstance (Max : 255).
2375 * @param value
2376 */
2377 public void setRecomLeft(int value)
2378 {
2379 if (value > 255)
2380 {
2381 _recomLeft = 255;
2382 }
2383 else if (value < 0)
2384 {
2385 _recomLeft = 0;
2386 }
2387 else
2388 {
2389 _recomLeft = value;
2390 }
2391 }
2392
2393 /**
2394 * @return the number of recommendation that the L2PcInstance can give.
2395 */
2396 public int getRecomLeft()
2397 {
2398 return _recomLeft;
2399 }
2400
2401 /**
2402 * Increment the number of recommendation that the L2PcInstance can give.
2403 */
2404 protected void decRecomLeft()
2405 {
2406 if (_recomLeft > 0)
2407 {
2408 _recomLeft--;
2409 }
2410 }
2411
2412 public void giveRecom(L2PcInstance target)
2413 {
2414 target.incRecomHave();
2415 decRecomLeft();
2416 }
2417
2418 /**
2419 * Set the exp of the L2PcInstance before a death
2420 * @param exp
2421 */
2422 public void setExpBeforeDeath(long exp)
2423 {
2424 _expBeforeDeath = exp;
2425 }
2426
2427 public long getExpBeforeDeath()
2428 {
2429 return _expBeforeDeath;
2430 }
2431
2432 /**
2433 * Return the Karma of the L2PcInstance.
2434 */
2435 @Override
2436 public int getKarma()
2437 {
2438 return _karma;
2439 }
2440
2441 /**
2442 * Set the Karma of the L2PcInstance and send a Server->Client packet StatusUpdate (broadcast).
2443 * @param karma
2444 */
2445 public void setKarma(int karma)
2446 {
2447 if (karma < 0)
2448 {
2449 karma = 0;
2450 }
2451 if ((_karma == 0) && (karma > 0))
2452 {
2453 Collection<L2Object> objs = getKnownList().getKnownObjects().values();
2454
2455 for (L2Object object : objs)
2456 {
2457 if (!(object instanceof L2GuardInstance))
2458 {
2459 continue;
2460 }
2461
2462 if (((L2GuardInstance) object).getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE)
2463 {
2464 ((L2GuardInstance) object).getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE, null);
2465 }
2466 }
2467 }
2468 else if ((_karma > 0) && (karma == 0))
2469 {
2470 // Send a Server->Client StatusUpdate packet with Karma and PvP Flag to the L2PcInstance and all L2PcInstance to inform (broadcast)
2471 setKarmaFlag(0);
2472 }
2473
2474 _karma = karma;
2475 broadcastKarma();
2476 }
2477
2478 public int getExpertiseArmorPenalty()
2479 {
2480 return _expertiseArmorPenalty;
2481 }
2482
2483 public int getExpertiseWeaponPenalty()
2484 {
2485 return _expertiseWeaponPenalty;
2486 }
2487
2488 public int getExpertisePenaltyBonus()
2489 {
2490 return _expertisePenaltyBonus;
2491 }
2492
2493 public void setExpertisePenaltyBonus(int bonus)
2494 {
2495 _expertisePenaltyBonus = bonus;
2496 }
2497
2498 public int getWeightPenalty()
2499 {
2500 if (_dietMode)
2501 {
2502 return 0;
2503 }
2504 return _curWeightPenalty;
2505 }
2506
2507 /**
2508 * Update the overloaded status of the L2PcInstance.
2509 */
2510 public void refreshOverloaded()
2511 {
2512 int maxLoad = getMaxLoad();
2513 if (maxLoad > 0)
2514 {
2515 long weightproc = (((getCurrentLoad() - getBonusWeightPenalty()) * 1000) / getMaxLoad());
2516 int newWeightPenalty;
2517 if ((weightproc < 500) || _dietMode)
2518 {
2519 newWeightPenalty = 0;
2520 }
2521 else if (weightproc < 666)
2522 {
2523 newWeightPenalty = 1;
2524 }
2525 else if (weightproc < 800)
2526 {
2527 newWeightPenalty = 2;
2528 }
2529 else if (weightproc < 1000)
2530 {
2531 newWeightPenalty = 3;
2532 }
2533 else
2534 {
2535 newWeightPenalty = 4;
2536 }
2537
2538 if (_curWeightPenalty != newWeightPenalty)
2539 {
2540 _curWeightPenalty = newWeightPenalty;
2541 if ((newWeightPenalty > 0) && !_dietMode)
2542 {
2543 super.addSkill(SkillTable.getInstance().getInfo(4270, newWeightPenalty));
2544 setIsOverloaded(getCurrentLoad() > maxLoad);
2545 }
2546 else
2547 {
2548 super.removeSkill(getKnownSkill(4270));
2549 setIsOverloaded(false);
2550 }
2551 sendPacket(new UserInfo(this));
2552 sendPacket(new EtcStatusUpdate(this));
2553 broadcastPacket(new CharInfo(this));
2554 broadcastPacket(new ExBrExtraUserInfo(this));
2555 }
2556 }
2557 }
2558
2559 public void refreshExpertisePenalty()
2560 {
2561 if (!Config.EXPERTISE_PENALTY)
2562 {
2563 return;
2564 }
2565
2566 final int expertiseLevel = getExpertiseLevel();
2567
2568 int armorPenalty = 0;
2569 int weaponPenalty = 0;
2570 int crystaltype;
2571
2572 for (L2ItemInstance item : getInventory().getItems())
2573 {
2574 if ((item != null) && item.isEquipped() && ((item.getItemType() != L2EtcItemType.ARROW) && (item.getItemType() != L2EtcItemType.BOLT)))
2575 {
2576 crystaltype = item.getItem().getCrystalType();
2577 if (crystaltype > expertiseLevel)
2578 {
2579 if (item.isWeapon() && (crystaltype > weaponPenalty))
2580 {
2581 weaponPenalty = crystaltype;
2582 }
2583 else if (crystaltype > armorPenalty)
2584 {
2585 armorPenalty = crystaltype;
2586 }
2587 }
2588 }
2589 }
2590
2591 boolean changed = false;
2592 final int bonus = getExpertisePenaltyBonus();
2593
2594 // calc weapon penalty
2595 weaponPenalty = weaponPenalty - expertiseLevel - bonus;
2596 if (weaponPenalty < 0)
2597 {
2598 weaponPenalty = 0;
2599 }
2600 else if (weaponPenalty > 4)
2601 {
2602 weaponPenalty = 4;
2603 }
2604
2605 if ((getExpertiseWeaponPenalty() != weaponPenalty) || (getSkillLevel(FrequentSkill.WEAPON_GRADE_PENALTY.getId()) != weaponPenalty))
2606 {
2607 _expertiseWeaponPenalty = weaponPenalty;
2608 if (_expertiseWeaponPenalty > 0)
2609 {
2610 super.addSkill(SkillTable.getInstance().getInfo(FrequentSkill.WEAPON_GRADE_PENALTY.getId(), _expertiseWeaponPenalty));
2611 }
2612 else
2613 {
2614 super.removeSkill(getKnownSkill(FrequentSkill.WEAPON_GRADE_PENALTY.getId()));
2615 }
2616 changed = true;
2617 }
2618
2619 // calc armor penalty
2620 armorPenalty = armorPenalty - expertiseLevel - bonus;
2621
2622 // if rune of crystal is in inventory then player have skill
2623 // and penalty needs to be reduced by skill level
2624 if (getFirstEffect(26048) != null)
2625 {
2626 armorPenalty -= getFirstEffect(26048).getLevel();
2627 weaponPenalty -= getFirstEffect(26048).getLevel();
2628 }
2629 L2Effect rune_sk = getFirstEffect(22041);
2630 if (rune_sk != null)
2631 {
2632 int skill_lvl = rune_sk.getLevel();
2633 if (skill_lvl == 1)
2634 {
2635 armorPenalty -= 3;
2636 weaponPenalty -= 3;
2637 }
2638 else if (skill_lvl == 2)
2639 {
2640 armorPenalty -= 5;
2641 weaponPenalty -= 5;
2642 }
2643 }
2644
2645 if (armorPenalty < 0)
2646 {
2647 armorPenalty = 0;
2648 }
2649 else if (armorPenalty > 4)
2650 {
2651 armorPenalty = 4;
2652 }
2653
2654 if ((getExpertiseArmorPenalty() != armorPenalty) || (getSkillLevel(FrequentSkill.ARMOR_GRADE_PENALTY.getId()) != armorPenalty))
2655 {
2656 _expertiseArmorPenalty = armorPenalty;
2657 if (_expertiseArmorPenalty > 0)
2658 {
2659 super.addSkill(SkillTable.getInstance().getInfo(FrequentSkill.ARMOR_GRADE_PENALTY.getId(), _expertiseArmorPenalty));
2660 }
2661 else
2662 {
2663 super.removeSkill(getKnownSkill(FrequentSkill.ARMOR_GRADE_PENALTY.getId()));
2664 }
2665 changed = true;
2666 }
2667
2668 if (changed)
2669 {
2670 sendPacket(new EtcStatusUpdate(this));
2671 }
2672 }
2673
2674 public void checkIfWeaponIsAllowed()
2675 {
2676 // Override for Gamemasters
2677 if (canOverrideCond(PcCondOverride.ITEM_CONDITIONS))
2678 {
2679 return;
2680 }
2681
2682 // Iterate through all effects currently on the character.
2683 for (L2Effect currenteffect : getAllEffects())
2684 {
2685 L2Skill effectSkill = currenteffect.getSkill();
2686
2687 // Ignore all buff skills that are party related (ie. songs, dances) while still remaining weapon dependant on cast though.
2688 if (!effectSkill.isOffensive() && !((effectSkill.getTargetType() == L2TargetType.TARGET_PARTY) && (effectSkill.getSkillType() == L2SkillType.BUFF)))
2689 {
2690 // Check to rest to assure current effect meets weapon requirements.
2691 if (!effectSkill.getWeaponDependancy(this))
2692 {
2693 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
2694 sm.addSkillName(effectSkill);
2695 sendPacket(sm);
2696
2697 if (Config.DEBUG)
2698 {
2699 _log.info(" | Skill " + effectSkill.getName() + " has been disabled for (" + getName() + "); Reason: Incompatible Weapon Type.");
2700 }
2701
2702 currenteffect.exit();
2703 }
2704 }
2705
2706 continue;
2707 }
2708 }
2709
2710 public void useEquippableItem(L2ItemInstance item, boolean abortAttack)
2711 {
2712 // Equip or unEquip
2713 L2ItemInstance[] items = null;
2714 final boolean isEquiped = item.isEquipped();
2715 final int oldInvLimit = getInventoryLimit();
2716 SystemMessage sm = null;
2717
2718 if (!fireEquipmentListeners(isEquiped, item))
2719 {
2720 return;
2721 }
2722 if (isEquiped)
2723 {
2724 if (item.getEnchantLevel() > 0)
2725 {
2726 sm = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
2727 sm.addNumber(item.getEnchantLevel());
2728 sm.addItemName(item);
2729 }
2730 else
2731 {
2732 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISARMED);
2733 sm.addItemName(item);
2734 }
2735 sendPacket(sm);
2736
2737 int slot = getInventory().getSlotFromItem(item);
2738 // we cant unequip talisman by body slot
2739 if (slot == L2Item.SLOT_DECO)
2740 {
2741 items = getInventory().unEquipItemInSlotAndRecord(item.getLocationSlot());
2742 }
2743 else
2744 {
2745 items = getInventory().unEquipItemInBodySlotAndRecord(slot);
2746 }
2747 }
2748 else
2749 {
2750 items = getInventory().equipItemAndRecord(item);
2751
2752 if (item.isEquipped())
2753 {
2754 if (item.getEnchantLevel() > 0)
2755 {
2756 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_S2_EQUIPPED);
2757 sm.addNumber(item.getEnchantLevel());
2758 sm.addItemName(item);
2759 }
2760 else
2761 {
2762 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_EQUIPPED);
2763 sm.addItemName(item);
2764 }
2765 sendPacket(sm);
2766
2767 // Consume mana - will start a task if required; returns if item is not a shadow item
2768 item.decreaseMana(false);
2769
2770 if ((item.getItem().getBodyPart() & L2Item.SLOT_MULTI_ALLWEAPON) != 0)
2771 {
2772 rechargeShots(true, true);
2773 }
2774 }
2775 else
2776 {
2777 sendPacket(SystemMessageId.CANNOT_EQUIP_ITEM_DUE_TO_BAD_CONDITION);
2778 }
2779 }
2780 refreshExpertisePenalty();
2781
2782 broadcastUserInfo();
2783
2784 InventoryUpdate iu = new InventoryUpdate();
2785 iu.addItems(Arrays.asList(items));
2786 sendPacket(iu);
2787
2788 if (abortAttack)
2789 {
2790 abortAttack();
2791 }
2792
2793 if (getInventoryLimit() != oldInvLimit)
2794 {
2795 sendPacket(new ExStorageMaxCount(this));
2796 }
2797 }
2798
2799 /**
2800 * @return the the PvP Kills of the L2PcInstance (Number of player killed during a PvP).
2801 */
2802 public int getPvpKills()
2803 {
2804 return _pvpKills;
2805 }
2806
2807 /**
2808 * Set the the PvP Kills of the L2PcInstance (Number of player killed during a PvP).
2809 * @param pvpKills
2810 */
2811 public void setPvpKills(int pvpKills)
2812 {
2813 _pvpKills = pvpKills;
2814 }
2815
2816 /**
2817 * @return the Fame of this L2PcInstance
2818 */
2819 public int getFame()
2820 {
2821 return _fame;
2822 }
2823
2824 /**
2825 * Set the Fame of this L2PcInstane
2826 * @param fame
2827 */
2828 public void setFame(int fame)
2829 {
2830 if (fame > Config.MAX_PERSONAL_FAME_POINTS)
2831 {
2832 _fame = Config.MAX_PERSONAL_FAME_POINTS;
2833 }
2834 else
2835 {
2836 _fame = fame;
2837 }
2838 }
2839
2840 /**
2841 * @return the ClassId object of the L2PcInstance contained in L2PcTemplate.
2842 */
2843 public ClassId getClassId()
2844 {
2845 return getTemplate().getClassId();
2846 }
2847
2848 /**
2849 * Set the template of the L2PcInstance.
2850 * @param Id The Identifier of the L2PcTemplate to set to the L2PcInstance
2851 */
2852 public void setClassId(int Id)
2853 {
2854 if (!_subclassLock.tryLock())
2855 {
2856 return;
2857 }
2858
2859 try
2860 {
2861 if ((getLvlJoinedAcademy() != 0) && (_clan != null) && (PlayerClass.values()[Id].getLevel() == ClassLevel.Third))
2862 {
2863 if (getLvlJoinedAcademy() <= 16)
2864 {
2865 _clan.addReputationScore(Config.JOIN_ACADEMY_MAX_REP_SCORE, true);
2866 }
2867 else if (getLvlJoinedAcademy() >= 39)
2868 {
2869 _clan.addReputationScore(Config.JOIN_ACADEMY_MIN_REP_SCORE, true);
2870 }
2871 else
2872 {
2873 _clan.addReputationScore((Config.JOIN_ACADEMY_MAX_REP_SCORE - ((getLvlJoinedAcademy() - 16) * 20)), true);
2874 }
2875 setLvlJoinedAcademy(0);
2876 // oust pledge member from the academy, cuz he has finished his 2nd class transfer
2877 SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.CLAN_MEMBER_S1_EXPELLED);
2878 msg.addPcName(this);
2879 _clan.broadcastToOnlineMembers(msg);
2880 _clan.broadcastToOnlineMembers(new PledgeShowMemberListDelete(getName()));
2881 _clan.removeClanMember(getObjectId(), 0);
2882 sendPacket(SystemMessageId.ACADEMY_MEMBERSHIP_TERMINATED);
2883
2884 // receive graduation gift
2885 getInventory().addItem("Gift", 8181, 1, this, null); // give academy circlet
2886 }
2887 if (isSubClassActive())
2888 {
2889 getSubClasses().get(_classIndex).setClassId(Id);
2890 }
2891 setTarget(this);
2892 broadcastPacket(new MagicSkillUse(this, 5103, 1, 1000, 0));
2893 setClassTemplate(Id);
2894 if (getClassId().level() == 3)
2895 {
2896 sendPacket(SystemMessageId.THIRD_CLASS_TRANSFER);
2897 }
2898 else
2899 {
2900 sendPacket(SystemMessageId.CLASS_TRANSFER);
2901 }
2902
2903 // Update class icon in party and clan
2904 if (isInParty())
2905 {
2906 getParty().broadcastPacket(new PartySmallWindowUpdate(this));
2907 }
2908
2909 if (getClan() != null)
2910 {
2911 getClan().broadcastToOnlineMembers(new PledgeShowMemberListUpdate(this));
2912 }
2913
2914 // Add AutoGet skills and normal skills and/or learnByFS depending on configurations.
2915 rewardSkills();
2916
2917 if (!canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && Config.DECREASE_SKILL_LEVEL)
2918 {
2919 checkPlayerSkills();
2920 }
2921 }
2922 finally
2923 {
2924 _subclassLock.unlock();
2925 }
2926 }
2927
2928 /**
2929 * Used for AltGameSkillLearn to set a custom skill learning class Id.
2930 */
2931 private ClassId _learningClass = getClassId();
2932
2933 /**
2934 * @return the custom skill learning class Id.
2935 */
2936 public ClassId getLearningClass()
2937 {
2938 return _learningClass;
2939 }
2940
2941 /**
2942 * @param learningClass the custom skill learning class Id to set.
2943 */
2944 public void setLearningClass(ClassId learningClass)
2945 {
2946 _learningClass = learningClass;
2947 }
2948
2949 /**
2950 * @return the Experience of the L2PcInstance.
2951 */
2952 public long getExp()
2953 {
2954 return getStat().getExp();
2955 }
2956
2957 public void setActiveEnchantAttrItem(L2ItemInstance stone)
2958 {
2959 _activeEnchantAttrItem = stone;
2960 }
2961
2962 public L2ItemInstance getActiveEnchantAttrItem()
2963 {
2964 return _activeEnchantAttrItem;
2965 }
2966
2967 public void setActiveEnchantItem(L2ItemInstance scroll)
2968 {
2969 // If we dont have a Enchant Item, we are not enchanting.
2970 if (scroll == null)
2971 {
2972 setActiveEnchantSupportItem(null);
2973 setActiveEnchantTimestamp(0);
2974 setIsEnchanting(false);
2975 }
2976 _activeEnchantItem = scroll;
2977 }
2978
2979 public L2ItemInstance getActiveEnchantItem()
2980 {
2981 return _activeEnchantItem;
2982 }
2983
2984 public void setActiveEnchantSupportItem(L2ItemInstance item)
2985 {
2986 _activeEnchantSupportItem = item;
2987 }
2988
2989 public L2ItemInstance getActiveEnchantSupportItem()
2990 {
2991 return _activeEnchantSupportItem;
2992 }
2993
2994 public long getActiveEnchantTimestamp()
2995 {
2996 return _activeEnchantTimestamp;
2997 }
2998
2999 public void setActiveEnchantTimestamp(long val)
3000 {
3001 _activeEnchantTimestamp = val;
3002 }
3003
3004 public void setIsEnchanting(boolean val)
3005 {
3006 _isEnchanting = val;
3007 }
3008
3009 public boolean isEnchanting()
3010 {
3011 return _isEnchanting;
3012 }
3013
3014 /**
3015 * Set the fists weapon of the L2PcInstance (used when no weapon is equiped).
3016 * @param weaponItem The fists L2Weapon to set to the L2PcInstance
3017 */
3018 public void setFistsWeaponItem(L2Weapon weaponItem)
3019 {
3020 _fistsWeaponItem = weaponItem;
3021 }
3022
3023 /**
3024 * @return the fists weapon of the L2PcInstance (used when no weapon is equipped).
3025 */
3026 public L2Weapon getFistsWeaponItem()
3027 {
3028 return _fistsWeaponItem;
3029 }
3030
3031 /**
3032 * @param classId
3033 * @return the fists weapon of the L2PcInstance Class (used when no weapon is equipped).
3034 */
3035 public L2Weapon findFistsWeaponItem(int classId)
3036 {
3037 L2Weapon weaponItem = null;
3038 if ((classId >= 0x00) && (classId <= 0x09))
3039 {
3040 // human fighter fists
3041 L2Item temp = ItemTable.getInstance().getTemplate(246);
3042 weaponItem = (L2Weapon) temp;
3043 }
3044 else if ((classId >= 0x0a) && (classId <= 0x11))
3045 {
3046 // human mage fists
3047 L2Item temp = ItemTable.getInstance().getTemplate(251);
3048 weaponItem = (L2Weapon) temp;
3049 }
3050 else if ((classId >= 0x12) && (classId <= 0x18))
3051 {
3052 // elven fighter fists
3053 L2Item temp = ItemTable.getInstance().getTemplate(244);
3054 weaponItem = (L2Weapon) temp;
3055 }
3056 else if ((classId >= 0x19) && (classId <= 0x1e))
3057 {
3058 // elven mage fists
3059 L2Item temp = ItemTable.getInstance().getTemplate(249);
3060 weaponItem = (L2Weapon) temp;
3061 }
3062 else if ((classId >= 0x1f) && (classId <= 0x25))
3063 {
3064 // dark elven fighter fists
3065 L2Item temp = ItemTable.getInstance().getTemplate(245);
3066 weaponItem = (L2Weapon) temp;
3067 }
3068 else if ((classId >= 0x26) && (classId <= 0x2b))
3069 {
3070 // dark elven mage fists
3071 L2Item temp = ItemTable.getInstance().getTemplate(250);
3072 weaponItem = (L2Weapon) temp;
3073 }
3074 else if ((classId >= 0x2c) && (classId <= 0x30))
3075 {
3076 // orc fighter fists
3077 L2Item temp = ItemTable.getInstance().getTemplate(248);
3078 weaponItem = (L2Weapon) temp;
3079 }
3080 else if ((classId >= 0x31) && (classId <= 0x34))
3081 {
3082 // orc mage fists
3083 L2Item temp = ItemTable.getInstance().getTemplate(252);
3084 weaponItem = (L2Weapon) temp;
3085 }
3086 else if ((classId >= 0x35) && (classId <= 0x39))
3087 {
3088 // dwarven fists
3089 L2Item temp = ItemTable.getInstance().getTemplate(247);
3090 weaponItem = (L2Weapon) temp;
3091 }
3092
3093 return weaponItem;
3094 }
3095
3096 /**
3097 * This method reward all AutoGet skills and Normal skills if Auto-Learn configuration is true.<br>
3098 */
3099 public void rewardSkills()
3100 {
3101 // Give all normal skills if activated Auto-Learn is activated, included AutoGet skills.
3102 if (Config.AUTO_LEARN_SKILLS)
3103 {
3104 giveAvailableSkills(Config.AUTO_LEARN_FS_SKILLS, true);
3105 }
3106 else
3107 {
3108 giveAvailableAutoGetSkills();
3109 }
3110
3111 checkItemRestriction();
3112 sendSkillList();
3113 }
3114
3115 /**
3116 * Re-give all skills which aren't saved to database, like Noble, Hero, Clan Skills.<br>
3117 */
3118 public void regiveTemporarySkills()
3119 {
3120 // Do not call this on enterworld or char load
3121
3122 // Add noble skills if noble
3123 if (isNoble())
3124 {
3125 setNoble(true);
3126 }
3127
3128 // Add Hero skills if hero
3129 if (isHero())
3130 {
3131 setHero(true);
3132 }
3133
3134 // Add clan skills
3135 if (getClan() != null)
3136 {
3137 L2Clan clan = getClan();
3138 clan.addSkillEffects(this);
3139
3140 if ((clan.getLevel() >= SiegeManager.getInstance().getSiegeClanMinLevel()) && isClanLeader())
3141 {
3142 SiegeManager.getInstance().addSiegeSkills(this);
3143 }
3144 if (getClan().getCastleId() > 0)
3145 {
3146 CastleManager.getInstance().getCastleByOwner(getClan()).giveResidentialSkills(this);
3147 }
3148 if (getClan().getFortId() > 0)
3149 {
3150 FortManager.getInstance().getFortByOwner(getClan()).giveResidentialSkills(this);
3151 }
3152 }
3153
3154 // Reload passive skills from armors / jewels / weapons
3155 getInventory().reloadEquippedItems();
3156
3157 // Add Death Penalty Buff Level
3158 restoreDeathPenaltyBuffLevel();
3159 }
3160
3161 /**
3162 * Give all available skills to the player.<br>
3163 * @param includedByFs
3164 * @param includeAutoGet
3165 * @return skillCounter, the amount of new skills added.
3166 */
3167 public int giveAvailableSkills(boolean includedByFs, boolean includeAutoGet)
3168 {
3169 int unLearnable = 0;
3170 int skillCounter = 0;
3171
3172 // Get available skills
3173 List<L2SkillLearn> skills = SkillTreesData.getInstance().getAvailableSkills(this, getClassId(), includedByFs, includeAutoGet);
3174 while (skills.size() > unLearnable)
3175 {
3176 for (L2SkillLearn s : skills)
3177 {
3178 L2Skill sk = SkillTable.getInstance().getInfo(s.getSkillId(), s.getSkillLevel());
3179 if ((sk == null) || ((sk.getId() == L2Skill.SKILL_DIVINE_INSPIRATION) && !Config.AUTO_LEARN_DIVINE_INSPIRATION && !canOverrideCond(PcCondOverride.SKILL_CONDITIONS)))
3180 {
3181 unLearnable++;
3182 continue;
3183 }
3184
3185 if (getSkillLevel(sk.getId()) == -1)
3186 {
3187 skillCounter++;
3188 }
3189
3190 // fix when learning toggle skills
3191 if (sk.isToggle())
3192 {
3193 L2Effect toggleEffect = getFirstEffect(sk.getId());
3194 if (toggleEffect != null)
3195 {
3196 // stop old toggle skill effect, and give new toggle skill effect back
3197 toggleEffect.exit();
3198 sk.getEffects(this, this);
3199 }
3200 }
3201 addSkill(sk, true);
3202 }
3203
3204 // Get new available skills, some skills depend of previous skills to be available.
3205 skills = SkillTreesData.getInstance().getAvailableSkills(this, getClassId(), includedByFs, includeAutoGet);
3206 }
3207
3208 sendMessage("You have learned " + skillCounter + " new skills.");
3209 return skillCounter;
3210 }
3211
3212 /**
3213 * Give all available AutoGet skills to the player.
3214 */
3215 public void giveAvailableAutoGetSkills()
3216 {
3217 // Get available skills
3218 final List<L2SkillLearn> autoGetSkills = SkillTreesData.getInstance().getAvailableAutoGetSkills(this);
3219 final SkillTable st = SkillTable.getInstance();
3220 L2Skill skill;
3221 for (L2SkillLearn s : autoGetSkills)
3222 {
3223 skill = st.getInfo(s.getSkillId(), s.getSkillLevel());
3224 if (skill != null)
3225 {
3226 addSkill(skill, true);
3227 }
3228 else
3229 {
3230 _log.warning("Skipping null autoGet Skill for player: " + this);
3231 }
3232 }
3233 }
3234
3235 /**
3236 * Set the Experience value of the L2PcInstance.
3237 * @param exp
3238 */
3239 public void setExp(long exp)
3240 {
3241 if (exp < 0)
3242 {
3243 exp = 0;
3244 }
3245
3246 getStat().setExp(exp);
3247 }
3248
3249 /**
3250 * @return the Race object of the L2PcInstance.
3251 */
3252 public Race getRace()
3253 {
3254 if (!isSubClassActive())
3255 {
3256 return getTemplate().getRace();
3257 }
3258 return CharTemplateTable.getInstance().getTemplate(_baseClass).getRace();
3259 }
3260
3261 public L2Radar getRadar()
3262 {
3263 return _radar;
3264 }
3265
3266 /* Return true if Hellbound minimap allowed */
3267 public boolean isMinimapAllowed()
3268 {
3269 return _minimapAllowed;
3270 }
3271
3272 /* Enable or disable minimap on Hellbound */
3273 public void setMinimapAllowed(boolean b)
3274 {
3275 _minimapAllowed = b;
3276 }
3277
3278 /**
3279 * @return the SP amount of the L2PcInstance.
3280 */
3281 public int getSp()
3282 {
3283 return getStat().getSp();
3284 }
3285
3286 /**
3287 * Set the SP amount of the L2PcInstance.
3288 * @param sp
3289 */
3290 public void setSp(int sp)
3291 {
3292 if (sp < 0)
3293 {
3294 sp = 0;
3295 }
3296
3297 super.getStat().setSp(sp);
3298 }
3299
3300 /**
3301 * @param castleId
3302 * @return true if this L2PcInstance is a clan leader in ownership of the passed castle
3303 */
3304 public boolean isCastleLord(int castleId)
3305 {
3306 L2Clan clan = getClan();
3307
3308 // player has clan and is the clan leader, check the castle info
3309 if ((clan != null) && (clan.getLeader().getPlayerInstance() == this))
3310 {
3311 // if the clan has a castle and it is actually the queried castle, return true
3312 Castle castle = CastleManager.getInstance().getCastleByOwner(clan);
3313 if ((castle != null) && (castle == CastleManager.getInstance().getCastleById(castleId)))
3314 {
3315 return true;
3316 }
3317 }
3318
3319 return false;
3320 }
3321
3322 /**
3323 * @return the Clan Identifier of the L2PcInstance.
3324 */
3325 public int getClanId()
3326 {
3327 return _clanId;
3328 }
3329
3330 /**
3331 * @return the Clan Crest Identifier of the L2PcInstance or 0.
3332 */
3333 public int getClanCrestId()
3334 {
3335 if (_clan != null)
3336 {
3337 return _clan.getCrestId();
3338 }
3339
3340 return 0;
3341 }
3342
3343 /**
3344 * @return The Clan CrestLarge Identifier or 0
3345 */
3346 public int getClanCrestLargeId()
3347 {
3348 if (_clan != null)
3349 {
3350 return _clan.getCrestLargeId();
3351 }
3352
3353 return 0;
3354 }
3355
3356 public long getClanJoinExpiryTime()
3357 {
3358 return _clanJoinExpiryTime;
3359 }
3360
3361 public void setClanJoinExpiryTime(long time)
3362 {
3363 _clanJoinExpiryTime = time;
3364 }
3365
3366 public long getClanCreateExpiryTime()
3367 {
3368 return _clanCreateExpiryTime;
3369 }
3370
3371 public void setClanCreateExpiryTime(long time)
3372 {
3373 _clanCreateExpiryTime = time;
3374 }
3375
3376 public void setOnlineTime(long time)
3377 {
3378 _onlineTime = time;
3379 _onlineBeginTime = System.currentTimeMillis();
3380 }
3381
3382 public long getZoneRestartLimitTime()
3383 {
3384 return _zoneRestartLimitTime;
3385 }
3386
3387 public void setZoneRestartLimitTime(long time)
3388 {
3389 _zoneRestartLimitTime = time;
3390 }
3391
3392 public void storeZoneRestartLimitTime()
3393 {
3394 if (isInsideZone(ZoneId.NO_RESTART))
3395 {
3396 L2NoRestartZone zone = null;
3397 for (L2ZoneType tmpzone : ZoneManager.getInstance().getZones(this))
3398 {
3399 if (tmpzone instanceof L2NoRestartZone)
3400 {
3401 zone = (L2NoRestartZone) tmpzone;
3402 break;
3403 }
3404 }
3405 if (zone != null)
3406 {
3407 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
3408 PreparedStatement statement = con.prepareStatement(UPDATE_ZONE_RESTART_LIMIT))
3409 {
3410 statement.setInt(1, getObjectId());
3411 statement.setLong(2, System.currentTimeMillis() + (zone.getRestartAllowedTime() * 1000));
3412 statement.execute();
3413 }
3414 catch (SQLException e)
3415 {
3416 _log.log(Level.WARNING, "Cannot store zone norestart limit for character " + getObjectId(), e);
3417 }
3418 }
3419 }
3420 }
3421
3422 private void restoreZoneRestartLimitTime()
3423 {
3424 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
3425 PreparedStatement ps1 = con.prepareStatement(LOAD_ZONE_RESTART_LIMIT))
3426 {
3427 ps1.setInt(1, getObjectId());
3428 try (ResultSet rset = ps1.executeQuery())
3429 {
3430 if (rset.next())
3431 {
3432 setZoneRestartLimitTime(rset.getLong("time_limit"));
3433 try (PreparedStatement ps2 = con.prepareStatement(DELETE_ZONE_RESTART_LIMIT))
3434 {
3435 ps2.setInt(1, getObjectId());
3436 ps2.executeUpdate();
3437 }
3438 }
3439 }
3440 }
3441 catch (Exception e)
3442 {
3443 _log.log(Level.WARNING, "Could not restore " + this + " zone restart time: " + e.getMessage(), e);
3444 }
3445 }
3446
3447 /**
3448 * Return the PcInventory Inventory of the L2PcInstance contained in _inventory.
3449 */
3450 @Override
3451 public PcInventory getInventory()
3452 {
3453 return _inventory;
3454 }
3455
3456 /**
3457 * Delete a ShortCut of the L2PcInstance _shortCuts.
3458 * @param objectId
3459 */
3460 public void removeItemFromShortCut(int objectId)
3461 {
3462 _shortCuts.deleteShortCutByObjectId(objectId);
3463 }
3464
3465 /**
3466 * @return True if the L2PcInstance is sitting.
3467 */
3468 public boolean isSitting()
3469 {
3470 return _waitTypeSitting;
3471 }
3472
3473 /**
3474 * Set _waitTypeSitting to given value
3475 * @param state
3476 */
3477 public void setIsSitting(boolean state)
3478 {
3479 _waitTypeSitting = state;
3480 }
3481
3482 /**
3483 * Sit down the L2PcInstance, set the AI Intention to AI_INTENTION_REST and send a Server->Client ChangeWaitType packet (broadcast)
3484 */
3485 public void sitDown()
3486 {
3487 sitDown(true);
3488 }
3489
3490 public void sitDown(boolean checkCast)
3491 {
3492 if (checkCast && isCastingNow())
3493 {
3494 sendMessage("Cannot sit while casting");
3495 return;
3496 }
3497
3498 if (!_waitTypeSitting && !isAttackingDisabled() && !isOutOfControl() && !isImmobilized())
3499 {
3500 breakAttack();
3501 setIsSitting(true);
3502 broadcastPacket(new ChangeWaitType(this, ChangeWaitType.WT_SITTING));
3503 // Schedule a sit down task to wait for the animation to finish
3504 ThreadPoolManager.getInstance().scheduleGeneral(new SitDownTask(), 2500);
3505 setIsParalyzed(true);
3506 }
3507 }
3508
3509 /**
3510 * Sit down Task
3511 */
3512 protected class SitDownTask implements Runnable
3513 {
3514 @Override
3515 public void run()
3516 {
3517 setIsParalyzed(false);
3518 getAI().setIntention(CtrlIntention.AI_INTENTION_REST);
3519 }
3520 }
3521
3522 /**
3523 * Stand up Task
3524 */
3525 protected class StandUpTask implements Runnable
3526 {
3527 @Override
3528 public void run()
3529 {
3530 setIsSitting(false);
3531 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
3532 }
3533 }
3534
3535 /**
3536 * Stand up the L2PcInstance, set the AI Intention to AI_INTENTION_IDLE and send a Server->Client ChangeWaitType packet (broadcast)
3537 */
3538 public void standUp()
3539 {
3540 if (L2Event.isParticipant(this) && getEventStatus().eventSitForced)
3541 {
3542 sendMessage("A dark force beyond your mortal understanding makes your knees to shake when you try to stand up...");
3543 }
3544 else if (_waitTypeSitting && !isInStoreMode() && !isAlikeDead())
3545 {
3546 if (_effects.isAffected(CharEffectList.EFFECT_FLAG_RELAXING))
3547 {
3548 stopEffects(L2EffectType.RELAXING);
3549 }
3550
3551 broadcastPacket(new ChangeWaitType(this, ChangeWaitType.WT_STANDING));
3552 // Schedule a stand up task to wait for the animation to finish
3553 ThreadPoolManager.getInstance().scheduleGeneral(new StandUpTask(), 2500);
3554 }
3555 }
3556
3557 /**
3558 * @return the PcWarehouse object of the L2PcInstance.
3559 */
3560 public PcWarehouse getWarehouse()
3561 {
3562 if (_warehouse == null)
3563 {
3564 _warehouse = new PcWarehouse(this);
3565 _warehouse.restore();
3566 }
3567 if (Config.WAREHOUSE_CACHE)
3568 {
3569 WarehouseCacheManager.getInstance().addCacheTask(this);
3570 }
3571 return _warehouse;
3572 }
3573
3574 /**
3575 * Free memory used by Warehouse
3576 */
3577 public void clearWarehouse()
3578 {
3579 if (_warehouse != null)
3580 {
3581 _warehouse.deleteMe();
3582 }
3583 _warehouse = null;
3584 }
3585
3586 /**
3587 * @return the PcFreight object of the L2PcInstance.
3588 */
3589 public PcFreight getFreight()
3590 {
3591 return _freight;
3592 }
3593
3594 /**
3595 * @return true if refund list is not empty
3596 */
3597 public boolean hasRefund()
3598 {
3599 return (_refund != null) && (_refund.getSize() > 0) && Config.ALLOW_REFUND;
3600 }
3601
3602 /**
3603 * @return refund object or create new if not exist
3604 */
3605 public PcRefund getRefund()
3606 {
3607 if (_refund == null)
3608 {
3609 _refund = new PcRefund(this);
3610 }
3611 return _refund;
3612 }
3613
3614 /**
3615 * Clear refund
3616 */
3617 public void clearRefund()
3618 {
3619 if (_refund != null)
3620 {
3621 _refund.deleteMe();
3622 }
3623 _refund = null;
3624 }
3625
3626 /**
3627 * @return the Identifier of the L2PcInstance.
3628 */
3629 @Deprecated
3630 public int getCharId()
3631 {
3632 return _charId;
3633 }
3634
3635 /**
3636 * Set the Identifier of the L2PcInstance.
3637 * @param charId
3638 */
3639 @Deprecated
3640 public void setCharId(int charId)
3641 {
3642 _charId = charId;
3643 }
3644
3645 /**
3646 * @return the Adena amount of the L2PcInstance.
3647 */
3648 public long getAdena()
3649 {
3650 return _inventory.getAdena();
3651 }
3652
3653 /**
3654 * @return the Ancient Adena amount of the L2PcInstance.
3655 */
3656 public long getAncientAdena()
3657 {
3658 return _inventory.getAncientAdena();
3659 }
3660
3661 /**
3662 * Add adena to Inventory of the L2PcInstance and send a Server->Client InventoryUpdate packet to the L2PcInstance.
3663 * @param process : String Identifier of process triggering this action
3664 * @param count : int Quantity of adena to be added
3665 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
3666 * @param sendMessage : boolean Specifies whether to send message to Client about this action
3667 */
3668 public void addAdena(String process, long count, L2Object reference, boolean sendMessage)
3669 {
3670 if (sendMessage)
3671 {
3672 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S1_ADENA);
3673 sm.addItemNumber(count);
3674 sendPacket(sm);
3675 }
3676
3677 if (count > 0)
3678 {
3679 _inventory.addAdena(process, count, this, reference);
3680
3681 // Send update packet
3682 if (!Config.FORCE_INVENTORY_UPDATE)
3683 {
3684 InventoryUpdate iu = new InventoryUpdate();
3685 iu.addItem(_inventory.getAdenaInstance());
3686 sendPacket(iu);
3687 }
3688 else
3689 {
3690 sendPacket(new ItemList(this, false));
3691 }
3692 }
3693 }
3694
3695 /**
3696 * Reduce adena in Inventory of the L2PcInstance and send a Server->Client InventoryUpdate packet to the L2PcInstance.
3697 * @param process : String Identifier of process triggering this action
3698 * @param count : long Quantity of adena to be reduced
3699 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
3700 * @param sendMessage : boolean Specifies whether to send message to Client about this action
3701 * @return boolean informing if the action was successful
3702 */
3703 public boolean reduceAdena(String process, long count, L2Object reference, boolean sendMessage)
3704 {
3705 if (count > getAdena())
3706 {
3707 if (sendMessage)
3708 {
3709 sendPacket(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
3710 }
3711 return false;
3712 }
3713
3714 if (count > 0)
3715 {
3716 L2ItemInstance adenaItem = _inventory.getAdenaInstance();
3717 if (!_inventory.reduceAdena(process, count, this, reference))
3718 {
3719 return false;
3720 }
3721
3722 // Send update packet
3723 if (!Config.FORCE_INVENTORY_UPDATE)
3724 {
3725 InventoryUpdate iu = new InventoryUpdate();
3726 iu.addItem(adenaItem);
3727 sendPacket(iu);
3728 }
3729 else
3730 {
3731 sendPacket(new ItemList(this, false));
3732 }
3733
3734 if (sendMessage)
3735 {
3736 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED_ADENA);
3737 sm.addItemNumber(count);
3738 sendPacket(sm);
3739 }
3740 }
3741
3742 return true;
3743 }
3744
3745 /**
3746 * Add ancient adena to Inventory of the L2PcInstance and send a Server->Client InventoryUpdate packet to the L2PcInstance.
3747 * @param process : String Identifier of process triggering this action
3748 * @param count : int Quantity of ancient adena to be added
3749 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
3750 * @param sendMessage : boolean Specifies whether to send message to Client about this action
3751 */
3752 public void addAncientAdena(String process, long count, L2Object reference, boolean sendMessage)
3753 {
3754 if (sendMessage)
3755 {
3756 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
3757 sm.addItemName(PcInventory.ANCIENT_ADENA_ID);
3758 sm.addItemNumber(count);
3759 sendPacket(sm);
3760 }
3761
3762 if (count > 0)
3763 {
3764 _inventory.addAncientAdena(process, count, this, reference);
3765
3766 if (!Config.FORCE_INVENTORY_UPDATE)
3767 {
3768 InventoryUpdate iu = new InventoryUpdate();
3769 iu.addItem(_inventory.getAncientAdenaInstance());
3770 sendPacket(iu);
3771 }
3772 else
3773 {
3774 sendPacket(new ItemList(this, false));
3775 }
3776 }
3777 }
3778
3779 /**
3780 * Reduce ancient adena in Inventory of the L2PcInstance and send a Server->Client InventoryUpdate packet to the L2PcInstance.
3781 * @param process : String Identifier of process triggering this action
3782 * @param count : long Quantity of ancient adena to be reduced
3783 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
3784 * @param sendMessage : boolean Specifies whether to send message to Client about this action
3785 * @return boolean informing if the action was successful
3786 */
3787 public boolean reduceAncientAdena(String process, long count, L2Object reference, boolean sendMessage)
3788 {
3789 if (count > getAncientAdena())
3790 {
3791 if (sendMessage)
3792 {
3793 sendPacket(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
3794 }
3795
3796 return false;
3797 }
3798
3799 if (count > 0)
3800 {
3801 L2ItemInstance ancientAdenaItem = _inventory.getAncientAdenaInstance();
3802 if (!_inventory.reduceAncientAdena(process, count, this, reference))
3803 {
3804 return false;
3805 }
3806
3807 if (!Config.FORCE_INVENTORY_UPDATE)
3808 {
3809 InventoryUpdate iu = new InventoryUpdate();
3810 iu.addItem(ancientAdenaItem);
3811 sendPacket(iu);
3812 }
3813 else
3814 {
3815 sendPacket(new ItemList(this, false));
3816 }
3817
3818 if (sendMessage)
3819 {
3820 if (count > 1)
3821 {
3822 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
3823 sm.addItemName(PcInventory.ANCIENT_ADENA_ID);
3824 sm.addItemNumber(count);
3825 sendPacket(sm);
3826 }
3827 else
3828 {
3829 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
3830 sm.addItemName(PcInventory.ANCIENT_ADENA_ID);
3831 sendPacket(sm);
3832 }
3833 }
3834 }
3835
3836 return true;
3837 }
3838
3839 /**
3840 * Adds item to inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
3841 * @param process : String Identifier of process triggering this action
3842 * @param item : L2ItemInstance to be added
3843 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
3844 * @param sendMessage : boolean Specifies whether to send message to Client about this action
3845 */
3846 public void addItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage)
3847 {
3848 if (item.getCount() > 0)
3849 {
3850 // Sends message to client if requested
3851 if (sendMessage)
3852 {
3853 if (item.getCount() > 1)
3854 {
3855 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S1_S2);
3856 sm.addItemName(item);
3857 sm.addItemNumber(item.getCount());
3858 sendPacket(sm);
3859 }
3860 else if (item.getEnchantLevel() > 0)
3861 {
3862 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_A_S1_S2);
3863 sm.addNumber(item.getEnchantLevel());
3864 sm.addItemName(item);
3865 sendPacket(sm);
3866 }
3867 else
3868 {
3869 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S1);
3870 sm.addItemName(item);
3871 sendPacket(sm);
3872 }
3873 }
3874
3875 // Add the item to inventory
3876 L2ItemInstance newitem = _inventory.addItem(process, item, this, reference);
3877
3878 // Send inventory update packet
3879 if (!Config.FORCE_INVENTORY_UPDATE)
3880 {
3881 InventoryUpdate playerIU = new InventoryUpdate();
3882 playerIU.addItem(newitem);
3883 sendPacket(playerIU);
3884 }
3885 else
3886 {
3887 sendPacket(new ItemList(this, false));
3888 }
3889
3890 // Update current load as well
3891 StatusUpdate su = new StatusUpdate(this);
3892 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
3893 sendPacket(su);
3894
3895 // If over capacity, drop the item
3896 if (!canOverrideCond(PcCondOverride.ITEM_CONDITIONS) && !_inventory.validateCapacity(0, item.isQuestItem()) && newitem.isDropable() && (!newitem.isStackable() || (newitem.getLastChange() != L2ItemInstance.MODIFIED)))
3897 {
3898 dropItem("InvDrop", newitem, null, true, true);
3899 }
3900 else if (CursedWeaponsManager.getInstance().isCursed(newitem.getItemId()))
3901 {
3902 CursedWeaponsManager.getInstance().activate(this, newitem);
3903 }
3904
3905 // Combat Flag
3906 else if (FortSiegeManager.getInstance().isCombat(item.getItemId()))
3907 {
3908 if (FortSiegeManager.getInstance().activateCombatFlag(this, item))
3909 {
3910 Fort fort = FortManager.getInstance().getFort(this);
3911 fort.getSiege().announceToPlayer(SystemMessage.getSystemMessage(SystemMessageId.C1_ACQUIRED_THE_FLAG), getName());
3912 }
3913 }
3914 // Territory Ward
3915 else if ((item.getItemId() >= 13560) && (item.getItemId() <= 13568))
3916 {
3917 TerritoryWard ward = TerritoryWarManager.getInstance().getTerritoryWard(item.getItemId() - 13479);
3918 if (ward != null)
3919 {
3920 ward.activate(this, item);
3921 }
3922 }
3923 }
3924 }
3925
3926 /**
3927 * Adds item to Inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
3928 * @param process : String Identifier of process triggering this action
3929 * @param itemId : int Item Identifier of the item to be added
3930 * @param count : long Quantity of items to be added
3931 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
3932 * @param sendMessage : boolean Specifies whether to send message to Client about this action
3933 * @return
3934 */
3935 public L2ItemInstance addItem(String process, int itemId, long count, L2Object reference, boolean sendMessage)
3936 {
3937 if (count > 0)
3938 {
3939 L2ItemInstance item = null;
3940 if (ItemTable.getInstance().getTemplate(itemId) != null)
3941 {
3942 item = ItemTable.getInstance().createDummyItem(itemId);
3943 }
3944 else
3945 {
3946 _log.log(Level.SEVERE, "Item doesn't exist so cannot be added. Item ID: " + itemId);
3947 return null;
3948 }
3949 // Sends message to client if requested
3950 if (sendMessage && ((!isCastingNow() && (item.getItemType() == L2EtcItemType.HERB)) || (item.getItemType() != L2EtcItemType.HERB)))
3951 {
3952 if (count > 1)
3953 {
3954 if (process.equalsIgnoreCase("sweep") || process.equalsIgnoreCase("Quest"))
3955 {
3956 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
3957 sm.addItemName(itemId);
3958 sm.addItemNumber(count);
3959 sendPacket(sm);
3960 }
3961 else
3962 {
3963 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S1_S2);
3964 sm.addItemName(itemId);
3965 sm.addItemNumber(count);
3966 sendPacket(sm);
3967 }
3968 }
3969 else
3970 {
3971 if (process.equalsIgnoreCase("sweep") || process.equalsIgnoreCase("Quest"))
3972 {
3973 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1);
3974 sm.addItemName(itemId);
3975 sendPacket(sm);
3976 }
3977 else
3978 {
3979 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S1);
3980 sm.addItemName(itemId);
3981 sendPacket(sm);
3982 }
3983 }
3984 }
3985 // Auto use herbs - autoloot
3986 if (item.getItemType() == L2EtcItemType.HERB) // If item is herb dont add it to iv :]
3987 {
3988 if (!isCastingNow())
3989 {
3990 L2ItemInstance herb = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
3991 IItemHandler handler = ItemHandler.getInstance().getHandler(herb.getEtcItem());
3992 if (handler == null)
3993 {
3994 _log.warning("No item handler registered for Herb - item ID " + herb.getItemId() + ".");
3995 }
3996 else
3997 {
3998 handler.useItem(this, herb, false);
3999 if (_herbstask >= 100)
4000 {
4001 _herbstask -= 100;
4002 }
4003 }
4004 }
4005 else
4006 {
4007 _herbstask += 100;
4008 ThreadPoolManager.getInstance().scheduleAi(new HerbTask(process, itemId, count, reference, sendMessage), _herbstask);
4009 }
4010 }
4011 else
4012 {
4013 // Add the item to inventory
4014 L2ItemInstance createdItem = _inventory.addItem(process, itemId, count, this, reference);
4015
4016 // If over capacity, drop the item
4017 if (!canOverrideCond(PcCondOverride.ITEM_CONDITIONS) && !_inventory.validateCapacity(0, item.isQuestItem()) && createdItem.isDropable() && (!createdItem.isStackable() || (createdItem.getLastChange() != L2ItemInstance.MODIFIED)))
4018 {
4019 dropItem("InvDrop", createdItem, null, true);
4020 }
4021 else if (CursedWeaponsManager.getInstance().isCursed(createdItem.getItemId()))
4022 {
4023 CursedWeaponsManager.getInstance().activate(this, createdItem);
4024 }
4025 else if (FortSiegeManager.getInstance().isCombat(createdItem.getItemId()))
4026 {
4027 if (FortSiegeManager.getInstance().activateCombatFlag(this, item))
4028 {
4029 Fort fort = FortManager.getInstance().getFort(this);
4030 fort.getSiege().announceToPlayer(SystemMessage.getSystemMessage(SystemMessageId.C1_ACQUIRED_THE_FLAG), getName());
4031 }
4032 }
4033 // Territory Ward
4034 else if ((createdItem.getItemId() >= 13560) && (createdItem.getItemId() <= 13568))
4035 {
4036 TerritoryWard ward = TerritoryWarManager.getInstance().getTerritoryWard(createdItem.getItemId() - 13479);
4037 if (ward != null)
4038 {
4039 ward.activate(this, createdItem);
4040 }
4041 }
4042 return createdItem;
4043 }
4044 }
4045 return null;
4046 }
4047
4048 /**
4049 * Destroy item from inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
4050 * @param process : String Identifier of process triggering this action
4051 * @param item : L2ItemInstance to be destroyed
4052 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
4053 * @param sendMessage : boolean Specifies whether to send message to Client about this action
4054 * @return boolean informing if the action was successful
4055 */
4056 public boolean destroyItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage)
4057 {
4058 return destroyItem(process, item, item.getCount(), reference, sendMessage);
4059 }
4060
4061 /**
4062 * Destroy item from inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
4063 * @param process : String Identifier of process triggering this action
4064 * @param item : L2ItemInstance to be destroyed
4065 * @param count
4066 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
4067 * @param sendMessage : boolean Specifies whether to send message to Client about this action
4068 * @return boolean informing if the action was successful
4069 */
4070 public boolean destroyItem(String process, L2ItemInstance item, long count, L2Object reference, boolean sendMessage)
4071 {
4072 item = _inventory.destroyItem(process, item, count, this, reference);
4073
4074 if (item == null)
4075 {
4076 if (sendMessage)
4077 {
4078 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
4079 }
4080 return false;
4081 }
4082
4083 // Send inventory update packet
4084 if (!Config.FORCE_INVENTORY_UPDATE)
4085 {
4086 InventoryUpdate playerIU = new InventoryUpdate();
4087 playerIU.addItem(item);
4088 sendPacket(playerIU);
4089 }
4090 else
4091 {
4092 sendPacket(new ItemList(this, false));
4093 }
4094
4095 // Update current load as well
4096 StatusUpdate su = new StatusUpdate(this);
4097 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
4098 sendPacket(su);
4099
4100 // Sends message to client if requested
4101 if (sendMessage)
4102 {
4103 if (count > 1)
4104 {
4105 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
4106 sm.addItemName(item);
4107 sm.addItemNumber(count);
4108 sendPacket(sm);
4109 }
4110 else
4111 {
4112 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
4113 sm.addItemName(item);
4114 sendPacket(sm);
4115 }
4116 }
4117
4118 return true;
4119 }
4120
4121 /**
4122 * Destroys item from inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
4123 * @param process : String Identifier of process triggering this action
4124 * @param objectId : int Item Instance identifier of the item to be destroyed
4125 * @param count : int Quantity of items to be destroyed
4126 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
4127 * @param sendMessage : boolean Specifies whether to send message to Client about this action
4128 * @return boolean informing if the action was successful
4129 */
4130 @Override
4131 public boolean destroyItem(String process, int objectId, long count, L2Object reference, boolean sendMessage)
4132 {
4133 L2ItemInstance item = _inventory.getItemByObjectId(objectId);
4134
4135 if (item == null)
4136 {
4137 if (sendMessage)
4138 {
4139 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
4140 }
4141
4142 return false;
4143 }
4144 return destroyItem(process, item, count, reference, sendMessage);
4145 }
4146
4147 /**
4148 * Destroys shots from inventory without logging and only occasional saving to database. Sends a Server->Client InventoryUpdate packet to the L2PcInstance.
4149 * @param process : String Identifier of process triggering this action
4150 * @param objectId : int Item Instance identifier of the item to be destroyed
4151 * @param count : int Quantity of items to be destroyed
4152 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
4153 * @param sendMessage : boolean Specifies whether to send message to Client about this action
4154 * @return boolean informing if the action was successful
4155 */
4156 public boolean destroyItemWithoutTrace(String process, int objectId, long count, L2Object reference, boolean sendMessage)
4157 {
4158 L2ItemInstance item = _inventory.getItemByObjectId(objectId);
4159
4160 if ((item == null) || (item.getCount() < count))
4161 {
4162 if (sendMessage)
4163 {
4164 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
4165 }
4166
4167 return false;
4168 }
4169
4170 return destroyItem(null, item, count, reference, sendMessage);
4171 }
4172
4173 /**
4174 * Destroy item from inventory by using its <B>itemId</B> and send a Server->Client InventoryUpdate packet to the L2PcInstance.
4175 * @param process : String Identifier of process triggering this action
4176 * @param itemId : int Item identifier of the item to be destroyed
4177 * @param count : int Quantity of items to be destroyed
4178 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
4179 * @param sendMessage : boolean Specifies whether to send message to Client about this action
4180 * @return boolean informing if the action was successful
4181 */
4182 @Override
4183 public boolean destroyItemByItemId(String process, int itemId, long count, L2Object reference, boolean sendMessage)
4184 {
4185 if (itemId == PcInventory.ADENA_ID)
4186 {
4187 return reduceAdena(process, count, reference, sendMessage);
4188 }
4189
4190 L2ItemInstance item = _inventory.getItemByItemId(itemId);
4191
4192 if ((item == null) || (item.getCount() < count) || (_inventory.destroyItemByItemId(process, itemId, count, this, reference) == null))
4193 {
4194 if (sendMessage)
4195 {
4196 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
4197 }
4198
4199 return false;
4200 }
4201
4202 // Send inventory update packet
4203 if (!Config.FORCE_INVENTORY_UPDATE)
4204 {
4205 InventoryUpdate playerIU = new InventoryUpdate();
4206 playerIU.addItem(item);
4207 sendPacket(playerIU);
4208 }
4209 else
4210 {
4211 sendPacket(new ItemList(this, false));
4212 }
4213
4214 // Update current load as well
4215 StatusUpdate su = new StatusUpdate(this);
4216 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
4217 sendPacket(su);
4218
4219 // Sends message to client if requested
4220 if (sendMessage)
4221 {
4222 if (count > 1)
4223 {
4224 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
4225 sm.addItemName(itemId);
4226 sm.addItemNumber(count);
4227 sendPacket(sm);
4228 }
4229 else
4230 {
4231 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
4232 sm.addItemName(itemId);
4233 sendPacket(sm);
4234 }
4235 }
4236
4237 return true;
4238 }
4239
4240 /**
4241 * Transfers item to another ItemContainer and send a Server->Client InventoryUpdate packet to the L2PcInstance.
4242 * @param process : String Identifier of process triggering this action
4243 * @param objectId : int Item Identifier of the item to be transfered
4244 * @param count : long Quantity of items to be transfered
4245 * @param target
4246 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
4247 * @return L2ItemInstance corresponding to the new item or the updated item in inventory
4248 */
4249 public L2ItemInstance transferItem(String process, int objectId, long count, Inventory target, L2Object reference)
4250 {
4251 L2ItemInstance oldItem = checkItemManipulation(objectId, count, "transfer");
4252 if (oldItem == null)
4253 {
4254 return null;
4255 }
4256 L2ItemInstance newItem = getInventory().transferItem(process, objectId, count, target, this, reference);
4257 if (newItem == null)
4258 {
4259 return null;
4260 }
4261
4262 // Send inventory update packet
4263 if (!Config.FORCE_INVENTORY_UPDATE)
4264 {
4265 InventoryUpdate playerIU = new InventoryUpdate();
4266
4267 if ((oldItem.getCount() > 0) && (oldItem != newItem))
4268 {
4269 playerIU.addModifiedItem(oldItem);
4270 }
4271 else
4272 {
4273 playerIU.addRemovedItem(oldItem);
4274 }
4275
4276 sendPacket(playerIU);
4277 }
4278 else
4279 {
4280 sendPacket(new ItemList(this, false));
4281 }
4282
4283 // Update current load as well
4284 StatusUpdate playerSU = new StatusUpdate(this);
4285 playerSU.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
4286 sendPacket(playerSU);
4287
4288 // Send target update packet
4289 if (target instanceof PcInventory)
4290 {
4291 L2PcInstance targetPlayer = ((PcInventory) target).getOwner();
4292
4293 if (!Config.FORCE_INVENTORY_UPDATE)
4294 {
4295 InventoryUpdate playerIU = new InventoryUpdate();
4296
4297 if (newItem.getCount() > count)
4298 {
4299 playerIU.addModifiedItem(newItem);
4300 }
4301 else
4302 {
4303 playerIU.addNewItem(newItem);
4304 }
4305
4306 targetPlayer.sendPacket(playerIU);
4307 }
4308 else
4309 {
4310 targetPlayer.sendPacket(new ItemList(targetPlayer, false));
4311 }
4312
4313 // Update current load as well
4314 playerSU = new StatusUpdate(targetPlayer);
4315 playerSU.addAttribute(StatusUpdate.CUR_LOAD, targetPlayer.getCurrentLoad());
4316 targetPlayer.sendPacket(playerSU);
4317 }
4318 else if (target instanceof PetInventory)
4319 {
4320 PetInventoryUpdate petIU = new PetInventoryUpdate();
4321
4322 if (newItem.getCount() > count)
4323 {
4324 petIU.addModifiedItem(newItem);
4325 }
4326 else
4327 {
4328 petIU.addNewItem(newItem);
4329 }
4330
4331 ((PetInventory) target).getOwner().sendPacket(petIU);
4332 }
4333 return newItem;
4334 }
4335
4336 /**
4337 * Use instead of calling {@link #addItem(String, L2ItemInstance, L2Object, boolean)} and {@link #destroyItemByItemId(String, int, long, L2Object, boolean)}<br>
4338 * This method validates slots and weight limit, for stackable and non-stackable items.
4339 * @param process a generic string representing the process that is exchanging this items
4340 * @param reference the (probably NPC) reference, could be null
4341 * @param coinId the item Id of the item given on the exchange
4342 * @param cost the amount of items given on the exchange
4343 * @param rewardId the item received on the exchange
4344 * @param count the amount of items received on the exchange
4345 * @param sendMessage if {@code true} it will send messages to the acting player
4346 * @return {@code true} if the player successfully exchanged the items, {@code false} otherwise
4347 */
4348 public boolean exchangeItemsById(String process, L2Object reference, int coinId, long cost, int rewardId, long count, boolean sendMessage)
4349 {
4350 final PcInventory inv = getInventory();
4351 if (!inv.validateCapacityByItemId(rewardId, count))
4352 {
4353 if (sendMessage)
4354 {
4355 sendPacket(SystemMessageId.SLOTS_FULL);
4356 }
4357 return false;
4358 }
4359
4360 if (!inv.validateWeightByItemId(rewardId, count))
4361 {
4362 if (sendMessage)
4363 {
4364 sendPacket(SystemMessageId.WEIGHT_LIMIT_EXCEEDED);
4365 }
4366 return false;
4367 }
4368
4369 if (destroyItemByItemId(process, coinId, cost, reference, sendMessage))
4370 {
4371 addItem(process, rewardId, count, reference, sendMessage);
4372 return true;
4373 }
4374 return false;
4375 }
4376
4377 /**
4378 * Drop item from inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
4379 * @param process String Identifier of process triggering this action
4380 * @param item L2ItemInstance to be dropped
4381 * @param reference L2Object Object referencing current action like NPC selling item or previous item in transformation
4382 * @param sendMessage boolean Specifies whether to send message to Client about this action
4383 * @param protectItem whether or not dropped item must be protected temporary against other players
4384 * @return boolean informing if the action was successfull
4385 */
4386 public boolean dropItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage, boolean protectItem)
4387 {
4388 item = _inventory.dropItem(process, item, this, reference);
4389
4390 if (item == null)
4391 {
4392 if (sendMessage)
4393 {
4394 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
4395 }
4396
4397 return false;
4398 }
4399
4400 item.dropMe(this, (getX() + Rnd.get(50)) - 25, (getY() + Rnd.get(50)) - 25, getZ() + 20);
4401
4402 if ((Config.AUTODESTROY_ITEM_AFTER > 0) && Config.DESTROY_DROPPED_PLAYER_ITEM && !Config.LIST_PROTECTED_ITEMS.contains(item.getItemId()))
4403 {
4404 if ((item.isEquipable() && Config.DESTROY_EQUIPABLE_PLAYER_ITEM) || !item.isEquipable())
4405 {
4406 ItemsAutoDestroy.getInstance().addItem(item);
4407 }
4408 }
4409
4410 // protection against auto destroy dropped item
4411 if (Config.DESTROY_DROPPED_PLAYER_ITEM)
4412 {
4413 if (!item.isEquipable() || (item.isEquipable() && Config.DESTROY_EQUIPABLE_PLAYER_ITEM))
4414 {
4415 item.setProtected(false);
4416 }
4417 else
4418 {
4419 item.setProtected(true);
4420 }
4421 }
4422 else
4423 {
4424 item.setProtected(true);
4425 }
4426
4427 // retail drop protection
4428 if (protectItem)
4429 {
4430 item.getDropProtection().protect(this);
4431 }
4432
4433 // Send inventory update packet
4434 if (!Config.FORCE_INVENTORY_UPDATE)
4435 {
4436 InventoryUpdate playerIU = new InventoryUpdate();
4437 playerIU.addItem(item);
4438 sendPacket(playerIU);
4439 }
4440 else
4441 {
4442 sendPacket(new ItemList(this, false));
4443 }
4444
4445 // Update current load as well
4446 StatusUpdate su = new StatusUpdate(this);
4447 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
4448 sendPacket(su);
4449
4450 // Sends message to client if requested
4451 if (sendMessage)
4452 {
4453 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_DROPPED_S1);
4454 sm.addItemName(item);
4455 sendPacket(sm);
4456 }
4457
4458 return true;
4459 }
4460
4461 public boolean dropItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage)
4462 {
4463 return dropItem(process, item, reference, sendMessage, false);
4464 }
4465
4466 /**
4467 * Drop item from inventory by using its <B>objectID</B> and send a Server->Client InventoryUpdate packet to the L2PcInstance.
4468 * @param process : String Identifier of process triggering this action
4469 * @param objectId : int Item Instance identifier of the item to be dropped
4470 * @param count : long Quantity of items to be dropped
4471 * @param x : int coordinate for drop X
4472 * @param y : int coordinate for drop Y
4473 * @param z : int coordinate for drop Z
4474 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
4475 * @param sendMessage : boolean Specifies whether to send message to Client about this action
4476 * @param protectItem
4477 * @return L2ItemInstance corresponding to the new item or the updated item in inventory
4478 */
4479 public L2ItemInstance dropItem(String process, int objectId, long count, int x, int y, int z, L2Object reference, boolean sendMessage, boolean protectItem)
4480 {
4481 L2ItemInstance invitem = _inventory.getItemByObjectId(objectId);
4482 L2ItemInstance item = _inventory.dropItem(process, objectId, count, this, reference);
4483
4484 if (item == null)
4485 {
4486 if (sendMessage)
4487 {
4488 sendPacket(SystemMessageId.NOT_ENOUGH_ITEMS);
4489 }
4490
4491 return null;
4492 }
4493
4494 item.dropMe(this, x, y, z);
4495
4496 if ((Config.AUTODESTROY_ITEM_AFTER > 0) && Config.DESTROY_DROPPED_PLAYER_ITEM && !Config.LIST_PROTECTED_ITEMS.contains(item.getItemId()))
4497 {
4498 if ((item.isEquipable() && Config.DESTROY_EQUIPABLE_PLAYER_ITEM) || !item.isEquipable())
4499 {
4500 ItemsAutoDestroy.getInstance().addItem(item);
4501 }
4502 }
4503 if (Config.DESTROY_DROPPED_PLAYER_ITEM)
4504 {
4505 if (!item.isEquipable() || (item.isEquipable() && Config.DESTROY_EQUIPABLE_PLAYER_ITEM))
4506 {
4507 item.setProtected(false);
4508 }
4509 else
4510 {
4511 item.setProtected(true);
4512 }
4513 }
4514 else
4515 {
4516 item.setProtected(true);
4517 }
4518
4519 // retail drop protection
4520 if (protectItem)
4521 {
4522 item.getDropProtection().protect(this);
4523 }
4524
4525 // Send inventory update packet
4526 if (!Config.FORCE_INVENTORY_UPDATE)
4527 {
4528 InventoryUpdate playerIU = new InventoryUpdate();
4529 playerIU.addItem(invitem);
4530 sendPacket(playerIU);
4531 }
4532 else
4533 {
4534 sendPacket(new ItemList(this, false));
4535 }
4536
4537 // Update current load as well
4538 StatusUpdate su = new StatusUpdate(this);
4539 su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
4540 sendPacket(su);
4541
4542 // Sends message to client if requested
4543 if (sendMessage)
4544 {
4545 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_DROPPED_S1);
4546 sm.addItemName(item);
4547 sendPacket(sm);
4548 }
4549
4550 return item;
4551 }
4552
4553 public L2ItemInstance checkItemManipulation(int objectId, long count, String action)
4554 {
4555 // TODO: if we remove objects that are not visisble from the L2World, we'll have to remove this check
4556 if (L2World.getInstance().findObject(objectId) == null)
4557 {
4558 _log.finest(getObjectId() + ": player tried to " + action + " item not available in L2World");
4559 return null;
4560 }
4561
4562 L2ItemInstance item = getInventory().getItemByObjectId(objectId);
4563
4564 if ((item == null) || (item.getOwnerId() != getObjectId()))
4565 {
4566 _log.finest(getObjectId() + ": player tried to " + action + " item he is not owner of");
4567 return null;
4568 }
4569
4570 if ((count < 0) || ((count > 1) && !item.isStackable()))
4571 {
4572 _log.finest(getObjectId() + ": player tried to " + action + " item with invalid count: " + count);
4573 return null;
4574 }
4575
4576 if (count > item.getCount())
4577 {
4578 _log.finest(getObjectId() + ": player tried to " + action + " more items than he owns");
4579 return null;
4580 }
4581
4582 // Pet is summoned and not the item that summoned the pet AND not the buggle from strider you're mounting
4583 if ((hasSummon() && (getSummon().getControlObjectId() == objectId)) || (getMountObjectID() == objectId))
4584 {
4585 if (Config.DEBUG)
4586 {
4587 _log.finest(getObjectId() + ": player tried to " + action + " item controling pet");
4588 }
4589
4590 return null;
4591 }
4592
4593 if ((getActiveEnchantItem() != null) && (getActiveEnchantItem().getObjectId() == objectId))
4594 {
4595 if (Config.DEBUG)
4596 {
4597 _log.finest(getObjectId() + ":player tried to " + action + " an enchant scroll he was using");
4598 }
4599
4600 return null;
4601 }
4602
4603 // We cannot put a Weapon with Augmention in WH while casting (Possible Exploit)
4604 if (item.isAugmented() && (isCastingNow() || isCastingSimultaneouslyNow()))
4605 {
4606 return null;
4607 }
4608
4609 return item;
4610 }
4611
4612 /**
4613 * Set _protectEndTime according settings.
4614 * @param protect
4615 */
4616 public void setProtection(boolean protect)
4617 {
4618 if (Config.DEVELOPER && (protect || (_protectEndTime > 0)))
4619 {
4620 _log.warning(getName() + ": Protection " + (protect ? "ON " + (GameTimeController.getGameTicks() + (Config.PLAYER_SPAWN_PROTECTION * GameTimeController.TICKS_PER_SECOND)) : "OFF") + " (currently " + GameTimeController.getGameTicks() + ")");
4621 }
4622
4623 _protectEndTime = protect ? GameTimeController.getGameTicks() + (Config.PLAYER_SPAWN_PROTECTION * GameTimeController.TICKS_PER_SECOND) : 0;
4624 }
4625
4626 public void setTeleportProtection(boolean protect)
4627 {
4628 if (Config.DEVELOPER && (protect || (_teleportProtectEndTime > 0)))
4629 {
4630 _log.warning(getName() + ": Tele Protection " + (protect ? "ON " + (GameTimeController.getGameTicks() + (Config.PLAYER_TELEPORT_PROTECTION * GameTimeController.TICKS_PER_SECOND)) : "OFF") + " (currently " + GameTimeController.getGameTicks() + ")");
4631 }
4632
4633 _teleportProtectEndTime = protect ? GameTimeController.getGameTicks() + (Config.PLAYER_TELEPORT_PROTECTION * GameTimeController.TICKS_PER_SECOND) : 0;
4634 }
4635
4636 /**
4637 * Set protection from agro mobs when getting up from fake death, according settings.
4638 * @param protect
4639 */
4640 public void setRecentFakeDeath(boolean protect)
4641 {
4642 _recentFakeDeathEndTime = protect ? GameTimeController.getGameTicks() + (Config.PLAYER_FAKEDEATH_UP_PROTECTION * GameTimeController.TICKS_PER_SECOND) : 0;
4643 }
4644
4645 public boolean isRecentFakeDeath()
4646 {
4647 return _recentFakeDeathEndTime > GameTimeController.getGameTicks();
4648 }
4649
4650 public final boolean isFakeDeath()
4651 {
4652 return _isFakeDeath;
4653 }
4654
4655 public final void setIsFakeDeath(boolean value)
4656 {
4657 _isFakeDeath = value;
4658 }
4659
4660 @Override
4661 public final boolean isAlikeDead()
4662 {
4663 if (super.isAlikeDead())
4664 {
4665 return true;
4666 }
4667
4668 return isFakeDeath();
4669 }
4670
4671 /**
4672 * @return the client owner of this char.
4673 */
4674 public L2GameClient getClient()
4675 {
4676 return _client;
4677 }
4678
4679 public void setClient(L2GameClient client)
4680 {
4681 _client = client;
4682 }
4683
4684 /**
4685 * Close the active connection with the client.
4686 * @param closeClient
4687 */
4688 private void closeNetConnection(boolean closeClient)
4689 {
4690 L2GameClient client = _client;
4691 if (client != null)
4692 {
4693 if (client.isDetached())
4694 {
4695 client.cleanMe(true);
4696 }
4697 else
4698 {
4699 if (!client.getConnection().isClosed())
4700 {
4701 if (closeClient)
4702 {
4703 client.close(LeaveWorld.STATIC_PACKET);
4704 }
4705 else
4706 {
4707 client.close(ServerClose.STATIC_PACKET);
4708 }
4709 }
4710 }
4711 }
4712 }
4713
4714 public Point3D getCurrentSkillWorldPosition()
4715 {
4716 return _currentSkillWorldPosition;
4717 }
4718
4719 public void setCurrentSkillWorldPosition(Point3D worldPosition)
4720 {
4721 _currentSkillWorldPosition = worldPosition;
4722 }
4723
4724 @Override
4725 public void enableSkill(L2Skill skill)
4726 {
4727 super.enableSkill(skill);
4728 _reuseTimeStampsSkills.remove(skill.getReuseHashCode());
4729 }
4730
4731 @Override
4732 protected boolean checkDoCastConditions(L2Skill skill)
4733 {
4734 if (!super.checkDoCastConditions(skill))
4735 {
4736 return false;
4737 }
4738
4739 switch (skill.getSkillType())
4740 {
4741 case SUMMON_TRAP:
4742 {
4743 if (isInsideZone(ZoneId.PEACE))
4744 {
4745 sendPacket(SystemMessageId.A_MALICIOUS_SKILL_CANNOT_BE_USED_IN_PEACE_ZONE);
4746 return false;
4747 }
4748 if ((getTrap() != null) && (getTrap().getSkill().getId() == ((L2SkillTrap) skill).getTriggerSkillId()))
4749 {
4750 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
4751 sm.addSkillName(skill);
4752 sendPacket(sm);
4753 return false;
4754 }
4755 break;
4756 }
4757 case SUMMON:
4758 {
4759 if (!((L2SkillSummon) skill).isCubic() && (hasSummon() || isMounted() || CharSummonTable.getInstance().getPets().contains(getObjectId()) || CharSummonTable.getInstance().getPets().contains(getObjectId())))
4760 {
4761 if (Config.DEBUG)
4762 {
4763 _log.fine("player has a pet already. ignore summon skill");
4764 }
4765
4766 sendPacket(SystemMessageId.YOU_ALREADY_HAVE_A_PET);
4767 return false;
4768 }
4769 }
4770 }
4771
4772 // TODO: Should possibly be checked only in L2PcInstance's useMagic
4773 // Can't use Hero and resurrect skills during Olympiad
4774 if (isInOlympiadMode() && (skill.isHeroSkill() || (skill.getSkillType() == L2SkillType.RESURRECT)))
4775 {
4776 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THIS_SKILL_IS_NOT_AVAILABLE_FOR_THE_OLYMPIAD_EVENT);
4777 sendPacket(sm);
4778 return false;
4779 }
4780
4781 final int charges = getCharges();
4782 // Check if the spell using charges or not in AirShip
4783 if (((charges < skill.getChargeConsume())) || (isInAirShip() && (skill.getSkillType() != L2SkillType.REFUEL)))
4784 {
4785 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
4786 sm.addSkillName(skill);
4787 sendPacket(sm);
4788 return false;
4789 }
4790 return true;
4791 }
4792
4793 /**
4794 * Returns true if cp update should be done, false if not
4795 * @param barPixels
4796 * @return boolean
4797 */
4798 private boolean needCpUpdate(int barPixels)
4799 {
4800 double currentCp = getCurrentCp();
4801
4802 if ((currentCp <= 1.0) || (getMaxCp() < barPixels))
4803 {
4804 return true;
4805 }
4806
4807 if ((currentCp <= _cpUpdateDecCheck) || (currentCp >= _cpUpdateIncCheck))
4808 {
4809 if (currentCp == getMaxCp())
4810 {
4811 _cpUpdateIncCheck = currentCp + 1;
4812 _cpUpdateDecCheck = currentCp - _cpUpdateInterval;
4813 }
4814 else
4815 {
4816 double doubleMulti = currentCp / _cpUpdateInterval;
4817 int intMulti = (int) doubleMulti;
4818
4819 _cpUpdateDecCheck = _cpUpdateInterval * (doubleMulti < intMulti ? intMulti-- : intMulti);
4820 _cpUpdateIncCheck = _cpUpdateDecCheck + _cpUpdateInterval;
4821 }
4822
4823 return true;
4824 }
4825
4826 return false;
4827 }
4828
4829 /**
4830 * Returns true if mp update should be done, false if not
4831 * @param barPixels
4832 * @return boolean
4833 */
4834 private boolean needMpUpdate(int barPixels)
4835 {
4836 double currentMp = getCurrentMp();
4837
4838 if ((currentMp <= 1.0) || (getMaxMp() < barPixels))
4839 {
4840 return true;
4841 }
4842
4843 if ((currentMp <= _mpUpdateDecCheck) || (currentMp >= _mpUpdateIncCheck))
4844 {
4845 if (currentMp == getMaxMp())
4846 {
4847 _mpUpdateIncCheck = currentMp + 1;
4848 _mpUpdateDecCheck = currentMp - _mpUpdateInterval;
4849 }
4850 else
4851 {
4852 double doubleMulti = currentMp / _mpUpdateInterval;
4853 int intMulti = (int) doubleMulti;
4854
4855 _mpUpdateDecCheck = _mpUpdateInterval * (doubleMulti < intMulti ? intMulti-- : intMulti);
4856 _mpUpdateIncCheck = _mpUpdateDecCheck + _mpUpdateInterval;
4857 }
4858
4859 return true;
4860 }
4861
4862 return false;
4863 }
4864
4865 /**
4866 * 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. <B><U> Actions</U> :</B> <li>Send the Server->Client packet StatusUpdate with current HP, MP and CP to this L2PcInstance</li><BR>
4867 * <li>Send the Server->Client packet PartySmallWindowUpdate with current HP, MP and Level to all other L2PcInstance of the Party</li> <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND current HP and MP to all L2PcInstance of the _statusListener</B></FONT>
4868 */
4869 @Override
4870 public void broadcastStatusUpdate()
4871 {
4872 // TODO We mustn't send these informations to other players
4873 // Send the Server->Client packet StatusUpdate with current HP and MP to all L2PcInstance that must be informed of HP/MP updates of this L2PcInstance
4874 // super.broadcastStatusUpdate();
4875
4876 // Send the Server->Client packet StatusUpdate with current HP, MP and CP to this L2PcInstance
4877 StatusUpdate su = new StatusUpdate(this);
4878 su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
4879 su.addAttribute(StatusUpdate.CUR_MP, (int) getCurrentMp());
4880 su.addAttribute(StatusUpdate.CUR_CP, (int) getCurrentCp());
4881 su.addAttribute(StatusUpdate.MAX_CP, getMaxCp());
4882 sendPacket(su);
4883
4884 final boolean needCpUpdate = needCpUpdate(352);
4885 final boolean needHpUpdate = needHpUpdate(352);
4886 // Check if a party is in progress and party window update is usefull
4887 L2Party party = _party;
4888 if ((party != null) && (needCpUpdate || needHpUpdate || needMpUpdate(352)))
4889 {
4890 // Send the Server->Client packet PartySmallWindowUpdate with current HP, MP and Level to all other L2PcInstance of the Party
4891 PartySmallWindowUpdate update = new PartySmallWindowUpdate(this);
4892 party.broadcastToPartyMembers(this, update);
4893 }
4894
4895 if (isInOlympiadMode() && isOlympiadStart() && (needCpUpdate || needHpUpdate))
4896 {
4897 final OlympiadGameTask game = OlympiadGameManager.getInstance().getOlympiadTask(getOlympiadGameId());
4898 if ((game != null) && game.isBattleStarted())
4899 {
4900 game.getZone().broadcastStatusUpdate(this);
4901 }
4902 }
4903
4904 // In duel MP updated only with CP or HP
4905 if (isInDuel() && (needCpUpdate || needHpUpdate))
4906 {
4907 ExDuelUpdateUserInfo update = new ExDuelUpdateUserInfo(this);
4908 DuelManager.getInstance().broadcastToOppositTeam(this, update);
4909 }
4910 }
4911
4912 /**
4913 * Send a Server->Client packet UserInfo to this L2PcInstance and CharInfo to all L2PcInstance in its _KnownPlayers. <B><U> Concept</U> :</B> Others L2PcInstance in the detection area of the L2PcInstance are identified in <B>_knownPlayers</B>. In order to inform other players of this
4914 * L2PcInstance state modifications, server just need to go through _knownPlayers to send Server->Client Packet <B><U> Actions</U> :</B> <li>Send a Server->Client packet UserInfo to this L2PcInstance (Public and Private Data)</li> <li>Send a Server->Client packet CharInfo to all L2PcInstance in
4915 * _KnownPlayers of the L2PcInstance (Public data only)</li> <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>
4916 */
4917 public final void broadcastUserInfo()
4918 {
4919 // Send a Server->Client packet UserInfo to this L2PcInstance
4920 sendPacket(new UserInfo(this));
4921
4922 // Send a Server->Client packet CharInfo to all L2PcInstance in _KnownPlayers of the L2PcInstance
4923 broadcastPacket(new CharInfo(this));
4924 broadcastPacket(new ExBrExtraUserInfo(this));
4925 if (TerritoryWarManager.getInstance().isTWInProgress() && (TerritoryWarManager.getInstance().checkIsRegistered(-1, getObjectId()) || TerritoryWarManager.getInstance().checkIsRegistered(-1, getClan())))
4926 {
4927 broadcastPacket(new ExDominionWarStart(this));
4928 }
4929 }
4930
4931 public final void broadcastTitleInfo()
4932 {
4933 // Send a Server->Client packet UserInfo to this L2PcInstance
4934 sendPacket(new UserInfo(this));
4935 sendPacket(new ExBrExtraUserInfo(this));
4936
4937 // Send a Server->Client packet TitleUpdate to all L2PcInstance in _KnownPlayers of the L2PcInstance
4938
4939 broadcastPacket(new NicknameChanged(this));
4940 }
4941
4942 @Override
4943 public final void broadcastPacket(L2GameServerPacket mov)
4944 {
4945 if (!(mov instanceof CharInfo))
4946 {
4947 sendPacket(mov);
4948 }
4949
4950 mov.setInvisible(getAppearance().getInvisible());
4951
4952 Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
4953 for (L2PcInstance player : plrs)
4954 {
4955 if (player == null)
4956 {
4957 continue;
4958 }
4959 player.sendPacket(mov);
4960 if (mov instanceof CharInfo)
4961 {
4962 int relation = getRelation(player);
4963 Integer oldrelation = getKnownList().getKnownRelations().get(player.getObjectId());
4964 if ((oldrelation != null) && (oldrelation != relation))
4965 {
4966 player.sendPacket(new RelationChanged(this, relation, isAutoAttackable(player)));
4967 if (hasSummon())
4968 {
4969 player.sendPacket(new RelationChanged(getSummon(), relation, isAutoAttackable(player)));
4970 }
4971 }
4972 }
4973 }
4974 }
4975
4976 @Override
4977 public void broadcastPacket(L2GameServerPacket mov, int radiusInKnownlist)
4978 {
4979 if (!(mov instanceof CharInfo))
4980 {
4981 sendPacket(mov);
4982 }
4983
4984 mov.setInvisible(getAppearance().getInvisible());
4985
4986 Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
4987 for (L2PcInstance player : plrs)
4988 {
4989 if (player == null)
4990 {
4991 continue;
4992 }
4993 if (isInsideRadius(player, radiusInKnownlist, false, false))
4994 {
4995 player.sendPacket(mov);
4996 if (mov instanceof CharInfo)
4997 {
4998 int relation = getRelation(player);
4999 Integer oldrelation = getKnownList().getKnownRelations().get(player.getObjectId());
5000 if ((oldrelation != null) && (oldrelation != relation))
5001 {
5002 player.sendPacket(new RelationChanged(this, relation, isAutoAttackable(player)));
5003 if (hasSummon())
5004 {
5005 player.sendPacket(new RelationChanged(getSummon(), relation, isAutoAttackable(player)));
5006 }
5007 }
5008 }
5009 }
5010 }
5011 }
5012
5013 /**
5014 * @return the Alliance Identifier of the L2PcInstance.
5015 */
5016 public int getAllyId()
5017 {
5018 if (_clan == null)
5019 {
5020 return 0;
5021 }
5022 return _clan.getAllyId();
5023 }
5024
5025 public int getAllyCrestId()
5026 {
5027 if (getClanId() == 0)
5028 {
5029 return 0;
5030 }
5031 if (getClan().getAllyId() == 0)
5032 {
5033 return 0;
5034 }
5035 return getClan().getAllyCrestId();
5036 }
5037
5038 public void queryGameGuard()
5039 {
5040 if (getClient() != null)
5041 {
5042 getClient().setGameGuardOk(false);
5043 sendPacket(GameGuardQuery.STATIC_PACKET);
5044 }
5045 if (Config.GAMEGUARD_ENFORCE)
5046 {
5047 ThreadPoolManager.getInstance().scheduleGeneral(new GameGuardCheck(), 30 * 1000);
5048 }
5049 }
5050
5051 protected class GameGuardCheck implements Runnable
5052 {
5053 @Override
5054 public void run()
5055 {
5056 L2GameClient client = getClient();
5057 if ((client != null) && !client.isAuthedGG() && isOnline())
5058 {
5059 AdminTable.getInstance().broadcastMessageToGMs("Client " + client + " failed to reply GameGuard query and is being kicked!");
5060 _log.info("Client " + client + " failed to reply GameGuard query and is being kicked!");
5061 client.close(LeaveWorld.STATIC_PACKET);
5062 }
5063 }
5064 }
5065
5066 /**
5067 * Send a Server->Client packet StatusUpdate to the L2PcInstance.
5068 */
5069 @Override
5070 public void sendPacket(L2GameServerPacket packet)
5071 {
5072 if (_client != null)
5073 {
5074 _client.sendPacket(packet);
5075 }
5076 }
5077
5078 /**
5079 * Send SystemMessage packet.
5080 * @param id SystemMessageId
5081 */
5082 @Override
5083 public void sendPacket(SystemMessageId id)
5084 {
5085 sendPacket(SystemMessage.getSystemMessage(id));
5086 }
5087
5088 /**
5089 * Manage Interact Task with another L2PcInstance. <B><U> Actions</U> :</B> <li>If the private store is a STORE_PRIVATE_SELL, send a Server->Client PrivateBuyListSell packet to the L2PcInstance</li> <li>If the private store is a STORE_PRIVATE_BUY, send a Server->Client PrivateBuyListBuy packet
5090 * to the L2PcInstance</li> <li>If the private store is a STORE_PRIVATE_MANUFACTURE, send a Server->Client RecipeShopSellList packet to the L2PcInstance</li>
5091 * @param target The L2Character targeted
5092 */
5093 public void doInteract(L2Character target)
5094 {
5095 if (target instanceof L2PcInstance)
5096 {
5097 L2PcInstance temp = (L2PcInstance) target;
5098 sendPacket(ActionFailed.STATIC_PACKET);
5099
5100 if ((temp.getPrivateStoreType() == STORE_PRIVATE_SELL) || (temp.getPrivateStoreType() == STORE_PRIVATE_PACKAGE_SELL))
5101 {
5102 sendPacket(new PrivateStoreListSell(this, temp));
5103 }
5104 else if (temp.getPrivateStoreType() == STORE_PRIVATE_BUY)
5105 {
5106 sendPacket(new PrivateStoreListBuy(this, temp));
5107 }
5108 else if (temp.getPrivateStoreType() == STORE_PRIVATE_MANUFACTURE)
5109 {
5110 sendPacket(new RecipeShopSellList(this, temp));
5111 }
5112
5113 }
5114 else
5115 {
5116 // _interactTarget=null should never happen but one never knows ^^;
5117 if (target != null)
5118 {
5119 target.onAction(this);
5120 }
5121 }
5122 }
5123
5124 /**
5125 * Manage AutoLoot Task. <B><U> Actions</U> :</B> <li>Send a System Message to the L2PcInstance : YOU_PICKED_UP_S1_ADENA or YOU_PICKED_UP_S1_S2</li> <li>Add the Item to the L2PcInstance inventory</li> <li>Send a Server->Client packet InventoryUpdate to this L2PcInstance with NewItem (use a new
5126 * slot) or ModifiedItem (increase amount)</li> <li>Send a Server->Client packet StatusUpdate to this L2PcInstance with current weight</li> <FONT COLOR=#FF0000><B> <U>Caution</U> : If a Party is in progress, distribute Items between party members</B></FONT>
5127 * @param target The L2ItemInstance dropped
5128 * @param item
5129 */
5130 public void doAutoLoot(L2Attackable target, L2Attackable.RewardItem item)
5131 {
5132 if (isInParty() && (ItemTable.getInstance().getTemplate(item.getItemId()).getItemType() != L2EtcItemType.HERB))
5133 {
5134 getParty().distributeItem(this, item, false, target);
5135 }
5136 else if (item.getItemId() == PcInventory.ADENA_ID)
5137 {
5138 addAdena("Loot", item.getCount(), target, true);
5139 }
5140 else
5141 {
5142 addItem("Loot", item.getItemId(), item.getCount(), target, true);
5143 }
5144 }
5145
5146 /**
5147 * Manage Pickup Task. <B><U> Actions</U> :</B> <li>Send a Server->Client packet StopMove to this L2PcInstance</li> <li>Remove the L2ItemInstance from the world and send server->client GetItem packets</li> <li>Send a System Message to the L2PcInstance : YOU_PICKED_UP_S1_ADENA or
5148 * YOU_PICKED_UP_S1_S2</li> <li>Add the Item to the L2PcInstance inventory</li> <li>Send a Server->Client packet InventoryUpdate to this L2PcInstance with NewItem (use a new slot) or ModifiedItem (increase amount)</li> <li>Send a Server->Client packet StatusUpdate to this L2PcInstance with
5149 * current weight</li> <FONT COLOR=#FF0000><B> <U>Caution</U> : If a Party is in progress, distribute Items between party members</B></FONT>
5150 * @param object The L2ItemInstance to pick up
5151 */
5152 protected void doPickupItem(L2Object object)
5153 {
5154 if (isAlikeDead() || isFakeDeath())
5155 {
5156 return;
5157 }
5158
5159 // Set the AI Intention to AI_INTENTION_IDLE
5160 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
5161
5162 // Check if the L2Object to pick up is a L2ItemInstance
5163 if (!(object instanceof L2ItemInstance))
5164 {
5165 // dont try to pickup anything that is not an item :)
5166 _log.warning(this + " trying to pickup wrong target." + getTarget());
5167 return;
5168 }
5169
5170 L2ItemInstance target = (L2ItemInstance) object;
5171
5172 // Send a Server->Client packet ActionFailed to this L2PcInstance
5173 sendPacket(ActionFailed.STATIC_PACKET);
5174
5175 // Send a Server->Client packet StopMove to this L2PcInstance
5176 StopMove sm = new StopMove(this);
5177 sendPacket(sm);
5178
5179 SystemMessage smsg = null;
5180 synchronized (target)
5181 {
5182 // Check if the target to pick up is visible
5183 if (!target.isVisible())
5184 {
5185 // Send a Server->Client packet ActionFailed to this L2PcInstance
5186 sendPacket(ActionFailed.STATIC_PACKET);
5187 return;
5188 }
5189
5190 if (!target.getDropProtection().tryPickUp(this))
5191 {
5192 sendPacket(ActionFailed.STATIC_PACKET);
5193 smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
5194 smsg.addItemName(target);
5195 sendPacket(smsg);
5196 return;
5197 }
5198
5199 if (((isInParty() && (getParty().getLootDistribution() == L2Party.ITEM_LOOTER)) || !isInParty()) && !_inventory.validateCapacity(target))
5200 {
5201 sendPacket(ActionFailed.STATIC_PACKET);
5202 sendPacket(SystemMessageId.SLOTS_FULL);
5203 return;
5204 }
5205
5206 if (isInvul() && !canOverrideCond(PcCondOverride.ITEM_CONDITIONS))
5207 {
5208 sendPacket(ActionFailed.STATIC_PACKET);
5209 smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
5210 smsg.addItemName(target);
5211 sendPacket(smsg);
5212 return;
5213 }
5214
5215 if ((target.getOwnerId() != 0) && (target.getOwnerId() != getObjectId()) && !isInLooterParty(target.getOwnerId()))
5216 {
5217 if (target.getItemId() == PcInventory.ADENA_ID)
5218 {
5219 smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1_ADENA);
5220 smsg.addItemNumber(target.getCount());
5221 }
5222 else if (target.getCount() > 1)
5223 {
5224 smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S2_S1_S);
5225 smsg.addItemName(target);
5226 smsg.addItemNumber(target.getCount());
5227 }
5228 else
5229 {
5230 smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
5231 smsg.addItemName(target);
5232 }
5233 sendPacket(ActionFailed.STATIC_PACKET);
5234 sendPacket(smsg);
5235 return;
5236 }
5237
5238 // You can pickup only 1 combat flag
5239 if (FortSiegeManager.getInstance().isCombat(target.getItemId()))
5240 {
5241 if (!FortSiegeManager.getInstance().checkIfCanPickup(this))
5242 {
5243 return;
5244 }
5245 }
5246
5247 if ((target.getItemLootShedule() != null) && ((target.getOwnerId() == getObjectId()) || isInLooterParty(target.getOwnerId())))
5248 {
5249 target.resetOwnerTimer();
5250 }
5251
5252 // Remove the L2ItemInstance from the world and send server->client GetItem packets
5253 target.pickupMe(this);
5254 if (Config.SAVE_DROPPED_ITEM)
5255 {
5256 ItemsOnGroundManager.getInstance().removeObject(target);
5257 }
5258 }
5259
5260 // Auto use herbs - pick up
5261 if (target.getItemType() == L2EtcItemType.HERB)
5262 {
5263 IItemHandler handler = ItemHandler.getInstance().getHandler(target.getEtcItem());
5264 if (handler == null)
5265 {
5266 _log.fine("No item handler registered for item ID " + target.getItemId() + ".");
5267 }
5268 else
5269 {
5270 handler.useItem(this, target, false);
5271 }
5272 ItemTable.getInstance().destroyItem("Consume", target, this, null);
5273 }
5274 // Cursed Weapons are not distributed
5275 else if (CursedWeaponsManager.getInstance().isCursed(target.getItemId()))
5276 {
5277 addItem("Pickup", target, null, true);
5278 }
5279 else if (FortSiegeManager.getInstance().isCombat(target.getItemId()))
5280 {
5281 addItem("Pickup", target, null, true);
5282 }
5283 else
5284 {
5285 // if item is instance of L2ArmorType or L2WeaponType broadcast an "Attention" system message
5286 if ((target.getItemType() instanceof L2ArmorType) || (target.getItemType() instanceof L2WeaponType))
5287 {
5288 if (target.getEnchantLevel() > 0)
5289 {
5290 smsg = SystemMessage.getSystemMessage(SystemMessageId.ANNOUNCEMENT_C1_PICKED_UP_S2_S3);
5291 smsg.addPcName(this);
5292 smsg.addNumber(target.getEnchantLevel());
5293 smsg.addItemName(target.getItemId());
5294 broadcastPacket(smsg, 1400);
5295 }
5296 else
5297 {
5298 smsg = SystemMessage.getSystemMessage(SystemMessageId.ANNOUNCEMENT_C1_PICKED_UP_S2);
5299 smsg.addPcName(this);
5300 smsg.addItemName(target.getItemId());
5301 broadcastPacket(smsg, 1400);
5302 }
5303 }
5304
5305 // Check if a Party is in progress
5306 if (isInParty())
5307 {
5308 getParty().distributeItem(this, target);
5309 }
5310 else if ((target.getItemId() == PcInventory.ADENA_ID) && (getInventory().getAdenaInstance() != null))
5311 {
5312 addAdena("Pickup", target.getCount(), null, true);
5313 ItemTable.getInstance().destroyItem("Pickup", target, this, null);
5314 }
5315 else
5316 {
5317 addItem("Pickup", target, null, true);
5318 // Auto-Equip arrows/bolts if player has a bow/crossbow and player picks up arrows/bolts.
5319 final L2ItemInstance weapon = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
5320 if (weapon != null)
5321 {
5322 final L2EtcItem etcItem = target.getEtcItem();
5323 if (etcItem != null)
5324 {
5325 final L2EtcItemType itemType = etcItem.getItemType();
5326 if ((weapon.getItemType() == L2WeaponType.BOW) && (itemType == L2EtcItemType.ARROW))
5327 {
5328 checkAndEquipArrows();
5329 }
5330 else if ((weapon.getItemType() == L2WeaponType.CROSSBOW) && (itemType == L2EtcItemType.BOLT))
5331 {
5332 checkAndEquipBolts();
5333 }
5334 }
5335 }
5336 }
5337 }
5338 }
5339
5340 public boolean canOpenPrivateStore()
5341 {
5342 return !isAlikeDead() && !isInOlympiadMode() && !isMounted() && !isInsideZone(ZoneId.NO_STORE) && !isCastingNow();
5343 }
5344
5345 public void tryOpenPrivateBuyStore()
5346 {
5347 // Player shouldn't be able to set stores if he/she is alike dead (dead or fake death)
5348 if (canOpenPrivateStore())
5349 {
5350 if ((getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_BUY) || (getPrivateStoreType() == (L2PcInstance.STORE_PRIVATE_BUY + 1)))
5351 {
5352 setPrivateStoreType(L2PcInstance.STORE_PRIVATE_NONE);
5353 }
5354 if (getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_NONE)
5355 {
5356 if (isSitting())
5357 {
5358 standUp();
5359 }
5360 setPrivateStoreType(L2PcInstance.STORE_PRIVATE_BUY + 1);
5361 sendPacket(new PrivateStoreManageListBuy(this));
5362 }
5363 }
5364 else
5365 {
5366 if (isInsideZone(ZoneId.NO_STORE))
5367 {
5368 sendPacket(SystemMessageId.NO_PRIVATE_STORE_HERE);
5369 }
5370 sendPacket(ActionFailed.STATIC_PACKET);
5371 }
5372 }
5373
5374 public void tryOpenPrivateSellStore(boolean isPackageSale)
5375 {
5376 // Player shouldn't be able to set stores if he/she is alike dead (dead or fake death)
5377 if (canOpenPrivateStore())
5378 {
5379 if ((getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_SELL) || (getPrivateStoreType() == (L2PcInstance.STORE_PRIVATE_SELL + 1)) || (getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_PACKAGE_SELL))
5380 {
5381 setPrivateStoreType(L2PcInstance.STORE_PRIVATE_NONE);
5382 }
5383
5384 if (getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_NONE)
5385 {
5386 if (isSitting())
5387 {
5388 standUp();
5389 }
5390 setPrivateStoreType(L2PcInstance.STORE_PRIVATE_SELL + 1);
5391 sendPacket(new PrivateStoreManageListSell(this, isPackageSale));
5392 }
5393 }
5394 else
5395 {
5396 if (isInsideZone(ZoneId.NO_STORE))
5397 {
5398 sendPacket(SystemMessageId.NO_PRIVATE_STORE_HERE);
5399 }
5400 sendPacket(ActionFailed.STATIC_PACKET);
5401 }
5402 }
5403
5404 public final PreparedListContainer getMultiSell()
5405 {
5406 return _currentMultiSell;
5407 }
5408
5409 public final void setMultiSell(PreparedListContainer list)
5410 {
5411 _currentMultiSell = list;
5412 }
5413
5414 @Override
5415 public boolean isTransformed()
5416 {
5417 return (_transformation != null) && !_transformation.isStance();
5418 }
5419
5420 public boolean isInStance()
5421 {
5422 return (_transformation != null) && _transformation.isStance();
5423 }
5424
5425 public void transform(L2Transformation transformation)
5426 {
5427 if (_transformation != null)
5428 {
5429 // You already polymorphed and cannot polymorph again.
5430 SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.YOU_ALREADY_POLYMORPHED_AND_CANNOT_POLYMORPH_AGAIN);
5431 sendPacket(msg);
5432 return;
5433 }
5434 if (!fireTransformListeners(transformation, true))
5435 {
5436 return;
5437 }
5438
5439 setQueuedSkill(null, false, false);
5440 if (isMounted())
5441 {
5442 // Get off the strider or something else if character is mounted
5443 dismount();
5444 }
5445
5446 _transformation = transformation;
5447 stopAllToggles();
5448 transformation.onTransform();
5449 sendSkillList();
5450 sendPacket(new SkillCoolTime(this));
5451 sendPacket(ExBasicActionList.getStaticPacket(this));
5452 broadcastUserInfo();
5453 }
5454
5455 @Override
5456 public synchronized void untransform()
5457 {
5458 if (_transformation != null)
5459 {
5460 if (!fireTransformListeners(_transformation, false))
5461 {
5462 return;
5463 }
5464 setQueuedSkill(null, false, false);
5465 setTransformAllowedSkills(new int[] {});
5466 _transformation.onUntransform();
5467 _transformation = null;
5468 stopEffects(L2EffectType.TRANSFORMATION);
5469 sendSkillList();
5470 sendPacket(new SkillCoolTime(this));
5471 sendPacket(ExBasicActionList.getStaticPacket(this));
5472 broadcastUserInfo();
5473 }
5474 }
5475
5476 public L2Transformation getTransformation()
5477 {
5478 return _transformation;
5479 }
5480
5481 /**
5482 * This returns the transformation Id of the current transformation. For example, if a player is transformed as a Buffalo, and then picks up the Zariche, the transform Id returned will be that of the Zariche, and NOT the Buffalo.
5483 * @return Transformation Id
5484 */
5485 public int getTransformationId()
5486 {
5487 return (_transformation == null ? 0 : _transformation.getId());
5488 }
5489
5490 /**
5491 * This returns the transformation Id stored inside the character table, selected by the method: transformSelectInfo() For example, if a player is transformed as a Buffalo, and then picks up the Zariche, the transform Id returned will be that of the Buffalo, and NOT the Zariche.
5492 * @return Transformation Id
5493 */
5494 public int transformId()
5495 {
5496 return _transformationId;
5497 }
5498
5499 /**
5500 * This is a simple query that inserts the transform Id into the character table for future reference.
5501 */
5502 public void transformInsertInfo()
5503 {
5504 _transformationId = getTransformationId();
5505
5506 if ((_transformationId == L2Transformation.TRANSFORM_AKAMANAH) || (_transformationId == L2Transformation.TRANSFORM_ZARICHE))
5507 {
5508 return;
5509 }
5510
5511 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
5512 PreparedStatement statement = con.prepareStatement(UPDATE_CHAR_TRANSFORM))
5513 {
5514 statement.setInt(1, _transformationId);
5515 statement.setInt(2, getObjectId());
5516 statement.execute();
5517 }
5518 catch (Exception e)
5519 {
5520 _log.log(Level.SEVERE, "Transformation insert info: ", e);
5521 }
5522 }
5523
5524 /**
5525 * This selects the current
5526 * @return transformation Id
5527 */
5528 public int transformSelectInfo()
5529 {
5530 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
5531 PreparedStatement statement = con.prepareStatement(SELECT_CHAR_TRANSFORM))
5532 {
5533 statement.setInt(1, getObjectId());
5534 try (ResultSet rset = statement.executeQuery())
5535 {
5536 if (rset.next())
5537 {
5538 _transformationId = rset.getInt("transform_id");
5539 }
5540 }
5541 }
5542 catch (Exception e)
5543 {
5544 _log.log(Level.SEVERE, "Transformation select info: ", e);
5545 }
5546 return _transformationId;
5547 }
5548
5549 /**
5550 * Set a target. <B><U> Actions</U> :</B> <li>Remove the L2PcInstance from the _statusListener of the old target if it was a L2Character</li> <li>Add the L2PcInstance to the _statusListener of the new target if it's a L2Character</li> <li>Target the new L2Object (add the target to the
5551 * L2PcInstance _target, _knownObject and L2PcInstance to _KnownObject of the L2Object)</li>
5552 * @param newTarget The L2Object to target
5553 */
5554 @Override
5555 public void setTarget(L2Object newTarget)
5556 {
5557
5558 if (newTarget != null)
5559 {
5560 boolean isParty = (((newTarget instanceof L2PcInstance) && isInParty() && getParty().getMembers().contains(newTarget)));
5561
5562 // Check if the new target is visible
5563 if (!isParty && !newTarget.isVisible())
5564 {
5565 newTarget = null;
5566 }
5567
5568 // Prevents /target exploiting
5569 if ((newTarget != null) && !isParty && (Math.abs(newTarget.getZ() - getZ()) > 1000))
5570 {
5571 newTarget = null;
5572 }
5573 }
5574 if (!isGM())
5575 {
5576 // Can't target and attack festival monsters if not participant
5577 if ((newTarget instanceof L2FestivalMonsterInstance) && !isFestivalParticipant())
5578 {
5579 newTarget = null;
5580 }
5581 else if (newTarget instanceof L2Vehicle)
5582 {
5583 newTarget = null;
5584 }
5585 else if (isInParty() && getParty().isInDimensionalRift())
5586 {
5587 byte riftType = getParty().getDimensionalRift().getType();
5588 byte riftRoom = getParty().getDimensionalRift().getCurrentRoom();
5589
5590 if ((newTarget != null) && !DimensionalRiftManager.getInstance().getRoom(riftType, riftRoom).checkIfInZone(newTarget.getX(), newTarget.getY(), newTarget.getZ()))
5591 {
5592 newTarget = null;
5593 }
5594 }
5595 }
5596
5597 // Get the current target
5598 L2Object oldTarget = getTarget();
5599
5600 if (oldTarget != null)
5601 {
5602 if (oldTarget.equals(newTarget))
5603 {
5604 return; // no target change
5605 }
5606
5607 // Remove the L2PcInstance from the _statusListener of the old target if it was a L2Character
5608 if (oldTarget instanceof L2Character)
5609 {
5610 ((L2Character) oldTarget).removeStatusListener(this);
5611 }
5612 }
5613
5614 // Add the L2PcInstance to the _statusListener of the new target if it's a L2Character
5615 if (newTarget instanceof L2Character)
5616 {
5617 ((L2Character) newTarget).addStatusListener(this);
5618 TargetSelected my = new TargetSelected(getObjectId(), newTarget.getObjectId(), getX(), getY(), getZ());
5619 broadcastPacket(my);
5620 }
5621 if ((newTarget == null) && (getTarget() != null))
5622 {
5623 broadcastPacket(new TargetUnselected(this));
5624 }
5625
5626 // Target the new L2Object (add the target to the L2PcInstance _target, _knownObject and L2PcInstance to _KnownObject of the L2Object)
5627 super.setTarget(newTarget);
5628 }
5629
5630 /**
5631 * Return the active weapon instance (always equiped in the right hand).
5632 */
5633 @Override
5634 public L2ItemInstance getActiveWeaponInstance()
5635 {
5636 return getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
5637 }
5638
5639 /**
5640 * Return the active weapon item (always equiped in the right hand).
5641 */
5642 @Override
5643 public L2Weapon getActiveWeaponItem()
5644 {
5645 L2ItemInstance weapon = getActiveWeaponInstance();
5646
5647 if (weapon == null)
5648 {
5649 return getFistsWeaponItem();
5650 }
5651
5652 return (L2Weapon) weapon.getItem();
5653 }
5654
5655 public L2ItemInstance getChestArmorInstance()
5656 {
5657 return getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST);
5658 }
5659
5660 public L2ItemInstance getLegsArmorInstance()
5661 {
5662 return getInventory().getPaperdollItem(Inventory.PAPERDOLL_LEGS);
5663 }
5664
5665 public L2Armor getActiveChestArmorItem()
5666 {
5667 L2ItemInstance armor = getChestArmorInstance();
5668
5669 if (armor == null)
5670 {
5671 return null;
5672 }
5673
5674 return (L2Armor) armor.getItem();
5675 }
5676
5677 public L2Armor getActiveLegsArmorItem()
5678 {
5679 L2ItemInstance legs = getLegsArmorInstance();
5680
5681 if (legs == null)
5682 {
5683 return null;
5684 }
5685
5686 return (L2Armor) legs.getItem();
5687 }
5688
5689 public boolean isWearingHeavyArmor()
5690 {
5691 L2ItemInstance legs = getLegsArmorInstance();
5692 L2ItemInstance armor = getChestArmorInstance();
5693
5694 if ((armor != null) && (legs != null))
5695 {
5696 if (((L2ArmorType) legs.getItemType() == L2ArmorType.HEAVY) && ((L2ArmorType) armor.getItemType() == L2ArmorType.HEAVY))
5697 {
5698 return true;
5699 }
5700 }
5701 if (armor != null)
5702 {
5703 if (((getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST).getItem().getBodyPart() == L2Item.SLOT_FULL_ARMOR) && ((L2ArmorType) armor.getItemType() == L2ArmorType.HEAVY)))
5704 {
5705 return true;
5706 }
5707 }
5708 return false;
5709 }
5710
5711 public boolean isWearingLightArmor()
5712 {
5713 L2ItemInstance legs = getLegsArmorInstance();
5714 L2ItemInstance armor = getChestArmorInstance();
5715
5716 if ((armor != null) && (legs != null))
5717 {
5718 if (((L2ArmorType) legs.getItemType() == L2ArmorType.LIGHT) && ((L2ArmorType) armor.getItemType() == L2ArmorType.LIGHT))
5719 {
5720 return true;
5721 }
5722 }
5723 if (armor != null)
5724 {
5725 if (((getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST).getItem().getBodyPart() == L2Item.SLOT_FULL_ARMOR) && ((L2ArmorType) armor.getItemType() == L2ArmorType.LIGHT)))
5726 {
5727 return true;
5728 }
5729 }
5730 return false;
5731 }
5732
5733 public boolean isWearingMagicArmor()
5734 {
5735 L2ItemInstance legs = getLegsArmorInstance();
5736 L2ItemInstance armor = getChestArmorInstance();
5737
5738 if ((armor != null) && (legs != null))
5739 {
5740 if (((L2ArmorType) legs.getItemType() == L2ArmorType.MAGIC) && ((L2ArmorType) armor.getItemType() == L2ArmorType.MAGIC))
5741 {
5742 return true;
5743 }
5744 }
5745 if (armor != null)
5746 {
5747 if (((getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST).getItem().getBodyPart() == L2Item.SLOT_FULL_ARMOR) && ((L2ArmorType) armor.getItemType() == L2ArmorType.MAGIC)))
5748 {
5749 return true;
5750 }
5751 }
5752 return false;
5753 }
5754
5755 public boolean isMarried()
5756 {
5757 return _married;
5758 }
5759
5760 public void setMarried(boolean state)
5761 {
5762 _married = state;
5763 }
5764
5765 public boolean isEngageRequest()
5766 {
5767 return _engagerequest;
5768 }
5769
5770 public void setEngageRequest(boolean state, int playerid)
5771 {
5772 _engagerequest = state;
5773 _engageid = playerid;
5774 }
5775
5776 public void setMarryRequest(boolean state)
5777 {
5778 _marryrequest = state;
5779 }
5780
5781 public boolean isMarryRequest()
5782 {
5783 return _marryrequest;
5784 }
5785
5786 public void setMarryAccepted(boolean state)
5787 {
5788 _marryaccepted = state;
5789 }
5790
5791 public boolean isMarryAccepted()
5792 {
5793 return _marryaccepted;
5794 }
5795
5796 public int getEngageId()
5797 {
5798 return _engageid;
5799 }
5800
5801 public int getPartnerId()
5802 {
5803 return _partnerId;
5804 }
5805
5806 public void setPartnerId(int partnerid)
5807 {
5808 _partnerId = partnerid;
5809 }
5810
5811 public int getCoupleId()
5812 {
5813 return _coupleId;
5814 }
5815
5816 public void setCoupleId(int coupleId)
5817 {
5818 _coupleId = coupleId;
5819 }
5820
5821 public void engageAnswer(int answer)
5822 {
5823 if (!_engagerequest)
5824 {
5825 return;
5826 }
5827 else if (_engageid == 0)
5828 {
5829 return;
5830 }
5831 else
5832 {
5833 L2PcInstance ptarget = L2World.getInstance().getPlayer(_engageid);
5834 setEngageRequest(false, 0);
5835 if (ptarget != null)
5836 {
5837 if (answer == 1)
5838 {
5839 CoupleManager.getInstance().createCouple(ptarget, L2PcInstance.this);
5840 ptarget.sendMessage("Request to Engage has been >ACCEPTED<");
5841 }
5842 else
5843 {
5844 ptarget.sendMessage("Request to Engage has been >DENIED<!");
5845 }
5846 }
5847 }
5848 }
5849
5850 /**
5851 * Return the secondary weapon instance (always equiped in the left hand).
5852 */
5853 @Override
5854 public L2ItemInstance getSecondaryWeaponInstance()
5855 {
5856 return getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
5857 }
5858
5859 /**
5860 * Return the secondary L2Item item (always equiped in the left hand).<BR>
5861 * Arrows, Shield..<BR>
5862 */
5863 @Override
5864 public L2Item getSecondaryWeaponItem()
5865 {
5866 L2ItemInstance item = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
5867 if (item != null)
5868 {
5869 return item.getItem();
5870 }
5871 return null;
5872 }
5873
5874 /**
5875 * Kill the L2Character, Apply Death Penalty, Manage gain/loss Karma and Item Drop. <B><U> Actions</U> :</B> <li>Reduce the Experience of the L2PcInstance in function of the calculated Death Penalty</li> <li>If necessary, unsummon the Pet of the killed L2PcInstance</li> <li>Manage Karma gain for
5876 * attacker and Karam loss for the killed L2PcInstance</li> <li>If the killed L2PcInstance has Karma, manage Drop Item</li> <li>Kill the L2PcInstance</li>
5877 * @param killer
5878 */
5879 @Override
5880 public boolean doDie(L2Character killer)
5881 {
5882 // Kill the L2PcInstance
5883 if (!super.doDie(killer))
5884 {
5885 return false;
5886 }
5887
5888 if (isMounted())
5889 {
5890 stopFeed();
5891 }
5892 synchronized (this)
5893 {
5894 if (isFakeDeath())
5895 {
5896 stopFakeDeath(true);
5897 }
5898 }
5899
5900 if (killer != null)
5901 {
5902 L2PcInstance pk = killer.getActingPlayer();
5903
5904 TvTEvent.onKill(killer, this);
5905 TvTRoundEvent.onKill(killer, this);
5906
5907 if (L2Event.isParticipant(pk) && (pk != null))
5908 {
5909 pk.getEventStatus().kills.add(this);
5910 }
5911
5912 // Rank Arena (For Dual Box)
5913 if ((killer instanceof L2PcInstance) && isInsideZone(ZoneId.PVP) && !isInSiege() && Config.RANK_ARENA_ENABLED)
5914 {
5915 L2PcInstance k = (L2PcInstance) killer;
5916 String killIp = k.getClient().getConnection().getInetAddress().getHostAddress();
5917 String DeathIp = getClient().getConnection().getInetAddress().getHostAddress();
5918 if (!killIp.equals(DeathIp) || Config.RANK_ARENA_ACCEPT_SAME_IP || (!killer.isGM() && !isGM()))
5919 {
5920 ArenaLeaderboard.getInstance().onKill(killer.getObjectId(), killer.getName());
5921 ArenaLeaderboard.getInstance().onDeath(getObjectId(), getName());
5922 }
5923 }
5924
5925 // Rank Arena
5926 if (Config.RANK_ARENA_ENABLED && (killer instanceof L2PcInstance) && isInsideZone(ZoneId.PVP) && !isInSiege() && !TvTEvent.isPlayerParticipant(getObjectId()))
5927 {
5928 if (!killer.isGM() && !isGM())
5929 {
5930 ArenaLeaderboard.getInstance().onKill(killer.getObjectId(), killer.getName());
5931 ArenaLeaderboard.getInstance().onDeath(getObjectId(), getName());
5932 }
5933 }
5934
5935 // Rank TvT
5936 if (Config.RANK_TVT_ENABLED && (killer instanceof L2PcInstance) && TvTEvent.isStarted() && TvTEvent.isPlayerParticipant(getObjectId()))
5937 {
5938 if (!killer.isGM() && !isGM())
5939 {
5940 TvTLeaderboard.getInstance().onKill(killer.getObjectId(), killer.getName());
5941 TvTLeaderboard.getInstance().onDeath(getObjectId(), getName());
5942 }
5943 }
5944
5945 // announce pvp/pk
5946 if (Config.ANNOUNCE_PK_PVP && (pk != null) && !pk.isGM())
5947 {
5948 String msg = "";
5949 if (getPvpFlag() == 0)
5950 {
5951 msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName());
5952 if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
5953 {
5954 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1);
5955 sm.addString(msg);
5956 Announcements.getInstance().announceToAll(sm);
5957 }
5958 else
5959 {
5960 Announcements.getInstance().announceToAll(msg);
5961 }
5962 }
5963 else if (getPvpFlag() != 0)
5964 {
5965 msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName());
5966 if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
5967 {
5968 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1);
5969 sm.addString(msg);
5970 Announcements.getInstance().announceToAll(sm);
5971 }
5972 else
5973 {
5974 Announcements.getInstance().announceToAll(msg);
5975 }
5976 }
5977 }
5978
5979 broadcastStatusUpdate();
5980 if ((pk != null) && Config.ALLOW_HITMAN_GDE)
5981 {
5982 Hitman.getInstance().onDeath(pk, this);
5983 }
5984 // Clear resurrect xp calculation
5985 setExpBeforeDeath(0);
5986
5987 // Issues drop of Cursed Weapon.
5988 if (isCursedWeaponEquipped())
5989 {
5990 CursedWeaponsManager.getInstance().drop(_cursedWeaponEquippedId, killer);
5991 }
5992 else if (isCombatFlagEquipped())
5993 {
5994 // TODO: Fort siege during TW??
5995 if (TerritoryWarManager.getInstance().isTWInProgress())
5996 {
5997 TerritoryWarManager.getInstance().dropCombatFlag(this, true, false);
5998 }
5999 else
6000 {
6001 Fort fort = FortManager.getInstance().getFort(this);
6002 if (fort != null)
6003 {
6004 FortSiegeManager.getInstance().dropCombatFlag(this, fort.getFortId());
6005 }
6006 else
6007 {
6008 int slot = getInventory().getSlotFromItem(getInventory().getItemByItemId(9819));
6009 getInventory().unEquipItemInBodySlot(slot);
6010 destroyItem("CombatFlag", getInventory().getItemByItemId(9819), null, true);
6011 }
6012 }
6013 }
6014 else
6015 {
6016 if ((pk == null) || !pk.isCursedWeaponEquipped())
6017 {
6018 onDieDropItem(killer); // Check if any item should be dropped
6019
6020 if (!(isInsideZone(ZoneId.PVP) && !isInsideZone(ZoneId.SIEGE)))
6021 {
6022 if ((pk != null) && (pk.getClan() != null) && (getClan() != null) && !isAcademyMember() && !(pk.isAcademyMember()))
6023 {
6024 if ((_clan.isAtWarWith(pk.getClanId()) && pk.getClan().isAtWarWith(_clan.getClanId())) || (isInSiege() && pk.isInSiege()))
6025 {
6026 if (AntiFeedManager.getInstance().check(killer, this))
6027 {
6028 // when your reputation score is 0 or below, the other clan cannot acquire any reputation points
6029 if (getClan().getReputationScore() > 0)
6030 {
6031 pk.getClan().addReputationScore(Config.REPUTATION_SCORE_PER_KILL, false);
6032 }
6033 // when the opposing sides reputation score is 0 or below, your clans reputation score does not decrease
6034 if (pk.getClan().getReputationScore() > 0)
6035 {
6036 _clan.takeReputationScore(Config.REPUTATION_SCORE_PER_KILL, false);
6037 }
6038 }
6039 }
6040 }
6041 }
6042
6043 if (Config.ALT_GAME_DELEVEL)
6044 {
6045 // If player is Lucky shouldn't get penalized.
6046 if (!isLucky() && !isInTownWarEvent())
6047 {
6048 // Reduce the Experience of the L2PcInstance in function of the calculated Death Penalty
6049 // NOTE: deathPenalty +- Exp will update karma
6050 // Penalty is lower if the player is at war with the pk (war has to be declared)
6051 final boolean siegeNpc = (killer instanceof L2DefenderInstance) || (killer instanceof L2FortCommanderInstance);
6052 final boolean atWar = (pk != null) && (getClan() != null) && (getClan().isAtWarWith(pk.getClanId()));
6053 deathPenalty(atWar, (pk != null), siegeNpc);
6054 }
6055 }
6056 else if (!(isInsideZone(ZoneId.PVP) && !isInSiege()) || (pk == null))
6057 {
6058 onDieUpdateKarma(); // Update karma if delevel is not allowed
6059 }
6060 }
6061 }
6062 }
6063
6064 // Unsummon Cubics
6065 if (!_cubics.isEmpty())
6066 {
6067 for (L2CubicInstance cubic : _cubics.values())
6068 {
6069 cubic.stopAction();
6070 cubic.cancelDisappear();
6071 }
6072 _cubics.clear();
6073 }
6074
6075 if (_fusionSkill != null)
6076 {
6077 abortCast();
6078 }
6079
6080 for (L2Character character : getKnownList().getKnownCharacters())
6081 {
6082 if ((character.getFusionSkill() != null) && (character.getFusionSkill().getTarget() == this))
6083 {
6084 character.abortCast();
6085 }
6086 }
6087
6088 if (isInParty() && getParty().isInDimensionalRift())
6089 {
6090 getParty().getDimensionalRift().getDeadMemberList().add(this);
6091 }
6092
6093 if (getAgathionId() != 0)
6094 {
6095 setAgathionId(0);
6096 }
6097
6098 // calculate death penalty buff
6099 calculateDeathPenaltyBuffLevel(killer);
6100
6101 stopRentPet();
6102 stopWaterTask();
6103
6104 AntiFeedManager.getInstance().setLastDeathTime(getObjectId());
6105
6106 if (isPhoenixBlessed() || (isAffected(CharEffectList.EFFECT_FLAG_CHARM_OF_COURAGE) && isInSiege()))
6107 {
6108 reviveRequest(this, null, false);
6109 }
6110 return true;
6111 }
6112
6113 private void onDieDropItem(L2Character killer)
6114 {
6115 if (L2Event.isParticipant(this) || (killer == null))
6116 {
6117 return;
6118 }
6119
6120 L2PcInstance pk = killer.getActingPlayer();
6121 if ((getKarma() <= 0) && (pk != null) && (pk.getClan() != null) && (getClan() != null) && (pk.getClan().isAtWarWith(getClanId())
6122 // || getClan().isAtWarWith(((L2PcInstance)killer).getClanId())
6123 ))
6124 {
6125 return;
6126 }
6127
6128 if ((!isInsideZone(ZoneId.PVP) || (pk == null)) && (!isGM() || Config.KARMA_DROP_GM))
6129 {
6130 boolean isKarmaDrop = false;
6131 boolean isKillerNpc = (killer instanceof L2Npc);
6132 int pkLimit = Config.KARMA_PK_LIMIT;
6133
6134 int dropEquip = 0;
6135 int dropEquipWeapon = 0;
6136 int dropItem = 0;
6137 int dropLimit = 0;
6138 int dropPercent = 0;
6139
6140 if ((getKarma() > 0) && (getPkKills() >= pkLimit))
6141 {
6142 isKarmaDrop = true;
6143 dropPercent = Config.KARMA_RATE_DROP;
6144 dropEquip = Config.KARMA_RATE_DROP_EQUIP;
6145 dropEquipWeapon = Config.KARMA_RATE_DROP_EQUIP_WEAPON;
6146 dropItem = Config.KARMA_RATE_DROP_ITEM;
6147 dropLimit = Config.KARMA_DROP_LIMIT;
6148 }
6149 else if (isKillerNpc && (getLevel() > 4) && !isFestivalParticipant())
6150 {
6151 dropPercent = Config.PLAYER_RATE_DROP;
6152 dropEquip = Config.PLAYER_RATE_DROP_EQUIP;
6153 dropEquipWeapon = Config.PLAYER_RATE_DROP_EQUIP_WEAPON;
6154 dropItem = Config.PLAYER_RATE_DROP_ITEM;
6155 dropLimit = Config.PLAYER_DROP_LIMIT;
6156 }
6157
6158 if ((dropPercent > 0) && (Rnd.get(100) < dropPercent))
6159 {
6160 int dropCount = 0;
6161
6162 int itemDropPercent = 0;
6163
6164 for (L2ItemInstance itemDrop : getInventory().getItems())
6165 {
6166 // Don't drop
6167 if (itemDrop.isShadowItem() || // Dont drop Shadow Items
6168 itemDrop.isTimeLimitedItem() || // Dont drop Time Limited Items
6169 !itemDrop.isDropable() || (itemDrop.getItemId() == PcInventory.ADENA_ID) || // Adena
6170 (itemDrop.getItem().getType2() == L2Item.TYPE2_QUEST) || // Quest Items
6171 (hasSummon() && (getSummon().getControlObjectId() == itemDrop.getItemId())) || // Control Item of active pet
6172 (Arrays.binarySearch(Config.KARMA_LIST_NONDROPPABLE_ITEMS, itemDrop.getItemId()) >= 0) || // Item listed in the non droppable item list
6173 (Arrays.binarySearch(Config.KARMA_LIST_NONDROPPABLE_PET_ITEMS, itemDrop.getItemId()) >= 0 // Item listed in the non droppable pet item list
6174 ))
6175 {
6176 continue;
6177 }
6178
6179 if (itemDrop.isEquipped())
6180 {
6181 // Set proper chance according to Item type of equipped Item
6182 itemDropPercent = itemDrop.getItem().getType2() == L2Item.TYPE2_WEAPON ? dropEquipWeapon : dropEquip;
6183 getInventory().unEquipItemInSlot(itemDrop.getLocationSlot());
6184 }
6185 else
6186 {
6187 itemDropPercent = dropItem; // Item in inventory
6188 }
6189
6190 // NOTE: Each time an item is dropped, the chance of another item being dropped gets lesser (dropCount * 2)
6191 if (Rnd.get(100) < itemDropPercent)
6192 {
6193 dropItem("DieDrop", itemDrop, killer, true);
6194
6195 if (isKarmaDrop)
6196 {
6197 _log.warning(getName() + " has karma and dropped id = " + itemDrop.getItemId() + ", count = " + itemDrop.getCount());
6198 }
6199 else
6200 {
6201 _log.warning(getName() + " dropped id = " + itemDrop.getItemId() + ", count = " + itemDrop.getCount());
6202 }
6203
6204 if (++dropCount >= dropLimit)
6205 {
6206 break;
6207 }
6208 }
6209 }
6210 }
6211 }
6212 }
6213
6214 private void onDieUpdateKarma()
6215 {
6216 // Karma lose for server that does not allow delevel
6217 if (getKarma() > 0)
6218 {
6219 // this formula seems to work relatively well:
6220 // baseKarma * thisLVL * (thisLVL/100)
6221 // Calculate the new Karma of the attacker : newKarma = baseKarma*pkCountMulti*lvlDiffMulti
6222 double karmaLost = Config.KARMA_LOST_BASE;
6223 karmaLost *= getLevel(); // multiply by char lvl
6224 karmaLost *= (getLevel() / 100.0); // divide by 0.charLVL
6225 karmaLost = Math.round(karmaLost);
6226 if (karmaLost < 0)
6227 {
6228 karmaLost = 1;
6229 }
6230
6231 // Decrease Karma of the L2PcInstance and Send it a Server->Client StatusUpdate packet with Karma and PvP Flag if necessary
6232 setKarma(getKarma() - (int) karmaLost);
6233 }
6234 }
6235
6236 public void onKillUpdatePvPKarma(L2Character target)
6237 {
6238 if (target == null)
6239 {
6240 return;
6241 }
6242 if (!(target instanceof L2Playable))
6243 {
6244 return;
6245 }
6246
6247 L2PcInstance targetPlayer = target.getActingPlayer();
6248
6249 if (targetPlayer == null)
6250 {
6251 return; // Target player is null
6252 }
6253 if (targetPlayer == this)
6254 {
6255 return; // Target player is self
6256 }
6257
6258 if (isCursedWeaponEquipped())
6259 {
6260 CursedWeaponsManager.getInstance().increaseKills(_cursedWeaponEquippedId);
6261 // Custom message for time left
6262 // CursedWeapon cw = CursedWeaponsManager.getInstance().getCursedWeapon(_cursedWeaponEquipedId);
6263 // SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.THERE_IS_S1_HOUR_AND_S2_MINUTE_LEFT_OF_THE_FIXED_USAGE_TIME);
6264 // int timeLeftInHours = (int)(((cw.getTimeLeft()/60000)/60));
6265 // msg.addItemName(_cursedWeaponEquipedId);
6266 // msg.addNumber(timeLeftInHours);
6267 // sendPacket(msg);
6268 return;
6269 }
6270
6271 if (isInTownWarEvent() && targetPlayer.isInTownWarEvent())
6272 {
6273 getInventory().addItem("TownWar", Config.TW_ITEM_ID, Config.TW_ITEM_AMOUNT, this, this);
6274 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
6275 sm.addItemName(Config.TW_ITEM_ID);
6276 sm.addItemNumber(Config.TW_ITEM_AMOUNT);
6277 sendPacket(sm);
6278 sendMessage("You received your prize for a Town War kill!");
6279 }
6280
6281 // If in duel and you kill (only can kill l2summon), do nothing
6282 if (isInDuel() && targetPlayer.isInDuel())
6283 {
6284 return;
6285 }
6286
6287 // If in Arena, do nothing
6288 if (isInsideZone(ZoneId.PVP) || targetPlayer.isInsideZone(ZoneId.PVP))
6289 {
6290 return;
6291 }
6292
6293 // Check if it's pvp
6294 if ((checkIfPvP(target) && // Can pvp and
6295 (targetPlayer.getPvpFlag() != 0 // Target player has pvp flag set
6296 )) || // or
6297 (isInsideZone(ZoneId.PVP) && // Player is inside pvp zone and
6298 targetPlayer.isInsideZone(ZoneId.PVP) // Target player is inside pvp zone
6299 ))
6300 {
6301 increasePvpKills(target);
6302 }
6303 else
6304 // Target player doesn't have pvp flag set
6305 {
6306 // check about wars
6307 if ((targetPlayer.getClan() != null) && (getClan() != null) && getClan().isAtWarWith(targetPlayer.getClanId()) && targetPlayer.getClan().isAtWarWith(getClanId()) && (targetPlayer.getPledgeType() != L2Clan.SUBUNIT_ACADEMY) && (getPledgeType() != L2Clan.SUBUNIT_ACADEMY))
6308 {
6309 // 'Both way war' -> 'PvP Kill'
6310 increasePvpKills(target);
6311 return;
6312 }
6313
6314 // 'No war' or 'One way war' -> 'Normal PK'
6315 if (targetPlayer.getKarma() > 0) // Target player has karma
6316 {
6317 if (Config.KARMA_AWARD_PK_KILL)
6318 {
6319 increasePvpKills(target);
6320 }
6321 }
6322 else if (targetPlayer.getPvpFlag() == 0) // Target player doesn't have karma
6323 {
6324 if (Config.ALLOW_HITMAN_GDE && Config.HITMAN_GDE_TAKE_KARMA && Hitman.getInstance().exists(targetPlayer.getObjectId()))
6325 {
6326 return;
6327 }
6328 increasePkKillsAndKarma(target);
6329 // Unequip adventurer items
6330 checkItemRestriction();
6331 }
6332 }
6333 }
6334
6335 /**
6336 * Increase the pvp kills count and send the info to the player
6337 * @param target
6338 */
6339 public void increasePvpKills(L2Character target)
6340 {
6341 if ((target instanceof L2PcInstance) && AntiFeedManager.getInstance().check(this, target))
6342 {
6343 if (!isInTownWarEvent() || Config.TW_GIVE_PVP_AND_PK_POINTS)
6344 {
6345 // Add karma to attacker and increase its PK counter
6346 setPvpKills(getPvpKills() + 1);
6347
6348 PvPColorSystem pvpcolor = new PvPColorSystem();
6349 pvpcolor.updateNameColor(this);
6350 pvpcolor.updateTitleColor(this);
6351 // Send a Server->Client UserInfo packet to attacker with its Karma and PK Counter
6352 sendPacket(new UserInfo(this));
6353 sendPacket(new ExBrExtraUserInfo(this));
6354 }
6355 }
6356 }
6357
6358 /**
6359 * Increase pk count, karma and send the info to the player
6360 * @param target
6361 */
6362 public void increasePkKillsAndKarma(L2Character target)
6363 {
6364 int baseKarma = Config.KARMA_MIN_KARMA;
6365 int newKarma = baseKarma;
6366 int karmaLimit = Config.KARMA_MAX_KARMA;
6367
6368 int pkLVL = getLevel();
6369 int pkPKCount = getPkKills();
6370
6371 int targLVL = target.getLevel();
6372
6373 int lvlDiffMulti = 0;
6374 int pkCountMulti = 0;
6375
6376 // Check if the attacker has a PK counter greater than 0
6377 if (pkPKCount > 0)
6378 {
6379 pkCountMulti = pkPKCount / 2;
6380 }
6381 else
6382 {
6383 pkCountMulti = 1;
6384 }
6385
6386 if (pkCountMulti < 1)
6387 {
6388 pkCountMulti = 1;
6389 }
6390
6391 // Calculate the level difference Multiplier between attacker and killed L2PcInstance
6392 if (pkLVL > targLVL)
6393 {
6394 lvlDiffMulti = pkLVL / targLVL;
6395 }
6396 else
6397 {
6398 lvlDiffMulti = 1;
6399 }
6400
6401 if (lvlDiffMulti < 1)
6402 {
6403 lvlDiffMulti = 1;
6404 }
6405
6406 // Calculate the new Karma of the attacker : newKarma = baseKarma*pkCountMulti*lvlDiffMulti
6407 newKarma *= pkCountMulti;
6408 newKarma *= lvlDiffMulti;
6409
6410 // Make sure newKarma is less than karmaLimit and higher than baseKarma
6411 if (newKarma < baseKarma)
6412 {
6413 newKarma = baseKarma;
6414 }
6415 if (newKarma > karmaLimit)
6416 {
6417 newKarma = karmaLimit;
6418 }
6419
6420 // Fix to prevent overflow (=> karma has a max value of 2 147 483 647)
6421 if (getKarma() > (Integer.MAX_VALUE - newKarma))
6422 {
6423 newKarma = Integer.MAX_VALUE - getKarma();
6424 }
6425
6426 // Add karma to attacker and increase its PK counter
6427 if (!isInTownWarEvent() || Config.TW_ALLOW_KARMA)
6428 {
6429 setKarma(getKarma() + newKarma);
6430 }
6431
6432 if ((target instanceof L2PcInstance) && AntiFeedManager.getInstance().check(this, target) && (!isInTownWarEvent() || Config.TW_GIVE_PVP_AND_PK_POINTS))
6433 {
6434 setPkKills(getPkKills() + 1);
6435 }
6436
6437 // Send a Server->Client UserInfo packet to attacker with its Karma and PK Counter
6438 sendPacket(new UserInfo(this));
6439 sendPacket(new ExBrExtraUserInfo(this));
6440 }
6441
6442 public int calculateKarmaLost(long exp)
6443 {
6444 // KARMA LOSS
6445 // When a PKer gets killed by another player or a L2MonsterInstance, it loses a certain amount of Karma based on their level.
6446 // this (with defaults) results in a level 1 losing about ~2 karma per death, and a lvl 70 loses about 11760 karma per death...
6447 // You lose karma as long as you were not in a pvp zone and you did not kill urself.
6448 // NOTE: exp for death (if delevel is allowed) is based on the players level
6449
6450 long expGained = Math.abs(exp);
6451 expGained /= Config.KARMA_XP_DIVIDER;
6452
6453 // FIXME Micht : Maybe this code should be fixed and karma set to a long value
6454 int karmaLost = 0;
6455 if (expGained > Integer.MAX_VALUE)
6456 {
6457 karmaLost = Integer.MAX_VALUE;
6458 }
6459 else
6460 {
6461 karmaLost = (int) expGained;
6462 }
6463
6464 if (karmaLost < Config.KARMA_LOST_BASE)
6465 {
6466 karmaLost = Config.KARMA_LOST_BASE;
6467 }
6468 if (karmaLost > getKarma())
6469 {
6470 karmaLost = getKarma();
6471 }
6472
6473 return karmaLost;
6474 }
6475
6476 public void updatePvPStatus()
6477 {
6478 if (isInsideZone(ZoneId.PVP))
6479 {
6480 return;
6481 }
6482 setPvpFlagLasts(System.currentTimeMillis() + Config.PVP_NORMAL_TIME);
6483
6484 if (getPvpFlag() == 0)
6485 {
6486 startPvPFlag();
6487 }
6488 }
6489
6490 public void updatePvPStatus(L2Character target)
6491 {
6492 L2PcInstance player_target = target.getActingPlayer();
6493
6494 if (player_target == null)
6495 {
6496 return;
6497 }
6498
6499 if ((isInDuel() && (player_target.getDuelId() == getDuelId())))
6500 {
6501 return;
6502 }
6503 if ((!isInsideZone(ZoneId.PVP) || !player_target.isInsideZone(ZoneId.PVP)) && (player_target.getKarma() == 0))
6504 {
6505 if (checkIfPvP(player_target))
6506 {
6507 setPvpFlagLasts(System.currentTimeMillis() + Config.PVP_PVP_TIME);
6508 }
6509 else
6510 {
6511 setPvpFlagLasts(System.currentTimeMillis() + Config.PVP_NORMAL_TIME);
6512 }
6513 if (getPvpFlag() == 0)
6514 {
6515 startPvPFlag();
6516 }
6517 }
6518 }
6519
6520 /**
6521 * TODO: Unhardcode by implementing Lucky effect (Support for effects on passive skills required).
6522 * @return Returns {@code true} if player has Lucky skill and is level 9 or less.
6523 */
6524 public boolean isLucky()
6525 {
6526 return ((getLevel() <= 9) && (getKnownSkill(L2Skill.SKILL_LUCKY) != null));
6527 }
6528
6529 /**
6530 * Restore the specified % of experience this L2PcInstance has lost and sends a Server->Client StatusUpdate packet.
6531 * @param restorePercent
6532 */
6533 public void restoreExp(double restorePercent)
6534 {
6535 if (getExpBeforeDeath() > 0)
6536 {
6537 // Restore the specified % of lost experience.
6538 getStat().addExp(Math.round(((getExpBeforeDeath() - getExp()) * restorePercent) / 100));
6539 setExpBeforeDeath(0);
6540 }
6541 }
6542
6543 /**
6544 * Reduce the Experience (and level if necessary) of the L2PcInstance in function of the calculated Death Penalty. <B><U> Actions</U> :</B> <li>Calculate the Experience loss</li> <li>Set the value of _expBeforeDeath</li> <li>Set the new Experience value of the L2PcInstance and Decrease its level
6545 * if necessary</li> <li>Send a Server->Client StatusUpdate packet with its new Experience</li>
6546 * @param atwar
6547 * @param killed_by_pc
6548 * @param killed_by_siege_npc
6549 */
6550 public void deathPenalty(boolean atwar, boolean killed_by_pc, boolean killed_by_siege_npc)
6551 {
6552 // TODO Need Correct Penalty
6553 // Get the level of the L2PcInstance
6554 final int lvl = getLevel();
6555
6556 int clan_luck = getSkillLevel(L2Skill.SKILL_CLAN_LUCK);
6557
6558 double clan_luck_modificator = 1.0;
6559
6560 if (!killed_by_pc)
6561 {
6562 switch (clan_luck)
6563 {
6564 case 3:
6565 clan_luck_modificator = 0.8;
6566 break;
6567 case 2:
6568 clan_luck_modificator = 0.8;
6569 break;
6570 case 1:
6571 clan_luck_modificator = 0.88;
6572 break;
6573 default:
6574 clan_luck_modificator = 1.0;
6575 break;
6576 }
6577 }
6578 else
6579 {
6580 switch (clan_luck)
6581 {
6582 case 3:
6583 clan_luck_modificator = 0.5;
6584 break;
6585 case 2:
6586 clan_luck_modificator = 0.5;
6587 break;
6588 case 1:
6589 clan_luck_modificator = 0.5;
6590 break;
6591 default:
6592 clan_luck_modificator = 1.0;
6593 break;
6594 }
6595 }
6596
6597 // The death steal you some Exp
6598 double percentLost = Config.PLAYER_XP_PERCENT_LOST[getLevel()] * clan_luck_modificator;
6599
6600 if (getKarma() > 0)
6601 {
6602 percentLost *= Config.RATE_KARMA_EXP_LOST;
6603 }
6604
6605 if (isFestivalParticipant() || atwar)
6606 {
6607 percentLost /= 4.0;
6608 }
6609
6610 // Calculate the Experience loss
6611 long lostExp = 0;
6612 if (!L2Event.isParticipant(this))
6613 {
6614 if (lvl < ExperienceTable.getInstance().getMaxLevel())
6615 {
6616 lostExp = Math.round(((getStat().getExpForLevel(lvl + 1) - getStat().getExpForLevel(lvl)) * percentLost) / 100);
6617 }
6618 else
6619 {
6620 lostExp = Math.round(((getStat().getExpForLevel(ExperienceTable.getInstance().getMaxLevel()) - getStat().getExpForLevel(ExperienceTable.getInstance().getMaxLevel() - 1)) * percentLost) / 100);
6621 }
6622 }
6623
6624 // Get the Experience before applying penalty
6625 setExpBeforeDeath(getExp());
6626
6627 // No xp loss inside pvp zone unless
6628 // - it's a siege zone and you're NOT participating
6629 // - you're killed by a non-pc whose not belong to the siege
6630 if (isInsideZone(ZoneId.PVP))
6631 {
6632 // No xp loss for siege participants inside siege zone
6633 if (isInsideZone(ZoneId.SIEGE))
6634 {
6635 if (isInSiege() && (killed_by_pc || killed_by_siege_npc))
6636 {
6637 lostExp = 0;
6638 }
6639 }
6640 else if (killed_by_pc)
6641 {
6642 lostExp = 0;
6643 }
6644 }
6645
6646 // Set the new Experience value of the L2PcInstance
6647 getStat().addExp(-lostExp);
6648 }
6649
6650 public boolean isPartyWaiting()
6651 {
6652 return PartyMatchWaitingList.getInstance().getPlayers().contains(this);
6653 }
6654
6655 public void setPartyRoom(int id)
6656 {
6657 _partyroom = id;
6658 }
6659
6660 public int getPartyRoom()
6661 {
6662 return _partyroom;
6663 }
6664
6665 public boolean isInPartyMatchRoom()
6666 {
6667 return _partyroom > 0;
6668 }
6669
6670 /**
6671 * Stop the HP/MP/CP Regeneration task. <B><U> Actions</U> :</B> <li>Set the RegenActive flag to False</li> <li>Stop the HP/MP/CP Regeneration task</li>
6672 */
6673 public void stopAllTimers()
6674 {
6675 stopHpMpRegeneration();
6676 stopWarnUserTakeBreak();
6677 stopWaterTask();
6678 stopFeed();
6679 clearPetData();
6680 storePetFood(_mountNpcId);
6681 stopRentPet();
6682 stopPvpRegTask();
6683 stopPunishTask(true);
6684 stopSoulTask();
6685 stopChargeTask();
6686 stopFameTask();
6687 stopVitalityTask();
6688 stopRecoBonusTask();
6689 stopRecoGiveTask();
6690 }
6691
6692 @Override
6693 public L2Summon getSummon()
6694 {
6695 return _summon;
6696 }
6697
6698 /**
6699 * @return {@code true} if the player has a pet, {@code false} otherwise
6700 */
6701 public boolean hasSummon()
6702 {
6703 return _summon != null;
6704 }
6705
6706 /**
6707 * @return the L2Decoy of the L2PcInstance or null.
6708 */
6709 public L2Decoy getDecoy()
6710 {
6711 return _decoy;
6712 }
6713
6714 /**
6715 * @return the L2Trap of the L2PcInstance or null.
6716 */
6717 public L2Trap getTrap()
6718 {
6719 return _trap;
6720 }
6721
6722 /**
6723 * Set the L2Summon of the L2PcInstance.
6724 * @param summon
6725 */
6726 public void setPet(L2Summon summon)
6727 {
6728 _summon = summon;
6729 }
6730
6731 /**
6732 * Set the L2Decoy of the L2PcInstance.
6733 * @param decoy
6734 */
6735 public void setDecoy(L2Decoy decoy)
6736 {
6737 _decoy = decoy;
6738 }
6739
6740 /**
6741 * Set the L2Trap of this L2PcInstance
6742 * @param trap
6743 */
6744 public void setTrap(L2Trap trap)
6745 {
6746 _trap = trap;
6747 }
6748
6749 /**
6750 * @return the L2Summon of the L2PcInstance or null.
6751 */
6752 public List<L2TamedBeastInstance> getTrainedBeasts()
6753 {
6754 return _tamedBeast;
6755 }
6756
6757 /**
6758 * Set the L2Summon of the L2PcInstance.
6759 * @param tamedBeast
6760 */
6761 public void addTrainedBeast(L2TamedBeastInstance tamedBeast)
6762 {
6763 if (_tamedBeast == null)
6764 {
6765 _tamedBeast = new FastList<>();
6766 }
6767 _tamedBeast.add(tamedBeast);
6768 }
6769
6770 /**
6771 * @return the L2PcInstance requester of a transaction (ex : FriendInvite, JoinAlly, JoinParty...).
6772 */
6773 public L2Request getRequest()
6774 {
6775 return _request;
6776 }
6777
6778 /**
6779 * Set the L2PcInstance requester of a transaction (ex : FriendInvite, JoinAlly, JoinParty...).
6780 * @param requester
6781 */
6782 public void setActiveRequester(L2PcInstance requester)
6783 {
6784 _activeRequester = requester;
6785 }
6786
6787 /**
6788 * @return the L2PcInstance requester of a transaction (ex : FriendInvite, JoinAlly, JoinParty...).
6789 */
6790 public L2PcInstance getActiveRequester()
6791 {
6792 L2PcInstance requester = _activeRequester;
6793 if (requester != null)
6794 {
6795 if (requester.isRequestExpired() && (_activeTradeList == null))
6796 {
6797 _activeRequester = null;
6798 }
6799 }
6800 return _activeRequester;
6801 }
6802
6803 /**
6804 * @return True if a transaction is in progress.
6805 */
6806 public boolean isProcessingRequest()
6807 {
6808 return (getActiveRequester() != null) || (_requestExpireTime > GameTimeController.getGameTicks());
6809 }
6810
6811 /**
6812 * @return True if a transaction is in progress.
6813 */
6814 public boolean isProcessingTransaction()
6815 {
6816 return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getGameTicks());
6817 }
6818
6819 /**
6820 * Select the Warehouse to be used in next activity.
6821 * @param partner
6822 */
6823 public void onTransactionRequest(L2PcInstance partner)
6824 {
6825 _requestExpireTime = GameTimeController.getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND);
6826 partner.setActiveRequester(this);
6827 }
6828
6829 /**
6830 * Return true if last request is expired.
6831 * @return
6832 */
6833 public boolean isRequestExpired()
6834 {
6835 return !(_requestExpireTime > GameTimeController.getGameTicks());
6836 }
6837
6838 /**
6839 * Select the Warehouse to be used in next activity.
6840 */
6841 public void onTransactionResponse()
6842 {
6843 _requestExpireTime = 0;
6844 }
6845
6846 /**
6847 * Select the Warehouse to be used in next activity.
6848 * @param warehouse
6849 */
6850 public void setActiveWarehouse(ItemContainer warehouse)
6851 {
6852 _activeWarehouse = warehouse;
6853 }
6854
6855 /**
6856 * @return active Warehouse.
6857 */
6858 public ItemContainer getActiveWarehouse()
6859 {
6860 return _activeWarehouse;
6861 }
6862
6863 /**
6864 * Select the TradeList to be used in next activity.
6865 * @param tradeList
6866 */
6867 public void setActiveTradeList(TradeList tradeList)
6868 {
6869 _activeTradeList = tradeList;
6870 }
6871
6872 /**
6873 * @return active TradeList.
6874 */
6875 public TradeList getActiveTradeList()
6876 {
6877 return _activeTradeList;
6878 }
6879
6880 public void onTradeStart(L2PcInstance partner)
6881 {
6882 _activeTradeList = new TradeList(this);
6883 _activeTradeList.setPartner(partner);
6884
6885 SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.BEGIN_TRADE_WITH_C1);
6886 msg.addPcName(partner);
6887 sendPacket(msg);
6888 sendPacket(new TradeStart(this));
6889 }
6890
6891 public void onTradeConfirm(L2PcInstance partner)
6892 {
6893 SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_CONFIRMED_TRADE);
6894 msg.addPcName(partner);
6895 sendPacket(msg);
6896 sendPacket(TradeOtherDone.STATIC_PACKET);
6897 }
6898
6899 public void onTradeCancel(L2PcInstance partner)
6900 {
6901 if (_activeTradeList == null)
6902 {
6903 return;
6904 }
6905
6906 _activeTradeList.lock();
6907 _activeTradeList = null;
6908
6909 sendPacket(new TradeDone(0));
6910 SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_CANCELED_TRADE);
6911 msg.addPcName(partner);
6912 sendPacket(msg);
6913 }
6914
6915 public void onTradeFinish(boolean successfull)
6916 {
6917 _activeTradeList = null;
6918 sendPacket(new TradeDone(1));
6919 if (successfull)
6920 {
6921 sendPacket(SystemMessageId.TRADE_SUCCESSFUL);
6922 }
6923 }
6924
6925 public void startTrade(L2PcInstance partner)
6926 {
6927 onTradeStart(partner);
6928 partner.onTradeStart(this);
6929 }
6930
6931 public void cancelActiveTrade()
6932 {
6933 if (_activeTradeList == null)
6934 {
6935 return;
6936 }
6937
6938 L2PcInstance partner = _activeTradeList.getPartner();
6939 if (partner != null)
6940 {
6941 partner.onTradeCancel(this);
6942 }
6943 onTradeCancel(this);
6944 }
6945
6946 /**
6947 * @return the _createList object of the L2PcInstance.
6948 */
6949 public L2ManufactureList getCreateList()
6950 {
6951 return _createList;
6952 }
6953
6954 /**
6955 * Set the _createList object of the L2PcInstance.
6956 * @param x
6957 */
6958 public void setCreateList(L2ManufactureList x)
6959 {
6960 _createList = x;
6961 }
6962
6963 /**
6964 * @return the _buyList object of the L2PcInstance.
6965 */
6966 public TradeList getSellList()
6967 {
6968 if (_sellList == null)
6969 {
6970 _sellList = new TradeList(this);
6971 }
6972 return _sellList;
6973 }
6974
6975 /**
6976 * @return the _buyList object of the L2PcInstance.
6977 */
6978 public TradeList getBuyList()
6979 {
6980 if (_buyList == null)
6981 {
6982 _buyList = new TradeList(this);
6983 }
6984 return _buyList;
6985 }
6986
6987 /**
6988 * Set the Private Store type of the L2PcInstance. <B><U> Values </U> :</B> <li>0 : STORE_PRIVATE_NONE</li> <li>1 : STORE_PRIVATE_SELL</li> <li>2 : sellmanage</li><BR>
6989 * <li>3 : STORE_PRIVATE_BUY</li><BR>
6990 * <li>4 : buymanage</li><BR>
6991 * <li>5 : STORE_PRIVATE_MANUFACTURE</li><BR>
6992 * @param type
6993 */
6994 public void setPrivateStoreType(int type)
6995 {
6996 _privatestore = type;
6997
6998 if (Config.OFFLINE_DISCONNECT_FINISHED && (_privatestore == STORE_PRIVATE_NONE) && ((getClient() == null) || getClient().isDetached()))
6999 {
7000 deleteMe();
7001 }
7002 }
7003
7004 /**
7005 * <B><U> Values </U> :</B> <li>0 : STORE_PRIVATE_NONE</li> <li>1 : STORE_PRIVATE_SELL</li> <li>2 : sellmanage</li><BR>
7006 * <li>3 : STORE_PRIVATE_BUY</li><BR>
7007 * <li>4 : buymanage</li><BR>
7008 * <li>5 : STORE_PRIVATE_MANUFACTURE</li><BR>
7009 * @return the Private Store type of the L2PcInstance.
7010 */
7011 public int getPrivateStoreType()
7012 {
7013 return _privatestore;
7014 }
7015
7016 /**
7017 * Set the _clan object, _clanId, _clanLeader Flag and title of the L2PcInstance.
7018 * @param clan
7019 */
7020 public void setClan(L2Clan clan)
7021 {
7022 _clan = clan;
7023 setTitle("");
7024
7025 if (clan == null)
7026 {
7027 _clanId = 0;
7028 _clanPrivileges = 0;
7029 _pledgeType = 0;
7030 _powerGrade = 0;
7031 _lvlJoinedAcademy = 0;
7032 _apprentice = 0;
7033 _sponsor = 0;
7034 _activeWarehouse = null;
7035 if (_isOnline)
7036 {
7037 CommunityServerThread.getInstance().sendPacket(new WorldInfo(this, null, WorldInfo.TYPE_UPDATE_PLAYER_DATA));
7038 }
7039 return;
7040 }
7041
7042 if (!clan.isMember(getObjectId()))
7043 {
7044 // char has been kicked from clan
7045 setClan(null);
7046 return;
7047 }
7048
7049 _clanId = clan.getClanId();
7050 if (_isOnline)
7051 {
7052 CommunityServerThread.getInstance().sendPacket(new WorldInfo(this, null, WorldInfo.TYPE_UPDATE_PLAYER_DATA));
7053 }
7054 }
7055
7056 /**
7057 * @return the _clan object of the L2PcInstance.
7058 */
7059 public L2Clan getClan()
7060 {
7061 return _clan;
7062 }
7063
7064 /**
7065 * @return True if the L2PcInstance is the leader of its clan.
7066 */
7067 public boolean isClanLeader()
7068 {
7069 if (getClan() == null)
7070 {
7071 return false;
7072 }
7073 return getObjectId() == getClan().getLeaderId();
7074 }
7075
7076 /**
7077 * Reduce the number of arrows/bolts owned by the L2PcInstance and send it Server->Client Packet InventoryUpdate or ItemList (to unequip if the last arrow was consummed).
7078 */
7079 @Override
7080 protected void reduceArrowCount(boolean bolts)
7081 {
7082 L2ItemInstance arrows = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
7083
7084 if (arrows == null)
7085 {
7086 getInventory().unEquipItemInSlot(Inventory.PAPERDOLL_LHAND);
7087 if (bolts)
7088 {
7089 _boltItem = null;
7090 }
7091 else
7092 {
7093 _arrowItem = null;
7094 }
7095 sendPacket(new ItemList(this, false));
7096 return;
7097 }
7098
7099 // Adjust item quantity
7100 if (arrows.getCount() > 1)
7101 {
7102 synchronized (arrows)
7103 {
7104 arrows.changeCountWithoutTrace(-1, this, null);
7105 arrows.setLastChange(L2ItemInstance.MODIFIED);
7106
7107 // could do also without saving, but let's save approx 1 of 10
7108 if ((GameTimeController.getGameTicks() % 10) == 0)
7109 {
7110 arrows.updateDatabase();
7111 }
7112 _inventory.refreshWeight();
7113 }
7114 }
7115 else
7116 {
7117 // Destroy entire item and save to database
7118 _inventory.destroyItem("Consume", arrows, this, null);
7119
7120 getInventory().unEquipItemInSlot(Inventory.PAPERDOLL_LHAND);
7121 if (bolts)
7122 {
7123 _boltItem = null;
7124 }
7125 else
7126 {
7127 _arrowItem = null;
7128 }
7129
7130 sendPacket(new ItemList(this, false));
7131 return;
7132 }
7133
7134 if (!Config.FORCE_INVENTORY_UPDATE)
7135 {
7136 InventoryUpdate iu = new InventoryUpdate();
7137 iu.addModifiedItem(arrows);
7138 sendPacket(iu);
7139 }
7140 else
7141 {
7142 sendPacket(new ItemList(this, false));
7143 }
7144 }
7145
7146 /**
7147 * Equip arrows needed in left hand and send a Server->Client packet ItemList to the L2PcINstance then return True.
7148 */
7149 @Override
7150 protected boolean checkAndEquipArrows()
7151 {
7152 // Check if nothing is equiped in left hand
7153 if (getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND) == null)
7154 {
7155 // Get the L2ItemInstance of the arrows needed for this bow
7156 _arrowItem = getInventory().findArrowForBow(getActiveWeaponItem());
7157 if (_arrowItem != null)
7158 {
7159 // Equip arrows needed in left hand
7160 getInventory().setPaperdollItem(Inventory.PAPERDOLL_LHAND, _arrowItem);
7161
7162 // Send a Server->Client packet ItemList to this L2PcINstance to update left hand equipement
7163 ItemList il = new ItemList(this, false);
7164 sendPacket(il);
7165 }
7166 }
7167 else
7168 {
7169 // Get the L2ItemInstance of arrows equiped in left hand
7170 _arrowItem = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
7171 }
7172 return _arrowItem != null;
7173 }
7174
7175 /**
7176 * Equip bolts needed in left hand and send a Server->Client packet ItemList to the L2PcINstance then return True.
7177 */
7178 @Override
7179 protected boolean checkAndEquipBolts()
7180 {
7181 // Check if nothing is equiped in left hand
7182 if (getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND) == null)
7183 {
7184 // Get the L2ItemInstance of the arrows needed for this bow
7185 _boltItem = getInventory().findBoltForCrossBow(getActiveWeaponItem());
7186 if (_boltItem != null)
7187 {
7188 // Equip arrows needed in left hand
7189 getInventory().setPaperdollItem(Inventory.PAPERDOLL_LHAND, _boltItem);
7190
7191 // Send a Server->Client packet ItemList to this L2PcINstance to update left hand equipement
7192 ItemList il = new ItemList(this, false);
7193 sendPacket(il);
7194 }
7195 }
7196 else
7197 {
7198 // Get the L2ItemInstance of arrows equiped in left hand
7199 _boltItem = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
7200 }
7201 return _boltItem != null;
7202 }
7203
7204 /**
7205 * Disarm the player's weapon.
7206 * @return {@code true} if the player was disarmed or doesn't have a weapon to disarm, {@code false} otherwise.
7207 */
7208 public boolean disarmWeapons()
7209 {
7210 // If there is no weapon to disarm then return true.
7211 final L2ItemInstance wpn = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
7212 if (wpn == null)
7213 {
7214 return true;
7215 }
7216
7217 // Don't allow disarming a cursed weapon
7218 if (isCursedWeaponEquipped())
7219 {
7220 return false;
7221 }
7222
7223 // Don't allow disarming a Combat Flag or Territory Ward.
7224 if (isCombatFlagEquipped())
7225 {
7226 return false;
7227 }
7228
7229 // Don't allow disarming if the weapon is force equip.
7230 if (wpn.getWeaponItem().isForceEquip())
7231 {
7232 return false;
7233 }
7234
7235 final L2ItemInstance[] unequiped = getInventory().unEquipItemInBodySlotAndRecord(wpn.getItem().getBodyPart());
7236 final InventoryUpdate iu = new InventoryUpdate();
7237 for (L2ItemInstance itm : unequiped)
7238 {
7239 iu.addModifiedItem(itm);
7240 }
7241
7242 sendPacket(iu);
7243 abortAttack();
7244 broadcastUserInfo();
7245
7246 // This can be 0 if the user pressed the right mousebutton twice very fast.
7247 if (unequiped.length > 0)
7248 {
7249 final SystemMessage sm;
7250 if (unequiped[0].getEnchantLevel() > 0)
7251 {
7252 sm = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
7253 sm.addNumber(unequiped[0].getEnchantLevel());
7254 sm.addItemName(unequiped[0]);
7255 }
7256 else
7257 {
7258 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISARMED);
7259 sm.addItemName(unequiped[0]);
7260 }
7261 sendPacket(sm);
7262 }
7263 return true;
7264 }
7265
7266 /**
7267 * Disarm the player's shield.
7268 * @return {@code true}.
7269 */
7270 public boolean disarmShield()
7271 {
7272 L2ItemInstance sld = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
7273 if (sld != null)
7274 {
7275 L2ItemInstance[] unequiped = getInventory().unEquipItemInBodySlotAndRecord(sld.getItem().getBodyPart());
7276 InventoryUpdate iu = new InventoryUpdate();
7277 for (L2ItemInstance itm : unequiped)
7278 {
7279 iu.addModifiedItem(itm);
7280 }
7281 sendPacket(iu);
7282
7283 abortAttack();
7284 broadcastUserInfo();
7285
7286 // this can be 0 if the user pressed the right mousebutton twice very fast
7287 if (unequiped.length > 0)
7288 {
7289 SystemMessage sm = null;
7290 if (unequiped[0].getEnchantLevel() > 0)
7291 {
7292 sm = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
7293 sm.addNumber(unequiped[0].getEnchantLevel());
7294 sm.addItemName(unequiped[0]);
7295 }
7296 else
7297 {
7298 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISARMED);
7299 sm.addItemName(unequiped[0]);
7300 }
7301 sendPacket(sm);
7302 }
7303 }
7304 return true;
7305 }
7306
7307 public boolean mount(L2Summon pet)
7308 {
7309 if (!disarmWeapons())
7310 {
7311 return false;
7312 }
7313 if (!disarmShield())
7314 {
7315 return false;
7316 }
7317 if (isTransformed())
7318 {
7319 return false;
7320 }
7321
7322 stopAllToggles();
7323 Ride mount = new Ride(this, true, pet.getTemplate().getNpcId());
7324 setMount(pet.getNpcId(), pet.getLevel(), mount.getMountType());
7325 setMountObjectID(pet.getControlObjectId());
7326 clearPetData();
7327 startFeed(pet.getNpcId());
7328 broadcastPacket(mount);
7329
7330 // Notify self and others about speed change
7331 broadcastUserInfo();
7332
7333 pet.unSummon(this);
7334
7335 return true;
7336 }
7337
7338 public boolean mount(int npcId, int controlItemObjId, boolean useFood)
7339 {
7340 if (!disarmWeapons())
7341 {
7342 return false;
7343 }
7344 if (!disarmShield())
7345 {
7346 return false;
7347 }
7348 if (isTransformed())
7349 {
7350 return false;
7351 }
7352
7353 stopAllToggles();
7354 Ride mount = new Ride(this, true, npcId);
7355 if (setMount(npcId, getLevel(), mount.getMountType()))
7356 {
7357 clearPetData();
7358 setMountObjectID(controlItemObjId);
7359 broadcastPacket(mount);
7360
7361 // Notify self and others about speed change
7362 broadcastUserInfo();
7363 if (useFood)
7364 {
7365 startFeed(npcId);
7366 }
7367 return true;
7368 }
7369 return false;
7370 }
7371
7372 public boolean mountPlayer(L2Summon pet)
7373 {
7374 if ((pet != null) && pet.isMountable() && !isMounted() && !isBetrayed())
7375 {
7376 if (isDead())
7377 {
7378 // A strider cannot be ridden when dead
7379 sendPacket(ActionFailed.STATIC_PACKET);
7380 sendPacket(SystemMessageId.STRIDER_CANT_BE_RIDDEN_WHILE_DEAD);
7381 return false;
7382 }
7383 else if (pet.isDead())
7384 {
7385 // A dead strider cannot be ridden.
7386 sendPacket(ActionFailed.STATIC_PACKET);
7387 sendPacket(SystemMessageId.DEAD_STRIDER_CANT_BE_RIDDEN);
7388 return false;
7389 }
7390 else if (pet.isInCombat() || pet.isRooted())
7391 {
7392 // A strider in battle cannot be ridden
7393 sendPacket(ActionFailed.STATIC_PACKET);
7394 sendPacket(SystemMessageId.STRIDER_IN_BATLLE_CANT_BE_RIDDEN);
7395 return false;
7396
7397 }
7398 else if (isInCombat())
7399 {
7400 // A strider cannot be ridden while in battle
7401 sendPacket(ActionFailed.STATIC_PACKET);
7402 sendPacket(SystemMessageId.STRIDER_CANT_BE_RIDDEN_WHILE_IN_BATTLE);
7403 return false;
7404 }
7405 else if (isSitting())
7406 {
7407 // A strider can be ridden only when standing
7408 sendPacket(ActionFailed.STATIC_PACKET);
7409 sendPacket(SystemMessageId.STRIDER_CAN_BE_RIDDEN_ONLY_WHILE_STANDING);
7410 return false;
7411 }
7412 else if (isFishing())
7413 {
7414 // You can't mount, dismount, break and drop items while fishing
7415 sendPacket(ActionFailed.STATIC_PACKET);
7416 sendPacket(SystemMessageId.CANNOT_DO_WHILE_FISHING_2);
7417 return false;
7418 }
7419 else if (isTransformed() || isCursedWeaponEquipped())
7420 {
7421 // no message needed, player while transformed doesn't have mount action
7422 sendPacket(ActionFailed.STATIC_PACKET);
7423 return false;
7424 }
7425 else if (getInventory().getItemByItemId(9819) != null)
7426 {
7427 sendPacket(ActionFailed.STATIC_PACKET);
7428 // FIXME: Wrong Message
7429 sendMessage("You cannot mount a steed while holding a flag.");
7430 return false;
7431 }
7432 else if (pet.isHungry())
7433 {
7434 sendPacket(ActionFailed.STATIC_PACKET);
7435 sendPacket(SystemMessageId.HUNGRY_STRIDER_NOT_MOUNT);
7436 return false;
7437 }
7438 else if (!Util.checkIfInRange(200, this, pet, true))
7439 {
7440 sendPacket(ActionFailed.STATIC_PACKET);
7441 sendPacket(SystemMessageId.TOO_FAR_AWAY_FROM_FENRIR_TO_MOUNT);
7442 return false;
7443 }
7444 else if (!pet.isDead() && !isMounted())
7445 {
7446 mount(pet);
7447 }
7448 }
7449 else if (isRentedPet())
7450 {
7451 stopRentPet();
7452 }
7453 else if (isMounted())
7454 {
7455 if ((getMountType() == 2) && isInsideZone(ZoneId.NO_LANDING))
7456 {
7457 sendPacket(ActionFailed.STATIC_PACKET);
7458 sendPacket(SystemMessageId.NO_DISMOUNT_HERE);
7459 return false;
7460 }
7461 else if (isHungry())
7462 {
7463 sendPacket(ActionFailed.STATIC_PACKET);
7464 sendPacket(SystemMessageId.HUNGRY_STRIDER_NOT_MOUNT);
7465 return false;
7466 }
7467 else
7468 {
7469 dismount();
7470 }
7471 }
7472 return true;
7473 }
7474
7475 public boolean dismount()
7476 {
7477 boolean wasFlying = isFlying();
7478
7479 sendPacket(new SetupGauge(3, 0, 0));
7480 int petId = _mountNpcId;
7481 if (setMount(0, 0, 0))
7482 {
7483 stopFeed();
7484 clearPetData();
7485 if (wasFlying)
7486 {
7487 removeSkill(SkillTable.FrequentSkill.WYVERN_BREATH.getSkill());
7488 }
7489 Ride dismount = new Ride(this, false, 0);
7490 broadcastPacket(dismount);
7491 setMountObjectID(0);
7492 storePetFood(petId);
7493 // Notify self and others about speed change
7494 broadcastUserInfo();
7495 return true;
7496 }
7497 return false;
7498 }
7499
7500 /**
7501 * Return True if the L2PcInstance use a dual weapon.
7502 */
7503 @Override
7504 public boolean isUsingDualWeapon()
7505 {
7506 L2Weapon weaponItem = getActiveWeaponItem();
7507 if (weaponItem == null)
7508 {
7509 return false;
7510 }
7511
7512 if (weaponItem.getItemType() == L2WeaponType.DUAL)
7513 {
7514 return true;
7515 }
7516 else if (weaponItem.getItemType() == L2WeaponType.DUALFIST)
7517 {
7518 return true;
7519 }
7520 else if (weaponItem.getItemType() == L2WeaponType.DUALDAGGER)
7521 {
7522 return true;
7523 }
7524 else
7525 {
7526 return false;
7527 }
7528 }
7529
7530 public void setUptime(long time)
7531 {
7532 _uptime = time;
7533 }
7534
7535 public long getUptime()
7536 {
7537 return System.currentTimeMillis() - _uptime;
7538 }
7539
7540 /**
7541 * Return True if the L2PcInstance is invulnerable.
7542 */
7543 @Override
7544 public boolean isInvul()
7545 {
7546 return super.isInvul() || (_teleportProtectEndTime > GameTimeController.getGameTicks());
7547 }
7548
7549 /**
7550 * Return True if the L2PcInstance has a Party in progress.
7551 */
7552 @Override
7553 public boolean isInParty()
7554 {
7555 return _party != null;
7556 }
7557
7558 /**
7559 * Set the _party object of the L2PcInstance (without joining it).
7560 * @param party
7561 */
7562 public void setParty(L2Party party)
7563 {
7564 _party = party;
7565 }
7566
7567 /**
7568 * Set the _party object of the L2PcInstance AND join it.
7569 * @param party
7570 */
7571 public void joinParty(L2Party party)
7572 {
7573 if (party != null)
7574 {
7575 // First set the party otherwise this wouldn't be considered
7576 // as in a party into the L2Character.updateEffectIcons() call.
7577 _party = party;
7578 party.addPartyMember(this);
7579 }
7580 }
7581
7582 /**
7583 * Manage the Leave Party task of the L2PcInstance.
7584 */
7585 public void leaveParty()
7586 {
7587 if (isInParty())
7588 {
7589 _party.removePartyMember(this, messageType.Disconnected);
7590 _party = null;
7591 }
7592 }
7593
7594 /**
7595 * Return the _party object of the L2PcInstance.
7596 */
7597 @Override
7598 public L2Party getParty()
7599 {
7600 return _party;
7601 }
7602
7603 /**
7604 * Return True if the L2PcInstance is a GM.
7605 */
7606 @Override
7607 public boolean isGM()
7608 {
7609 return getAccessLevel().isGm();
7610 }
7611
7612 /**
7613 * Set the _accessLevel of the L2PcInstance.
7614 * @param level
7615 */
7616 public void setAccessLevel(int level)
7617 {
7618 _accessLevel = AdminTable.getInstance().getAccessLevel(level);
7619
7620 getAppearance().setNameColor(_accessLevel.getNameColor());
7621 getAppearance().setTitleColor(_accessLevel.getTitleColor());
7622 broadcastUserInfo();
7623
7624 CharNameTable.getInstance().addName(this);
7625
7626 if (!AdminTable.getInstance().hasAccessLevel(level))
7627 {
7628 _log.warning("Tryed to set unregistered access level " + level + " for " + toString() + ". Setting access level without privileges!");
7629 }
7630 else if (level > 0)
7631 {
7632 _log.warning(_accessLevel.getName() + " access level set for character " + getName() + "! Just a warning to be careful ;)");
7633 }
7634 }
7635
7636 public void setAccountAccesslevel(int level)
7637 {
7638 LoginServerThread.getInstance().sendAccessLevel(getAccountName(), level);
7639 }
7640
7641 /**
7642 * @return the _accessLevel of the L2PcInstance.
7643 */
7644 @Override
7645 public L2AccessLevel getAccessLevel()
7646 {
7647 if (Config.EVERYBODY_HAS_ADMIN_RIGHTS)
7648 {
7649 return AdminTable.getInstance().getMasterAccessLevel();
7650 }
7651 else if (_accessLevel == null)
7652 {
7653 setAccessLevel(0);
7654 }
7655
7656 return _accessLevel;
7657 }
7658
7659 /**
7660 * Update Stats of the L2PcInstance client side by sending Server->Client packet UserInfo/StatusUpdate to this L2PcInstance and CharInfo/StatusUpdate to all L2PcInstance in its _KnownPlayers (broadcast).
7661 * @param broadcastType
7662 */
7663 public void updateAndBroadcastStatus(int broadcastType)
7664 {
7665 refreshOverloaded();
7666 refreshExpertisePenalty();
7667 // Send a Server->Client packet UserInfo to this L2PcInstance and CharInfo to all L2PcInstance in its _KnownPlayers (broadcast)
7668 if (broadcastType == 1)
7669 {
7670 sendPacket(new UserInfo(this));
7671 sendPacket(new ExBrExtraUserInfo(this));
7672 }
7673 if (broadcastType == 2)
7674 {
7675 broadcastUserInfo();
7676 }
7677 }
7678
7679 /**
7680 * Send a Server->Client StatusUpdate packet with Karma and PvP Flag to the L2PcInstance and all L2PcInstance to inform (broadcast).
7681 * @param flag
7682 */
7683 public void setKarmaFlag(int flag)
7684 {
7685 sendPacket(new UserInfo(this));
7686 sendPacket(new ExBrExtraUserInfo(this));
7687 Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
7688 for (L2PcInstance player : plrs)
7689 {
7690 player.sendPacket(new RelationChanged(this, getRelation(player), isAutoAttackable(player)));
7691 if (hasSummon())
7692 {
7693 player.sendPacket(new RelationChanged(getSummon(), getRelation(player), isAutoAttackable(player)));
7694 }
7695 }
7696 }
7697
7698 /**
7699 * Send a Server->Client StatusUpdate packet with Karma to the L2PcInstance and all L2PcInstance to inform (broadcast).
7700 */
7701 public void broadcastKarma()
7702 {
7703 StatusUpdate su = new StatusUpdate(this);
7704 su.addAttribute(StatusUpdate.KARMA, getKarma());
7705 sendPacket(su);
7706
7707 Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
7708 for (L2PcInstance player : plrs)
7709 {
7710 player.sendPacket(new RelationChanged(this, getRelation(player), isAutoAttackable(player)));
7711 if (hasSummon())
7712 {
7713 player.sendPacket(new RelationChanged(getSummon(), getRelation(player), isAutoAttackable(player)));
7714 }
7715 }
7716 }
7717
7718 /**
7719 * 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).
7720 * @param isOnline
7721 * @param updateInDb
7722 */
7723 public void setOnlineStatus(boolean isOnline, boolean updateInDb)
7724 {
7725 if (_isOnline != isOnline)
7726 {
7727 _isOnline = isOnline;
7728 }
7729
7730 if (Config.ALLOW_HITMAN_GDE && Hitman.getInstance().exists(getObjectId()))
7731 {
7732 Hitman.getInstance().getTarget(getObjectId()).setOnline(isOnline);
7733 }
7734
7735 // Update the characters table of the database with online status and lastAccess (called when login and logout)
7736 if (updateInDb)
7737 {
7738 updateOnlineStatus();
7739 }
7740 }
7741
7742 public void setIsIn7sDungeon(boolean isIn7sDungeon)
7743 {
7744 _isIn7sDungeon = isIn7sDungeon;
7745 }
7746
7747 /**
7748 * Update the characters table of the database with online status and lastAccess of this L2PcInstance (called when login and logout).
7749 */
7750 public void updateOnlineStatus()
7751 {
7752 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
7753 PreparedStatement statement = con.prepareStatement("UPDATE characters SET online=?, lastAccess=? WHERE charId=?"))
7754 {
7755 statement.setInt(1, isOnlineInt());
7756 statement.setLong(2, System.currentTimeMillis());
7757 statement.setInt(3, getObjectId());
7758 statement.execute();
7759 }
7760 catch (Exception e)
7761 {
7762 _log.log(Level.SEVERE, "Failed updating character online status.", e);
7763 }
7764 }
7765
7766 /**
7767 * Create a new player in the characters table of the database.
7768 * @return
7769 */
7770 private boolean createDb()
7771 {
7772 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
7773 PreparedStatement statement = con.prepareStatement(INSERT_CHARACTER))
7774 {
7775 statement.setString(1, _accountName);
7776 statement.setInt(2, getObjectId());
7777 statement.setString(3, getName());
7778 statement.setInt(4, getLevel());
7779 statement.setInt(5, getMaxHp());
7780 statement.setDouble(6, getCurrentHp());
7781 statement.setInt(7, getMaxCp());
7782 statement.setDouble(8, getCurrentCp());
7783 statement.setInt(9, getMaxMp());
7784 statement.setDouble(10, getCurrentMp());
7785 statement.setInt(11, getAppearance().getFace());
7786 statement.setInt(12, getAppearance().getHairStyle());
7787 statement.setInt(13, getAppearance().getHairColor());
7788 statement.setInt(14, getAppearance().getSex() ? 1 : 0);
7789 statement.setLong(15, getExp());
7790 statement.setInt(16, getSp());
7791 statement.setInt(17, getKarma());
7792 statement.setInt(18, getFame());
7793 statement.setInt(19, getPvpKills());
7794 statement.setInt(20, getPkKills());
7795 statement.setInt(21, getClanId());
7796 statement.setInt(22, getRace().ordinal());
7797 statement.setInt(23, getClassId().getId());
7798 statement.setLong(24, getDeleteTimer());
7799 statement.setInt(25, hasDwarvenCraft() ? 1 : 0);
7800 statement.setString(26, getTitle());
7801 statement.setInt(27, getAppearance().getTitleColor());
7802 statement.setInt(28, getAccessLevel().getLevel());
7803 statement.setInt(29, isOnlineInt());
7804 statement.setInt(30, isIn7sDungeon() ? 1 : 0);
7805 statement.setInt(31, getClanPrivileges());
7806 statement.setInt(32, getWantsPeace());
7807 statement.setInt(33, getBaseClass());
7808 statement.setInt(34, getNewbie());
7809 statement.setInt(35, isNoble() ? 1 : 0);
7810 statement.setLong(36, 0);
7811 statement.setDate(37, new Date(getCreateDate().getTimeInMillis()));
7812 statement.executeUpdate();
7813 }
7814 catch (Exception e)
7815 {
7816 _log.log(Level.SEVERE, "Could not insert char data: " + e.getMessage(), e);
7817 return false;
7818 }
7819 return true;
7820 }
7821
7822 /**
7823 * Retrieve a L2PcInstance from the characters table of the database and add it in _allObjects of the L2world. <B><U> Actions</U> :</B> <li>Retrieve the L2PcInstance from the characters table of the database</li> <li>Add the L2PcInstance object in _allObjects</li> <li>Set the x,y,z position of
7824 * the L2PcInstance and make it invisible</li> <li>Update the overloaded status of the L2PcInstance</li>
7825 * @param objectId Identifier of the object to initialized
7826 * @return The L2PcInstance loaded from the database
7827 */
7828 private static L2PcInstance restore(int objectId)
7829 {
7830 L2PcInstance player = null;
7831 double currentCp = 0;
7832 double currentHp = 0;
7833 double currentMp = 0;
7834 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
7835 PreparedStatement statement = con.prepareStatement(RESTORE_CHARACTER))
7836 {
7837 // Retrieve the L2PcInstance from the characters table of the database
7838 statement.setInt(1, objectId);
7839 try (ResultSet rset = statement.executeQuery())
7840 {
7841 if (rset.next())
7842 {
7843 final int activeClassId = rset.getInt("classid");
7844 final boolean female = rset.getInt("sex") != Sex.MALE;
7845 final L2PcTemplate template = CharTemplateTable.getInstance().getTemplate(activeClassId);
7846 PcAppearance app = new PcAppearance(rset.getByte("face"), rset.getByte("hairColor"), rset.getByte("hairStyle"), female);
7847
7848 player = new L2PcInstance(objectId, template, rset.getString("account_name"), app);
7849 player.setName(rset.getString("char_name"));
7850 player._lastAccess = rset.getLong("lastAccess");
7851
7852 player.getStat().setExp(rset.getLong("exp"));
7853 player.setExpBeforeDeath(rset.getLong("expBeforeDeath"));
7854 player.getStat().setLevel(rset.getByte("level"));
7855 player.getStat().setSp(rset.getInt("sp"));
7856
7857 player.setWantsPeace(rset.getInt("wantspeace"));
7858
7859 player.setHeading(rset.getInt("heading"));
7860
7861 player.setKarma(rset.getInt("karma"));
7862 player.setFame(rset.getInt("fame"));
7863 player.setPvpKills(rset.getInt("pvpkills"));
7864 player.setPkKills(rset.getInt("pkkills"));
7865 player.setOnlineTime(rset.getLong("onlinetime"));
7866 player.setNewbie(rset.getInt("newbie"));
7867 player.setNoble(rset.getInt("nobless") == 1);
7868
7869 player.setClanJoinExpiryTime(rset.getLong("clan_join_expiry_time"));
7870 if (player.getClanJoinExpiryTime() < System.currentTimeMillis())
7871 {
7872 player.setClanJoinExpiryTime(0);
7873 }
7874 player.setClanCreateExpiryTime(rset.getLong("clan_create_expiry_time"));
7875 if (player.getClanCreateExpiryTime() < System.currentTimeMillis())
7876 {
7877 player.setClanCreateExpiryTime(0);
7878 }
7879
7880 int clanId = rset.getInt("clanid");
7881 player.setPowerGrade(rset.getInt("power_grade"));
7882 player.setPledgeType(rset.getInt("subpledge"));
7883 // player.setApprentice(rset.getInt("apprentice"));
7884
7885 if (clanId > 0)
7886 {
7887 player.setClan(ClanTable.getInstance().getClan(clanId));
7888 }
7889
7890 if (player.getClan() != null)
7891 {
7892 if (player.getClan().getLeaderId() != player.getObjectId())
7893 {
7894 if (player.getPowerGrade() == 0)
7895 {
7896 player.setPowerGrade(5);
7897 }
7898 player.setClanPrivileges(player.getClan().getRankPrivs(player.getPowerGrade()));
7899 }
7900 else
7901 {
7902 player.setClanPrivileges(L2Clan.CP_ALL);
7903 player.setPowerGrade(1);
7904 }
7905 player.setPledgeClass(L2ClanMember.calculatePledgeClass(player));
7906 }
7907 else
7908 {
7909 if (player.isNoble())
7910 {
7911 player.setPledgeClass(5);
7912 }
7913
7914 if (player.isHero())
7915 {
7916 player.setPledgeClass(8);
7917 }
7918
7919 player.setClanPrivileges(L2Clan.CP_NOTHING);
7920 }
7921
7922 player.setDeleteTimer(rset.getLong("deletetime"));
7923
7924 player.setTitle(rset.getString("title"));
7925 player.getAppearance().setTitleColor(rset.getInt("title_color"));
7926 player.setAccessLevel(rset.getInt("accesslevel"));
7927 player.setFistsWeaponItem(player.findFistsWeaponItem(activeClassId));
7928 player.setUptime(System.currentTimeMillis());
7929
7930 currentHp = rset.getDouble("curHp");
7931 currentCp = rset.getDouble("curCp");
7932 currentMp = rset.getDouble("curMp");
7933
7934 player._classIndex = 0;
7935 try
7936 {
7937 player.setBaseClass(rset.getInt("base_class"));
7938 }
7939 catch (Exception e)
7940 {
7941 // TODO: Should this be logged?
7942 player.setBaseClass(activeClassId);
7943 }
7944
7945 // Restore Subclass Data (cannot be done earlier in function)
7946 if (restoreSubClassData(player))
7947 {
7948 if (activeClassId != player.getBaseClass())
7949 {
7950 for (SubClass subClass : player.getSubClasses().values())
7951 {
7952 if (subClass.getClassId() == activeClassId)
7953 {
7954 player._classIndex = subClass.getClassIndex();
7955 }
7956 }
7957 }
7958 }
7959
7960 if ((player.getClassIndex() == 0) && (activeClassId != player.getBaseClass()))
7961 {
7962 // Subclass in use but doesn't exist in DB -
7963 // a possible restart-while-modifysubclass cheat has been attempted.
7964 // Switching to use base class
7965 player.setClassId(player.getBaseClass());
7966 _log.warning("Player " + player.getName() + " reverted to base class. Possibly has tried a relogin exploit while subclassing.");
7967 }
7968 else
7969 {
7970 player._activeClass = activeClassId;
7971 }
7972
7973 player.setApprentice(rset.getInt("apprentice"));
7974 player.setSponsor(rset.getInt("sponsor"));
7975 player.setLvlJoinedAcademy(rset.getInt("lvl_joined_academy"));
7976 player.setIsIn7sDungeon(rset.getInt("isin7sdungeon") == 1);
7977 player.setPunishLevel(rset.getInt("punish_level"));
7978 if (player.getPunishLevel() != PunishLevel.NONE)
7979 {
7980 player.setPunishTimer(rset.getLong("punish_timer"));
7981 }
7982 else
7983 {
7984 player.setPunishTimer(0);
7985 }
7986
7987 CursedWeaponsManager.getInstance().checkPlayer(player);
7988
7989 player.setAllianceWithVarkaKetra(rset.getInt("varka_ketra_ally"));
7990
7991 player.setDeathPenaltyBuffLevel(rset.getInt("death_penalty_level"));
7992
7993 player.setVitalityPoints(rset.getInt("vitality_points"), true);
7994
7995 player.setHitmanTarget(rset.getInt("hitman_target"));
7996
7997 // Set the x,y,z position of the L2PcInstance and make it invisible
7998 player.setXYZInvisible(rset.getInt("x"), rset.getInt("y"), rset.getInt("z"));
7999
8000 // Set Teleport Bookmark Slot
8001 player.setBookMarkSlot(rset.getInt("BookmarkSlot"));
8002
8003 // Pc Bang
8004 player.setPcBangPoints(rset.getInt("pccafe_points"));
8005
8006 // character creation Time
8007 player.getCreateDate().setTime(rset.getDate("createDate"));
8008
8009 // Language
8010 player.setLang(rset.getString("language"));
8011
8012 // Retrieve the name and ID of the other characters assigned to this account.
8013 try (PreparedStatement stmt = con.prepareStatement("SELECT charId, char_name FROM characters WHERE account_name=? AND charId<>?"))
8014 {
8015 stmt.setString(1, player._accountName);
8016 stmt.setInt(2, objectId);
8017 try (ResultSet chars = stmt.executeQuery())
8018 {
8019 while (chars.next())
8020 {
8021 player._chars.put(chars.getInt("charId"), chars.getString("char_name"));
8022 }
8023 }
8024 }
8025 }
8026 }
8027
8028 if (player == null)
8029 {
8030 return null;
8031 }
8032
8033 // Set Hero status if it applies
8034 if (Hero.getInstance().isHero(objectId))
8035 {
8036 player.setHero(true);
8037 }
8038
8039 // Retrieve from the database all items of this L2PcInstance and add them to _inventory
8040 player.getInventory().restore();
8041 player.getFreight().restore();
8042 if (!Config.WAREHOUSE_CACHE)
8043 {
8044 player.getWarehouse();
8045 }
8046
8047 // Retrieve from the database all secondary data of this L2PcInstance
8048 // Note that Clan, Noblesse and Hero skills are given separately and not here.
8049 // Retrieve from the database all skills of this L2PcInstance and add them to _skills
8050 player.restoreCharData();
8051
8052 // Buff and status icons
8053 if (Config.STORE_SKILL_COOLTIME)
8054 {
8055 player.restoreEffects();
8056 }
8057
8058 // Reward auto-get skills and all available skills if auto-learn skills is true.
8059 player.rewardSkills();
8060
8061 player.restoreItemReuse();
8062
8063 // Restore current Cp, HP and MP values
8064 player.setCurrentCp(currentCp);
8065 player.setCurrentHp(currentHp);
8066 player.setCurrentMp(currentMp);
8067
8068 if (currentHp < 0.5)
8069 {
8070 player.setIsDead(true);
8071 player.stopHpMpRegeneration();
8072 }
8073
8074 // Restore pet if exists in the world
8075 player.setPet(L2World.getInstance().getPet(player.getObjectId()));
8076 if (player.hasSummon())
8077 {
8078 player.getSummon().setOwner(player);
8079 }
8080
8081 // Update the overloaded status of the L2PcInstance
8082 player.refreshOverloaded();
8083 // Update the expertise status of the L2PcInstance
8084 player.refreshExpertisePenalty();
8085
8086 player.restoreFriendList();
8087
8088 if (Config.STORE_UI_SETTINGS)
8089 {
8090 player.restoreUISettings();
8091 }
8092
8093 player.restoreZoneRestartLimitTime();
8094 PremiumTable.loadState(player); // restore premium status
8095 }
8096 catch (Exception e)
8097 {
8098 _log.log(Level.SEVERE, "Failed loading character.", e);
8099 }
8100 player._account = new L2Account(player.getAccountName());
8101 return player;
8102 }
8103
8104 /**
8105 * @return
8106 */
8107 public Forum getMail()
8108 {
8109 if (_forumMail == null)
8110 {
8111 setMail(ForumsBBSManager.getInstance().getForumByName("MailRoot").getChildByName(getName()));
8112
8113 if (_forumMail == null)
8114 {
8115 ForumsBBSManager.getInstance().createNewForum(getName(), ForumsBBSManager.getInstance().getForumByName("MailRoot"), Forum.MAIL, Forum.OWNERONLY, getObjectId());
8116 setMail(ForumsBBSManager.getInstance().getForumByName("MailRoot").getChildByName(getName()));
8117 }
8118 }
8119
8120 return _forumMail;
8121 }
8122
8123 /**
8124 * @param forum
8125 */
8126 public void setMail(Forum forum)
8127 {
8128 _forumMail = forum;
8129 }
8130
8131 /**
8132 * @return
8133 */
8134 public Forum getMemo()
8135 {
8136 if (_forumMemo == null)
8137 {
8138 setMemo(ForumsBBSManager.getInstance().getForumByName("MemoRoot").getChildByName(_accountName));
8139
8140 if (_forumMemo == null)
8141 {
8142 ForumsBBSManager.getInstance().createNewForum(_accountName, ForumsBBSManager.getInstance().getForumByName("MemoRoot"), Forum.MEMO, Forum.OWNERONLY, getObjectId());
8143 setMemo(ForumsBBSManager.getInstance().getForumByName("MemoRoot").getChildByName(_accountName));
8144 }
8145 }
8146
8147 return _forumMemo;
8148 }
8149
8150 /**
8151 * @param forum
8152 */
8153 public void setMemo(Forum forum)
8154 {
8155 _forumMemo = forum;
8156 }
8157
8158 /**
8159 * Restores sub-class data for the L2PcInstance, used to check the current class index for the character.
8160 * @param player
8161 * @return
8162 */
8163 private static boolean restoreSubClassData(L2PcInstance player)
8164 {
8165 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
8166 PreparedStatement statement = con.prepareStatement(RESTORE_CHAR_SUBCLASSES))
8167 {
8168 statement.setInt(1, player.getObjectId());
8169 try (ResultSet rset = statement.executeQuery())
8170 {
8171 while (rset.next())
8172 {
8173 SubClass subClass = new SubClass();
8174 subClass.setClassId(rset.getInt("class_id"));
8175 subClass.setLevel(rset.getByte("level"));
8176 subClass.setExp(rset.getLong("exp"));
8177 subClass.setSp(rset.getInt("sp"));
8178 subClass.setClassIndex(rset.getInt("class_index"));
8179
8180 // Enforce the correct indexing of _subClasses against their class indexes.
8181 player.getSubClasses().put(subClass.getClassIndex(), subClass);
8182 }
8183 }
8184 }
8185 catch (Exception e)
8186 {
8187 _log.log(Level.WARNING, "Could not restore classes for " + player.getName() + ": " + e.getMessage(), e);
8188 }
8189 return true;
8190 }
8191
8192 /**
8193 * Restores:
8194 * <ul>
8195 * <li>Skills</li>
8196 * <li>Macros</li>
8197 * <li>Short-cuts</li>
8198 * <li>Henna</li>
8199 * <li>Teleport Bookmark</li>
8200 * <li>Recipe Book</li>
8201 * <li>Recipe Shop List (If configuration enabled)</li>
8202 * <li>Premium Item List</li>
8203 * <li>Pet Inventory Items</li>
8204 * </ul>
8205 */
8206 private void restoreCharData()
8207 {
8208 // Retrieve from the database all skills of this L2PcInstance and add them to _skills.
8209 restoreSkills();
8210
8211 // Retrieve from the database all macroses of this L2PcInstance and add them to _macros.
8212 _macros.restore();
8213
8214 // Retrieve from the database all shortCuts of this L2PcInstance and add them to _shortCuts.
8215 _shortCuts.restore();
8216
8217 // Retrieve from the database all henna of this L2PcInstance and add them to _henna.
8218 restoreHenna();
8219
8220 // Retrieve from the database all teleport bookmark of this L2PcInstance and add them to _tpbookmark.
8221 restoreTeleportBookmark();
8222
8223 // Retrieve from the database the recipe book of this L2PcInstance.
8224 restoreRecipeBook(true);
8225
8226 // Restore Recipe Shop list.
8227 if (Config.STORE_RECIPE_SHOPLIST)
8228 {
8229 restoreRecipeShopList();
8230 }
8231
8232 // Load Premium Item List.
8233 loadPremiumItemList();
8234
8235 // Restore items in pet inventory.
8236 restorePetInventoryItems();
8237 }
8238
8239 /**
8240 * Restore recipe book data for this L2PcInstance.
8241 * @param loadCommon
8242 */
8243 private void restoreRecipeBook(boolean loadCommon)
8244 {
8245 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
8246 {
8247 String sql = loadCommon ? "SELECT id, type, classIndex FROM character_recipebook WHERE charId=?" : "SELECT id FROM character_recipebook WHERE charId=? AND classIndex=? AND type = 1";
8248 PreparedStatement statement = con.prepareStatement(sql);
8249 statement.setInt(1, getObjectId());
8250 if (!loadCommon)
8251 {
8252 statement.setInt(2, _classIndex);
8253 }
8254 ResultSet rset = statement.executeQuery();
8255
8256 _dwarvenRecipeBook.clear();
8257
8258 L2RecipeList recipe;
8259 RecipeData rd = RecipeData.getInstance();
8260 while (rset.next())
8261 {
8262 recipe = rd.getRecipeList(rset.getInt("id"));
8263 if (loadCommon)
8264 {
8265 if (rset.getInt(2) == 1)
8266 {
8267 if (rset.getInt(3) == _classIndex)
8268 {
8269 registerDwarvenRecipeList(recipe, false);
8270 }
8271 }
8272 else
8273 {
8274 registerCommonRecipeList(recipe, false);
8275 }
8276 }
8277 else
8278 {
8279 registerDwarvenRecipeList(recipe, false);
8280 }
8281 }
8282
8283 rset.close();
8284 statement.close();
8285 }
8286 catch (Exception e)
8287 {
8288 _log.log(Level.SEVERE, "Could not restore recipe book data:" + e.getMessage(), e);
8289 }
8290 }
8291
8292 public Map<Integer, L2PremiumItem> getPremiumItemList()
8293 {
8294 return _premiumItems;
8295 }
8296
8297 private void loadPremiumItemList()
8298 {
8299 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
8300 {
8301 String sql = "SELECT itemNum, itemId, itemCount, itemSender FROM character_premium_items WHERE charId=?";
8302 PreparedStatement statement = con.prepareStatement(sql);
8303 statement.setInt(1, getObjectId());
8304 ResultSet rset = statement.executeQuery();
8305 while (rset.next())
8306 {
8307 int itemNum = rset.getInt("itemNum");
8308 int itemId = rset.getInt("itemId");
8309 long itemCount = rset.getLong("itemCount");
8310 String itemSender = rset.getString("itemSender");
8311 _premiumItems.put(itemNum, new L2PremiumItem(itemId, itemCount, itemSender));
8312 }
8313 rset.close();
8314 statement.close();
8315 }
8316 catch (Exception e)
8317 {
8318 _log.log(Level.SEVERE, "Could not restore premium items: " + e.getMessage(), e);
8319 }
8320 }
8321
8322 public void updatePremiumItem(int itemNum, long newcount)
8323 {
8324 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
8325 PreparedStatement statement = con.prepareStatement("UPDATE character_premium_items SET itemCount=? WHERE charId=? AND itemNum=? "))
8326 {
8327 statement.setLong(1, newcount);
8328 statement.setInt(2, getObjectId());
8329 statement.setInt(3, itemNum);
8330 statement.execute();
8331 }
8332 catch (Exception e)
8333 {
8334 _log.log(Level.SEVERE, "Could not update premium items: " + e.getMessage(), e);
8335 }
8336 }
8337
8338 public void deletePremiumItem(int itemNum)
8339 {
8340 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
8341 PreparedStatement statement = con.prepareStatement("DELETE FROM character_premium_items WHERE charId=? AND itemNum=? "))
8342 {
8343 statement.setInt(1, getObjectId());
8344 statement.setInt(2, itemNum);
8345 statement.execute();
8346 }
8347 catch (Exception e)
8348 {
8349 _log.log(Level.SEVERE, "Could not delete premium item: " + e);
8350 }
8351 }
8352
8353 /**
8354 * Update L2PcInstance stats in the characters table of the database.
8355 * @param storeActiveEffects
8356 */
8357 public synchronized void store(boolean storeActiveEffects)
8358 {
8359 // update client coords, if these look like true
8360 // if (isInsideRadius(getClientX(), getClientY(), 1000, true))
8361 // setXYZ(getClientX(), getClientY(), getClientZ());
8362
8363 storeCharBase();
8364 storeCharSub();
8365 storeEffect(storeActiveEffects);
8366 storeItemReuseDelay();
8367 transformInsertInfo();
8368 if (Config.STORE_RECIPE_SHOPLIST)
8369 {
8370 storeRecipeShopList();
8371 }
8372 if (Config.STORE_UI_SETTINGS)
8373 {
8374 storeUISettings();
8375 }
8376 SevenSigns.getInstance().saveSevenSignsData(getObjectId());
8377 }
8378
8379 @Override
8380 public void store()
8381 {
8382 store(true);
8383 }
8384
8385 private void storeCharBase()
8386 {
8387 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
8388 {
8389 // Get the exp, level, and sp of base class to store in base table
8390 long exp = getStat().getBaseExp();
8391 int level = getStat().getBaseLevel();
8392 int sp = getStat().getBaseSp();
8393
8394 // Update base class
8395 PreparedStatement statement = con.prepareStatement(UPDATE_CHARACTER);
8396
8397 statement.setInt(1, level);
8398 statement.setInt(2, getMaxHp());
8399 statement.setDouble(3, getCurrentHp());
8400 statement.setInt(4, getMaxCp());
8401 statement.setDouble(5, getCurrentCp());
8402 statement.setInt(6, getMaxMp());
8403 statement.setDouble(7, getCurrentMp());
8404 statement.setInt(8, getAppearance().getFace());
8405 statement.setInt(9, getAppearance().getHairStyle());
8406 statement.setInt(10, getAppearance().getHairColor());
8407 statement.setInt(11, getAppearance().getSex() ? 1 : 0);
8408 statement.setInt(12, getHeading());
8409 statement.setInt(13, _observerMode ? _lastX : getX());
8410 statement.setInt(14, _observerMode ? _lastY : getY());
8411 statement.setInt(15, _observerMode ? _lastZ : getZ());
8412 statement.setLong(16, exp);
8413 statement.setLong(17, getExpBeforeDeath());
8414 statement.setInt(18, sp);
8415 statement.setInt(19, getKarma());
8416 statement.setInt(20, getFame());
8417 statement.setInt(21, getPvpKills());
8418 statement.setInt(22, getPkKills());
8419 statement.setInt(23, getClanId());
8420 statement.setInt(24, getRace().ordinal());
8421 statement.setInt(25, getClassId().getId());
8422 statement.setLong(26, getDeleteTimer());
8423 statement.setString(27, getTitle());
8424 statement.setInt(28, getAppearance().getTitleColor());
8425 statement.setInt(29, getAccessLevel().getLevel());
8426 statement.setInt(30, isOnlineInt());
8427 statement.setInt(31, isIn7sDungeon() ? 1 : 0);
8428 statement.setInt(32, getClanPrivileges());
8429 statement.setInt(33, getWantsPeace());
8430 statement.setInt(34, getBaseClass());
8431
8432 long totalOnlineTime = _onlineTime;
8433
8434 if (_onlineBeginTime > 0)
8435 {
8436 totalOnlineTime += (System.currentTimeMillis() - _onlineBeginTime) / 1000;
8437 }
8438
8439 statement.setLong(35, totalOnlineTime);
8440 statement.setInt(36, getPunishLevel().value());
8441 statement.setLong(37, getPunishTimer());
8442 statement.setInt(38, getNewbie());
8443 statement.setInt(39, isNoble() ? 1 : 0);
8444 statement.setInt(40, getPowerGrade());
8445 statement.setInt(41, getPledgeType());
8446 statement.setInt(42, getLvlJoinedAcademy());
8447 statement.setLong(43, getApprentice());
8448 statement.setLong(44, getSponsor());
8449 statement.setInt(45, getAllianceWithVarkaKetra());
8450 statement.setLong(46, getClanJoinExpiryTime());
8451 statement.setLong(47, getClanCreateExpiryTime());
8452 statement.setString(48, getName());
8453 statement.setLong(49, getDeathPenaltyBuffLevel());
8454 statement.setInt(50, getBookMarkSlot());
8455 statement.setInt(51, getVitalityPoints());
8456 statement.setInt(52, getPcBangPoints());
8457 statement.setString(53, getLang());
8458 statement.setLong(54, getGamePoints());
8459 statement.setInt(55, getHitmanTarget());
8460 statement.setInt(56, getObjectId());
8461
8462 statement.execute();
8463 statement.close();
8464 }
8465 catch (Exception e)
8466 {
8467 _log.log(Level.WARNING, "Could not store char base data: " + this + " - " + e.getMessage(), e);
8468 }
8469 }
8470
8471 private void storeCharSub()
8472 {
8473 if (getTotalSubClasses() <= 0)
8474 {
8475 return;
8476 }
8477
8478 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
8479 PreparedStatement statement = con.prepareStatement(UPDATE_CHAR_SUBCLASS))
8480 {
8481 for (SubClass subClass : getSubClasses().values())
8482 {
8483 statement.setLong(1, subClass.getExp());
8484 statement.setInt(2, subClass.getSp());
8485 statement.setInt(3, subClass.getLevel());
8486 statement.setInt(4, subClass.getClassId());
8487 statement.setInt(5, getObjectId());
8488 statement.setInt(6, subClass.getClassIndex());
8489
8490 statement.execute();
8491 statement.clearParameters();
8492 }
8493 }
8494 catch (Exception e)
8495 {
8496 _log.log(Level.WARNING, "Could not store sub class data for " + getName() + ": " + e.getMessage(), e);
8497 }
8498 }
8499
8500 @Override
8501 public void storeEffect(boolean storeEffects)
8502 {
8503 if (!Config.STORE_SKILL_COOLTIME)
8504 {
8505 return;
8506 }
8507
8508 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
8509 {
8510 // Delete all current stored effects for char to avoid dupe
8511 PreparedStatement statement = con.prepareStatement(DELETE_SKILL_SAVE);
8512
8513 statement.setInt(1, getObjectId());
8514 statement.setInt(2, getClassIndex());
8515 statement.execute();
8516 statement.close();
8517
8518 int buff_index = 0;
8519
8520 final List<Integer> storedSkills = new FastList<>();
8521
8522 // Store all effect data along with calulated remaining
8523 // reuse delays for matching skills. 'restore_type'= 0.
8524 statement = con.prepareStatement(ADD_SKILL_SAVE);
8525
8526 if (storeEffects)
8527 {
8528 for (L2Effect effect : getAllEffects())
8529 {
8530 if (effect == null)
8531 {
8532 continue;
8533 }
8534
8535 switch (effect.getEffectType())
8536 {
8537 case HEAL_OVER_TIME:
8538 case CPHEAL_OVER_TIME:
8539 // TODO: Fix me.
8540 case HIDE:
8541 continue;
8542 }
8543
8544 L2Skill skill = effect.getSkill();
8545 if (storedSkills.contains(skill.getReuseHashCode()))
8546 {
8547 continue;
8548 }
8549
8550 storedSkills.add(skill.getReuseHashCode());
8551
8552 if (effect.getInUse() && !skill.isToggle())
8553 {
8554
8555 statement.setInt(1, getObjectId());
8556 statement.setInt(2, skill.getId());
8557 statement.setInt(3, skill.getLevel());
8558 statement.setInt(4, effect.getCount());
8559 statement.setInt(5, effect.getTime());
8560
8561 if (_reuseTimeStampsSkills.containsKey(skill.getReuseHashCode()))
8562 {
8563 TimeStamp t = _reuseTimeStampsSkills.get(skill.getReuseHashCode());
8564 statement.setLong(6, t.hasNotPassed() ? t.getReuse() : 0);
8565 statement.setDouble(7, t.hasNotPassed() ? t.getStamp() : 0);
8566 }
8567 else
8568 {
8569 statement.setLong(6, 0);
8570 statement.setDouble(7, 0);
8571 }
8572
8573 statement.setInt(8, 0);
8574 statement.setInt(9, getClassIndex());
8575 statement.setInt(10, ++buff_index);
8576 statement.execute();
8577 }
8578 }
8579 }
8580
8581 // Store the reuse delays of remaining skills which
8582 // lost effect but still under reuse delay. 'restore_type' 1.
8583 int hash;
8584 TimeStamp t;
8585 for (Entry<Integer, TimeStamp> ts : _reuseTimeStampsSkills.entrySet())
8586 {
8587 hash = ts.getKey();
8588 if (storedSkills.contains(hash))
8589 {
8590 continue;
8591 }
8592 t = ts.getValue();
8593 if ((t != null) && t.hasNotPassed())
8594 {
8595 storedSkills.add(hash);
8596
8597 statement.setInt(1, getObjectId());
8598 statement.setInt(2, t.getSkillId());
8599 statement.setInt(3, t.getSkillLvl());
8600 statement.setInt(4, -1);
8601 statement.setInt(5, -1);
8602 statement.setLong(6, t.getReuse());
8603 statement.setDouble(7, t.getStamp());
8604 statement.setInt(8, 1);
8605 statement.setInt(9, getClassIndex());
8606 statement.setInt(10, ++buff_index);
8607 statement.execute();
8608 }
8609 }
8610 statement.close();
8611 }
8612 catch (Exception e)
8613 {
8614 _log.log(Level.WARNING, "Could not store char effect data: ", e);
8615 }
8616 }
8617
8618 private void storeItemReuseDelay()
8619 {
8620 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
8621 PreparedStatement ps1 = con.prepareStatement(DELETE_ITEM_REUSE_SAVE);
8622 PreparedStatement ps2 = con.prepareStatement(ADD_ITEM_REUSE_SAVE))
8623 {
8624 ps1.setInt(1, getObjectId());
8625 ps1.execute();
8626
8627 for (TimeStamp ts : _reuseTimeStampsItems.values())
8628 {
8629 if ((ts != null) && ts.hasNotPassed())
8630 {
8631 ps2.setInt(1, getObjectId());
8632 ps2.setInt(2, ts.getItemId());
8633 ps2.setInt(3, ts.getItemObjectId());
8634 ps2.setLong(4, ts.getReuse());
8635 ps2.setDouble(5, ts.getStamp());
8636 ps2.execute();
8637 }
8638 }
8639 }
8640 catch (Exception e)
8641 {
8642 _log.log(Level.WARNING, "Could not store char item reuse data: ", e);
8643 }
8644 }
8645
8646 /**
8647 * @return True if the L2PcInstance is on line.
8648 */
8649 public boolean isOnline()
8650 {
8651 return _isOnline;
8652 }
8653
8654 public int isOnlineInt()
8655 {
8656 if (_isOnline && (getClient() != null))
8657 {
8658 return getClient().isDetached() ? 2 : 1;
8659 }
8660 return 0;
8661 }
8662
8663 public boolean isIn7sDungeon()
8664 {
8665 return _isIn7sDungeon;
8666 }
8667
8668 /**
8669 * 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. <B><U> Concept</U> :</B> All skills own by a L2PcInstance are identified in <B>_skills</B> <B><U> Actions</U> :</B> <li>Replace
8670 * oldSkill by newSkill or Add the newSkill</li> <li>If an old skill has been replaced, remove all its Func objects of L2Character calculator set</li> <li>Add Func objects of newSkill to the calculator set of the L2Character</li>
8671 * @param newSkill The L2Skill to add to the L2Character
8672 * @param store
8673 * @return The L2Skill replaced or null if just added a new L2Skill
8674 */
8675 public L2Skill addSkill(L2Skill newSkill, boolean store)
8676 {
8677 // Add a skill to the L2PcInstance _skills and its Func objects to the calculator set of the L2PcInstance
8678 L2Skill oldSkill = super.addSkill(newSkill);
8679
8680 // Add or update a L2PcInstance skill in the character_skills table of the database
8681 if (store)
8682 {
8683 storeSkill(newSkill, oldSkill, -1);
8684 }
8685 return oldSkill;
8686 }
8687
8688 @Override
8689 public L2Skill removeSkill(L2Skill skill, boolean store)
8690 {
8691 if (store)
8692 {
8693 return removeSkill(skill);
8694 }
8695 return super.removeSkill(skill, true);
8696 }
8697
8698 public L2Skill removeSkill(L2Skill skill, boolean store, boolean cancelEffect)
8699 {
8700 if (store)
8701 {
8702 return removeSkill(skill);
8703 }
8704 return super.removeSkill(skill, cancelEffect);
8705 }
8706
8707 /**
8708 * 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. <B><U> Concept</U> :</B> All skills own by a L2Character are identified in <B>_skills</B> <B><U> Actions</U> :</B> <li>Remove the
8709 * skill from the L2Character _skills</li> <li>Remove all its Func objects from the L2Character calculator set</li> <B><U> Overridden in </U> :</B> <li>L2PcInstance : Save update in the character_skills table of the database</li>
8710 * @param skill The L2Skill to remove from the L2Character
8711 * @return The L2Skill removed
8712 */
8713 @Override
8714 public L2Skill removeSkill(L2Skill skill)
8715 {
8716 // Remove a skill from the L2Character and its Func objects from calculator set of the L2Character
8717 final L2Skill oldSkill = super.removeSkill(skill);
8718 if (oldSkill != null)
8719 {
8720 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
8721 PreparedStatement statement = con.prepareStatement(DELETE_SKILL_FROM_CHAR))
8722 {
8723 // Remove or update a L2PcInstance skill from the character_skills table of the database
8724 statement.setInt(1, oldSkill.getId());
8725 statement.setInt(2, getObjectId());
8726 statement.setInt(3, getClassIndex());
8727 statement.execute();
8728 }
8729 catch (Exception e)
8730 {
8731 _log.log(Level.WARNING, "Error could not delete skill: " + e.getMessage(), e);
8732 }
8733 }
8734
8735 if ((transformId() > 0) || isCursedWeaponEquipped())
8736 {
8737 return oldSkill;
8738 }
8739
8740 final L2ShortCut[] allShortCuts = getAllShortCuts();
8741 for (L2ShortCut sc : allShortCuts)
8742 {
8743 if ((sc != null) && (skill != null) && (sc.getId() == skill.getId()) && (sc.getType() == L2ShortCut.TYPE_SKILL) && !((skill.getId() >= 3080) && (skill.getId() <= 3259)))
8744 {
8745 deleteShortCut(sc.getSlot(), sc.getPage());
8746 }
8747 }
8748 return oldSkill;
8749 }
8750
8751 /**
8752 * Add or update a L2PcInstance skill in the character_skills table of the database.<br>
8753 * If newClassIndex > -1, the skill will be stored with that class index, not the current one.
8754 * @param newSkill
8755 * @param oldSkill
8756 * @param newClassIndex
8757 */
8758 private void storeSkill(L2Skill newSkill, L2Skill oldSkill, int newClassIndex)
8759 {
8760 int classIndex = _classIndex;
8761
8762 if (newClassIndex > -1)
8763 {
8764 classIndex = newClassIndex;
8765 }
8766
8767 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
8768 {
8769 if ((oldSkill != null) && (newSkill != null))
8770 {
8771 try (PreparedStatement ps = con.prepareStatement(UPDATE_CHARACTER_SKILL_LEVEL))
8772 {
8773 ps.setInt(1, newSkill.getLevel());
8774 ps.setInt(2, oldSkill.getId());
8775 ps.setInt(3, getObjectId());
8776 ps.setInt(4, classIndex);
8777 ps.execute();
8778 }
8779 }
8780 else if (newSkill != null)
8781 {
8782 try (PreparedStatement ps = con.prepareStatement(ADD_NEW_SKILL))
8783 {
8784 ps.setInt(1, getObjectId());
8785 ps.setInt(2, newSkill.getId());
8786 ps.setInt(3, newSkill.getLevel());
8787 ps.setInt(4, classIndex);
8788 ps.execute();
8789 }
8790 }
8791 else
8792 {
8793 _log.warning("Could not store new skill, it's null!");
8794 }
8795 }
8796 catch (Exception e)
8797 {
8798 _log.log(Level.WARNING, "Error could not store char skills: " + e.getMessage(), e);
8799 }
8800 }
8801
8802 /**
8803 * Retrieve from the database all skills of this L2PcInstance and add them to _skills.
8804 */
8805 private void restoreSkills()
8806 {
8807 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
8808 PreparedStatement statement = con.prepareStatement(RESTORE_SKILLS_FOR_CHAR))
8809 {
8810 // Retrieve all skills of this L2PcInstance from the database
8811 statement.setInt(1, getObjectId());
8812 statement.setInt(2, getClassIndex());
8813 final ResultSet rset = statement.executeQuery();
8814
8815 // Go though the recordset of this SQL query
8816 while (rset.next())
8817 {
8818 final int id = rset.getInt("skill_id");
8819 final int level = rset.getInt("skill_level");
8820
8821 // Create a L2Skill object for each record
8822 final L2Skill skill = SkillTable.getInstance().getInfo(id, level);
8823
8824 if (skill == null)
8825 {
8826 _log.warning("Skipped null skill Id: " + id + " Level: " + level + " while restoring player skills for playerObjId: " + getObjectId());
8827 continue;
8828 }
8829
8830 // Add the L2Skill object to the L2Character _skills and its Func objects to the calculator set of the L2Character
8831 super.addSkill(skill);
8832
8833 if (Config.SKILL_CHECK_ENABLE && (!canOverrideCond(PcCondOverride.SKILL_CONDITIONS) || Config.SKILL_CHECK_GM))
8834 {
8835 if (!SkillTreesData.getInstance().isSkillAllowed(this, skill))
8836 {
8837 Util.handleIllegalPlayerAction(this, "Player " + getName() + " has invalid skill " + skill.getName() + " (" + skill.getId() + "/" + skill.getLevel() + "), class:" + ClassListData.getInstance().getClass(getClassId()).getClassName(), 1);
8838 if (Config.SKILL_CHECK_REMOVE)
8839 {
8840 removeSkill(skill);
8841 }
8842 }
8843 }
8844 }
8845 rset.close();
8846 }
8847 catch (Exception e)
8848 {
8849 _log.log(Level.WARNING, "Could not restore character " + this + " skills: " + e.getMessage(), e);
8850 }
8851 }
8852
8853 /**
8854 * Retrieve from the database all skill effects of this L2PcInstance and add them to the player.
8855 */
8856 @Override
8857 public void restoreEffects()
8858 {
8859 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
8860 {
8861 PreparedStatement statement;
8862 ResultSet rset;
8863
8864 statement = con.prepareStatement(RESTORE_SKILL_SAVE);
8865 statement.setInt(1, getObjectId());
8866 statement.setInt(2, getClassIndex());
8867 rset = statement.executeQuery();
8868
8869 while (rset.next())
8870 {
8871 int effectCount = rset.getInt("effect_count");
8872 int effectCurTime = rset.getInt("effect_cur_time");
8873 long reuseDelay = rset.getLong("reuse_delay");
8874 long systime = rset.getLong("systime");
8875 int restoreType = rset.getInt("restore_type");
8876
8877 final L2Skill skill = SkillTable.getInstance().getInfo(rset.getInt("skill_id"), rset.getInt("skill_level"));
8878 if (skill == null)
8879 {
8880 continue;
8881 }
8882
8883 final long remainingTime = systime - System.currentTimeMillis();
8884 if (remainingTime > 10)
8885 {
8886 disableSkill(skill, remainingTime);
8887 addTimeStamp(skill, reuseDelay, systime);
8888 }
8889
8890 /**
8891 * Restore Type 1 The remaning skills lost effect upon logout but were still under a high reuse delay.
8892 */
8893 if (restoreType > 0)
8894 {
8895 continue;
8896 }
8897
8898 /**
8899 * Restore Type 0 These skill were still in effect on the character upon logout. Some of which were self casted and might still have had a long reuse delay which also is restored.
8900 */
8901 if (skill.hasEffects())
8902 {
8903 Env env = new Env();
8904 env.setCharacter(this);
8905 env.setTarget(this);
8906 env.setSkill(skill);
8907
8908 L2Effect ef;
8909 for (EffectTemplate et : skill.getEffectTemplates())
8910 {
8911 ef = et.getEffect(env);
8912 if (ef != null)
8913 {
8914 ef.setCount(effectCount);
8915 ef.setFirstTime(effectCurTime);
8916 ef.scheduleEffect();
8917 }
8918 }
8919 }
8920 }
8921
8922 rset.close();
8923 statement.close();
8924
8925 statement = con.prepareStatement(DELETE_SKILL_SAVE);
8926 statement.setInt(1, getObjectId());
8927 statement.setInt(2, getClassIndex());
8928 statement.executeUpdate();
8929 statement.close();
8930 }
8931 catch (Exception e)
8932 {
8933 _log.log(Level.WARNING, "Could not restore " + this + " active effect data: " + e.getMessage(), e);
8934 }
8935 }
8936
8937 /**
8938 * Retrieve from the database all Item Reuse Time of this L2PcInstance and add them to the player.
8939 */
8940 private void restoreItemReuse()
8941 {
8942 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
8943 {
8944 PreparedStatement statement = con.prepareStatement(RESTORE_ITEM_REUSE_SAVE);
8945 statement.setInt(1, getObjectId());
8946 final ResultSet rset = statement.executeQuery();
8947 int itemId;
8948 @SuppressWarnings("unused")
8949 int itemObjId;
8950 long reuseDelay;
8951 long systime;
8952 boolean isInInventory;
8953 long remainingTime;
8954 while (rset.next())
8955 {
8956 itemId = rset.getInt("itemId");
8957 itemObjId = rset.getInt("itemObjId");
8958 reuseDelay = rset.getLong("reuseDelay");
8959 systime = rset.getLong("systime");
8960 isInInventory = true;
8961
8962 // Using item Id
8963 L2ItemInstance item = getInventory().getItemByItemId(itemId);
8964 if (item == null)
8965 {
8966 item = getWarehouse().getItemByItemId(itemId);
8967 isInInventory = false;
8968 }
8969
8970 if ((item != null) && (item.getItemId() == itemId) && (item.getReuseDelay() > 0))
8971 {
8972 remainingTime = systime - System.currentTimeMillis();
8973 // Hardcoded to 10 seconds.
8974 if (remainingTime > 10)
8975 {
8976 addTimeStampItem(item, reuseDelay, systime);
8977
8978 if (isInInventory && item.isEtcItem())
8979 {
8980 final int group = item.getSharedReuseGroup();
8981 if (group > 0)
8982 {
8983 sendPacket(new ExUseSharedGroupItem(itemId, group, (int) remainingTime, (int) reuseDelay));
8984 }
8985 }
8986 }
8987 }
8988 }
8989
8990 rset.close();
8991 statement.close();
8992
8993 statement = con.prepareStatement(DELETE_ITEM_REUSE_SAVE);
8994 statement.setInt(1, getObjectId());
8995 statement.executeUpdate();
8996 statement.close();
8997 }
8998 catch (Exception e)
8999 {
9000 _log.log(Level.WARNING, "Could not restore " + this + " Item Reuse data: " + e.getMessage(), e);
9001 }
9002 }
9003
9004 /**
9005 * Retrieve from the database all Henna of this L2PcInstance, add them to _henna and calculate stats of the L2PcInstance.
9006 */
9007 private void restoreHenna()
9008 {
9009 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
9010 {
9011 PreparedStatement statement = con.prepareStatement(RESTORE_CHAR_HENNAS);
9012 statement.setInt(1, getObjectId());
9013 statement.setInt(2, getClassIndex());
9014 ResultSet rset = statement.executeQuery();
9015
9016 for (int i = 0; i < 3; i++)
9017 {
9018 _henna[i] = null;
9019 }
9020
9021 int slot;
9022 int symbolId;
9023 while (rset.next())
9024 {
9025 slot = rset.getInt("slot");
9026 if ((slot < 1) || (slot > 3))
9027 {
9028 continue;
9029 }
9030
9031 symbolId = rset.getInt("symbol_id");
9032 if (symbolId == 0)
9033 {
9034 continue;
9035 }
9036 _henna[slot - 1] = HennaData.getInstance().getHenna(symbolId);
9037 }
9038
9039 rset.close();
9040 statement.close();
9041 }
9042 catch (Exception e)
9043 {
9044 _log.log(Level.SEVERE, "Failed restoing character " + this + " hennas.", e);
9045 }
9046
9047 // Calculate Henna modifiers of this L2PcInstance
9048 recalcHennaStats();
9049 }
9050
9051 /**
9052 * @return the number of Henna empty slot of the L2PcInstance.
9053 */
9054 public int getHennaEmptySlots()
9055 {
9056 int totalSlots = 0;
9057 if (getClassId().level() == 1)
9058 {
9059 totalSlots = 2;
9060 }
9061 else
9062 {
9063 totalSlots = 3;
9064 }
9065
9066 for (int i = 0; i < 3; i++)
9067 {
9068 if (_henna[i] != null)
9069 {
9070 totalSlots--;
9071 }
9072 }
9073
9074 if (totalSlots <= 0)
9075 {
9076 return 0;
9077 }
9078
9079 return totalSlots;
9080 }
9081
9082 /**
9083 * Remove a Henna of the L2PcInstance, save update in the character_hennas table of the database and send Server->Client HennaInfo/UserInfo packet to this L2PcInstance.
9084 * @param slot
9085 * @return
9086 */
9087 public boolean removeHenna(int slot)
9088 {
9089 if (!fireHennaListeners(getHenna(slot + 1), false))
9090 {
9091 return false;
9092 }
9093
9094 if ((slot < 1) || (slot > 3))
9095 {
9096 return false;
9097 }
9098
9099 slot--;
9100
9101 L2Henna henna = _henna[slot];
9102 if (henna == null)
9103 {
9104 return false;
9105 }
9106
9107 _henna[slot] = null;
9108
9109 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
9110 PreparedStatement statement = con.prepareStatement(DELETE_CHAR_HENNA))
9111 {
9112 statement.setInt(1, getObjectId());
9113 statement.setInt(2, slot + 1);
9114 statement.setInt(3, getClassIndex());
9115 statement.execute();
9116 }
9117 catch (Exception e)
9118 {
9119 _log.log(Level.SEVERE, "Failed remocing character henna.", e);
9120 }
9121
9122 // Calculate Henna modifiers of this L2PcInstance
9123 recalcHennaStats();
9124
9125 // Send Server->Client HennaInfo packet to this L2PcInstance
9126 sendPacket(new HennaInfo(this));
9127
9128 // Send Server->Client UserInfo packet to this L2PcInstance
9129 sendPacket(new UserInfo(this));
9130 sendPacket(new ExBrExtraUserInfo(this));
9131 // Add the recovered dyes to the player's inventory and notify them.
9132 getInventory().addItem("Henna", henna.getDyeItemId(), henna.getCancelCount(), this, null);
9133 reduceAdena("Henna", henna.getCancelFee(), this, false);
9134
9135 final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
9136 sm.addItemName(henna.getDyeItemId());
9137 sm.addItemNumber(henna.getCancelCount());
9138 sendPacket(sm);
9139 sendPacket(SystemMessageId.SYMBOL_DELETED);
9140 return true;
9141 }
9142
9143 /**
9144 * 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.
9145 * @param henna the henna to add to the player.
9146 * @return {@code true} if the henna is added to the player, {@code false} otherwise.
9147 */
9148 public boolean addHenna(L2Henna henna)
9149 {
9150 if (!fireHennaListeners(henna, true))
9151 {
9152 return false;
9153 }
9154 for (int i = 0; i < 3; i++)
9155 {
9156 if (_henna[i] == null)
9157 {
9158 _henna[i] = henna;
9159
9160 // Calculate Henna modifiers of this L2PcInstance
9161 recalcHennaStats();
9162
9163 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
9164 PreparedStatement statement = con.prepareStatement(ADD_CHAR_HENNA))
9165 {
9166 statement.setInt(1, getObjectId());
9167 statement.setInt(2, henna.getDyeId());
9168 statement.setInt(3, i + 1);
9169 statement.setInt(4, getClassIndex());
9170 statement.execute();
9171 }
9172 catch (Exception e)
9173 {
9174 _log.log(Level.SEVERE, "Failed saving character henna.", e);
9175 }
9176
9177 // Send Server->Client HennaInfo packet to this L2PcInstance
9178 sendPacket(new HennaInfo(this));
9179
9180 // Send Server->Client UserInfo packet to this L2PcInstance
9181 sendPacket(new UserInfo(this));
9182 sendPacket(new ExBrExtraUserInfo(this));
9183
9184 return true;
9185 }
9186 }
9187 return false;
9188 }
9189
9190 /**
9191 * Calculate Henna modifiers of this L2PcInstance.
9192 */
9193 private void recalcHennaStats()
9194 {
9195 _hennaINT = 0;
9196 _hennaSTR = 0;
9197 _hennaCON = 0;
9198 _hennaMEN = 0;
9199 _hennaWIT = 0;
9200 _hennaDEX = 0;
9201
9202 for (L2Henna h : _henna)
9203 {
9204 if (h == null)
9205 {
9206 continue;
9207 }
9208
9209 _hennaINT += ((_hennaINT + h.getStatINT()) > 5) ? 5 - _hennaINT : h.getStatINT();
9210 _hennaSTR += ((_hennaSTR + h.getStatSTR()) > 5) ? 5 - _hennaSTR : h.getStatSTR();
9211 _hennaMEN += ((_hennaMEN + h.getStatMEN()) > 5) ? 5 - _hennaMEN : h.getStatMEN();
9212 _hennaCON += ((_hennaCON + h.getStatCON()) > 5) ? 5 - _hennaCON : h.getStatCON();
9213 _hennaWIT += ((_hennaWIT + h.getStatWIT()) > 5) ? 5 - _hennaWIT : h.getStatWIT();
9214 _hennaDEX += ((_hennaDEX + h.getStatDEX()) > 5) ? 5 - _hennaDEX : h.getStatDEX();
9215 }
9216 }
9217
9218 /**
9219 * @param slot the character inventory henna slot.
9220 * @return the Henna of this L2PcInstance corresponding to the selected slot.
9221 */
9222 public L2Henna getHenna(int slot)
9223 {
9224 if ((slot < 1) || (slot > 3))
9225 {
9226 return null;
9227 }
9228 return _henna[slot - 1];
9229 }
9230
9231 /**
9232 * @return the henna holder for this player.
9233 */
9234 public L2Henna[] getHennaList()
9235 {
9236 return _henna;
9237 }
9238
9239 /**
9240 * @return the INT Henna modifier of this L2PcInstance.
9241 */
9242 public int getHennaStatINT()
9243 {
9244 return _hennaINT;
9245 }
9246
9247 /**
9248 * @return the STR Henna modifier of this L2PcInstance.
9249 */
9250 public int getHennaStatSTR()
9251 {
9252 return _hennaSTR;
9253 }
9254
9255 /**
9256 * @return the CON Henna modifier of this L2PcInstance.
9257 */
9258 public int getHennaStatCON()
9259 {
9260 return _hennaCON;
9261 }
9262
9263 /**
9264 * @return the MEN Henna modifier of this L2PcInstance.
9265 */
9266 public int getHennaStatMEN()
9267 {
9268 return _hennaMEN;
9269 }
9270
9271 /**
9272 * @return the WIT Henna modifier of this L2PcInstance.
9273 */
9274 public int getHennaStatWIT()
9275 {
9276 return _hennaWIT;
9277 }
9278
9279 /**
9280 * @return the DEX Henna modifier of this L2PcInstance.
9281 */
9282 public int getHennaStatDEX()
9283 {
9284 return _hennaDEX;
9285 }
9286
9287 /**
9288 * Return True if the L2PcInstance is autoAttackable.<br>
9289 * <B><U>Actions</U>:</B>
9290 * <ul>
9291 * <li>Check if the attacker isn't the L2PcInstance Pet</li>
9292 * <li>Check if the attacker is L2MonsterInstance</li>
9293 * <li>If the attacker is a L2PcInstance, check if it is not in the same party</li>
9294 * <li>Check if the L2PcInstance has Karma</li>
9295 * <li>If the attacker is a L2PcInstance, check if it is not in the same siege clan (Attacker, Defender)</li>
9296 * </ul>
9297 */
9298 @Override
9299 public boolean isAutoAttackable(L2Character attacker)
9300 {
9301 if (attacker == null)
9302 {
9303 return false;
9304 }
9305
9306 // Check if the attacker isn't the L2PcInstance Pet
9307 if ((attacker == this) || (attacker == getSummon()))
9308 {
9309 return false;
9310 }
9311
9312 // Friendly mobs doesnt attack players
9313 if (attacker instanceof L2FriendlyMobInstance)
9314 {
9315 return false;
9316 }
9317
9318 // Check if the attacker is a L2MonsterInstance
9319 if (attacker instanceof L2MonsterInstance)
9320 {
9321 return true;
9322 }
9323
9324 // is AutoAttackable if both players are in the same duel and the duel is still going on
9325 if ((attacker instanceof L2PcInstance) && (getDuelState() == Duel.DUELSTATE_DUELLING) && (getDuelId() == ((L2PcInstance) attacker).getDuelId()))
9326 {
9327 return true;
9328 }
9329
9330 // Check if the attacker is not in the same party. NOTE: Party checks goes before oly checks in order to prevent patry member autoattack at oly.
9331 if ((getParty() != null) && getParty().getMembers().contains(attacker))
9332 {
9333 return false;
9334 }
9335
9336 // Check if the attacker is in olympia and olympia start
9337 if ((attacker instanceof L2PcInstance) && ((L2PcInstance) attacker).isInOlympiadMode())
9338 {
9339 if (isInOlympiadMode() && isOlympiadStart() && (((L2PcInstance) attacker).getOlympiadGameId() == getOlympiadGameId()))
9340 {
9341 return true;
9342 }
9343 if (isFakeDeath())
9344 {
9345 return false;
9346 }
9347 else
9348 {
9349 return false;
9350 }
9351 }
9352
9353 // Check if the attacker is in TvT and TvT is started
9354 if (TvTEvent.isStarted() && TvTEvent.isPlayerParticipant(getObjectId()))
9355 {
9356 return true;
9357 }
9358
9359 // Check if the attacker is a L2Playable
9360 if (attacker instanceof L2Playable)
9361 {
9362 if (isInsideZone(ZoneId.PEACE))
9363 {
9364 return false;
9365 }
9366
9367 // Get L2PcInstance
9368 L2PcInstance attackerPlayer = attacker.getActingPlayer();
9369
9370 if (getClan() != null)
9371 {
9372 Siege siege = SiegeManager.getInstance().getSiege(getX(), getY(), getZ());
9373 if (siege != null)
9374 {
9375 // Check if a siege is in progress and if attacker and the L2PcInstance aren't in the Defender clan
9376 if (siege.checkIsDefender(attackerPlayer.getClan()) && siege.checkIsDefender(getClan()))
9377 {
9378 return false;
9379 }
9380
9381 // Check if a siege is in progress and if attacker and the L2PcInstance aren't in the Attacker clan
9382 if (siege.checkIsAttacker(attackerPlayer.getClan()) && siege.checkIsAttacker(getClan()))
9383 {
9384 return false;
9385 }
9386 }
9387
9388 // Check if clan is at war
9389 if ((getClan() != null) && (attackerPlayer.getClan() != null) && getClan().isAtWarWith(attackerPlayer.getClanId()) && attackerPlayer.getClan().isAtWarWith(getClanId()) && (getWantsPeace() == 0) && (attackerPlayer.getWantsPeace() == 0) && !isAcademyMember())
9390 {
9391 return true;
9392 }
9393 }
9394
9395 // Check if the L2PcInstance is in an arena, but NOT siege zone. NOTE: This check comes before clan/ally checks, but after party checks.
9396 // This is done because in arenas, clan/ally members can autoattack if they arent in party.
9397 if ((isInsideZone(ZoneId.PVP) && attackerPlayer.isInsideZone(ZoneId.PVP)) && !(isInsideZone(ZoneId.SIEGE) && attackerPlayer.isInsideZone(ZoneId.SIEGE)))
9398 {
9399 return true;
9400 }
9401
9402 if (isInTownWarEvent())
9403 {
9404 return true;
9405 }
9406
9407 // Check if the attacker is in TvT Round and TvT Round is started
9408 if (TvTRoundEvent.isStarted() && TvTRoundEvent.isPlayerParticipant(getObjectId()))
9409 {
9410 return true;
9411 }
9412
9413 // Check if the attacker is not in the same clan
9414 if ((getClan() != null) && getClan().isMember(attacker.getObjectId()))
9415 {
9416 return false;
9417 }
9418
9419 // Check if the attacker is not in the same ally
9420 if ((attacker instanceof L2PcInstance) && (getAllyId() != 0) && (getAllyId() == attackerPlayer.getAllyId()))
9421 {
9422 return false;
9423 }
9424
9425 // Now check again if the L2PcInstance is in pvp zone, but this time at siege PvP zone, applying clan/ally checks
9426 if ((isInsideZone(ZoneId.PVP) && attackerPlayer.isInsideZone(ZoneId.PVP)) && (isInsideZone(ZoneId.SIEGE) && attackerPlayer.isInsideZone(ZoneId.SIEGE)))
9427 {
9428 return true;
9429 }
9430 }
9431 else if (attacker instanceof L2DefenderInstance)
9432 {
9433 if (getClan() != null)
9434 {
9435 Siege siege = SiegeManager.getInstance().getSiege(this);
9436 return ((siege != null) && siege.checkIsAttacker(getClan()));
9437 }
9438 }
9439
9440 // Check if the L2PcInstance has Karma
9441 if ((getKarma() > 0) || (getPvpFlag() > 0))
9442 {
9443 return true;
9444 }
9445
9446 return false;
9447 }
9448
9449 /**
9450 * Check if the active L2Skill can be casted.<br>
9451 * <B><U>Actions</U>:</B>
9452 * <ul>
9453 * <li>Check if the skill isn't toggle and is offensive</li>
9454 * <li>Check if the target is in the skill cast range</li>
9455 * <li>Check if the skill is Spoil type and if the target isn't already spoiled</li>
9456 * <li>Check if the caster owns enought consummed Item, enough HP and MP to cast the skill</li>
9457 * <li>Check if the caster isn't sitting</li>
9458 * <li>Check if all skills are enabled and this skill is enabled</li>
9459 * <li>Check if the caster own the weapon needed</li>
9460 * <li>Check if the skill is active</li>
9461 * <li>Check if all casting conditions are completed</li>
9462 * <li>Notify the AI with AI_INTENTION_CAST and target</li>
9463 * </ul>
9464 * @param skill The L2Skill to use
9465 * @param forceUse used to force ATTACK on players
9466 * @param dontMove used to prevent movement, if not in range
9467 */
9468 @Override
9469 public boolean useMagic(L2Skill skill, boolean forceUse, boolean dontMove)
9470 {
9471 // Check if the skill is active
9472 if (skill.isPassive())
9473 {
9474 // just ignore the passive skill request. why does the client send it anyway ??
9475 // Send a Server->Client packet ActionFailed to the L2PcInstance
9476 sendPacket(ActionFailed.STATIC_PACKET);
9477 return false;
9478 }
9479
9480 // ************************************* Check Casting in Progress *******************************************
9481
9482 // If a skill is currently being used, queue this one if this is not the same
9483 if (isCastingNow())
9484 {
9485 SkillDat currentSkill = getCurrentSkill();
9486 // Check if new skill different from current skill in progress
9487 if ((currentSkill != null) && (skill.getId() == currentSkill.getSkillId()))
9488 {
9489 sendPacket(ActionFailed.STATIC_PACKET);
9490 return false;
9491 }
9492
9493 // Create a new SkillDat object and queue it in the player _queuedSkill
9494 setQueuedSkill(skill, forceUse, dontMove);
9495 sendPacket(ActionFailed.STATIC_PACKET);
9496 return false;
9497 }
9498 setIsCastingNow(true);
9499 // Create a new SkillDat object and set the player _currentSkill
9500 // This is used mainly to save & queue the button presses, since L2Character has
9501 // _lastSkillCast which could otherwise replace it
9502 setCurrentSkill(skill, forceUse, dontMove);
9503
9504 if (getQueuedSkill() != null)
9505 {
9506 setQueuedSkill(null, false, false);
9507 }
9508
9509 if (!checkUseMagicConditions(skill, forceUse, dontMove))
9510 {
9511 setIsCastingNow(false);
9512 return false;
9513 }
9514
9515 // Check if the target is correct and Notify the AI with AI_INTENTION_CAST and target
9516 L2Object target = null;
9517 switch (skill.getTargetType())
9518 {
9519 case TARGET_AURA: // AURA, SELF should be cast even if no target has been found
9520 case TARGET_FRONT_AURA:
9521 case TARGET_BEHIND_AURA:
9522 case TARGET_GROUND:
9523 case TARGET_SELF:
9524 case TARGET_AURA_CORPSE_MOB:
9525 target = this;
9526 break;
9527 default:
9528
9529 // Get the first target of the list
9530 target = skill.getFirstOfTargetList(this);
9531 break;
9532 }
9533
9534 // Notify the AI with AI_INTENTION_CAST and target
9535 getAI().setIntention(CtrlIntention.AI_INTENTION_CAST, skill, target);
9536 return true;
9537 }
9538
9539 private boolean checkUseMagicConditions(L2Skill skill, boolean forceUse, boolean dontMove)
9540 {
9541 L2SkillType sklType = skill.getSkillType();
9542
9543 // ************************************* Check Player State *******************************************
9544
9545 // Abnormal effects(ex : Stun, Sleep...) are checked in L2Character useMagic()
9546 if (isOutOfControl() || isParalyzed() || isStunned() || isSleeping())
9547 {
9548 sendPacket(ActionFailed.STATIC_PACKET);
9549 return false;
9550 }
9551
9552 // Check if the player is dead
9553 if (isDead())
9554 {
9555 // Send a Server->Client packet ActionFailed to the L2PcInstance
9556 sendPacket(ActionFailed.STATIC_PACKET);
9557 return false;
9558 }
9559
9560 if (isFishing() && ((sklType != L2SkillType.PUMPING) && (sklType != L2SkillType.REELING) && (sklType != L2SkillType.FISHING)))
9561 {
9562 // Only fishing skills are available
9563 sendPacket(SystemMessageId.ONLY_FISHING_SKILLS_NOW);
9564 return false;
9565 }
9566
9567 if (inObserverMode())
9568 {
9569 sendPacket(SystemMessageId.OBSERVERS_CANNOT_PARTICIPATE);
9570 abortCast();
9571 sendPacket(ActionFailed.STATIC_PACKET);
9572 return false;
9573 }
9574
9575 // Check if the caster is sitting
9576 if (isSitting())
9577 {
9578 // Send a System Message to the caster
9579 sendPacket(SystemMessageId.CANT_MOVE_SITTING);
9580
9581 // Send a Server->Client packet ActionFailed to the L2PcInstance
9582 sendPacket(ActionFailed.STATIC_PACKET);
9583 return false;
9584 }
9585
9586 // Check if the skill type is TOGGLE
9587 if (skill.isToggle())
9588 {
9589 // Get effects of the skill
9590 L2Effect effect = getFirstEffect(skill.getId());
9591
9592 if (effect != null)
9593 {
9594 effect.exit();
9595
9596 // Send a Server->Client packet ActionFailed to the L2PcInstance
9597 sendPacket(ActionFailed.STATIC_PACKET);
9598 return false;
9599 }
9600 }
9601
9602 // Check if the player uses "Fake Death" skill
9603 // Note: do not check this before TOGGLE reset
9604 if (isFakeDeath())
9605 {
9606 // Send a Server->Client packet ActionFailed to the L2PcInstance
9607 sendPacket(ActionFailed.STATIC_PACKET);
9608 return false;
9609 }
9610
9611 // ************************************* Check Target *******************************************
9612 // Create and set a L2Object containing the target of the skill
9613 L2Object target = null;
9614 L2TargetType sklTargetType = skill.getTargetType();
9615 Point3D worldPosition = getCurrentSkillWorldPosition();
9616
9617 if ((sklTargetType == L2TargetType.TARGET_GROUND) && (worldPosition == null))
9618 {
9619 _log.info("WorldPosition is null for skill: " + skill.getName() + ", player: " + getName() + ".");
9620 sendPacket(ActionFailed.STATIC_PACKET);
9621 return false;
9622 }
9623
9624 switch (sklTargetType)
9625 {
9626 // Target the player if skill type is AURA, PARTY, CLAN or SELF
9627 case TARGET_AURA:
9628 case TARGET_FRONT_AURA:
9629 case TARGET_BEHIND_AURA:
9630 case TARGET_PARTY:
9631 case TARGET_ALLY:
9632 case TARGET_CLAN:
9633 case TARGET_PARTY_CLAN:
9634 case TARGET_GROUND:
9635 case TARGET_SELF:
9636 case TARGET_AREA_SUMMON:
9637 case TARGET_AURA_CORPSE_MOB:
9638 target = this;
9639 break;
9640 case TARGET_PET:
9641 case TARGET_SUMMON:
9642 target = getSummon();
9643 break;
9644 default:
9645 target = getTarget();
9646 break;
9647 }
9648
9649 // Check the validity of the target
9650 if (target == null)
9651 {
9652 sendPacket(ActionFailed.STATIC_PACKET);
9653 return false;
9654 }
9655
9656 // skills can be used on Walls and Doors only during siege
9657 if (target.isDoor())
9658 {
9659 if ((((L2DoorInstance) target).getCastle() != null) && (((L2DoorInstance) target).getCastle().getCastleId() > 0)) // If its castle door
9660 {
9661 if (!((L2DoorInstance) target).getCastle().getSiege().getIsInProgress())
9662 {
9663 return false;
9664 }
9665 }
9666 else if ((((L2DoorInstance) target).getFort() != null) && (((L2DoorInstance) target).getFort().getFortId() > 0) && !((L2DoorInstance) target).getIsShowHp()) // If its fort door
9667 {
9668 if (!((L2DoorInstance) target).getFort().getSiege().getIsInProgress())
9669 {
9670 return false;
9671 }
9672 }
9673 }
9674
9675 // Are the target and the player in the same duel?
9676 if (isInDuel())
9677 {
9678 // Get L2PcInstance
9679 if (target instanceof L2Playable)
9680 {
9681 // Get L2PcInstance
9682 L2PcInstance cha = target.getActingPlayer();
9683 if (cha.getDuelId() != getDuelId())
9684 {
9685 sendMessage("You cannot do this while duelling.");
9686 sendPacket(ActionFailed.STATIC_PACKET);
9687 return false;
9688 }
9689 }
9690 }
9691
9692 // ************************************* Check skill availability *******************************************
9693
9694 // Check if it's ok to summon
9695 // siege golem (13), Wild Hog Cannon (299), Swoop Cannon (448)
9696 if (((skill.getId() == 13) || (skill.getId() == 299) || (skill.getId() == 448)) && ((!SiegeManager.getInstance().checkIfOkToSummon(this, false) && !FortSiegeManager.getInstance().checkIfOkToSummon(this, false)) || (SevenSigns.getInstance().checkSummonConditions(this))))
9697 {
9698 return false;
9699 }
9700
9701 // Check if this skill is enabled (ex : reuse time)
9702 if (isSkillDisabled(skill))
9703 {
9704 SystemMessage sm = null;
9705 if (_reuseTimeStampsSkills.containsKey(skill.getReuseHashCode()))
9706 {
9707 int remainingTime = (int) (_reuseTimeStampsSkills.get(skill.getReuseHashCode()).getRemaining() / 1000);
9708 int hours = remainingTime / 3600;
9709 int minutes = (remainingTime % 3600) / 60;
9710 int seconds = (remainingTime % 60);
9711 if (hours > 0)
9712 {
9713 sm = SystemMessage.getSystemMessage(SystemMessageId.S2_HOURS_S3_MINUTES_S4_SECONDS_REMAINING_FOR_REUSE_S1);
9714 sm.addSkillName(skill);
9715 sm.addNumber(hours);
9716 sm.addNumber(minutes);
9717 }
9718 else if (minutes > 0)
9719 {
9720 sm = SystemMessage.getSystemMessage(SystemMessageId.S2_MINUTES_S3_SECONDS_REMAINING_FOR_REUSE_S1);
9721 sm.addSkillName(skill);
9722 sm.addNumber(minutes);
9723 }
9724 else
9725 {
9726 sm = SystemMessage.getSystemMessage(SystemMessageId.S2_SECONDS_REMAINING_FOR_REUSE_S1);
9727 sm.addSkillName(skill);
9728 }
9729
9730 sm.addNumber(seconds);
9731 }
9732 else
9733 {
9734 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_PREPARED_FOR_REUSE);
9735 sm.addSkillName(skill);
9736 }
9737
9738 sendPacket(sm);
9739 return false;
9740 }
9741
9742 // ************************************* Check casting conditions *******************************************
9743
9744 // Check if all casting conditions are completed
9745 if (!skill.checkCondition(this, target, false))
9746 {
9747 // Send a Server->Client packet ActionFailed to the L2PcInstance
9748 sendPacket(ActionFailed.STATIC_PACKET);
9749 return false;
9750 }
9751
9752 // ************************************* Check Skill Type *******************************************
9753
9754 // Check if this is offensive magic skill
9755 if (skill.isOffensive())
9756 {
9757 if ((isInsidePeaceZone(this, target)) && !allowPeaceAttack())
9758 {
9759 // If L2Character or target is in a peace zone, send a system message TARGET_IN_PEACEZONE a Server->Client packet ActionFailed
9760 sendPacket(SystemMessageId.TARGET_IN_PEACEZONE);
9761 sendPacket(ActionFailed.STATIC_PACKET);
9762 return false;
9763 }
9764
9765 if (isInOlympiadMode() && !isOlympiadStart())
9766 {
9767 // if L2PcInstance is in Olympia and the match isn't already start, send a Server->Client packet ActionFailed
9768 sendPacket(ActionFailed.STATIC_PACKET);
9769 return false;
9770 }
9771
9772 if ((target.getActingPlayer() != null) && (getSiegeState() > 0) && isInsideZone(ZoneId.SIEGE) && (target.getActingPlayer().getSiegeState() == getSiegeState()) && (target.getActingPlayer() != this) && (target.getActingPlayer().getSiegeSide() == getSiegeSide()))
9773 {
9774 //
9775 if (TerritoryWarManager.getInstance().isTWInProgress())
9776 {
9777 sendPacket(SystemMessageId.YOU_CANNOT_ATTACK_A_MEMBER_OF_THE_SAME_TERRITORY);
9778 }
9779 else
9780 {
9781 sendPacket(SystemMessageId.FORCED_ATTACK_IS_IMPOSSIBLE_AGAINST_SIEGE_SIDE_TEMPORARY_ALLIED_MEMBERS);
9782 }
9783 sendPacket(ActionFailed.STATIC_PACKET);
9784 return false;
9785 }
9786
9787 // Check if the target is attackable
9788 if (!target.isAttackable() && !allowPeaceAttack())
9789 {
9790 // If target is not attackable, send a Server->Client packet ActionFailed
9791 sendPacket(ActionFailed.STATIC_PACKET);
9792 return false;
9793 }
9794 // Check for Event Mob's
9795 if ((target instanceof L2EventMonsterInstance) && ((L2EventMonsterInstance) target).eventSkillAttackBlocked())
9796 {
9797 sendPacket(ActionFailed.STATIC_PACKET);
9798 return false;
9799 }
9800
9801 // Check if a Forced ATTACK is in progress on non-attackable target
9802 if (!target.isAutoAttackable(this) && !forceUse)
9803 {
9804 switch (sklTargetType)
9805 {
9806 case TARGET_AURA:
9807 case TARGET_FRONT_AURA:
9808 case TARGET_BEHIND_AURA:
9809 case TARGET_AURA_CORPSE_MOB:
9810 case TARGET_CLAN:
9811 case TARGET_PARTY_CLAN:
9812 case TARGET_ALLY:
9813 case TARGET_PARTY:
9814 case TARGET_SELF:
9815 case TARGET_GROUND:
9816 case TARGET_AREA_SUMMON:
9817 break;
9818 default: // Send a Server->Client packet ActionFailed to the L2PcInstance
9819 sendPacket(ActionFailed.STATIC_PACKET);
9820 return false;
9821 }
9822 }
9823
9824 // Check if the target is in the skill cast range
9825 if (dontMove)
9826 {
9827 // Calculate the distance between the L2PcInstance and the target
9828 if (sklTargetType == L2TargetType.TARGET_GROUND)
9829 {
9830 if (!isInsideRadius(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), skill.getCastRange() + getTemplate().getCollisionRadius(), false, false))
9831 {
9832 // Send a System Message to the caster
9833 sendPacket(SystemMessageId.TARGET_TOO_FAR);
9834
9835 // Send a Server->Client packet ActionFailed to the L2PcInstance
9836 sendPacket(ActionFailed.STATIC_PACKET);
9837 return false;
9838 }
9839 }
9840 else if ((skill.getCastRange() > 0) && !isInsideRadius(target, skill.getCastRange() + getTemplate().getCollisionRadius(), false, false))
9841 {
9842 // Send a System Message to the caster
9843 sendPacket(SystemMessageId.TARGET_TOO_FAR);
9844
9845 // Send a Server->Client packet ActionFailed to the L2PcInstance
9846 sendPacket(ActionFailed.STATIC_PACKET);
9847 return false;
9848 }
9849 }
9850 }
9851
9852 if (skill.getSkillType() == L2SkillType.INSTANT_JUMP)
9853 {
9854 // You cannot jump while rooted right ;)
9855 if (isMovementDisabled())
9856 {
9857 // Sends message that skill cannot be used...
9858 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
9859 sm.addSkillName(skill.getId());
9860 sendPacket(sm);
9861
9862 // Send a Server->Client packet ActionFailed to the L2PcInstance
9863 sendPacket(ActionFailed.STATIC_PACKET);
9864
9865 return false;
9866 }
9867 // And this skill cannot be used in peace zone, not even on NPCs!
9868 if (isInsideZone(ZoneId.PEACE) && !allowPeaceAttack())
9869 {
9870 // Sends a sys msg to client
9871 sendPacket(SystemMessageId.TARGET_IN_PEACEZONE);
9872
9873 // Send a Server->Client packet ActionFailed to the L2PcInstance
9874 sendPacket(ActionFailed.STATIC_PACKET);
9875
9876 return false;
9877 }
9878
9879 }
9880 // Check if the skill is defensive
9881 if (!skill.isOffensive() && (target instanceof L2MonsterInstance) && !forceUse && !skill.isNeutral())
9882 {
9883 // check if the target is a monster and if force attack is set.. if not then we don't want to cast.
9884 switch (sklTargetType)
9885 {
9886 case TARGET_PET:
9887 case TARGET_SUMMON:
9888 case TARGET_AURA:
9889 case TARGET_FRONT_AURA:
9890 case TARGET_BEHIND_AURA:
9891 case TARGET_AURA_CORPSE_MOB:
9892 case TARGET_CLAN:
9893 case TARGET_PARTY_CLAN:
9894 case TARGET_SELF:
9895 case TARGET_PARTY:
9896 case TARGET_ALLY:
9897 case TARGET_CORPSE_MOB:
9898 case TARGET_AREA_CORPSE_MOB:
9899 case TARGET_GROUND:
9900 break;
9901 default:
9902 {
9903 switch (sklType)
9904 {
9905 case BEAST_FEED:
9906 case DELUXE_KEY_UNLOCK:
9907 case UNLOCK:
9908 break;
9909 default:
9910 sendPacket(ActionFailed.STATIC_PACKET);
9911 return false;
9912 }
9913 break;
9914 }
9915 }
9916 }
9917
9918 // Check if the skill is Spoil type and if the target isn't already spoiled
9919 if (sklType == L2SkillType.SPOIL)
9920 {
9921 if (!(target instanceof L2MonsterInstance))
9922 {
9923 // Send a System Message to the L2PcInstance
9924 sendPacket(SystemMessageId.INCORRECT_TARGET);
9925
9926 // Send a Server->Client packet ActionFailed to the L2PcInstance
9927 sendPacket(ActionFailed.STATIC_PACKET);
9928 return false;
9929 }
9930 }
9931
9932 // Check if the skill is Drain Soul (Soul Crystals) and if the target is a MOB
9933 if (sklType == L2SkillType.DRAIN_SOUL)
9934 {
9935 if (!(target instanceof L2MonsterInstance))
9936 {
9937 // Send a System Message to the L2PcInstance
9938 sendPacket(SystemMessageId.INCORRECT_TARGET);
9939
9940 // Send a Server->Client packet ActionFailed to the L2PcInstance
9941 sendPacket(ActionFailed.STATIC_PACKET);
9942 return false;
9943 }
9944 }
9945
9946 // Check if this is a Pvp skill and target isn't a non-flagged/non-karma player
9947 switch (sklTargetType)
9948 {
9949 case TARGET_PARTY:
9950 case TARGET_ALLY: // For such skills, checkPvpSkill() is called from L2Skill.getTargetList()
9951 case TARGET_CLAN: // For such skills, checkPvpSkill() is called from L2Skill.getTargetList()
9952 case TARGET_PARTY_CLAN: // For such skills, checkPvpSkill() is called from L2Skill.getTargetList()
9953 case TARGET_AURA:
9954 case TARGET_FRONT_AURA:
9955 case TARGET_BEHIND_AURA:
9956 case TARGET_GROUND:
9957 case TARGET_SELF:
9958 break;
9959 default:
9960 if (!checkPvpSkill(target, skill) && !allowPeaceAttack())
9961 {
9962 // Send a System Message to the L2PcInstance
9963 sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
9964
9965 // Send a Server->Client packet ActionFailed to the L2PcInstance
9966 sendPacket(ActionFailed.STATIC_PACKET);
9967 return false;
9968 }
9969 }
9970
9971 // TODO: Unhardcode skillId 844 which is the outpost construct skill
9972 if (((sklTargetType == L2TargetType.TARGET_HOLY) && !checkIfOkToCastSealOfRule(CastleManager.getInstance().getCastle(this), false, skill, target)) || ((sklTargetType == L2TargetType.TARGET_FLAGPOLE) && !checkIfOkToCastFlagDisplay(FortManager.getInstance().getFort(this), false, skill, target)) || ((sklType == L2SkillType.SIEGEFLAG) && !L2SkillSiegeFlag.checkIfOkToPlaceFlag(this, false, skill.getId() == 844)) || ((sklType == L2SkillType.STRSIEGEASSAULT) && !checkIfOkToUseStriderSiegeAssault()) || ((sklType == L2SkillType.SUMMON_FRIEND) && !(checkSummonerStatus(this) && checkSummonTargetStatus(target, this))))
9973 {
9974 sendPacket(ActionFailed.STATIC_PACKET);
9975 abortCast();
9976 return false;
9977 }
9978
9979 // GeoData Los Check here
9980 if (skill.getCastRange() > 0)
9981 {
9982 if (sklTargetType == L2TargetType.TARGET_GROUND)
9983 {
9984 if (!GeoData.getInstance().canSeeTarget(this, worldPosition))
9985 {
9986 sendPacket(SystemMessageId.CANT_SEE_TARGET);
9987 sendPacket(ActionFailed.STATIC_PACKET);
9988 return false;
9989 }
9990 }
9991 else if (!GeoData.getInstance().canSeeTarget(this, target))
9992 {
9993 sendPacket(SystemMessageId.CANT_SEE_TARGET);
9994 sendPacket(ActionFailed.STATIC_PACKET);
9995 return false;
9996 }
9997 }
9998 // finally, after passing all conditions
9999 return true;
10000 }
10001
10002 public boolean checkIfOkToUseStriderSiegeAssault()
10003 {
10004 Castle castle = CastleManager.getInstance().getCastle(this);
10005 Fort fort = FortManager.getInstance().getFort(this);
10006
10007 if ((castle == null) && (fort == null))
10008 {
10009 return false;
10010 }
10011
10012 if (castle != null)
10013 {
10014 return checkIfOkToUseStriderSiegeAssault(castle);
10015 }
10016 return checkIfOkToUseStriderSiegeAssault(fort);
10017 }
10018
10019 public boolean checkIfOkToUseStriderSiegeAssault(Castle castle)
10020 {
10021 String text = "";
10022
10023 if ((castle == null) || (castle.getCastleId() <= 0))
10024 {
10025 text = "You must be on castle ground to use strider siege assault";
10026 }
10027 else if (!castle.getSiege().getIsInProgress())
10028 {
10029 text = "You can only use strider siege assault during a siege.";
10030 }
10031 else if (!(getTarget() instanceof L2DoorInstance))
10032 {
10033 text = "You can only use strider siege assault on doors and walls.";
10034 }
10035 else if (!isRidingStrider())
10036 {
10037 text = "You can only use strider siege assault when on strider.";
10038 }
10039 else
10040 {
10041 return true;
10042 }
10043
10044 sendMessage(text);
10045
10046 return false;
10047 }
10048
10049 public boolean checkIfOkToUseStriderSiegeAssault(Fort fort)
10050 {
10051 String text = "";
10052
10053 if ((fort == null) || (fort.getFortId() <= 0))
10054 {
10055 text = "You must be on fort ground to use strider siege assault";
10056 }
10057 else if (!fort.getSiege().getIsInProgress())
10058 {
10059 text = "You can only use strider siege assault during a siege.";
10060 }
10061 else if (!(getTarget() instanceof L2DoorInstance))
10062 {
10063 text = "You can only use strider siege assault on doors and walls.";
10064 }
10065 else if (!isRidingStrider())
10066 {
10067 text = "You can only use strider siege assault when on strider.";
10068 }
10069 else
10070 {
10071 return true;
10072 }
10073
10074 sendMessage(text);
10075
10076 return false;
10077 }
10078
10079 public boolean checkIfOkToCastSealOfRule(Castle castle, boolean isCheckOnly, L2Skill skill, L2Object target)
10080 {
10081 SystemMessage sm;
10082 if ((castle == null) || (castle.getCastleId() <= 0))
10083 {
10084 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
10085 sm.addSkillName(skill);
10086 }
10087 else if (!castle.getArtefacts().contains(target))
10088 {
10089 sm = SystemMessage.getSystemMessage(SystemMessageId.INCORRECT_TARGET);
10090 }
10091 else if (!castle.getSiege().getIsInProgress())
10092 {
10093 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
10094 sm.addSkillName(skill);
10095 }
10096 else if (!Util.checkIfInRange(200, this, target, true))
10097 {
10098 sm = SystemMessage.getSystemMessage(SystemMessageId.DIST_TOO_FAR_CASTING_STOPPED);
10099 }
10100 else if (castle.getSiege().getAttackerClan(getClan()) == null)
10101 {
10102 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
10103 sm.addSkillName(skill);
10104 }
10105 else
10106 {
10107 if (!isCheckOnly)
10108 {
10109 sm = SystemMessage.getSystemMessage(SystemMessageId.OPPONENT_STARTED_ENGRAVING);
10110 castle.getSiege().announceToPlayer(sm, false);
10111 }
10112 return true;
10113 }
10114
10115 sendPacket(sm);
10116 return false;
10117 }
10118
10119 public boolean checkIfOkToCastFlagDisplay(Fort fort, boolean isCheckOnly, L2Skill skill, L2Object target)
10120 {
10121 SystemMessage sm;
10122
10123 if ((fort == null) || (fort.getFortId() <= 0))
10124 {
10125 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
10126 sm.addSkillName(skill);
10127 }
10128 else if (fort.getFlagPole() != target)
10129 {
10130 sm = SystemMessage.getSystemMessage(SystemMessageId.INCORRECT_TARGET);
10131 }
10132 else if (!fort.getSiege().getIsInProgress())
10133 {
10134 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
10135 sm.addSkillName(skill);
10136 }
10137 else if (!Util.checkIfInRange(200, this, target, true))
10138 {
10139 sm = SystemMessage.getSystemMessage(SystemMessageId.DIST_TOO_FAR_CASTING_STOPPED);
10140 }
10141 else if (fort.getSiege().getAttackerClan(getClan()) == null)
10142 {
10143 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
10144 sm.addSkillName(skill);
10145 }
10146 else
10147 {
10148 if (!isCheckOnly)
10149 {
10150 fort.getSiege().announceToPlayer(SystemMessage.getSystemMessage(SystemMessageId.S1_TRYING_RAISE_FLAG), getClan().getName());
10151 }
10152 return true;
10153 }
10154
10155 sendPacket(sm);
10156 return false;
10157 }
10158
10159 public boolean isInLooterParty(int LooterId)
10160 {
10161 L2PcInstance looter = L2World.getInstance().getPlayer(LooterId);
10162
10163 // if L2PcInstance is in a CommandChannel
10164 if (isInParty() && getParty().isInCommandChannel() && (looter != null))
10165 {
10166 return getParty().getCommandChannel().getMembers().contains(looter);
10167 }
10168
10169 if (isInParty() && (looter != null))
10170 {
10171 return getParty().getMembers().contains(looter);
10172 }
10173
10174 return false;
10175 }
10176
10177 /**
10178 * Check if the requested casting is a Pc->Pc skill cast and if it's a valid pvp condition
10179 * @param target L2Object instance containing the target
10180 * @param skill L2Skill instance with the skill being casted
10181 * @return False if the skill is a pvpSkill and target is not a valid pvp target
10182 */
10183 public boolean checkPvpSkill(L2Object target, L2Skill skill)
10184 {
10185 return checkPvpSkill(target, skill, false);
10186 }
10187
10188 /**
10189 * Check if the requested casting is a Pc->Pc skill cast and if it's a valid pvp condition
10190 * @param target L2Object instance containing the target
10191 * @param skill L2Skill instance with the skill being casted
10192 * @param srcIsSummon is L2Summon - caster?
10193 * @return False if the skill is a pvpSkill and target is not a valid pvp target
10194 */
10195 public boolean checkPvpSkill(L2Object target, L2Skill skill, boolean srcIsSummon)
10196 {
10197 // check for PC->PC Pvp status
10198 if (target instanceof L2Summon)
10199 {
10200 target = target.getActingPlayer();
10201 }
10202 if ((target != null) && // target not null and
10203 (target != this) && // target is not self and
10204 (target instanceof L2PcInstance) && // target is L2PcInstance and
10205 !(isInDuel() && (((L2PcInstance) target).getDuelId() == getDuelId())) && // self is not in a duel and attacking opponent
10206 !isInsideZone(ZoneId.PVP) && // Pc is not in PvP zone
10207 !target.isInsideZone(ZoneId.PVP) // target is not in PvP zone
10208 )
10209 {
10210 SkillDat skilldat = getCurrentSkill();
10211 SkillDat skilldatpet = getCurrentPetSkill();
10212 if (skill.isPvpSkill()) // pvp skill
10213 {
10214 if ((getClan() != null) && (((L2PcInstance) target).getClan() != null))
10215 {
10216 if (getClan().isAtWarWith(((L2PcInstance) target).getClan().getClanId()) && ((L2PcInstance) target).getClan().isAtWarWith(getClan().getClanId()))
10217 {
10218 return true; // in clan war player can attack whites even with sleep etc.
10219 }
10220 }
10221 if ((((L2PcInstance) target).getPvpFlag() == 0) && // target's pvp flag is not set and
10222 (((L2PcInstance) target).getKarma() == 0 // target has no karma
10223 ))
10224 {
10225 return false;
10226 }
10227 }
10228 else if (((skilldat != null) && !skilldat.isCtrlPressed() && skill.isOffensive() && !srcIsSummon) || ((skilldatpet != null) && !skilldatpet.isCtrlPressed() && skill.isOffensive() && srcIsSummon))
10229 {
10230 if (isInTownWarEvent())
10231 {
10232 return true;
10233 }
10234 if ((getClan() != null) && (((L2PcInstance) target).getClan() != null))
10235 {
10236 if (getClan().isAtWarWith(((L2PcInstance) target).getClan().getClanId()) && ((L2PcInstance) target).getClan().isAtWarWith(getClan().getClanId()))
10237 {
10238 return true; // in clan war player can attack whites even without ctrl
10239 }
10240 }
10241 if ((((L2PcInstance) target).getPvpFlag() == 0) && // target's pvp flag is not set and
10242 (((L2PcInstance) target).getKarma() == 0 // target has no karma
10243 ))
10244 {
10245 return false;
10246 }
10247 }
10248 }
10249
10250 return true;
10251 }
10252
10253 /**
10254 * @return True if the L2PcInstance is a Mage.
10255 */
10256 public boolean isMageClass()
10257 {
10258 return getClassId().isMage();
10259 }
10260
10261 public boolean isMounted()
10262 {
10263 return _mountType > 0;
10264 }
10265
10266 /**
10267 * Set the type of Pet mounted (0 : none, 1 : Stridder, 2 : Wyvern) and send a Server->Client packet InventoryUpdate to the L2PcInstance.
10268 * @return
10269 */
10270 public boolean checkLandingState()
10271 {
10272 // Check if char is in a no landing zone
10273 if (isInsideZone(ZoneId.NO_LANDING))
10274 {
10275 return true;
10276 }
10277 else
10278 // if this is a castle that is currently being sieged, and the rider is NOT a castle owner
10279 // he cannot land.
10280 // castle owner is the leader of the clan that owns the castle where the pc is
10281 if (isInsideZone(ZoneId.SIEGE) && !((getClan() != null) && (CastleManager.getInstance().getCastle(this) == CastleManager.getInstance().getCastleByOwner(getClan())) && (this == getClan().getLeader().getPlayerInstance())))
10282 {
10283 return true;
10284 }
10285
10286 return false;
10287 }
10288
10289 // returns false if the change of mount type fails.
10290 public boolean setMount(int npcId, int npcLevel, int mountType)
10291 {
10292 switch (mountType)
10293 {
10294 case 0:
10295 setIsFlying(false);
10296 /*
10297 * not used any more setIsRidingFenrirWolf(false); setIsRidingWFenrirWolf(false); setIsRidingGreatSnowWolf(false);
10298 */
10299 setIsRidingStrider(false);
10300 break; // Dismounted
10301 case 1:
10302 setIsRidingStrider(true);
10303 if (isNoble())
10304 {
10305 L2Skill striderAssaultSkill = SkillTable.FrequentSkill.STRIDER_SIEGE_ASSAULT.getSkill();
10306 addSkill(striderAssaultSkill, false); // not saved to DB
10307 }
10308 break;
10309 case 2:
10310 setIsFlying(true);
10311 break; // Flying Wyvern
10312 case 3:
10313 /*
10314 * not used any more switch (npcId) { case 16041: setIsRidingFenrirWolf(true); break; case 16042: setIsRidingWFenrirWolf(true); break; case 16037: setIsRidingGreatSnowWolf(true); break; }
10315 */
10316 break;
10317 }
10318
10319 _mountType = mountType;
10320 _mountNpcId = npcId;
10321 _mountLevel = npcLevel;
10322
10323 return true;
10324 }
10325
10326 /**
10327 * @return the type of Pet mounted (0 : none, 1 : Strider, 2 : Wyvern, 3: Wolf).
10328 */
10329 public int getMountType()
10330 {
10331 return _mountType;
10332 }
10333
10334 @Override
10335 public final void stopAllEffects()
10336 {
10337 super.stopAllEffects();
10338 updateAndBroadcastStatus(2);
10339 }
10340
10341 @Override
10342 public final void stopAllEffectsExceptThoseThatLastThroughDeath()
10343 {
10344 super.stopAllEffectsExceptThoseThatLastThroughDeath();
10345 updateAndBroadcastStatus(2);
10346 }
10347
10348 public final void stopAllEffectsNotStayOnSubclassChange()
10349 {
10350 for (L2Effect effect : _effects.getAllEffects())
10351 {
10352 if ((effect != null) && !effect.getSkill().isStayOnSubclassChange())
10353 {
10354 effect.exit(true);
10355 }
10356 }
10357 updateAndBroadcastStatus(2);
10358 }
10359
10360 /**
10361 * Stop all toggle-type effects
10362 */
10363 public final void stopAllToggles()
10364 {
10365 _effects.stopAllToggles();
10366 }
10367
10368 public final void stopCubics()
10369 {
10370 if (!_cubics.isEmpty())
10371 {
10372 for (L2CubicInstance cubic : _cubics.values())
10373 {
10374 cubic.stopAction();
10375 cubic.cancelDisappear();
10376 }
10377 _cubics.clear();
10378 broadcastUserInfo();
10379 }
10380 }
10381
10382 public final void stopCubicsByOthers()
10383 {
10384 if (!_cubics.isEmpty())
10385 {
10386 final Iterator<L2CubicInstance> iter = _cubics.values().iterator();
10387 L2CubicInstance cubic;
10388 boolean broadcast = false;
10389 while (iter.hasNext())
10390 {
10391 cubic = iter.next();
10392 if (cubic.givenByOther())
10393 {
10394 cubic.stopAction();
10395 cubic.cancelDisappear();
10396 iter.remove();
10397 broadcast = true;
10398 }
10399 }
10400 if (broadcast)
10401 {
10402 broadcastUserInfo();
10403 }
10404 }
10405 }
10406
10407 /**
10408 * Send a Server->Client packet UserInfo to this L2PcInstance and CharInfo to all L2PcInstance in its _KnownPlayers.<br>
10409 * <B><U>Concept</U>:</B><br>
10410 * Others L2PcInstance in the detection area of the L2PcInstance are identified in <B>_knownPlayers</B>.<br>
10411 * In order to inform other players of this L2PcInstance state modifications, server just need to go through _knownPlayers to send Server->Client Packet<br>
10412 * <B><U>Actions</U>:</B>
10413 * <ul>
10414 * <li>Send a Server->Client packet UserInfo to this L2PcInstance (Public and Private Data)</li>
10415 * <li>Send a Server->Client packet CharInfo to all L2PcInstance in _KnownPlayers of the L2PcInstance (Public data only)</li>
10416 * </ul>
10417 * <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>
10418 */
10419 @Override
10420 public void updateAbnormalEffect()
10421 {
10422 broadcastUserInfo();
10423 }
10424
10425 /**
10426 * Disable the Inventory and create a new task to enable it after 1.5s.
10427 */
10428 public void tempInventoryDisable()
10429 {
10430 _inventoryDisable = true;
10431
10432 ThreadPoolManager.getInstance().scheduleGeneral(new InventoryEnable(), 1500);
10433 }
10434
10435 /**
10436 * @return True if the Inventory is disabled.
10437 */
10438 public boolean isInventoryDisabled()
10439 {
10440 return _inventoryDisable;
10441 }
10442
10443 protected class InventoryEnable implements Runnable
10444 {
10445 @Override
10446 public void run()
10447 {
10448 _inventoryDisable = false;
10449 }
10450 }
10451
10452 public FastMap<Integer, L2CubicInstance> getCubics()
10453 {
10454 return _cubics;
10455 }
10456
10457 /**
10458 * Add a L2CubicInstance to the L2PcInstance _cubics.
10459 * @param id
10460 * @param level
10461 * @param matk
10462 * @param cubicDelay
10463 * @param cubicSkillChance
10464 * @param cubicMaxCount
10465 * @param cubicDuration
10466 * @param givenByOther
10467 */
10468 public void addCubic(int id, int level, double matk, int cubicDelay, int cubicSkillChance, int cubicMaxCount, int cubicDuration, boolean givenByOther)
10469 {
10470 _cubics.put(id, new L2CubicInstance(this, id, level, (int) matk, cubicDelay, cubicSkillChance, cubicMaxCount, cubicDuration, givenByOther));
10471 }
10472
10473 /**
10474 * @param id a L2CubicInstance from the L2PcInstance _cubics.
10475 */
10476 public void delCubic(int id)
10477 {
10478 _cubics.remove(id);
10479 }
10480
10481 /**
10482 * @param id
10483 * @return the L2CubicInstance corresponding to the Identifier of the L2PcInstance _cubics.
10484 */
10485 public L2CubicInstance getCubic(int id)
10486 {
10487 return _cubics.get(id);
10488 }
10489
10490 /**
10491 * @return the modifier corresponding to the Enchant Effect of the Active Weapon (Min : 127).
10492 */
10493 public int getEnchantEffect()
10494 {
10495 L2ItemInstance wpn = getActiveWeaponInstance();
10496
10497 if (wpn == null)
10498 {
10499 return 0;
10500 }
10501
10502 return Math.min(127, wpn.getEnchantLevel());
10503 }
10504
10505 /**
10506 * Set the _lastFolkNpc of the L2PcInstance corresponding to the last Folk wich one the player talked.
10507 * @param folkNpc
10508 */
10509 public void setLastFolkNPC(L2Npc folkNpc)
10510 {
10511 _lastFolkNpc = folkNpc;
10512 }
10513
10514 /**
10515 * @return the _lastFolkNpc of the L2PcInstance corresponding to the last Folk wich one the player talked.
10516 */
10517 public L2Npc getLastFolkNPC()
10518 {
10519 return _lastFolkNpc;
10520 }
10521
10522 /**
10523 * @return True if L2PcInstance is a participant in the Festival of Darkness.
10524 */
10525 public boolean isFestivalParticipant()
10526 {
10527 return SevenSignsFestival.getInstance().isParticipant(this);
10528 }
10529
10530 public void addAutoSoulShot(int itemId)
10531 {
10532 _activeSoulShots.add(itemId);
10533 }
10534
10535 public boolean removeAutoSoulShot(int itemId)
10536 {
10537 return _activeSoulShots.remove(itemId);
10538 }
10539
10540 public Set<Integer> getAutoSoulShot()
10541 {
10542 return _activeSoulShots;
10543 }
10544
10545 @Override
10546 public void rechargeShots(boolean physical, boolean magic)
10547 {
10548 L2ItemInstance item;
10549 IItemHandler handler;
10550
10551 if ((_activeSoulShots == null) || _activeSoulShots.isEmpty())
10552 {
10553 return;
10554 }
10555
10556 for (int itemId : _activeSoulShots)
10557 {
10558 item = getInventory().getItemByItemId(itemId);
10559
10560 if (item != null)
10561 {
10562 if (magic)
10563 {
10564 if (item.getItem().getDefaultAction() == L2ActionType.spiritshot)
10565 {
10566 handler = ItemHandler.getInstance().getHandler(item.getEtcItem());
10567 if (handler != null)
10568 {
10569 handler.useItem(this, item, false);
10570 }
10571 }
10572 }
10573
10574 if (physical)
10575 {
10576 if (item.getItem().getDefaultAction() == L2ActionType.soulshot)
10577 {
10578 handler = ItemHandler.getInstance().getHandler(item.getEtcItem());
10579 if (handler != null)
10580 {
10581 handler.useItem(this, item, false);
10582 }
10583 }
10584 }
10585 }
10586 else
10587 {
10588 removeAutoSoulShot(itemId);
10589 }
10590 }
10591 }
10592
10593 /**
10594 * Cancel autoshot for all shots matching crystaltype<BR>
10595 * {@link L2Item#getCrystalType()}
10596 * @param crystalType int type to disable
10597 */
10598 public void disableAutoShotByCrystalType(int crystalType)
10599 {
10600 for (int itemId : _activeSoulShots)
10601 {
10602 if (ItemTable.getInstance().getTemplate(itemId).getCrystalType() == crystalType)
10603 {
10604 disableAutoShot(itemId);
10605 }
10606 }
10607 }
10608
10609 /**
10610 * Cancel autoshot use for shot itemId
10611 * @param itemId int id to disable
10612 * @return true if canceled.
10613 */
10614 public boolean disableAutoShot(int itemId)
10615 {
10616 if (_activeSoulShots.contains(itemId))
10617 {
10618 removeAutoSoulShot(itemId);
10619 sendPacket(new ExAutoSoulShot(itemId, 0));
10620
10621 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.AUTO_USE_OF_S1_CANCELLED);
10622 sm.addItemName(itemId);
10623 sendPacket(sm);
10624 return true;
10625 }
10626 return false;
10627 }
10628
10629 /**
10630 * Cancel all autoshots for player
10631 */
10632 public void disableAutoShotsAll()
10633 {
10634 for (int itemId : _activeSoulShots)
10635 {
10636 sendPacket(new ExAutoSoulShot(itemId, 0));
10637 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.AUTO_USE_OF_S1_CANCELLED);
10638 sm.addItemName(itemId);
10639 sendPacket(sm);
10640 }
10641 _activeSoulShots.clear();
10642 }
10643
10644 private ScheduledFuture<?> _taskWarnUserTakeBreak;
10645
10646 protected class WarnUserTakeBreak implements Runnable
10647 {
10648 @Override
10649 public void run()
10650 {
10651 if (isOnline())
10652 {
10653 SystemMessageId.PLAYING_FOR_LONG_TIME.setParamCount(1);
10654 sendPacket(SystemMessageId.PLAYING_FOR_LONG_TIME);
10655 }
10656 else
10657 {
10658 stopWarnUserTakeBreak();
10659 }
10660 }
10661 }
10662
10663 protected class RentPetTask implements Runnable
10664 {
10665 @Override
10666 public void run()
10667 {
10668 stopRentPet();
10669 }
10670 }
10671
10672 protected class WaterTask implements Runnable
10673 {
10674 @Override
10675 public void run()
10676 {
10677 double reduceHp = getMaxHp() / 100.0;
10678
10679 if (reduceHp < 1)
10680 {
10681 reduceHp = 1;
10682 }
10683
10684 reduceCurrentHp(reduceHp, L2PcInstance.this, false, false, null);
10685 // reduced hp, becouse not rest
10686 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.DROWN_DAMAGE_S1);
10687 sm.addNumber((int) reduceHp);
10688 sendPacket(sm);
10689
10690 }
10691 }
10692
10693 private class LookingForFishTask implements Runnable
10694 {
10695 boolean _isNoob, _isUpperGrade;
10696 int _fishGroup;
10697 double _fishGutsCheck;
10698 long _endTaskTime;
10699
10700 protected LookingForFishTask(int startCombatTime, double fishGutsCheck, int fishGroup, boolean isNoob, boolean isUpperGrade)
10701 {
10702 _fishGutsCheck = fishGutsCheck;
10703 _endTaskTime = System.currentTimeMillis() + (startCombatTime * 1000) + 10000;
10704 _fishGroup = fishGroup;
10705 _isNoob = isNoob;
10706 _isUpperGrade = isUpperGrade;
10707 }
10708
10709 @Override
10710 public void run()
10711 {
10712 if (System.currentTimeMillis() >= _endTaskTime)
10713 {
10714 endFishing(false);
10715 return;
10716 }
10717 if (_fishGroup == -1)
10718 {
10719 return;
10720 }
10721 int check = Rnd.get(100);
10722 if (_fishGutsCheck > check)
10723 {
10724 stopLookingForFishTask();
10725 startFishCombat(_isNoob, _isUpperGrade);
10726 }
10727 }
10728
10729 }
10730
10731 public int getClanPrivileges()
10732 {
10733 return _clanPrivileges;
10734 }
10735
10736 public void setClanPrivileges(int n)
10737 {
10738 _clanPrivileges = n;
10739 }
10740
10741 // baron etc
10742 public void setPledgeClass(int classId)
10743 {
10744 _pledgeClass = classId;
10745 checkItemRestriction();
10746 }
10747
10748 public int getPledgeClass()
10749 {
10750 return _pledgeClass;
10751 }
10752
10753 public void setPledgeType(int typeId)
10754 {
10755 _pledgeType = typeId;
10756 }
10757
10758 public int getPledgeType()
10759 {
10760 return _pledgeType;
10761 }
10762
10763 public int getApprentice()
10764 {
10765 return _apprentice;
10766 }
10767
10768 public void setApprentice(int apprentice_id)
10769 {
10770 _apprentice = apprentice_id;
10771 }
10772
10773 public int getSponsor()
10774 {
10775 return _sponsor;
10776 }
10777
10778 public void setSponsor(int sponsor_id)
10779 {
10780 _sponsor = sponsor_id;
10781 }
10782
10783 public int getBookMarkSlot()
10784 {
10785 return _bookmarkslot;
10786 }
10787
10788 public void setBookMarkSlot(int slot)
10789 {
10790 _bookmarkslot = slot;
10791 sendPacket(new ExGetBookMarkInfoPacket(this));
10792 }
10793
10794 @Override
10795 public void sendMessage(String message)
10796 {
10797 sendPacket(SystemMessage.sendString(message));
10798 }
10799
10800 public void enterObserverMode(int x, int y, int z)
10801 {
10802 _lastX = getX();
10803 _lastY = getY();
10804 _lastZ = getZ();
10805
10806 stopEffects(L2EffectType.HIDE);
10807
10808 _observerMode = true;
10809 setTarget(null);
10810 setIsParalyzed(true);
10811 startParalyze();
10812 setIsInvul(true);
10813 getAppearance().setInvisible();
10814 // sendPacket(new GMHide(1));
10815 sendPacket(new ObservationMode(x, y, z));
10816 getKnownList().removeAllKnownObjects(); // reinit knownlist
10817 setXYZ(x, y, z);
10818 broadcastUserInfo();
10819 }
10820
10821 public void setLastCords(int x, int y, int z)
10822 {
10823 _lastX = getX();
10824 _lastY = getY();
10825 _lastZ = getZ();
10826 }
10827
10828 public void enterOlympiadObserverMode(Location loc, int id)
10829 {
10830 if (hasSummon())
10831 {
10832 getSummon().unSummon(this);
10833 }
10834
10835 stopEffects(L2EffectType.HIDE);
10836
10837 if (!_cubics.isEmpty())
10838 {
10839 for (L2CubicInstance cubic : _cubics.values())
10840 {
10841 cubic.stopAction();
10842 cubic.cancelDisappear();
10843 }
10844 _cubics.clear();
10845 }
10846
10847 if (getParty() != null)
10848 {
10849 getParty().removePartyMember(this, messageType.Expelled);
10850 }
10851
10852 _olympiadGameId = id;
10853 if (isSitting())
10854 {
10855 standUp();
10856 }
10857 if (!_observerMode)
10858 {
10859 _lastX = getX();
10860 _lastY = getY();
10861 _lastZ = getZ();
10862 }
10863
10864 _observerMode = true;
10865 setTarget(null);
10866 setIsInvul(true);
10867 getAppearance().setInvisible();
10868 teleToLocation(loc, false);
10869 sendPacket(new ExOlympiadMode(3));
10870
10871 broadcastUserInfo();
10872 }
10873
10874 public void leaveObserverMode()
10875 {
10876 setTarget(null);
10877 getKnownList().removeAllKnownObjects(); // reinit knownlist
10878 setXYZ(_lastX, _lastY, _lastZ);
10879 setIsParalyzed(false);
10880 stopParalyze(false);
10881 if (!isGM())
10882 {
10883 getAppearance().setVisible();
10884 setIsInvul(false);
10885 }
10886 if (hasAI())
10887 {
10888 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
10889 }
10890
10891 setFalling(); // prevent receive falling damage
10892 _observerMode = false;
10893 setLastCords(0, 0, 0);
10894 sendPacket(new ObservationReturn(this));
10895 broadcastUserInfo();
10896 }
10897
10898 public void leaveOlympiadObserverMode()
10899 {
10900 if (_olympiadGameId == -1)
10901 {
10902 return;
10903 }
10904 _olympiadGameId = -1;
10905 _observerMode = false;
10906 setTarget(null);
10907 sendPacket(new ExOlympiadMode(0));
10908 setInstanceId(0);
10909 teleToLocation(_lastX, _lastY, _lastZ, true);
10910 if (!isGM())
10911 {
10912 getAppearance().setVisible();
10913 setIsInvul(false);
10914 }
10915 if (hasAI())
10916 {
10917 getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
10918 }
10919 setLastCords(0, 0, 0);
10920 broadcastUserInfo();
10921 }
10922
10923 public void setOlympiadSide(int i)
10924 {
10925 _olympiadSide = i;
10926 }
10927
10928 public int getOlympiadSide()
10929 {
10930 return _olympiadSide;
10931 }
10932
10933 public void setOlympiadGameId(int id)
10934 {
10935 _olympiadGameId = id;
10936 }
10937
10938 public int getOlympiadGameId()
10939 {
10940 return _olympiadGameId;
10941 }
10942
10943 public int getLastX()
10944 {
10945 return _lastX;
10946 }
10947
10948 public int getLastY()
10949 {
10950 return _lastY;
10951 }
10952
10953 public int getLastZ()
10954 {
10955 return _lastZ;
10956 }
10957
10958 public boolean inObserverMode()
10959 {
10960 return _observerMode;
10961 }
10962
10963 public int getTeleMode()
10964 {
10965 return _telemode;
10966 }
10967
10968 public void setTeleMode(int mode)
10969 {
10970 _telemode = mode;
10971 }
10972
10973 public void setLoto(int i, int val)
10974 {
10975 _loto[i] = val;
10976 }
10977
10978 public int getLoto(int i)
10979 {
10980 return _loto[i];
10981 }
10982
10983 public void setRace(int i, int val)
10984 {
10985 _race[i] = val;
10986 }
10987
10988 public int getRace(int i)
10989 {
10990 return _race[i];
10991 }
10992
10993 public boolean getMessageRefusal()
10994 {
10995 return _messageRefusal;
10996 }
10997
10998 public void setMessageRefusal(boolean mode)
10999 {
11000 _messageRefusal = mode;
11001 sendPacket(new EtcStatusUpdate(this));
11002 }
11003
11004 public void setDietMode(boolean mode)
11005 {
11006 _dietMode = mode;
11007 }
11008
11009 public boolean getDietMode()
11010 {
11011 return _dietMode;
11012 }
11013
11014 public void setTradeRefusal(boolean mode)
11015 {
11016 _tradeRefusal = mode;
11017 }
11018
11019 public boolean getTradeRefusal()
11020 {
11021 return _tradeRefusal;
11022 }
11023
11024 public void setExchangeRefusal(boolean mode)
11025 {
11026 _exchangeRefusal = mode;
11027 }
11028
11029 public boolean getExchangeRefusal()
11030 {
11031 return _exchangeRefusal;
11032 }
11033
11034 public BlockList getBlockList()
11035 {
11036 return _blockList;
11037 }
11038
11039 public void setHero(boolean hero)
11040 {
11041 if (hero && (_baseClass == _activeClass))
11042 {
11043 for (L2Skill skill : SkillTreesData.getInstance().getHeroSkillTree().values())
11044 {
11045 addSkill(skill, false); // Dont Save Hero skills to database
11046 }
11047 }
11048 else
11049 {
11050 for (L2Skill skill : SkillTreesData.getInstance().getHeroSkillTree().values())
11051 {
11052 super.removeSkill(skill); // Just Remove skills from nonHero characters
11053 }
11054 }
11055 _hero = hero;
11056
11057 sendSkillList();
11058 }
11059
11060 public void setIsInOlympiadMode(boolean b)
11061 {
11062 _inOlympiadMode = b;
11063 }
11064
11065 public void setIsOlympiadStart(boolean b)
11066 {
11067 _OlympiadStart = b;
11068 }
11069
11070 public boolean isOlympiadStart()
11071 {
11072 return _OlympiadStart;
11073 }
11074
11075 public boolean isHero()
11076 {
11077 return _hero;
11078 }
11079
11080 public boolean isInOlympiadMode()
11081 {
11082 return _inOlympiadMode;
11083 }
11084
11085 public boolean isInDuel()
11086 {
11087 return _isInDuel;
11088 }
11089
11090 public int getDuelId()
11091 {
11092 return _duelId;
11093 }
11094
11095 public void setDuelState(int mode)
11096 {
11097 _duelState = mode;
11098 }
11099
11100 public int getDuelState()
11101 {
11102 return _duelState;
11103 }
11104
11105 /**
11106 * Sets up the duel state using a non 0 duelId.
11107 * @param duelId 0=not in a duel
11108 */
11109 public void setIsInDuel(int duelId)
11110 {
11111 if (duelId > 0)
11112 {
11113 _isInDuel = true;
11114 _duelState = Duel.DUELSTATE_DUELLING;
11115 _duelId = duelId;
11116 }
11117 else
11118 {
11119 if (_duelState == Duel.DUELSTATE_DEAD)
11120 {
11121 enableAllSkills();
11122 getStatus().startHpMpRegeneration();
11123 }
11124 _isInDuel = false;
11125 _duelState = Duel.DUELSTATE_NODUEL;
11126 _duelId = 0;
11127 }
11128 }
11129
11130 /**
11131 * This returns a SystemMessage stating why the player is not available for duelling.
11132 * @return S1_CANNOT_DUEL... message
11133 */
11134 public SystemMessage getNoDuelReason()
11135 {
11136 SystemMessage sm = SystemMessage.getSystemMessage(_noDuelReason);
11137 sm.addPcName(this);
11138 _noDuelReason = SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL;
11139 return sm;
11140 }
11141
11142 /**
11143 * Checks if this player might join / start a duel.<br>
11144 * To get the reason use getNoDuelReason() after calling this function.
11145 * @return true if the player might join/start a duel.
11146 */
11147 public boolean canDuel()
11148 {
11149 if (isInCombat() || (getPunishLevel() == PunishLevel.JAIL))
11150 {
11151 _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_CURRENTLY_ENGAGED_IN_BATTLE;
11152 return false;
11153 }
11154 if (isDead() || isAlikeDead() || ((getCurrentHp() < (getMaxHp() / 2)) || (getCurrentMp() < (getMaxMp() / 2))))
11155 {
11156 _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_HP_OR_MP_IS_BELOW_50_PERCENT;
11157 return false;
11158 }
11159 if (isInDuel())
11160 {
11161 _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_ALREADY_ENGAGED_IN_A_DUEL;
11162 return false;
11163 }
11164 if (isInOlympiadMode())
11165 {
11166 _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_PARTICIPATING_IN_THE_OLYMPIAD;
11167 return false;
11168 }
11169 if (isCursedWeaponEquipped())
11170 {
11171 _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_IN_A_CHAOTIC_STATE;
11172 return false;
11173 }
11174 if (getPrivateStoreType() != STORE_PRIVATE_NONE)
11175 {
11176 _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_CURRENTLY_ENGAGED_IN_A_PRIVATE_STORE_OR_MANUFACTURE;
11177 return false;
11178 }
11179 if (isMounted() || isInBoat())
11180 {
11181 _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_CURRENTLY_RIDING_A_BOAT_STEED_OR_STRIDER;
11182 return false;
11183 }
11184 if (isFishing())
11185 {
11186 _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_CURRENTLY_FISHING;
11187 return false;
11188 }
11189 if (isInsideZone(ZoneId.PVP) || isInsideZone(ZoneId.PEACE) || isInsideZone(ZoneId.SIEGE))
11190 {
11191 _noDuelReason = SystemMessageId.C1_CANNOT_MAKE_A_CHALLANGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA;
11192 return false;
11193 }
11194 return true;
11195 }
11196
11197 public boolean isNoble()
11198 {
11199 return _noble;
11200 }
11201
11202 public void setNoble(boolean val)
11203 {
11204 final Collection<L2Skill> nobleSkillTree = SkillTreesData.getInstance().getNobleSkillTree().values();
11205 if (val)
11206 {
11207 for (L2Skill skill : nobleSkillTree)
11208 {
11209 addSkill(skill, false);
11210 }
11211 }
11212 else
11213 {
11214 for (L2Skill skill : nobleSkillTree)
11215 {
11216 super.removeSkill(skill);
11217 }
11218 }
11219
11220 _noble = val;
11221
11222 sendSkillList();
11223 }
11224
11225 public void setLvlJoinedAcademy(int lvl)
11226 {
11227 _lvlJoinedAcademy = lvl;
11228 }
11229
11230 public int getLvlJoinedAcademy()
11231 {
11232 return _lvlJoinedAcademy;
11233 }
11234
11235 public boolean isAcademyMember()
11236 {
11237 return _lvlJoinedAcademy > 0;
11238 }
11239
11240 @Override
11241 public void setTeam(int team)
11242 {
11243 super.setTeam(team);
11244 broadcastUserInfo();
11245 if (hasSummon())
11246 {
11247 getSummon().broadcastStatusUpdate();
11248 }
11249 }
11250
11251 public void setWantsPeace(int wantsPeace)
11252 {
11253 _wantsPeace = wantsPeace;
11254 }
11255
11256 public int getWantsPeace()
11257 {
11258 return _wantsPeace;
11259 }
11260
11261 public boolean isFishing()
11262 {
11263 return _fishing;
11264 }
11265
11266 public void setFishing(boolean fishing)
11267 {
11268 _fishing = fishing;
11269 }
11270
11271 public void setAllianceWithVarkaKetra(int sideAndLvlOfAlliance)
11272 {
11273 // [-5,-1] varka, 0 neutral, [1,5] ketra
11274 _alliedVarkaKetra = sideAndLvlOfAlliance;
11275 }
11276
11277 public int getAllianceWithVarkaKetra()
11278 {
11279 return _alliedVarkaKetra;
11280 }
11281
11282 public boolean isAlliedWithVarka()
11283 {
11284 return (_alliedVarkaKetra < 0);
11285 }
11286
11287 public boolean isAlliedWithKetra()
11288 {
11289 return (_alliedVarkaKetra > 0);
11290 }
11291
11292 public void sendSkillList()
11293 {
11294 boolean isDisabled = false;
11295 SkillList sl = new SkillList();
11296
11297 for (L2Skill s : getAllSkills())
11298 {
11299 if (s == null)
11300 {
11301 continue;
11302 }
11303 if ((s.getId() > 9000) && (s.getId() < 9007))
11304 {
11305 continue; // Fake skills to change base stats
11306 }
11307 if ((_transformation != null) && (!containsAllowedTransformSkill(s.getId()) && !s.allowOnTransform()))
11308 {
11309 continue;
11310 }
11311 if (getClan() != null)
11312 {
11313 isDisabled = s.isClanSkill() && (getClan().getReputationScore() < 0);
11314 }
11315
11316 boolean isEnchantable = SkillTable.getInstance().isEnchantable(s.getId());
11317 if (isEnchantable)
11318 {
11319 L2EnchantSkillLearn esl = EnchantGroupsData.getInstance().getSkillEnchantmentBySkillId(s.getId());
11320 if (esl != null)
11321 {
11322 // if player dont have min level to enchant
11323 if (s.getLevel() < esl.getBaseLevel())
11324 {
11325 isEnchantable = false;
11326 }
11327 }
11328 // if no enchant data
11329 else
11330 {
11331 isEnchantable = false;
11332 }
11333 }
11334
11335 sl.addSkill(s.getDisplayId(), s.getLevel(), s.isPassive(), isDisabled, isEnchantable);
11336 }
11337
11338 sendPacket(sl);
11339 }
11340
11341 /**
11342 * 1. Add the specified class ID as a subclass (up to the maximum number of <b>three</b>) for this character.<BR>
11343 * 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.
11344 * @param classId
11345 * @param classIndex
11346 * @return boolean subclassAdded
11347 */
11348 public boolean addSubClass(int classId, int classIndex)
11349 {
11350 if (!_subclassLock.tryLock())
11351 {
11352 return false;
11353 }
11354
11355 try
11356 {
11357 if ((getTotalSubClasses() == Config.MAX_SUBCLASS) || (classIndex == 0))
11358 {
11359 return false;
11360 }
11361
11362 if (getSubClasses().containsKey(classIndex))
11363 {
11364 return false;
11365 }
11366
11367 // Note: Never change _classIndex in any method other than setActiveClass().
11368
11369 SubClass newClass = new SubClass();
11370 newClass.setClassId(classId);
11371 newClass.setClassIndex(classIndex);
11372
11373 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
11374 PreparedStatement statement = con.prepareStatement(ADD_CHAR_SUBCLASS))
11375 {
11376 // Store the basic info about this new sub-class.
11377 statement.setInt(1, getObjectId());
11378 statement.setInt(2, newClass.getClassId());
11379 statement.setLong(3, newClass.getExp());
11380 statement.setInt(4, newClass.getSp());
11381 statement.setInt(5, newClass.getLevel());
11382 statement.setInt(6, newClass.getClassIndex()); // <-- Added
11383 statement.execute();
11384 }
11385 catch (Exception e)
11386 {
11387 _log.log(Level.WARNING, "WARNING: Could not add character sub class for " + getName() + ": " + e.getMessage(), e);
11388 return false;
11389 }
11390
11391 // Commit after database INSERT incase exception is thrown.
11392 getSubClasses().put(newClass.getClassIndex(), newClass);
11393
11394 final ClassId subTemplate = ClassId.getClassId(classId);
11395 final Map<Integer, L2SkillLearn> skillTree = SkillTreesData.getInstance().getCompleteClassSkillTree(subTemplate);
11396 final Map<Integer, L2Skill> prevSkillList = new HashMap<>();
11397 for (L2SkillLearn skillInfo : skillTree.values())
11398 {
11399 if (skillInfo.getGetLevel() <= 40)
11400 {
11401 L2Skill prevSkill = prevSkillList.get(skillInfo.getSkillId());
11402 L2Skill newSkill = SkillTable.getInstance().getInfo(skillInfo.getSkillId(), skillInfo.getSkillLevel());
11403
11404 if ((prevSkill != null) && (prevSkill.getLevel() > newSkill.getLevel()))
11405 {
11406 continue;
11407 }
11408
11409 prevSkillList.put(newSkill.getId(), newSkill);
11410 storeSkill(newSkill, prevSkill, classIndex);
11411 }
11412 }
11413 return true;
11414 }
11415 finally
11416 {
11417 _subclassLock.unlock();
11418 }
11419 }
11420
11421 /**
11422 * 1. Completely erase all existance of the subClass linked to the classIndex.<BR>
11423 * 2. Send over the newClassId to addSubClass()to create a new instance on this classIndex.<BR>
11424 * 3. Upon Exception, revert the player to their BaseClass to avoid further problems.<BR>
11425 * @param classIndex
11426 * @param newClassId
11427 * @return boolean subclassAdded
11428 */
11429 public boolean modifySubClass(int classIndex, int newClassId)
11430 {
11431 if (!_subclassLock.tryLock())
11432 {
11433 return false;
11434 }
11435
11436 try
11437 {
11438 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
11439 {
11440 // Remove all henna info stored for this sub-class.
11441 PreparedStatement statement = con.prepareStatement(DELETE_CHAR_HENNAS);
11442 statement.setInt(1, getObjectId());
11443 statement.setInt(2, classIndex);
11444 statement.execute();
11445 statement.close();
11446
11447 // Remove all shortcuts info stored for this sub-class.
11448 statement = con.prepareStatement(DELETE_CHAR_SHORTCUTS);
11449 statement.setInt(1, getObjectId());
11450 statement.setInt(2, classIndex);
11451 statement.execute();
11452 statement.close();
11453
11454 // Remove all effects info stored for this sub-class.
11455 statement = con.prepareStatement(DELETE_SKILL_SAVE);
11456 statement.setInt(1, getObjectId());
11457 statement.setInt(2, classIndex);
11458 statement.execute();
11459 statement.close();
11460
11461 // Remove all skill info stored for this sub-class.
11462 statement = con.prepareStatement(DELETE_CHAR_SKILLS);
11463 statement.setInt(1, getObjectId());
11464 statement.setInt(2, classIndex);
11465 statement.execute();
11466 statement.close();
11467
11468 // Remove all basic info stored about this sub-class.
11469 statement = con.prepareStatement(DELETE_CHAR_SUBCLASS);
11470 statement.setInt(1, getObjectId());
11471 statement.setInt(2, classIndex);
11472 statement.execute();
11473 statement.close();
11474 }
11475 catch (Exception e)
11476 {
11477 _log.log(Level.WARNING, "Could not modify sub class for " + getName() + " to class index " + classIndex + ": " + e.getMessage(), e);
11478
11479 // This must be done in order to maintain data consistency.
11480 getSubClasses().remove(classIndex);
11481 return false;
11482 }
11483
11484 getSubClasses().remove(classIndex);
11485 }
11486 finally
11487 {
11488 _subclassLock.unlock();
11489 }
11490
11491 return addSubClass(newClassId, classIndex);
11492 }
11493
11494 public boolean isSubClassActive()
11495 {
11496 return _classIndex > 0;
11497 }
11498
11499 public Map<Integer, SubClass> getSubClasses()
11500 {
11501 if (_subClasses == null)
11502 {
11503 _subClasses = new FastMap<>();
11504 }
11505
11506 return _subClasses;
11507 }
11508
11509 public int getTotalSubClasses()
11510 {
11511 return getSubClasses().size();
11512 }
11513
11514 public int getBaseClass()
11515 {
11516 return _baseClass;
11517 }
11518
11519 public int getActiveClass()
11520 {
11521 return _activeClass;
11522 }
11523
11524 public int getClassIndex()
11525 {
11526 return _classIndex;
11527 }
11528
11529 private void setClassTemplate(int classId)
11530 {
11531 _activeClass = classId;
11532
11533 final L2PcTemplate pcTemplate = CharTemplateTable.getInstance().getTemplate(classId);
11534 if (pcTemplate == null)
11535 {
11536 _log.severe("Missing template for classId: " + classId);
11537 throw new Error();
11538 }
11539 // Set the template of the L2PcInstance
11540 setTemplate(pcTemplate);
11541 fireProfessionChangeListeners(pcTemplate);
11542 }
11543
11544 /**
11545 * Changes the character's class based on the given class index.<br>
11546 * An index of zero specifies the character's original (base) class, while indexes 1-3 specifies the character's sub-classes respectively.<br>
11547 * <font color="00FF00"/>WARNING: Use only on subclase change</font>
11548 * @param classIndex
11549 * @return
11550 */
11551 public boolean setActiveClass(int classIndex)
11552 {
11553 if (!_subclassLock.tryLock())
11554 {
11555 return false;
11556 }
11557
11558 try
11559 {
11560 // Cannot switch or change subclasses while transformed
11561 if (_transformation != null)
11562 {
11563 return false;
11564 }
11565
11566 // Remove active item skills before saving char to database
11567 // because next time when choosing this class, weared items can
11568 // be different
11569 for (L2ItemInstance item : getInventory().getAugmentedItems())
11570 {
11571 if ((item != null) && item.isEquipped())
11572 {
11573 item.getAugmentation().removeBonus(this);
11574 }
11575 }
11576
11577 // abort any kind of cast.
11578 abortCast();
11579
11580 // Stop casting for any player that may be casting a force buff on this l2pcinstance.
11581 for (L2Character character : getKnownList().getKnownCharacters())
11582 {
11583 if ((character.getFusionSkill() != null) && (character.getFusionSkill().getTarget() == this))
11584 {
11585 character.abortCast();
11586 }
11587 }
11588
11589 // 1. Call store() before modifying _classIndex to avoid skill effects rollover.
11590 // 2. Register the correct _classId against applied 'classIndex'.
11591 store(Config.SUBCLASS_STORE_SKILL_COOLTIME);
11592 _reuseTimeStampsSkills.clear();
11593
11594 // clear charges
11595 _charges.set(0);
11596 stopChargeTask();
11597
11598 if (hasSummon() && getSummon().isServitor())
11599 {
11600 getSummon().unSummon(this);
11601 }
11602
11603 if (classIndex == 0)
11604 {
11605 setClassTemplate(getBaseClass());
11606 }
11607 else
11608 {
11609 try
11610 {
11611 setClassTemplate(getSubClasses().get(classIndex).getClassId());
11612 }
11613 catch (Exception e)
11614 {
11615 _log.log(Level.WARNING, "Could not switch " + getName() + "'s sub class to class index " + classIndex + ": " + e.getMessage(), e);
11616 return false;
11617 }
11618 }
11619 _classIndex = classIndex;
11620
11621 setLearningClass(getClassId());
11622
11623 if (isInParty())
11624 {
11625 getParty().recalculatePartyLevel();
11626 }
11627
11628 // Update the character's change in class status.
11629 // 1. Remove any active cubics from the player.
11630 // 2. Renovate the characters table in the database with the new class info, storing also buff/effect data.
11631 // 3. Remove all existing skills.
11632 // 4. Restore all the learned skills for the current class from the database.
11633 // 5. Restore effect/buff data for the new class.
11634 // 6. Restore henna data for the class, applying the new stat modifiers while removing existing ones.
11635 // 7. Reset HP/MP/CP stats and send Server->Client character status packet to reflect changes.
11636 // 8. Restore shortcut data related to this class.
11637 // 9. Resend a class change animation effect to broadcast to all nearby players.
11638 for (L2Skill oldSkill : getAllSkills())
11639 {
11640 super.removeSkill(oldSkill);
11641 }
11642
11643 stopAllEffectsExceptThoseThatLastThroughDeath();
11644 stopAllEffectsNotStayOnSubclassChange();
11645 stopCubics();
11646
11647 restoreRecipeBook(false);
11648
11649 // Restore any Death Penalty Buff
11650 restoreDeathPenaltyBuffLevel();
11651
11652 restoreSkills();
11653 rewardSkills();
11654 regiveTemporarySkills();
11655
11656 // Prevents some issues when changing between subclases that shares skills
11657 if ((_disabledSkills != null) && !_disabledSkills.isEmpty())
11658 {
11659 _disabledSkills.clear();
11660 }
11661
11662 restoreEffects();
11663 updateEffectIcons();
11664 sendPacket(new EtcStatusUpdate(this));
11665
11666 // if player has quest 422: Repent Your Sins, remove it
11667 QuestState st = getQuestState("422_RepentYourSins");
11668 if (st != null)
11669 {
11670 st.exitQuest(true);
11671 }
11672
11673 for (int i = 0; i < 3; i++)
11674 {
11675 _henna[i] = null;
11676 }
11677
11678 restoreHenna();
11679 sendPacket(new HennaInfo(this));
11680
11681 if (getCurrentHp() > getMaxHp())
11682 {
11683 setCurrentHp(getMaxHp());
11684 }
11685 if (getCurrentMp() > getMaxMp())
11686 {
11687 setCurrentMp(getMaxMp());
11688 }
11689 if (getCurrentCp() > getMaxCp())
11690 {
11691 setCurrentCp(getMaxCp());
11692 }
11693
11694 refreshOverloaded();
11695 refreshExpertisePenalty();
11696 broadcastUserInfo();
11697
11698 // Clear resurrect xp calculation
11699 setExpBeforeDeath(0);
11700
11701 _shortCuts.restore();
11702 sendPacket(new ShortCutInit(this));
11703
11704 broadcastPacket(new SocialAction(getObjectId(), SocialAction.LEVEL_UP));
11705 sendPacket(new SkillCoolTime(this));
11706 sendPacket(new ExStorageMaxCount(this));
11707
11708 return true;
11709 }
11710 finally
11711 {
11712 _subclassLock.unlock();
11713 }
11714 }
11715
11716 public boolean isLocked()
11717 {
11718 return _subclassLock.isLocked();
11719 }
11720
11721 public void stopWarnUserTakeBreak()
11722 {
11723 if (_taskWarnUserTakeBreak != null)
11724 {
11725 _taskWarnUserTakeBreak.cancel(true);
11726 // ThreadPoolManager.getInstance().removeGeneral((Runnable)_taskWarnUserTakeBreak);
11727 _taskWarnUserTakeBreak = null;
11728 }
11729 }
11730
11731 public void startWarnUserTakeBreak()
11732 {
11733 if (_taskWarnUserTakeBreak == null)
11734 {
11735 _taskWarnUserTakeBreak = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new WarnUserTakeBreak(), 7200000, 7200000);
11736 }
11737 }
11738
11739 public void stopRentPet()
11740 {
11741 if (_taskRentPet != null)
11742 {
11743 // if the rent of a wyvern expires while over a flying zone, tp to down before unmounting
11744 if (checkLandingState() && (getMountType() == 2))
11745 {
11746 teleToLocation(MapRegionManager.TeleportWhereType.Town);
11747 }
11748
11749 if (dismount()) // this should always be true now, since we teleported already
11750 {
11751 _taskRentPet.cancel(true);
11752 _taskRentPet = null;
11753 }
11754 }
11755 }
11756
11757 public void startRentPet(int seconds)
11758 {
11759 if (_taskRentPet == null)
11760 {
11761 _taskRentPet = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new RentPetTask(), seconds * 1000L, seconds * 1000L);
11762 }
11763 }
11764
11765 public boolean isRentedPet()
11766 {
11767 if (_taskRentPet != null)
11768 {
11769 return true;
11770 }
11771
11772 return false;
11773 }
11774
11775 public void stopWaterTask()
11776 {
11777 if (_taskWater != null)
11778 {
11779 _taskWater.cancel(false);
11780 _taskWater = null;
11781 sendPacket(new SetupGauge(2, 0));
11782 }
11783 }
11784
11785 public void startWaterTask()
11786 {
11787 if (!isDead() && (_taskWater == null))
11788 {
11789 int timeinwater = (int) calcStat(Stats.BREATH, 60000, this, null);
11790
11791 sendPacket(new SetupGauge(2, timeinwater));
11792 _taskWater = ThreadPoolManager.getInstance().scheduleEffectAtFixedRate(new WaterTask(), timeinwater, 1000);
11793 }
11794 }
11795
11796 public boolean isInWater()
11797 {
11798 if (_taskWater != null)
11799 {
11800 return true;
11801 }
11802
11803 return false;
11804 }
11805
11806 public void checkWaterState()
11807 {
11808 if (isInsideZone(ZoneId.WATER))
11809 {
11810 startWaterTask();
11811 }
11812 else
11813 {
11814 stopWaterTask();
11815 }
11816 }
11817
11818 public void onPlayerEnter()
11819 {
11820 startWarnUserTakeBreak();
11821
11822 if (SevenSigns.getInstance().isSealValidationPeriod() || SevenSigns.getInstance().isCompResultsPeriod())
11823 {
11824 if (!isGM() && isIn7sDungeon() && (SevenSigns.getInstance().getPlayerCabal(getObjectId()) != SevenSigns.getInstance().getCabalHighestScore()))
11825 {
11826 teleToLocation(MapRegionManager.TeleportWhereType.Town);
11827 setIsIn7sDungeon(false);
11828 sendMessage("You have been teleported to the nearest town due to the beginning of the Seal Validation period.");
11829 }
11830 }
11831 else
11832 {
11833 if (!isGM() && isIn7sDungeon() && (SevenSigns.getInstance().getPlayerCabal(getObjectId()) == SevenSigns.CABAL_NULL))
11834 {
11835 teleToLocation(MapRegionManager.TeleportWhereType.Town);
11836 setIsIn7sDungeon(false);
11837 sendMessage("You have been teleported to the nearest town because you have not signed for any cabal.");
11838 }
11839 }
11840
11841 // jail task
11842 updatePunishState();
11843
11844 if (isGM())
11845 {
11846 if (isInvul())
11847 {
11848 sendMessage("Entering world in Invulnerable mode.");
11849 }
11850 if (getAppearance().getInvisible())
11851 {
11852 sendMessage("Entering world in Invisible mode.");
11853 }
11854 if (isSilenceMode())
11855 {
11856 sendMessage("Entering world in Silence mode.");
11857 }
11858
11859 if (GlobalVariablesManager.getInstance().isVariableStored(COND_EXCEPTIONS))
11860 {
11861 String exes = GlobalVariablesManager.getInstance().getStoredVariable(COND_EXCEPTIONS);
11862 if (Util.isDigit(exes))
11863 {
11864 _exceptions = Long.valueOf(exes);
11865 }
11866 else
11867 {
11868 _exceptions = PcCondOverride.getAllExceptionsMask();
11869 }
11870 }
11871 else
11872 {
11873 _exceptions = PcCondOverride.getAllExceptionsMask();
11874 }
11875 }
11876
11877 revalidateZone(true);
11878
11879 notifyFriends();
11880 if (!canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && Config.DECREASE_SKILL_LEVEL)
11881 {
11882 checkPlayerSkills();
11883 }
11884 }
11885
11886 public long getLastAccess()
11887 {
11888 return _lastAccess;
11889 }
11890
11891 @Override
11892 public void doRevive()
11893 {
11894 super.doRevive();
11895 stopEffects(L2EffectType.CHARMOFCOURAGE);
11896 updateEffectIcons();
11897 sendPacket(new EtcStatusUpdate(this));
11898 _reviveRequested = 0;
11899 _revivePower = 0;
11900
11901 if (isMounted())
11902 {
11903 startFeed(_mountNpcId);
11904 }
11905 if (isInParty() && getParty().isInDimensionalRift())
11906 {
11907 if (!DimensionalRiftManager.getInstance().checkIfInPeaceZone(getX(), getY(), getZ()))
11908 {
11909 getParty().getDimensionalRift().memberRessurected(this);
11910 }
11911 }
11912 }
11913
11914 @Override
11915 public void setName(String value)
11916 {
11917 super.setName(value);
11918 if (Config.CACHE_CHAR_NAMES)
11919 {
11920 CharNameTable.getInstance().addName(this);
11921 }
11922 }
11923
11924 @Override
11925 public void doRevive(double revivePower)
11926 {
11927 // Restore the player's lost experience,
11928 // depending on the % return of the skill used (based on its power).
11929 restoreExp(revivePower);
11930 doRevive();
11931 }
11932
11933 public void reviveRequest(L2PcInstance reviver, L2Skill skill, boolean Pet)
11934 {
11935 if (isResurrectionBlocked())
11936 {
11937 return;
11938 }
11939
11940 if (_reviveRequested == 1)
11941 {
11942 if (_revivePet == Pet)
11943 {
11944 reviver.sendPacket(SystemMessageId.RES_HAS_ALREADY_BEEN_PROPOSED); // Resurrection is already been proposed.
11945 }
11946 else
11947 {
11948 if (Pet)
11949 {
11950 reviver.sendPacket(SystemMessageId.CANNOT_RES_PET2); // A pet cannot be resurrected while it's owner is in the process of resurrecting.
11951 }
11952 else
11953 {
11954 reviver.sendPacket(SystemMessageId.MASTER_CANNOT_RES); // While a pet is attempting to resurrect, it cannot help in resurrecting its master.
11955 }
11956 }
11957 return;
11958 }
11959 if ((Pet && hasSummon() && getSummon().isDead()) || (!Pet && isDead()))
11960 {
11961 _reviveRequested = 1;
11962 int restoreExp = 0;
11963 if (isPhoenixBlessed() || (Config.TW_RESS_ON_DEATH && isInTownWarEvent()))
11964 {
11965 _revivePower = 100;
11966 }
11967 else if (isAffected(CharEffectList.EFFECT_FLAG_CHARM_OF_COURAGE))
11968 {
11969 _revivePower = 0;
11970 }
11971 else
11972 {
11973 _revivePower = Formulas.calculateSkillResurrectRestorePercent(skill.getPower(), reviver);
11974 }
11975
11976 restoreExp = (int) Math.round(((getExpBeforeDeath() - getExp()) * _revivePower) / 100);
11977
11978 _revivePet = Pet;
11979
11980 if (isAffected(CharEffectList.EFFECT_FLAG_CHARM_OF_COURAGE))
11981 {
11982 ConfirmDlg dlg = new ConfirmDlg(SystemMessageId.RESURRECT_USING_CHARM_OF_COURAGE.getId());
11983 dlg.addTime(60000);
11984 sendPacket(dlg);
11985 return;
11986 }
11987 ConfirmDlg dlg = new ConfirmDlg(SystemMessageId.RESSURECTION_REQUEST_BY_C1_FOR_S2_XP.getId());
11988 dlg.addPcName(reviver);
11989 dlg.addString(Integer.toString(restoreExp));
11990 sendPacket(dlg);
11991 }
11992 }
11993
11994 public void reviveAnswer(int answer)
11995 {
11996 if ((_reviveRequested != 1) || (!isDead() && !_revivePet) || (_revivePet && hasSummon() && !getSummon().isDead()))
11997 {
11998 return;
11999 }
12000 // If character refuses a PhoenixBless autoress, cancel all buffs he had
12001 if ((answer == 0) && isPhoenixBlessed())
12002 {
12003 stopPhoenixBlessing(null);
12004 stopAllEffectsExceptThoseThatLastThroughDeath();
12005 }
12006 if (answer == 1)
12007 {
12008 if (!_revivePet)
12009 {
12010 if (_revivePower != 0)
12011 {
12012 doRevive(_revivePower);
12013 }
12014 else
12015 {
12016 doRevive();
12017 }
12018 }
12019 else if (hasSummon())
12020 {
12021 if (_revivePower != 0)
12022 {
12023 getSummon().doRevive(_revivePower);
12024 }
12025 else
12026 {
12027 getSummon().doRevive();
12028 }
12029 }
12030 }
12031 _reviveRequested = 0;
12032 _revivePower = 0;
12033 }
12034
12035 public boolean isReviveRequested()
12036 {
12037 return (_reviveRequested == 1);
12038 }
12039
12040 public boolean isRevivingPet()
12041 {
12042 return _revivePet;
12043 }
12044
12045 public void removeReviving()
12046 {
12047 _reviveRequested = 0;
12048 _revivePower = 0;
12049 }
12050
12051 public void onActionRequest()
12052 {
12053 if (isSpawnProtected())
12054 {
12055 sendPacket(SystemMessageId.YOU_ARE_NO_LONGER_PROTECTED_FROM_AGGRESSIVE_MONSTERS);
12056
12057 if (Config.RESTORE_SERVITOR_ON_RECONNECT && !hasSummon() && CharSummonTable.getInstance().getServitors().containsKey(getObjectId()))
12058 {
12059 CharSummonTable.getInstance().restoreServitor(this);
12060 }
12061 if (Config.RESTORE_PET_ON_RECONNECT && !hasSummon() && CharSummonTable.getInstance().getPets().containsKey(getObjectId()))
12062 {
12063 CharSummonTable.getInstance().restorePet(this);
12064 }
12065 }
12066 if (isTeleportProtected())
12067 {
12068 sendMessage("Teleport spawn protection ended.");
12069 }
12070 setProtection(false);
12071 setTeleportProtection(false);
12072 }
12073
12074 /**
12075 * Expertise of the L2PcInstance (None=0, D=1, C=2, B=3, A=4, S=5, S80=6, S84=7)
12076 * @return int Expertise skill level.
12077 */
12078 public int getExpertiseLevel()
12079 {
12080 int level = getSkillLevel(239);
12081 if (level < 0)
12082 {
12083 level = 0;
12084 }
12085 return level;
12086 }
12087
12088 @Override
12089 public void teleToLocation(int x, int y, int z, int heading, boolean allowRandomOffset)
12090 {
12091 if ((getVehicle() != null) && !getVehicle().isTeleporting())
12092 {
12093 setVehicle(null);
12094 }
12095
12096 if (isFlyingMounted() && (z < -1005))
12097 {
12098 z = -1005;
12099 }
12100
12101 super.teleToLocation(x, y, z, heading, allowRandomOffset);
12102 }
12103
12104 @Override
12105 public final void onTeleported()
12106 {
12107 super.onTeleported();
12108
12109 if (isInAirShip())
12110 {
12111 getAirShip().sendInfo(this);
12112 }
12113
12114 // Force a revalidation
12115 revalidateZone(true);
12116
12117 checkItemRestriction();
12118
12119 if ((Config.PLAYER_TELEPORT_PROTECTION > 0) && !isInOlympiadMode())
12120 {
12121 setTeleportProtection(true);
12122 }
12123
12124 // Trained beast is lost after teleport
12125 if (getTrainedBeasts() != null)
12126 {
12127 for (L2TamedBeastInstance tamedBeast : getTrainedBeasts())
12128 {
12129 tamedBeast.deleteMe();
12130 }
12131 getTrainedBeasts().clear();
12132 }
12133
12134 // Modify the position of the pet if necessary
12135 if (hasSummon())
12136 {
12137 getSummon().setFollowStatus(false);
12138 getSummon().teleToLocation(getPosition().getX(), getPosition().getY(), getPosition().getZ(), false);
12139 ((L2SummonAI) getSummon().getAI()).setStartFollowController(true);
12140 getSummon().setFollowStatus(true);
12141 getSummon().updateAndBroadcastStatus(0);
12142 }
12143
12144 TvTEvent.onTeleported(this);
12145 TvTRoundEvent.onTeleported(this);
12146 }
12147
12148 @Override
12149 public void setIsTeleporting(boolean teleport)
12150 {
12151 setIsTeleporting(teleport, true);
12152 }
12153
12154 public void setIsTeleporting(boolean teleport, boolean useWatchDog)
12155 {
12156 super.setIsTeleporting(teleport);
12157 if (!useWatchDog)
12158 {
12159 return;
12160 }
12161 if (teleport)
12162 {
12163 if ((_teleportWatchdog == null) && (Config.TELEPORT_WATCHDOG_TIMEOUT > 0))
12164 {
12165 synchronized (this)
12166 {
12167 if (_teleportWatchdog == null)
12168 {
12169 _teleportWatchdog = ThreadPoolManager.getInstance().scheduleGeneral(new TeleportWatchdog(), Config.TELEPORT_WATCHDOG_TIMEOUT * 1000);
12170 }
12171 }
12172 }
12173 }
12174 else
12175 {
12176 if (_teleportWatchdog != null)
12177 {
12178 _teleportWatchdog.cancel(false);
12179 // ThreadPoolManager.getInstance().removeGeneral((Runnable)_teleportWatchdog);
12180 _teleportWatchdog = null;
12181 }
12182 }
12183 }
12184
12185 private class TeleportWatchdog implements Runnable
12186 {
12187 private final L2PcInstance _player;
12188
12189 TeleportWatchdog()
12190 {
12191 _player = L2PcInstance.this;
12192 }
12193
12194 @Override
12195 public void run()
12196 {
12197 if ((_player == null) || !_player.isTeleporting())
12198 {
12199 return;
12200 }
12201
12202 if (Config.DEBUG)
12203 {
12204 _log.warning("Player " + _player.getName() + " teleport timeout expired");
12205 }
12206 _player.onTeleported();
12207 }
12208 }
12209
12210 public void setLastServerPosition(int x, int y, int z)
12211 {
12212 _lastServerPosition.setXYZ(x, y, z);
12213 }
12214
12215 public Point3D getLastServerPosition()
12216 {
12217 return _lastServerPosition;
12218 }
12219
12220 public boolean checkLastServerPosition(int x, int y, int z)
12221 {
12222 return _lastServerPosition.equals(x, y, z);
12223 }
12224
12225 public int getLastServerDistance(int x, int y, int z)
12226 {
12227 double dx = (x - _lastServerPosition.getX());
12228 double dy = (y - _lastServerPosition.getY());
12229 double dz = (z - _lastServerPosition.getZ());
12230
12231 return (int) Math.sqrt((dx * dx) + (dy * dy) + (dz * dz));
12232 }
12233
12234 @Override
12235 public void addExpAndSp(long addToExp, int addToSp)
12236 {
12237 if ((Config.Boost_EXP_COMMAND && _addXpSp) || (!Config.Boost_EXP_COMMAND))
12238 {
12239 getStat().addExpAndSp(addToExp, addToSp, false);
12240 }
12241 }
12242
12243 public void addExpAndSp(long addToExp, int addToSp, boolean useVitality)
12244 {
12245 if ((Config.Boost_EXP_COMMAND && _addXpSp) || (!Config.Boost_EXP_COMMAND))
12246 {
12247 getStat().addExpAndSp(addToExp, addToSp, useVitality);
12248 }
12249 }
12250
12251 public void removeExpAndSp(long removeExp, int removeSp)
12252 {
12253 getStat().removeExpAndSp(removeExp, removeSp, true);
12254 }
12255
12256 public void removeExpAndSp(long removeExp, int removeSp, boolean sendMessage)
12257 {
12258 getStat().removeExpAndSp(removeExp, removeSp, sendMessage);
12259 }
12260
12261 @Override
12262 public void reduceCurrentHp(double value, L2Character attacker, boolean awake, boolean isDOT, L2Skill skill)
12263 {
12264 if (skill != null)
12265 {
12266 getStatus().reduceHp(value, attacker, awake, isDOT, skill.isToggle(), skill.getDmgDirectlyToHP());
12267 }
12268 else
12269 {
12270 getStatus().reduceHp(value, attacker, awake, isDOT, false, false);
12271 }
12272
12273 // notify the tamed beast of attacks
12274 if (getTrainedBeasts() != null)
12275 {
12276 for (L2TamedBeastInstance tamedBeast : getTrainedBeasts())
12277 {
12278 tamedBeast.onOwnerGotAttacked(attacker);
12279 }
12280 }
12281 }
12282
12283 public void broadcastSnoop(int type, String name, String _text)
12284 {
12285 if (!_snoopListener.isEmpty())
12286 {
12287 Snoop sn = new Snoop(getObjectId(), getName(), type, name, _text);
12288
12289 for (L2PcInstance pci : _snoopListener)
12290 {
12291 if (pci != null)
12292 {
12293 pci.sendPacket(sn);
12294 }
12295 }
12296 }
12297 }
12298
12299 public void addSnooper(L2PcInstance pci)
12300 {
12301 if (!_snoopListener.contains(pci))
12302 {
12303 _snoopListener.add(pci);
12304 }
12305 }
12306
12307 public void removeSnooper(L2PcInstance pci)
12308 {
12309 _snoopListener.remove(pci);
12310 }
12311
12312 public void addSnooped(L2PcInstance pci)
12313 {
12314 if (!_snoopedPlayer.contains(pci))
12315 {
12316 _snoopedPlayer.add(pci);
12317 }
12318 }
12319
12320 public void removeSnooped(L2PcInstance pci)
12321 {
12322 _snoopedPlayer.remove(pci);
12323 }
12324
12325 public void addBypass(String bypass)
12326 {
12327 if (bypass == null)
12328 {
12329 return;
12330 }
12331
12332 _validBypass.add(bypass);
12333 }
12334
12335 public void addBypass2(String bypass)
12336 {
12337 if (bypass == null)
12338 {
12339 return;
12340 }
12341
12342 _validBypass2.add(bypass);
12343 }
12344
12345 public boolean validateBypass(String cmd)
12346 {
12347 if (!Config.BYPASS_VALIDATION)
12348 {
12349 return true;
12350 }
12351
12352 for (String bp : _validBypass)
12353 {
12354 if (bp == null)
12355 {
12356 continue;
12357 }
12358
12359 if (bp.equals(cmd))
12360 {
12361 return true;
12362 }
12363 }
12364
12365 for (String bp : _validBypass2)
12366 {
12367 if (bp == null)
12368 {
12369 continue;
12370 }
12371
12372 if (cmd.startsWith(bp))
12373 {
12374 return true;
12375 }
12376 }
12377
12378 _log.warning("[L2PcInstance] player [" + getName() + "] sent invalid bypass '" + cmd + "'.");
12379 return false;
12380 }
12381
12382 /**
12383 * Performs following tests:
12384 * <ul>
12385 * <li>Inventory contains item</li>
12386 * <li>Item owner id == owner id</li>
12387 * <li>It isnt pet control item while mounting pet or pet summoned</li>
12388 * <li>It isnt active enchant item</li>
12389 * <li>It isnt cursed weapon/item</li>
12390 * <li>It isnt wear item</li>
12391 * </ul>
12392 * @param objectId item object id
12393 * @param action just for login porpouse
12394 * @return
12395 */
12396 public boolean validateItemManipulation(int objectId, String action)
12397 {
12398 L2ItemInstance item = getInventory().getItemByObjectId(objectId);
12399
12400 if ((item == null) || (item.getOwnerId() != getObjectId()))
12401 {
12402 _log.finest(getObjectId() + ": player tried to " + action + " item he is not owner of");
12403 return false;
12404 }
12405
12406 // Pet is summoned and not the item that summoned the pet AND not the buggle from strider you're mounting
12407 if ((hasSummon() && (getSummon().getControlObjectId() == objectId)) || (getMountObjectID() == objectId))
12408 {
12409 if (Config.DEBUG)
12410 {
12411 _log.finest(getObjectId() + ": player tried to " + action + " item controling pet");
12412 }
12413
12414 return false;
12415 }
12416
12417 if ((getActiveEnchantItem() != null) && (getActiveEnchantItem().getObjectId() == objectId))
12418 {
12419 if (Config.DEBUG)
12420 {
12421 _log.finest(getObjectId() + ":player tried to " + action + " an enchant scroll he was using");
12422 }
12423
12424 return false;
12425 }
12426
12427 if (CursedWeaponsManager.getInstance().isCursed(item.getItemId()))
12428 {
12429 // can not trade a cursed weapon
12430 return false;
12431 }
12432
12433 return true;
12434 }
12435
12436 public void clearBypass()
12437 {
12438 _validBypass.clear();
12439 _validBypass2.clear();
12440 }
12441
12442 /**
12443 * @return Returns the inBoat.
12444 */
12445 public boolean isInBoat()
12446 {
12447 return (_vehicle != null) && _vehicle.isBoat();
12448 }
12449
12450 /**
12451 * @return
12452 */
12453 public L2BoatInstance getBoat()
12454 {
12455 return (L2BoatInstance) _vehicle;
12456 }
12457
12458 /**
12459 * @return Returns the inAirShip.
12460 */
12461 public boolean isInAirShip()
12462 {
12463 return (_vehicle != null) && _vehicle.isAirShip();
12464 }
12465
12466 /**
12467 * @return
12468 */
12469 public L2AirShipInstance getAirShip()
12470 {
12471 return (L2AirShipInstance) _vehicle;
12472 }
12473
12474 public L2Vehicle getVehicle()
12475 {
12476 return _vehicle;
12477 }
12478
12479 public void setVehicle(L2Vehicle v)
12480 {
12481 if ((v == null) && (_vehicle != null))
12482 {
12483 _vehicle.removePassenger(this);
12484 }
12485
12486 _vehicle = v;
12487 }
12488
12489 public boolean isInVehicle()
12490 {
12491 return _vehicle != null;
12492 }
12493
12494 public void setInCrystallize(boolean inCrystallize)
12495 {
12496 _inCrystallize = inCrystallize;
12497 }
12498
12499 public boolean isInCrystallize()
12500 {
12501 return _inCrystallize;
12502 }
12503
12504 /**
12505 * @return
12506 */
12507 public Point3D getInVehiclePosition()
12508 {
12509 return _inVehiclePosition;
12510 }
12511
12512 public void setInVehiclePosition(Point3D pt)
12513 {
12514 _inVehiclePosition = pt;
12515 }
12516
12517 /**
12518 * Manage the delete task of a L2PcInstance (Leave Party, Unsummon pet, Save its inventory in the database, Remove it from the world...).<br>
12519 * <B><U>Actions</U>:</B>
12520 * <ul>
12521 * <li>If the L2PcInstance is in observer mode, set its position to its position before entering in observer mode</li>
12522 * <li>Set the online Flag to True or False and update the characters table of the database with online status and lastAccess</li>
12523 * <li>Stop the HP/MP/CP Regeneration task</li>
12524 * <li>Cancel Crafting, Attak or Cast</li>
12525 * <li>Remove the L2PcInstance from the world</li>
12526 * <li>Stop Party and Unsummon Pet</li>
12527 * <li>Update database with items in its inventory and remove them from the world</li>
12528 * <li>Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI</li>
12529 * <li>Close the connection with the client</li>
12530 * </ul>
12531 */
12532 @Override
12533 public void deleteMe()
12534 {
12535 cleanup();
12536 store();
12537 super.deleteMe();
12538 }
12539
12540 private synchronized void cleanup()
12541 {
12542 // 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)
12543 try
12544 {
12545 if (!isOnline())
12546 {
12547 _log.log(Level.SEVERE, "deleteMe() called on offline character " + this, new RuntimeException());
12548 }
12549 setOnlineStatus(false, true);
12550 }
12551 catch (Exception e)
12552 {
12553 _log.log(Level.SEVERE, "deleteMe()", e);
12554 }
12555
12556 try
12557 {
12558 if (Config.ENABLE_BLOCK_CHECKER_EVENT && (getBlockCheckerArena() != -1))
12559 {
12560 HandysBlockCheckerManager.getInstance().onDisconnect(this);
12561 }
12562 }
12563 catch (Exception e)
12564 {
12565 _log.log(Level.SEVERE, "deleteMe()", e);
12566 }
12567
12568 try
12569 {
12570 _isOnline = false;
12571 abortAttack();
12572 abortCast();
12573 stopMove(null);
12574 setDebug(null);
12575 }
12576 catch (Exception e)
12577 {
12578 _log.log(Level.SEVERE, "deleteMe()", e);
12579 }
12580
12581 // remove combat flag
12582 try
12583 {
12584 if (getInventory().getItemByItemId(9819) != null)
12585 {
12586 Fort fort = FortManager.getInstance().getFort(this);
12587 if (fort != null)
12588 {
12589 FortSiegeManager.getInstance().dropCombatFlag(this, fort.getFortId());
12590 }
12591 else
12592 {
12593 int slot = getInventory().getSlotFromItem(getInventory().getItemByItemId(9819));
12594 getInventory().unEquipItemInBodySlot(slot);
12595 destroyItem("CombatFlag", getInventory().getItemByItemId(9819), null, true);
12596 }
12597 }
12598 else if (isCombatFlagEquipped())
12599 {
12600 TerritoryWarManager.getInstance().dropCombatFlag(this, false, false);
12601 }
12602 }
12603 catch (Exception e)
12604 {
12605 _log.log(Level.SEVERE, "deleteMe()", e);
12606 }
12607
12608 try
12609 {
12610 PartyMatchWaitingList.getInstance().removePlayer(this);
12611 if (_partyroom != 0)
12612 {
12613 PartyMatchRoom room = PartyMatchRoomList.getInstance().getRoom(_partyroom);
12614 if (room != null)
12615 {
12616 room.deleteMember(this);
12617 }
12618 }
12619 }
12620 catch (Exception e)
12621 {
12622 _log.log(Level.SEVERE, "deleteMe()", e);
12623 }
12624
12625 try
12626 {
12627 if (isFlying())
12628 {
12629 removeSkill(SkillTable.getInstance().getInfo(4289, 1));
12630 }
12631 }
12632 catch (Exception e)
12633 {
12634 _log.log(Level.SEVERE, "deleteMe()", e);
12635 }
12636
12637 try
12638 {
12639 CommunityServerThread.getInstance().sendPacket(new WorldInfo(this, null, WorldInfo.TYPE_UPDATE_PLAYER_STATUS));
12640 }
12641 catch (Exception e)
12642 {
12643 _log.log(Level.SEVERE, "deleteMe()", e);
12644 }
12645 // Recommendations must be saved before task (timer) is canceled
12646 try
12647 {
12648 storeRecommendations();
12649 }
12650 catch (Exception e)
12651 {
12652 _log.log(Level.SEVERE, "deleteMe()", e);
12653 }
12654 // Stop the HP/MP/CP Regeneration task (scheduled tasks)
12655 try
12656 {
12657 stopAllTimers();
12658 }
12659 catch (Exception e)
12660 {
12661 _log.log(Level.SEVERE, "deleteMe()", e);
12662 }
12663
12664 try
12665 {
12666 setIsTeleporting(false);
12667 }
12668 catch (Exception e)
12669 {
12670 _log.log(Level.SEVERE, "deleteMe()", e);
12671 }
12672
12673 // Stop crafting, if in progress
12674 try
12675 {
12676 RecipeController.getInstance().requestMakeItemAbort(this);
12677 }
12678 catch (Exception e)
12679 {
12680 _log.log(Level.SEVERE, "deleteMe()", e);
12681 }
12682
12683 // Cancel Attak or Cast
12684 try
12685 {
12686 setTarget(null);
12687 }
12688 catch (Exception e)
12689 {
12690 _log.log(Level.SEVERE, "deleteMe()", e);
12691 }
12692
12693 // Bot punishment
12694 if (Config.ENABLE_BOTREPORT)
12695 {
12696 // Save punish
12697 if (isBeingPunished())
12698 {
12699 try
12700 {
12701 BotManager.getInstance().savePlayerPunish(this);
12702 }
12703 catch (Exception e)
12704 {
12705 _log.log(Level.SEVERE, "deleteMe()", e);
12706 }
12707 }
12708 // Save report points left
12709 if (_account != null)
12710 {
12711 try
12712 {
12713 _account.updatePoints(this._accountName);
12714 }
12715 catch (Exception e)
12716 {
12717 e.printStackTrace();
12718 }
12719 }
12720 }
12721
12722 try
12723 {
12724 if (_fusionSkill != null)
12725 {
12726 abortCast();
12727 }
12728
12729 for (L2Character character : getKnownList().getKnownCharacters())
12730 {
12731 if ((character.getFusionSkill() != null) && (character.getFusionSkill().getTarget() == this))
12732 {
12733 character.abortCast();
12734 }
12735 }
12736 }
12737 catch (Exception e)
12738 {
12739 _log.log(Level.SEVERE, "deleteMe()", e);
12740 }
12741
12742 try
12743 {
12744 for (L2Effect effect : getAllEffects())
12745 {
12746 if (effect.getSkill().isToggle())
12747 {
12748 effect.exit();
12749 continue;
12750 }
12751
12752 switch (effect.getEffectType())
12753 {
12754 case SIGNET_GROUND:
12755 case SIGNET_EFFECT:
12756 effect.exit();
12757 break;
12758 }
12759 }
12760 }
12761 catch (Exception e)
12762 {
12763 _log.log(Level.SEVERE, "deleteMe()", e);
12764 }
12765
12766 // Remove from world regions zones
12767 final L2WorldRegion oldRegion = getWorldRegion();
12768
12769 if (oldRegion != null)
12770 {
12771 oldRegion.removeFromZones(this);
12772 }
12773
12774 // Remove the L2PcInstance from the world
12775 try
12776 {
12777 decayMe();
12778 }
12779 catch (Exception e)
12780 {
12781 _log.log(Level.SEVERE, "deleteMe()", e);
12782 }
12783
12784 // If a Party is in progress, leave it (and festival party)
12785 if (isInParty())
12786 {
12787 try
12788 {
12789 leaveParty();
12790 }
12791 catch (Exception e)
12792 {
12793 _log.log(Level.SEVERE, "deleteMe()", e);
12794 }
12795 }
12796
12797 if (OlympiadManager.getInstance().isRegistered(this) || (getOlympiadGameId() != -1))
12798 {
12799 OlympiadManager.getInstance().removeDisconnectedCompetitor(this);
12800 }
12801
12802 // If the L2PcInstance has Pet, unsummon it
12803 if (hasSummon())
12804 {
12805 try
12806 {
12807 getSummon().setRestoreSummon(true);
12808
12809 getSummon().unSummon(this);
12810 // Dead pet wasn't unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
12811 if (hasSummon())
12812 {
12813 getSummon().broadcastNpcInfo(0);
12814 }
12815 }
12816 catch (Exception e)
12817 {
12818 _log.log(Level.SEVERE, "deleteMe()", e);
12819 }// returns pet to control item
12820 }
12821
12822 if (getClan() != null)
12823 {
12824 // set the status for pledge member list to OFFLINE
12825 try
12826 {
12827 L2ClanMember clanMember = getClan().getClanMember(getObjectId());
12828 if (clanMember != null)
12829 {
12830 clanMember.setPlayerInstance(null);
12831 }
12832
12833 }
12834 catch (Exception e)
12835 {
12836 _log.log(Level.SEVERE, "deleteMe()", e);
12837 }
12838 }
12839
12840 if (getActiveRequester() != null)
12841 {
12842 // deals with sudden exit in the middle of transaction
12843 setActiveRequester(null);
12844 cancelActiveTrade();
12845 }
12846
12847 // If the L2PcInstance is a GM, remove it from the GM List
12848 if (isGM())
12849 {
12850 try
12851 {
12852 AdminTable.getInstance().deleteGm(this);
12853 }
12854 catch (Exception e)
12855 {
12856 _log.log(Level.SEVERE, "deleteMe()", e);
12857 }
12858 }
12859
12860 try
12861 {
12862 // Check if the L2PcInstance is in observer mode to set its position to its position
12863 // before entering in observer mode
12864 if (inObserverMode())
12865 {
12866 setXYZInvisible(_lastX, _lastY, _lastZ);
12867 }
12868
12869 if (getVehicle() != null)
12870 {
12871 getVehicle().oustPlayer(this);
12872 }
12873 }
12874 catch (Exception e)
12875 {
12876 _log.log(Level.SEVERE, "deleteMe()", e);
12877 }
12878
12879 // remove player from instance and set spawn location if any
12880 try
12881 {
12882 final int instanceId = getInstanceId();
12883 if ((instanceId != 0) && !Config.RESTORE_PLAYER_INSTANCE)
12884 {
12885 final Instance inst = InstanceManager.getInstance().getInstance(instanceId);
12886 if (inst != null)
12887 {
12888 inst.removePlayer(getObjectId());
12889 final Location loc = inst.getSpawnLoc();
12890 if (loc != null)
12891 {
12892 final int x = loc.getX() + Rnd.get(-30, 30);
12893 final int y = loc.getY() + Rnd.get(-30, 30);
12894 setXYZInvisible(x, y, loc.getZ());
12895 if (hasSummon()) // dead pet
12896 {
12897 getSummon().teleToLocation(loc, true);
12898 getSummon().setInstanceId(0);
12899 }
12900 }
12901 }
12902 }
12903 }
12904 catch (Exception e)
12905 {
12906 _log.log(Level.SEVERE, "deleteMe()", e);
12907 }
12908
12909 // TvT Event removal
12910 try
12911 {
12912 TvTEvent.onLogout(this);
12913 }
12914 catch (Exception e)
12915 {
12916 _log.log(Level.SEVERE, "deleteMe()", e);
12917 }
12918
12919 // TvT Round Event removal
12920 try
12921 {
12922 TvTRoundEvent.onLogout(this);
12923 }
12924 catch (Exception e)
12925 {
12926 _log.log(Level.SEVERE, "deleteMe()", e);
12927 }
12928
12929 // Update database with items in its inventory and remove them from the world
12930 try
12931 {
12932 getInventory().deleteMe();
12933 }
12934 catch (Exception e)
12935 {
12936 _log.log(Level.SEVERE, "deleteMe()", e);
12937 }
12938
12939 // Update database with items in its warehouse and remove them from the world
12940 try
12941 {
12942 clearWarehouse();
12943 }
12944 catch (Exception e)
12945 {
12946 _log.log(Level.SEVERE, "deleteMe()", e);
12947 }
12948 if (Config.WAREHOUSE_CACHE)
12949 {
12950 WarehouseCacheManager.getInstance().remCacheTask(this);
12951 }
12952
12953 try
12954 {
12955 getFreight().deleteMe();
12956 }
12957 catch (Exception e)
12958 {
12959 _log.log(Level.SEVERE, "deleteMe()", e);
12960 }
12961
12962 try
12963 {
12964 clearRefund();
12965 }
12966 catch (Exception e)
12967 {
12968 _log.log(Level.SEVERE, "deleteMe()", e);
12969 }
12970
12971 if (isCursedWeaponEquipped())
12972 {
12973 try
12974 {
12975 CursedWeaponsManager.getInstance().getCursedWeapon(_cursedWeaponEquippedId).setPlayer(null);
12976 }
12977 catch (Exception e)
12978 {
12979 _log.log(Level.SEVERE, "deleteMe()", e);
12980 }
12981 }
12982
12983 // Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI
12984 try
12985 {
12986 getKnownList().removeAllKnownObjects();
12987 }
12988 catch (Exception e)
12989 {
12990 _log.log(Level.SEVERE, "deleteMe()", e);
12991 }
12992
12993 if (getClanId() > 0)
12994 {
12995 getClan().broadcastToOtherOnlineMembers(new PledgeShowMemberListUpdate(this), this);
12996 // ClanTable.getInstance().getClan(getClanId()).broadcastToOnlineMembers(new PledgeShowMemberListAdd(this));
12997 }
12998
12999 for (L2PcInstance player : _snoopedPlayer)
13000 {
13001 player.removeSnooper(this);
13002 }
13003
13004 for (L2PcInstance player : _snoopListener)
13005 {
13006 player.removeSnooped(this);
13007 }
13008
13009 // Remove L2Object object from _allObjects of L2World
13010 L2World.getInstance().removeObject(this);
13011 L2World.getInstance().removeFromAllPlayers(this); // force remove in case of crash during teleport
13012
13013 // update bbs
13014 try
13015 {
13016 RegionBBSManager.getInstance().changeCommunityBoard();
13017 }
13018 catch (Exception e)
13019 {
13020 _log.log(Level.WARNING, "Exception on deleteMe() changeCommunityBoard: " + e.getMessage(), e);
13021 }
13022
13023 try
13024 {
13025 notifyFriends();
13026 getBlockList().playerLogout();
13027 }
13028 catch (Exception e)
13029 {
13030 _log.log(Level.WARNING, "Exception on deleteMe() notifyFriends: " + e.getMessage(), e);
13031 }
13032 }
13033
13034 private L2Fish _fish;
13035
13036 // startFishing() was stripped of any pre-fishing related checks, namely the fishing zone check.
13037 // Also worthy of note is the fact the code to find the hook landing position was also striped.
13038 // The stripped code was moved into fishing.java.
13039 // In my opinion it makes more sense for it to be there since all other skill related checks were also there.
13040 // Last but not least, moving the zone check there, fixed a bug where baits would always be consumed no matter if fishing actualy took place.
13041 // startFishing() now takes up 3 arguments, wich are acurately described as being the hook landing coordinates.
13042 public void startFishing(int _x, int _y, int _z)
13043 {
13044 stopMove(null);
13045 setIsImmobilized(true);
13046 _fishing = true;
13047 _fishx = _x;
13048 _fishy = _y;
13049 _fishz = _z;
13050 // broadcastUserInfo();
13051 // Starts fishing
13052 int lvl = getRandomFishLvl();
13053 int grade = getRandomFishGrade();
13054 int group = getRandomFishGroup(grade);
13055 List<L2Fish> fishs = FishData.getInstance().getFish(lvl, group, grade);
13056 if ((fishs == null) || fishs.isEmpty())
13057 {
13058 sendMessage("Error - Fishes are not definied");
13059 endFishing(false);
13060 return;
13061 }
13062 int check = Rnd.get(fishs.size());
13063 // Use a copy constructor else the fish data may be over-written below
13064 _fish = fishs.get(check).clone();
13065 fishs.clear();
13066 fishs = null;
13067 sendPacket(SystemMessageId.CAST_LINE_AND_START_FISHING);
13068 if (!GameTimeController.getInstance().isNowNight() && _lure.isNightLure())
13069 {
13070 _fish.setFishGroup(-1);
13071 }
13072 // sendMessage("Hook x,y: " + _x + "," + _y + " - Water Z, Player Z:" + _z + ", " + getZ()); //debug line, uncoment to show coordinates used in fishing.
13073 broadcastPacket(new ExFishingStart(this, _fish.getFishGroup(), _x, _y, _z, _lure.isNightLure()));
13074 sendPacket(new PlaySound(1, "SF_P_01", 0, 0, 0, 0, 0));
13075 startLookingForFishTask();
13076 }
13077
13078 public void stopLookingForFishTask()
13079 {
13080 if (_taskforfish != null)
13081 {
13082 _taskforfish.cancel(false);
13083 _taskforfish = null;
13084 }
13085 }
13086
13087 public void startLookingForFishTask()
13088 {
13089 if (!isDead() && (_taskforfish == null))
13090 {
13091 int checkDelay = 0;
13092 boolean isNoob = false;
13093 boolean isUpperGrade = false;
13094
13095 if (_lure != null)
13096 {
13097 int lureid = _lure.getItemId();
13098 isNoob = _fish.getFishGrade() == 0;
13099 isUpperGrade = _fish.getFishGrade() == 2;
13100 if ((lureid == 6519) || (lureid == 6522) || (lureid == 6525) || (lureid == 8505) || (lureid == 8508) || (lureid == 8511))
13101 {
13102 checkDelay = _fish.getGutsCheckTime() * 133;
13103 }
13104 else if ((lureid == 6520) || (lureid == 6523) || (lureid == 6526) || ((lureid >= 8505) && (lureid <= 8513)) || ((lureid >= 7610) && (lureid <= 7613)) || ((lureid >= 7807) && (lureid <= 7809)) || ((lureid >= 8484) && (lureid <= 8486)))
13105 {
13106 checkDelay = _fish.getGutsCheckTime() * 100;
13107 }
13108 else if ((lureid == 6521) || (lureid == 6524) || (lureid == 6527) || (lureid == 8507) || (lureid == 8510) || (lureid == 8513))
13109 {
13110 checkDelay = _fish.getGutsCheckTime() * 66;
13111 }
13112 }
13113 _taskforfish = ThreadPoolManager.getInstance().scheduleEffectAtFixedRate(new LookingForFishTask(_fish.getStartCombatTime(), _fish.getFishGuts(), _fish.getFishGroup(), isNoob, isUpperGrade), 10000, checkDelay);
13114 }
13115 }
13116
13117 private int getRandomFishGrade()
13118 {
13119 switch (_lure.getItemId())
13120 {
13121 case 7807: // green for beginners
13122 case 7808: // purple for beginners
13123 case 7809: // yellow for beginners
13124 case 8486: // prize-winning for beginners
13125 return 0;
13126 case 8485: // prize-winning luminous
13127 case 8506: // green luminous
13128 case 8509: // purple luminous
13129 case 8512: // yellow luminous
13130 return 2;
13131 default:
13132 return 1;
13133 }
13134 }
13135
13136 private int getRandomFishGroup(int group)
13137 {
13138 int check = Rnd.get(100);
13139 int type = 1;
13140 switch (group)
13141 {
13142 case 0: // fish for novices
13143 switch (_lure.getItemId())
13144 {
13145 case 7807: // green lure, preferred by fast-moving (nimble) fish (type 5)
13146 if (check <= 54)
13147 {
13148 type = 5;
13149 }
13150 else if (check <= 77)
13151 {
13152 type = 4;
13153 }
13154 else
13155 {
13156 type = 6;
13157 }
13158 break;
13159 case 7808: // purple lure, preferred by fat fish (type 4)
13160 if (check <= 54)
13161 {
13162 type = 4;
13163 }
13164 else if (check <= 77)
13165 {
13166 type = 6;
13167 }
13168 else
13169 {
13170 type = 5;
13171 }
13172 break;
13173 case 7809: // yellow lure, preferred by ugly fish (type 6)
13174 if (check <= 54)
13175 {
13176 type = 6;
13177 }
13178 else if (check <= 77)
13179 {
13180 type = 5;
13181 }
13182 else
13183 {
13184 type = 4;
13185 }
13186 break;
13187 case 8486: // prize-winning fishing lure for beginners
13188 if (check <= 33)
13189 {
13190 type = 4;
13191 }
13192 else if (check <= 66)
13193 {
13194 type = 5;
13195 }
13196 else
13197 {
13198 type = 6;
13199 }
13200 break;
13201 }
13202 break;
13203 case 1: // normal fish
13204 switch (_lure.getItemId())
13205 {
13206 case 7610:
13207 case 7611:
13208 case 7612:
13209 case 7613:
13210 type = 3;
13211 break;
13212 case 6519: // all theese lures (green) are prefered by fast-moving (nimble) fish (type 1)
13213 case 8505:
13214 case 6520:
13215 case 6521:
13216 case 8507:
13217 if (check <= 54)
13218 {
13219 type = 1;
13220 }
13221 else if (check <= 74)
13222 {
13223 type = 0;
13224 }
13225 else if (check <= 94)
13226 {
13227 type = 2;
13228 }
13229 else
13230 {
13231 type = 3;
13232 }
13233 break;
13234 case 6522: // all theese lures (purple) are prefered by fat fish (type 0)
13235 case 8508:
13236 case 6523:
13237 case 6524:
13238 case 8510:
13239 if (check <= 54)
13240 {
13241 type = 0;
13242 }
13243 else if (check <= 74)
13244 {
13245 type = 1;
13246 }
13247 else if (check <= 94)
13248 {
13249 type = 2;
13250 }
13251 else
13252 {
13253 type = 3;
13254 }
13255 break;
13256 case 6525: // all theese lures (yellow) are prefered by ugly fish (type 2)
13257 case 8511:
13258 case 6526:
13259 case 6527:
13260 case 8513:
13261 if (check <= 55)
13262 {
13263 type = 2;
13264 }
13265 else if (check <= 74)
13266 {
13267 type = 1;
13268 }
13269 else if (check <= 94)
13270 {
13271 type = 0;
13272 }
13273 else
13274 {
13275 type = 3;
13276 }
13277 break;
13278 case 8484: // prize-winning fishing lure
13279 if (check <= 33)
13280 {
13281 type = 0;
13282 }
13283 else if (check <= 66)
13284 {
13285 type = 1;
13286 }
13287 else
13288 {
13289 type = 2;
13290 }
13291 break;
13292 }
13293 break;
13294 case 2: // upper grade fish, luminous lure
13295 switch (_lure.getItemId())
13296 {
13297 case 8506: // green lure, preferred by fast-moving (nimble) fish (type 8)
13298 if (check <= 54)
13299 {
13300 type = 8;
13301 }
13302 else if (check <= 77)
13303 {
13304 type = 7;
13305 }
13306 else
13307 {
13308 type = 9;
13309 }
13310 break;
13311 case 8509: // purple lure, preferred by fat fish (type 7)
13312 if (check <= 54)
13313 {
13314 type = 7;
13315 }
13316 else if (check <= 77)
13317 {
13318 type = 9;
13319 }
13320 else
13321 {
13322 type = 8;
13323 }
13324 break;
13325 case 8512: // yellow lure, preferred by ugly fish (type 9)
13326 if (check <= 54)
13327 {
13328 type = 9;
13329 }
13330 else if (check <= 77)
13331 {
13332 type = 8;
13333 }
13334 else
13335 {
13336 type = 7;
13337 }
13338 break;
13339 case 8485: // prize-winning fishing lure
13340 if (check <= 33)
13341 {
13342 type = 7;
13343 }
13344 else if (check <= 66)
13345 {
13346 type = 8;
13347 }
13348 else
13349 {
13350 type = 9;
13351 }
13352 break;
13353 }
13354 }
13355 return type;
13356 }
13357
13358 private int getRandomFishLvl()
13359 {
13360 int skilllvl = getSkillLevel(1315);
13361 final L2Effect e = getFirstEffect(2274);
13362 if (e != null)
13363 {
13364 skilllvl = (int) e.getSkill().getPower();
13365 }
13366 if (skilllvl <= 0)
13367 {
13368 return 1;
13369 }
13370 int randomlvl;
13371 int check = Rnd.get(100);
13372
13373 if (check <= 50)
13374 {
13375 randomlvl = skilllvl;
13376 }
13377 else if (check <= 85)
13378 {
13379 randomlvl = skilllvl - 1;
13380 if (randomlvl <= 0)
13381 {
13382 randomlvl = 1;
13383 }
13384 }
13385 else
13386 {
13387 randomlvl = skilllvl + 1;
13388 if (randomlvl > 27)
13389 {
13390 randomlvl = 27;
13391 }
13392 }
13393
13394 return randomlvl;
13395 }
13396
13397 public void startFishCombat(boolean isNoob, boolean isUpperGrade)
13398 {
13399 _fishCombat = new L2Fishing(this, _fish, isNoob, isUpperGrade);
13400 }
13401
13402 public void endFishing(boolean win)
13403 {
13404 _fishing = false;
13405 _fishx = 0;
13406 _fishy = 0;
13407 _fishz = 0;
13408 // broadcastUserInfo();
13409 if (_fishCombat == null)
13410 {
13411 sendPacket(SystemMessageId.BAIT_LOST_FISH_GOT_AWAY);
13412 }
13413 _fishCombat = null;
13414 _lure = null;
13415 // Ends fishing
13416 broadcastPacket(new ExFishingEnd(win, this));
13417 sendPacket(SystemMessageId.REEL_LINE_AND_STOP_FISHING);
13418 setIsImmobilized(false);
13419 stopLookingForFishTask();
13420 }
13421
13422 public L2Fishing getFishCombat()
13423 {
13424 return _fishCombat;
13425 }
13426
13427 public int getFishx()
13428 {
13429 return _fishx;
13430 }
13431
13432 public int getFishy()
13433 {
13434 return _fishy;
13435 }
13436
13437 public int getFishz()
13438 {
13439 return _fishz;
13440 }
13441
13442 public void setLure(L2ItemInstance lure)
13443 {
13444 _lure = lure;
13445 }
13446
13447 public L2ItemInstance getLure()
13448 {
13449 return _lure;
13450 }
13451
13452 public int getInventoryLimit()
13453 {
13454 int ivlim;
13455 if (isGM())
13456 {
13457 ivlim = Config.INVENTORY_MAXIMUM_GM;
13458 }
13459 else if (getRace() == Race.Dwarf)
13460 {
13461 ivlim = Config.INVENTORY_MAXIMUM_DWARF;
13462 }
13463 else
13464 {
13465 ivlim = Config.INVENTORY_MAXIMUM_NO_DWARF;
13466 }
13467 ivlim += (int) getStat().calcStat(Stats.INV_LIM, 0, null, null);
13468
13469 return ivlim;
13470 }
13471
13472 public int getWareHouseLimit()
13473 {
13474 int whlim;
13475 if (getRace() == Race.Dwarf)
13476 {
13477 whlim = Config.WAREHOUSE_SLOTS_DWARF;
13478 }
13479 else
13480 {
13481 whlim = Config.WAREHOUSE_SLOTS_NO_DWARF;
13482 }
13483
13484 whlim += (int) getStat().calcStat(Stats.WH_LIM, 0, null, null);
13485
13486 return whlim;
13487 }
13488
13489 public int getPrivateSellStoreLimit()
13490 {
13491 int pslim;
13492
13493 if (getRace() == Race.Dwarf)
13494 {
13495 pslim = Config.MAX_PVTSTORESELL_SLOTS_DWARF;
13496 }
13497 else
13498 {
13499 pslim = Config.MAX_PVTSTORESELL_SLOTS_OTHER;
13500 }
13501
13502 pslim += (int) getStat().calcStat(Stats.P_SELL_LIM, 0, null, null);
13503
13504 return pslim;
13505 }
13506
13507 public int getPrivateBuyStoreLimit()
13508 {
13509 int pblim;
13510
13511 if (getRace() == Race.Dwarf)
13512 {
13513 pblim = Config.MAX_PVTSTOREBUY_SLOTS_DWARF;
13514 }
13515 else
13516 {
13517 pblim = Config.MAX_PVTSTOREBUY_SLOTS_OTHER;
13518 }
13519 pblim += (int) getStat().calcStat(Stats.P_BUY_LIM, 0, null, null);
13520
13521 return pblim;
13522 }
13523
13524 public int getDwarfRecipeLimit()
13525 {
13526 int recdlim = Config.DWARF_RECIPE_LIMIT;
13527 recdlim += (int) getStat().calcStat(Stats.REC_D_LIM, 0, null, null);
13528 return recdlim;
13529 }
13530
13531 public int getCommonRecipeLimit()
13532 {
13533 int recclim = Config.COMMON_RECIPE_LIMIT;
13534 recclim += (int) getStat().calcStat(Stats.REC_C_LIM, 0, null, null);
13535 return recclim;
13536 }
13537
13538 /**
13539 * @return Returns the mountNpcId.
13540 */
13541 public int getMountNpcId()
13542 {
13543 return _mountNpcId;
13544 }
13545
13546 /**
13547 * @return Returns the mountLevel.
13548 */
13549 public int getMountLevel()
13550 {
13551 return _mountLevel;
13552 }
13553
13554 public void setMountObjectID(int newID)
13555 {
13556 _mountObjectID = newID;
13557 }
13558
13559 public int getMountObjectID()
13560 {
13561 return _mountObjectID;
13562 }
13563
13564 private L2ItemInstance _lure = null;
13565 private int _shortBuffTaskSkillId = 0;
13566
13567 /**
13568 * @return the current skill in use or return null.
13569 */
13570 public SkillDat getCurrentSkill()
13571 {
13572 return _currentSkill;
13573 }
13574
13575 /**
13576 * Create a new SkillDat object and set the player _currentSkill.
13577 * @param currentSkill
13578 * @param ctrlPressed
13579 * @param shiftPressed
13580 */
13581 public void setCurrentSkill(L2Skill currentSkill, boolean ctrlPressed, boolean shiftPressed)
13582 {
13583 if (currentSkill == null)
13584 {
13585 _currentSkill = null;
13586 return;
13587 }
13588 _currentSkill = new SkillDat(currentSkill, ctrlPressed, shiftPressed);
13589 }
13590
13591 /**
13592 * @return the current pet skill in use or return null.
13593 */
13594 public SkillDat getCurrentPetSkill()
13595 {
13596 return _currentPetSkill;
13597 }
13598
13599 /**
13600 * Create a new SkillDat object and set the player _currentPetSkill.
13601 * @param currentSkill
13602 * @param ctrlPressed
13603 * @param shiftPressed
13604 */
13605 public void setCurrentPetSkill(L2Skill currentSkill, boolean ctrlPressed, boolean shiftPressed)
13606 {
13607 if (currentSkill == null)
13608 {
13609 _currentPetSkill = null;
13610 return;
13611 }
13612 _currentPetSkill = new SkillDat(currentSkill, ctrlPressed, shiftPressed);
13613 }
13614
13615 public SkillDat getQueuedSkill()
13616 {
13617 return _queuedSkill;
13618 }
13619
13620 /**
13621 * Create a new SkillDat object and queue it in the player _queuedSkill.
13622 * @param queuedSkill
13623 * @param ctrlPressed
13624 * @param shiftPressed
13625 */
13626 public void setQueuedSkill(L2Skill queuedSkill, boolean ctrlPressed, boolean shiftPressed)
13627 {
13628 if (queuedSkill == null)
13629 {
13630 _queuedSkill = null;
13631 return;
13632 }
13633 _queuedSkill = new SkillDat(queuedSkill, ctrlPressed, shiftPressed);
13634 }
13635
13636 /**
13637 * returns punishment level of player
13638 * @return
13639 */
13640 public PunishLevel getPunishLevel()
13641 {
13642 return _punishLevel;
13643 }
13644
13645 /**
13646 * @return True if player is jailed
13647 */
13648 public boolean isInJail()
13649 {
13650 return _punishLevel == PunishLevel.JAIL;
13651 }
13652
13653 /**
13654 * @return True if player is chat banned
13655 */
13656 public boolean isChatBanned()
13657 {
13658 return _punishLevel == PunishLevel.CHAT;
13659 }
13660
13661 public void setPunishLevel(int state)
13662 {
13663 switch (state)
13664 {
13665 case 0:
13666 {
13667 _punishLevel = PunishLevel.NONE;
13668 break;
13669 }
13670 case 1:
13671 {
13672 _punishLevel = PunishLevel.CHAT;
13673 break;
13674 }
13675 case 2:
13676 {
13677 _punishLevel = PunishLevel.JAIL;
13678 break;
13679 }
13680 case 3:
13681 {
13682 _punishLevel = PunishLevel.CHAR;
13683 break;
13684 }
13685 case 4:
13686 {
13687 _punishLevel = PunishLevel.ACC;
13688 break;
13689 }
13690 }
13691 }
13692
13693 /**
13694 * Sets punish level for player based on delay
13695 * @param state
13696 * @param delayInMinutes 0 - Indefinite
13697 */
13698 public void setPunishLevel(PunishLevel state, int delayInMinutes)
13699 {
13700 long delayInMilliseconds = delayInMinutes * 60000L;
13701 switch (state)
13702 {
13703 case NONE: // Remove Punishments
13704 {
13705 switch (_punishLevel)
13706 {
13707 case CHAT:
13708 {
13709 _punishLevel = state;
13710 stopPunishTask(true);
13711 sendPacket(new EtcStatusUpdate(this));
13712 sendMessage("Your Chat ban has been lifted");
13713 break;
13714 }
13715 case JAIL:
13716 {
13717 _punishLevel = state;
13718 // Open a Html message to inform the player
13719 NpcHtmlMessage htmlMsg = new NpcHtmlMessage(0);
13720 String jailInfos = HtmCache.getInstance().getHtm(getHtmlPrefix(), "data/html/jail_out.htm");
13721 if (jailInfos != null)
13722 {
13723 htmlMsg.setHtml(jailInfos);
13724 }
13725 else
13726 {
13727 htmlMsg.setHtml("<html><body>You are free for now, respect server rules!</body></html>");
13728 }
13729 sendPacket(htmlMsg);
13730 stopPunishTask(true);
13731 teleToLocation(17836, 170178, -3507, true); // Floran
13732 break;
13733 }
13734 }
13735 break;
13736 }
13737 case CHAT: // Chat Ban
13738 {
13739 // not allow player to escape jail using chat ban
13740 if (_punishLevel == PunishLevel.JAIL)
13741 {
13742 break;
13743 }
13744 _punishLevel = state;
13745 _punishTimer = 0;
13746 sendPacket(new EtcStatusUpdate(this));
13747 // Remove the task if any
13748 stopPunishTask(false);
13749
13750 if (delayInMinutes > 0)
13751 {
13752 _punishTimer = delayInMilliseconds;
13753
13754 // start the countdown
13755 _punishTask = ThreadPoolManager.getInstance().scheduleGeneral(new PunishTask(), _punishTimer);
13756 sendMessage("You are chat banned for " + delayInMinutes + " minutes.");
13757 }
13758 else
13759 {
13760 sendMessage("You have been chat banned");
13761 }
13762 break;
13763
13764 }
13765 case JAIL: // Jail Player
13766 {
13767 _punishLevel = state;
13768 _punishTimer = 0;
13769 // Remove the task if any
13770 stopPunishTask(false);
13771
13772 if (delayInMinutes > 0)
13773 {
13774 _punishTimer = delayInMilliseconds;
13775
13776 // start the countdown
13777 _punishTask = ThreadPoolManager.getInstance().scheduleGeneral(new PunishTask(), _punishTimer);
13778 sendMessage("You are in jail for " + delayInMinutes + " minutes.");
13779 }
13780
13781 if (!TvTEvent.isInactive() && TvTEvent.isPlayerParticipant(getObjectId()))
13782 {
13783 TvTEvent.removeParticipant(getObjectId());
13784 }
13785 if (!TvTRoundEvent.isInactive() && TvTRoundEvent.isPlayerParticipant(getObjectId()))
13786 {
13787 TvTRoundEvent.removeParticipant(getObjectId());
13788 }
13789 if (OlympiadManager.getInstance().isRegisteredInComp(this))
13790 {
13791 OlympiadManager.getInstance().removeDisconnectedCompetitor(this);
13792 }
13793
13794 // Open a Html message to inform the player
13795 NpcHtmlMessage htmlMsg = new NpcHtmlMessage(0);
13796 String jailInfos = HtmCache.getInstance().getHtm(getHtmlPrefix(), "data/html/jail_in.htm");
13797 if (jailInfos != null)
13798 {
13799 htmlMsg.setHtml(jailInfos);
13800 }
13801 else
13802 {
13803 htmlMsg.setHtml("<html><body>You have been put in jail by an admin.</body></html>");
13804 }
13805 sendPacket(htmlMsg);
13806 setInstanceId(0);
13807 setIsIn7sDungeon(false);
13808
13809 teleToLocation(-114356, -249645, -2984, false); // Jail
13810 break;
13811 }
13812 case CHAR: // Ban Character
13813 {
13814 setAccessLevel(-1);
13815 logout();
13816 break;
13817 }
13818 case ACC: // Ban Account
13819 {
13820 setAccountAccesslevel(-1);
13821 logout();
13822 break;
13823 }
13824 default:
13825 {
13826 _punishLevel = state;
13827 break;
13828 }
13829 }
13830
13831 // store in database
13832 storeCharBase();
13833 }
13834
13835 public long getPunishTimer()
13836 {
13837 return _punishTimer;
13838 }
13839
13840 public void setPunishTimer(long time)
13841 {
13842 _punishTimer = time;
13843 }
13844
13845 private void updatePunishState()
13846 {
13847 if (getPunishLevel() != PunishLevel.NONE)
13848 {
13849 // If punish timer exists, restart punishtask.
13850 if (_punishTimer > 0)
13851 {
13852 _punishTask = ThreadPoolManager.getInstance().scheduleGeneral(new PunishTask(), _punishTimer);
13853 sendMessage("You are still " + getPunishLevel().string() + " for " + Math.round(_punishTimer / 60000f) + " minutes.");
13854 }
13855 if (getPunishLevel() == PunishLevel.JAIL)
13856 {
13857 // If player escaped, put him back in jail
13858 if (!isInsideZone(ZoneId.JAIL))
13859 {
13860 teleToLocation(-114356, -249645, -2984, true);
13861 }
13862 }
13863 }
13864 }
13865
13866 public void stopPunishTask(boolean save)
13867 {
13868 if (_punishTask != null)
13869 {
13870 if (save)
13871 {
13872 long delay = _punishTask.getDelay(TimeUnit.MILLISECONDS);
13873 if (delay < 0)
13874 {
13875 delay = 0;
13876 }
13877 setPunishTimer(delay);
13878 }
13879 _punishTask.cancel(false);
13880 // ThreadPoolManager.getInstance().removeGeneral((Runnable)_punishTask);
13881 _punishTask = null;
13882 }
13883 }
13884
13885 protected class PunishTask implements Runnable
13886 {
13887 @Override
13888 public void run()
13889 {
13890 L2PcInstance.this.setPunishLevel(PunishLevel.NONE, 0);
13891 }
13892 }
13893
13894 public void startFameTask(long delay, int fameFixRate)
13895 {
13896 if ((getLevel() < 40) || (getClassId().level() < 2))
13897 {
13898 return;
13899 }
13900 if (_fameTask == null)
13901 {
13902 _fameTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FameTask(fameFixRate), delay, delay);
13903 }
13904 }
13905
13906 public void stopFameTask()
13907 {
13908 if (_fameTask != null)
13909 {
13910 _fameTask.cancel(false);
13911 // ThreadPoolManager.getInstance().removeGeneral((Runnable)_fameTask);
13912 _fameTask = null;
13913 }
13914 }
13915
13916 private class FameTask implements Runnable
13917 {
13918 private final L2PcInstance _player;
13919 private final int _value;
13920
13921 protected FameTask(int value)
13922 {
13923 _player = L2PcInstance.this;
13924 _value = value;
13925 }
13926
13927 @Override
13928 public void run()
13929 {
13930 if ((_player == null) || (_player.isDead() && !Config.FAME_FOR_DEAD_PLAYERS))
13931 {
13932 return;
13933 }
13934 if (((_player.getClient() == null) || _player.getClient().isDetached()) && !Config.OFFLINE_FAME)
13935 {
13936 return;
13937 }
13938 _player.setFame(_player.getFame() + _value);
13939 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.ACQUIRED_S1_REPUTATION_SCORE);
13940 sm.addNumber(_value);
13941 _player.sendPacket(sm);
13942 _player.sendPacket(new UserInfo(_player));
13943 }
13944 }
13945
13946 public void startVitalityTask()
13947 {
13948 if (Config.ENABLE_VITALITY && (_vitalityTask == null))
13949 {
13950 _vitalityTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new VitalityTask(this), 1000, 60000);
13951 }
13952 }
13953
13954 public void stopVitalityTask()
13955 {
13956 if (_vitalityTask != null)
13957 {
13958 _vitalityTask.cancel(false);
13959 // ThreadPoolManager.getInstance().removeGeneral((Runnable)_vitalityTask);
13960 _vitalityTask = null;
13961 }
13962 }
13963
13964 private class VitalityTask implements Runnable
13965 {
13966 private final L2PcInstance _player;
13967
13968 protected VitalityTask(L2PcInstance player)
13969 {
13970 _player = player;
13971 }
13972
13973 @Override
13974 public void run()
13975 {
13976 if (!_player.isInsideZone(ZoneId.PEACE))
13977 {
13978 return;
13979 }
13980
13981 if (_player.getVitalityPoints() >= PcStat.MAX_VITALITY_POINTS)
13982 {
13983 return;
13984 }
13985
13986 _player.updateVitalityPoints(Config.RATE_RECOVERY_VITALITY_PEACE_ZONE, false, false);
13987 _player.sendPacket(new ExVitalityPointInfo(getVitalityPoints()));
13988 }
13989 }
13990
13991 /**
13992 * @return
13993 */
13994 public int getPowerGrade()
13995 {
13996 return _powerGrade;
13997 }
13998
13999 /**
14000 * @param power
14001 */
14002 public void setPowerGrade(int power)
14003 {
14004 _powerGrade = power;
14005 }
14006
14007 public boolean isCursedWeaponEquipped()
14008 {
14009 return _cursedWeaponEquippedId != 0;
14010 }
14011
14012 public void setCursedWeaponEquippedId(int value)
14013 {
14014 _cursedWeaponEquippedId = value;
14015 }
14016
14017 public int getCursedWeaponEquippedId()
14018 {
14019 return _cursedWeaponEquippedId;
14020 }
14021
14022 public boolean isCombatFlagEquipped()
14023 {
14024 return _combatFlagEquippedId;
14025 }
14026
14027 public void setCombatFlagEquipped(boolean value)
14028 {
14029 _combatFlagEquippedId = value;
14030 }
14031
14032 public final void setIsRidingStrider(boolean mode)
14033 {
14034 _isRidingStrider = mode;
14035 }
14036
14037 public final boolean isRidingStrider()
14038 {
14039 return _isRidingStrider;
14040 }
14041
14042 /**
14043 * Returns the Number of Souls this L2PcInstance got.
14044 * @return
14045 */
14046 public int getSouls()
14047 {
14048 return _souls;
14049 }
14050
14051 /**
14052 * Absorbs a Soul from a Npc.
14053 * @param skill
14054 * @param npc
14055 */
14056 public void absorbSoul(L2Skill skill, L2Npc npc)
14057 {
14058 if (_souls >= skill.getNumSouls())
14059 {
14060 sendPacket(SystemMessageId.SOUL_CANNOT_BE_INCREASED_ANYMORE);
14061 return;
14062 }
14063
14064 increaseSouls(1);
14065
14066 if (npc != null)
14067 {
14068 broadcastPacket(new ExSpawnEmitter(this, npc), 500);
14069 }
14070 }
14071
14072 /**
14073 * Increase Souls
14074 * @param count
14075 */
14076 public void increaseSouls(int count)
14077 {
14078 if ((count < 0) || (count > 45))
14079 {
14080 return;
14081 }
14082
14083 _souls += count;
14084
14085 if (getSouls() > 45)
14086 {
14087 _souls = 45;
14088 }
14089
14090 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOUR_SOUL_HAS_INCREASED_BY_S1_SO_IT_IS_NOW_AT_S2);
14091 sm.addNumber(count);
14092 sm.addNumber(_souls);
14093 sendPacket(sm);
14094
14095 restartSoulTask();
14096
14097 sendPacket(new EtcStatusUpdate(this));
14098 }
14099
14100 /**
14101 * Decreases existing Souls.
14102 * @param count
14103 * @param skill
14104 * @return
14105 */
14106 public boolean decreaseSouls(int count, L2Skill skill)
14107 {
14108 _souls -= count;
14109
14110 if (getSouls() < 0)
14111 {
14112 _souls = 0;
14113 }
14114
14115 if (getSouls() == 0)
14116 {
14117 stopSoulTask();
14118 }
14119 else
14120 {
14121 restartSoulTask();
14122 }
14123
14124 sendPacket(new EtcStatusUpdate(this));
14125 return true;
14126 }
14127
14128 /**
14129 * Clear out all Souls from this L2PcInstance
14130 */
14131 public void clearSouls()
14132 {
14133 _souls = 0;
14134 stopSoulTask();
14135 sendPacket(new EtcStatusUpdate(this));
14136 }
14137
14138 /**
14139 * Starts/Restarts the SoulTask to Clear Souls after 10 Mins.
14140 */
14141 private void restartSoulTask()
14142 {
14143 synchronized (this)
14144 {
14145 if (_soulTask != null)
14146 {
14147 _soulTask.cancel(false);
14148 _soulTask = null;
14149 }
14150 _soulTask = ThreadPoolManager.getInstance().scheduleGeneral(new SoulTask(), 600000);
14151 }
14152 }
14153
14154 /**
14155 * Stops the Clearing Task.
14156 */
14157 public void stopSoulTask()
14158 {
14159 if (_soulTask != null)
14160 {
14161 _soulTask.cancel(false);
14162 _soulTask = null;
14163 }
14164 }
14165
14166 protected class SoulTask implements Runnable
14167 {
14168 @Override
14169 public void run()
14170 {
14171 clearSouls();
14172 }
14173 }
14174
14175 /**
14176 * @param magicId
14177 * @param level
14178 * @param time
14179 */
14180 public void shortBuffStatusUpdate(int magicId, int level, int time)
14181 {
14182 if (_shortBuffTask != null)
14183 {
14184 _shortBuffTask.cancel(false);
14185 _shortBuffTask = null;
14186 }
14187 _shortBuffTask = ThreadPoolManager.getInstance().scheduleGeneral(new ShortBuffTask(), time * 1000);
14188 setShortBuffTaskSkillId(magicId);
14189
14190 sendPacket(new ShortBuffStatusUpdate(magicId, level, time));
14191 }
14192
14193 public int getShortBuffTaskSkillId()
14194 {
14195 return _shortBuffTaskSkillId;
14196 }
14197
14198 public void setShortBuffTaskSkillId(int id)
14199 {
14200 _shortBuffTaskSkillId = id;
14201 }
14202
14203 public int getDeathPenaltyBuffLevel()
14204 {
14205 return _deathPenaltyBuffLevel;
14206 }
14207
14208 public void setDeathPenaltyBuffLevel(int level)
14209 {
14210 _deathPenaltyBuffLevel = level;
14211 }
14212
14213 public void calculateDeathPenaltyBuffLevel(L2Character killer)
14214 {
14215 if (((getKarma() > 0) || (Rnd.get(1, 100) <= Config.DEATH_PENALTY_CHANCE)) && !(killer instanceof L2PcInstance) && !(canOverrideCond(PcCondOverride.DEATH_PENALTY)) && !(getCharmOfLuck() && killer.isRaid()) && !isPhoenixBlessed() && !isLucky() && !(TvTEvent.isStarted() && TvTEvent.isPlayerParticipant(getObjectId())) && !(TvTRoundEvent.isStarted() && TvTRoundEvent.isPlayerParticipant(getObjectId())) && !(isInsideZone(ZoneId.PVP) || isInsideZone(ZoneId.SIEGE)))
14216 {
14217 increaseDeathPenaltyBuffLevel();
14218 }
14219 }
14220
14221 public void increaseDeathPenaltyBuffLevel()
14222 {
14223 if (getDeathPenaltyBuffLevel() >= 15)
14224 {
14225 return;
14226 }
14227
14228 if (getDeathPenaltyBuffLevel() != 0)
14229 {
14230 L2Skill skill = SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel());
14231
14232 if (skill != null)
14233 {
14234 removeSkill(skill, true);
14235 }
14236 }
14237
14238 _deathPenaltyBuffLevel++;
14239
14240 addSkill(SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel()), false);
14241 sendPacket(new EtcStatusUpdate(this));
14242 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.DEATH_PENALTY_LEVEL_S1_ADDED);
14243 sm.addNumber(getDeathPenaltyBuffLevel());
14244 sendPacket(sm);
14245 }
14246
14247 public void reduceDeathPenaltyBuffLevel()
14248 {
14249 if (getDeathPenaltyBuffLevel() <= 0)
14250 {
14251 return;
14252 }
14253
14254 L2Skill skill = SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel());
14255
14256 if (skill != null)
14257 {
14258 removeSkill(skill, true);
14259 }
14260
14261 _deathPenaltyBuffLevel--;
14262
14263 if (getDeathPenaltyBuffLevel() > 0)
14264 {
14265 addSkill(SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel()), false);
14266 sendPacket(new EtcStatusUpdate(this));
14267 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.DEATH_PENALTY_LEVEL_S1_ADDED);
14268 sm.addNumber(getDeathPenaltyBuffLevel());
14269 sendPacket(sm);
14270 }
14271 else
14272 {
14273 sendPacket(new EtcStatusUpdate(this));
14274 sendPacket(SystemMessageId.DEATH_PENALTY_LIFTED);
14275 }
14276 }
14277
14278 public void restoreDeathPenaltyBuffLevel()
14279 {
14280 if (getDeathPenaltyBuffLevel() > 0)
14281 {
14282 addSkill(SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel()), false);
14283 }
14284 }
14285
14286 private final Map<Integer, TimeStamp> _reuseTimeStampsItems = new FastMap<>();
14287
14288 @Override
14289 public void addTimeStampItem(L2ItemInstance item, long reuse)
14290 {
14291 _reuseTimeStampsItems.put(item.getObjectId(), new TimeStamp(item, reuse));
14292 }
14293
14294 public void addTimeStampItem(L2ItemInstance item, long reuse, long systime)
14295 {
14296 _reuseTimeStampsItems.put(item.getObjectId(), new TimeStamp(item, reuse, systime));
14297 }
14298
14299 @Override
14300 public long getItemRemainingReuseTime(int itemObjId)
14301 {
14302 if (!_reuseTimeStampsItems.containsKey(itemObjId))
14303 {
14304 return -1;
14305 }
14306 return _reuseTimeStampsItems.get(itemObjId).getRemaining();
14307 }
14308
14309 public long getReuseDelayOnGroup(int group)
14310 {
14311 if (group > 0)
14312 {
14313 for (TimeStamp ts : _reuseTimeStampsItems.values())
14314 {
14315 if ((ts.getSharedReuseGroup() == group) && ts.hasNotPassed())
14316 {
14317 return ts.getRemaining();
14318 }
14319 }
14320 }
14321 return 0;
14322 }
14323
14324 private final Map<Integer, TimeStamp> _reuseTimeStampsSkills = new FastMap<>();
14325
14326 public Map<Integer, TimeStamp> getSkillReuseTimeStamps()
14327 {
14328 return _reuseTimeStampsSkills;
14329 }
14330
14331 @Override
14332 public long getSkillRemainingReuseTime(int skillReuseHashId)
14333 {
14334 if (!_reuseTimeStampsSkills.containsKey(skillReuseHashId))
14335 {
14336 return -1;
14337 }
14338 return _reuseTimeStampsSkills.get(skillReuseHashId).getRemaining();
14339 }
14340
14341 public boolean hasSkillReuse(int skillReuseHashId)
14342 {
14343 if (!_reuseTimeStampsSkills.containsKey(skillReuseHashId))
14344 {
14345 return false;
14346 }
14347 return _reuseTimeStampsSkills.get(skillReuseHashId).hasNotPassed();
14348 }
14349
14350 public TimeStamp getSkillReuseTimeStamp(int skillReuseHashId)
14351 {
14352 return _reuseTimeStampsSkills.get(skillReuseHashId);
14353 }
14354
14355 /**
14356 * Index according to skill id the current timestamp of use.
14357 * @param skill
14358 * @param reuse delay
14359 */
14360 @Override
14361 public void addTimeStamp(L2Skill skill, long reuse)
14362 {
14363 _reuseTimeStampsSkills.put(skill.getReuseHashCode(), new TimeStamp(skill, reuse));
14364 }
14365
14366 /**
14367 * Index according to skill this TimeStamp instance for restoration purposes only.
14368 * @param skill
14369 * @param reuse
14370 * @param systime
14371 */
14372 public void addTimeStamp(L2Skill skill, long reuse, long systime)
14373 {
14374 _reuseTimeStampsSkills.put(skill.getReuseHashCode(), new TimeStamp(skill, reuse, systime));
14375 }
14376
14377 @Override
14378 public L2PcInstance getActingPlayer()
14379 {
14380 return this;
14381 }
14382
14383 @Override
14384 public final void sendDamageMessage(L2Character target, int damage, boolean mcrit, boolean pcrit, boolean miss)
14385 {
14386 // Check if hit is missed
14387 if (miss)
14388 {
14389 if (target instanceof L2PcInstance)
14390 {
14391 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_EVADED_C2_ATTACK);
14392 sm.addPcName((L2PcInstance) target);
14393 sm.addCharName(this);
14394 target.sendPacket(sm);
14395 }
14396 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_ATTACK_WENT_ASTRAY);
14397 sm.addPcName(this);
14398 sendPacket(sm);
14399 return;
14400 }
14401
14402 // Check if hit is critical
14403 if (pcrit)
14404 {
14405 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAD_CRITICAL_HIT);
14406 sm.addPcName(this);
14407 sendPacket(sm);
14408 if ((target instanceof L2Npc) && (getSkillLevel(467) > 0))
14409 {
14410 L2Skill skill = SkillTable.getInstance().getInfo(467, getSkillLevel(467));
14411 if (Rnd.get(100) < skill.getCritChance())
14412 {
14413 absorbSoul(skill, ((L2Npc) target));
14414 }
14415 }
14416 }
14417 if (mcrit)
14418 {
14419 sendPacket(SystemMessageId.CRITICAL_HIT_MAGIC);
14420 }
14421
14422 if (isInOlympiadMode() && (target instanceof L2PcInstance) && ((L2PcInstance) target).isInOlympiadMode() && ((((L2PcInstance) target).getOlympiadGameId() == getOlympiadGameId()) && !((L2PcInstance) target).isInvul() && !((L2PcInstance) target).inObserverMode()))
14423 {
14424 OlympiadGameManager.getInstance().notifyCompetitorDamage(this, damage);
14425 }
14426
14427 final SystemMessage sm;
14428
14429 if (target.isInvul() && !(target instanceof L2Npc))
14430 {
14431 sm = SystemMessage.getSystemMessage(SystemMessageId.ATTACK_WAS_BLOCKED);
14432 }
14433 else if ((target instanceof L2DoorInstance) || (target instanceof L2ControlTowerInstance))
14434 {
14435 sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_DID_S1_DMG);
14436 sm.addNumber(damage);
14437 }
14438 else
14439 {
14440 sm = SystemMessage.getSystemMessage(SystemMessageId.C1_GAVE_C2_DAMAGE_OF_S3);
14441 sm.addPcName(this);
14442 sm.addCharName(target);
14443 sm.addNumber(damage);
14444 }
14445
14446 sendPacket(sm);
14447 }
14448
14449 /**
14450 * @param npcId
14451 */
14452 public void setAgathionId(int npcId)
14453 {
14454 _agathionId = npcId;
14455 }
14456
14457 /**
14458 * @return
14459 */
14460 public int getAgathionId()
14461 {
14462 return _agathionId;
14463 }
14464
14465 public int getVitalityPoints()
14466 {
14467 return getStat().getVitalityPoints();
14468 }
14469
14470 /**
14471 * @return Vitality Level
14472 */
14473 public int getVitalityLevel()
14474 {
14475 return getStat().getVitalityLevel();
14476 }
14477
14478 public void setVitalityPoints(int points, boolean quiet)
14479 {
14480 getStat().setVitalityPoints(points, quiet);
14481 }
14482
14483 public void updateVitalityPoints(float points, boolean useRates, boolean quiet)
14484 {
14485 getStat().updateVitalityPoints(points, useRates, quiet);
14486 }
14487
14488 /**
14489 * Function for skill summon friend or Gate Chant. Request Teleport
14490 * @param requester
14491 * @param skill
14492 * @return
14493 */
14494 public boolean teleportRequest(L2PcInstance requester, L2Skill skill)
14495 {
14496 if ((_summonRequest.getTarget() != null) && (requester != null))
14497 {
14498 return false;
14499 }
14500 _summonRequest.setTarget(requester, skill);
14501 return true;
14502 }
14503
14504 /**
14505 * Action teleport
14506 * @param answer
14507 * @param requesterId
14508 */
14509 public void teleportAnswer(int answer, int requesterId)
14510 {
14511 if (_summonRequest.getTarget() == null)
14512 {
14513 return;
14514 }
14515 if ((answer == 1) && (_summonRequest.getTarget().getObjectId() == requesterId))
14516 {
14517 teleToTarget(this, _summonRequest.getTarget(), _summonRequest.getSkill());
14518 }
14519 _summonRequest.setTarget(null, null);
14520 }
14521
14522 public static void teleToTarget(L2PcInstance targetChar, L2PcInstance summonerChar, L2Skill summonSkill)
14523 {
14524 if ((targetChar == null) || (summonerChar == null) || (summonSkill == null))
14525 {
14526 return;
14527 }
14528
14529 if (!checkSummonerStatus(summonerChar))
14530 {
14531 return;
14532 }
14533 if (!checkSummonTargetStatus(targetChar, summonerChar))
14534 {
14535 return;
14536 }
14537
14538 int itemConsumeId = summonSkill.getTargetConsumeId();
14539 int itemConsumeCount = summonSkill.getTargetConsume();
14540 if ((itemConsumeId != 0) && (itemConsumeCount != 0))
14541 {
14542 if (targetChar.getInventory().getInventoryItemCount(itemConsumeId, 0) < itemConsumeCount)
14543 {
14544 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_REQUIRED_FOR_SUMMONING);
14545 sm.addItemName(summonSkill.getTargetConsumeId());
14546 targetChar.sendPacket(sm);
14547 return;
14548 }
14549 targetChar.getInventory().destroyItemByItemId("Consume", itemConsumeId, itemConsumeCount, summonerChar, targetChar);
14550 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
14551 sm.addItemName(summonSkill.getTargetConsumeId());
14552 targetChar.sendPacket(sm);
14553 }
14554 targetChar.teleToLocation(summonerChar.getX(), summonerChar.getY(), summonerChar.getZ(), true);
14555 }
14556
14557 public void reloadRune()
14558 {
14559 int skillExpLvl = 0;
14560 int skillExp1Lvl = 0;
14561 int skillSpLvl = 0;
14562 int skillSp1Lvl = 0;
14563 int skillGradeLvl = 0;
14564 int skillGrade1Lvl = 0;
14565 int skillMaxWeightLvl = 0;
14566
14567 removeRuneSkill();
14568
14569 for (L2ItemInstance i : getInventory().getItems())
14570 {
14571 if ((i == null) || !i.isRune())
14572 {
14573 continue;
14574 }
14575 switch (i.getItemId())
14576 {
14577 // Rune of Exp 30%
14578 case 20335:
14579 case 20337:
14580 case 20339:
14581 case 20572:
14582 case 20742:
14583 case 21084:
14584 if (skillExp1Lvl == 0)
14585 {
14586 skillExp1Lvl = 1;
14587 }
14588 break;
14589 // Rune of Exp 50%
14590 case 20336:
14591 case 20338:
14592 case 20340:
14593 skillExp1Lvl = 2;
14594 break;
14595 // Rune of SP 30%
14596 case 20341:
14597 case 20343:
14598 case 20345:
14599 case 20741:
14600 case 21086:
14601 if (skillSp1Lvl == 0)
14602 {
14603 skillSp1Lvl = 1;
14604 }
14605 break;
14606 // Rune of SP 50%
14607 case 20342:
14608 case 20344:
14609 case 20346:
14610 skillSp1Lvl = 2;
14611 break;
14612 // Rune of Crystal level 3
14613 case 20347:
14614 case 20349:
14615 case 20351:
14616 if (skillGrade1Lvl == 0)
14617 {
14618 skillGrade1Lvl = 1;
14619 }
14620 break;
14621 // Rune of Crystal level 5
14622 case 20348:
14623 case 20350:
14624 case 20352:
14625 skillGrade1Lvl = 2;
14626 break;
14627 // Rune of Exp. points
14628 case 22054:
14629 case 22055:
14630 case 22056:
14631 case 22057:
14632 skillExpLvl++;
14633 break;
14634 // Rune of SP
14635 case 22058:
14636 case 22059:
14637 case 22060:
14638 case 22061:
14639 skillSpLvl++;
14640 break;
14641 // Crystal form Rune (Rune of Crystal)
14642 case 22062:
14643 case 22063:
14644 case 22064:
14645 case 22065:
14646 skillGradeLvl++;
14647 break;
14648 // Rune of Feather
14649 case 22066:
14650 skillMaxWeightLvl = 1;
14651 break;
14652 }
14653 }
14654 addRuneSkill(22039, skillExp1Lvl, 26046, skillExpLvl);
14655 addRuneSkill(22040, skillSp1Lvl, 26047, skillSpLvl);
14656 addRuneSkill(22041, skillGrade1Lvl, 26048, skillGradeLvl);
14657 addRuneSkill(26049, skillMaxWeightLvl, 0, 0);
14658 }
14659
14660 private void addRuneSkill(int SkillId1, int Lvl1, int SkillId2, int Lvl2)
14661 {
14662 if (Lvl1 > 0)
14663 {
14664 L2Skill Skill1 = SkillTable.getInstance().getInfo(SkillId1, Lvl1);
14665 if (Skill1 != null)
14666 {
14667 addSkill(Skill1, false);
14668 }
14669 if ((Skill1.getId() == 22041) || (Skill1.getId() == 26048))
14670 {
14671 refreshExpertisePenalty();
14672 }
14673 }
14674 if (Lvl2 > 5)
14675 {
14676 Lvl2 = 5;
14677 }
14678 if (Lvl1 == 1)
14679 {
14680 Lvl2 -= 3;
14681 }
14682 if ((Lvl2 > 0) && (Lvl1 != 2))
14683 {
14684 L2Skill Skill2 = SkillTable.getInstance().getInfo(SkillId2, Lvl2);
14685 if (Skill2 != null)
14686 {
14687 addSkill(Skill2, false);
14688 }
14689 if ((Skill2.getId() == 22041) || (Skill2.getId() == 26048))
14690 {
14691 refreshExpertisePenalty();
14692 }
14693 }
14694 }
14695
14696 private void removeRuneSkill()
14697 {
14698 for (L2Skill charSkill : getAllSkills())
14699 {
14700 switch (charSkill.getId())
14701 {
14702 case 22039:
14703 case 22040:
14704 case 22041:
14705 case 26046:
14706 case 26047:
14707 case 26048:
14708 case 26049:
14709 removeSkill(charSkill, false, true);
14710 break;
14711 }
14712 if ((charSkill.getId() == 22041) || (charSkill.getId() == 26048))
14713 {
14714 refreshExpertisePenalty();
14715 }
14716 }
14717 }
14718
14719 public static boolean checkSummonerStatus(L2PcInstance summonerChar)
14720 {
14721 if (summonerChar == null)
14722 {
14723 return false;
14724 }
14725
14726 if (summonerChar.isInOlympiadMode())
14727 {
14728 summonerChar.sendPacket(SystemMessageId.THIS_ITEM_IS_NOT_AVAILABLE_FOR_THE_OLYMPIAD_EVENT);
14729 return false;
14730 }
14731
14732 if (summonerChar.inObserverMode())
14733 {
14734 return false;
14735 }
14736
14737 if (!TvTEvent.onEscapeUse(summonerChar.getObjectId()))
14738 {
14739 summonerChar.sendPacket(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING);
14740 return false;
14741 }
14742
14743 if (!TvTRoundEvent.onEscapeUse(summonerChar.getObjectId()))
14744 {
14745 summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
14746 return false;
14747 }
14748
14749 if (summonerChar.isInsideZone(ZoneId.NO_SUMMON_FRIEND) || summonerChar.isFlyingMounted())
14750 {
14751 summonerChar.sendPacket(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING);
14752 return false;
14753 }
14754 return true;
14755 }
14756
14757 public static boolean checkSummonTargetStatus(L2Object target, L2PcInstance summonerChar)
14758 {
14759 if ((target == null) || !(target instanceof L2PcInstance))
14760 {
14761 return false;
14762 }
14763
14764 L2PcInstance targetChar = (L2PcInstance) target;
14765
14766 if (targetChar.isAlikeDead())
14767 {
14768 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_DEAD_AT_THE_MOMENT_AND_CANNOT_BE_SUMMONED);
14769 sm.addPcName(targetChar);
14770 summonerChar.sendPacket(sm);
14771 return false;
14772 }
14773
14774 if (targetChar.isInStoreMode())
14775 {
14776 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CURRENTLY_TRADING_OR_OPERATING_PRIVATE_STORE_AND_CANNOT_BE_SUMMONED);
14777 sm.addPcName(targetChar);
14778 summonerChar.sendPacket(sm);
14779 return false;
14780 }
14781
14782 if (targetChar.isRooted() || targetChar.isInCombat())
14783 {
14784 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ENGAGED_IN_COMBAT_AND_CANNOT_BE_SUMMONED);
14785 sm.addPcName(targetChar);
14786 summonerChar.sendPacket(sm);
14787 return false;
14788 }
14789
14790 if (targetChar.isInOlympiadMode())
14791 {
14792 summonerChar.sendPacket(SystemMessageId.YOU_CANNOT_SUMMON_PLAYERS_WHO_ARE_IN_OLYMPIAD);
14793 return false;
14794 }
14795
14796 if (targetChar.isFestivalParticipant() || targetChar.isFlyingMounted())
14797 {
14798 summonerChar.sendPacket(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING);
14799 return false;
14800 }
14801
14802 if (targetChar.inObserverMode())
14803 {
14804 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_STATE_FORBIDS_SUMMONING);
14805 sm.addCharName(targetChar);
14806 summonerChar.sendPacket(sm);
14807 return false;
14808 }
14809
14810 if (targetChar.isCombatFlagEquipped())
14811 {
14812 summonerChar.sendPacket(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING);
14813 return false;
14814 }
14815
14816 if (!TvTEvent.onEscapeUse(targetChar.getObjectId()))
14817 {
14818 summonerChar.sendPacket(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING);
14819 return false;
14820 }
14821
14822 if (!TvTRoundEvent.onEscapeUse(targetChar.getObjectId()))
14823 {
14824 summonerChar.sendPacket(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING);
14825 return false;
14826 }
14827
14828 if (targetChar.isInsideZone(ZoneId.NO_SUMMON_FRIEND))
14829 {
14830 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IN_SUMMON_BLOCKING_AREA);
14831 sm.addString(targetChar.getName());
14832 summonerChar.sendPacket(sm);
14833 return false;
14834 }
14835
14836 if (summonerChar.getInstanceId() > 0)
14837 {
14838 Instance summonerInstance = InstanceManager.getInstance().getInstance(summonerChar.getInstanceId());
14839 if (!Config.ALLOW_SUMMON_TO_INSTANCE || !summonerInstance.isSummonAllowed())
14840 {
14841 summonerChar.sendPacket(SystemMessageId.YOU_MAY_NOT_SUMMON_FROM_YOUR_CURRENT_LOCATION);
14842 return false;
14843 }
14844 }
14845
14846 // on retail character can enter 7s dungeon with summon friend,
14847 // but will be teleported away by mobs
14848 // because currently this is not working in L2J we do not allowing summoning
14849 if (summonerChar.isIn7sDungeon())
14850 {
14851 int targetCabal = SevenSigns.getInstance().getPlayerCabal(targetChar.getObjectId());
14852 if (SevenSigns.getInstance().isSealValidationPeriod())
14853 {
14854 if (targetCabal != SevenSigns.getInstance().getCabalHighestScore())
14855 {
14856 summonerChar.sendPacket(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING);
14857 return false;
14858 }
14859 }
14860 else
14861 {
14862 if (targetCabal == SevenSigns.CABAL_NULL)
14863 {
14864 summonerChar.sendPacket(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING);
14865 return false;
14866 }
14867 }
14868 }
14869
14870 return true;
14871 }
14872
14873 public void gatesRequest(L2DoorInstance door)
14874 {
14875 _gatesRequest.setTarget(door);
14876 }
14877
14878 public void gatesAnswer(int answer, int type)
14879 {
14880 if (_gatesRequest.getDoor() == null)
14881 {
14882 return;
14883 }
14884
14885 if ((answer == 1) && (getTarget() == _gatesRequest.getDoor()) && (type == 1))
14886 {
14887 _gatesRequest.getDoor().openMe();
14888 }
14889 else if ((answer == 1) && (getTarget() == _gatesRequest.getDoor()) && (type == 0))
14890 {
14891 _gatesRequest.getDoor().closeMe();
14892 }
14893
14894 _gatesRequest.setTarget(null);
14895 }
14896
14897 public void checkItemRestriction()
14898 {
14899 for (int i = 0; i < Inventory.PAPERDOLL_TOTALSLOTS; i++)
14900 {
14901 L2ItemInstance equippedItem = getInventory().getPaperdollItem(i);
14902 if ((equippedItem != null) && !equippedItem.getItem().checkCondition(this, this, false))
14903 {
14904 getInventory().unEquipItemInSlot(i);
14905
14906 InventoryUpdate iu = new InventoryUpdate();
14907 iu.addModifiedItem(equippedItem);
14908 sendPacket(iu);
14909
14910 SystemMessage sm = null;
14911 if (equippedItem.getItem().getBodyPart() == L2Item.SLOT_BACK)
14912 {
14913 sendPacket(SystemMessageId.CLOAK_REMOVED_BECAUSE_ARMOR_SET_REMOVED);
14914 return;
14915 }
14916
14917 if (equippedItem.getEnchantLevel() > 0)
14918 {
14919 sm = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
14920 sm.addNumber(equippedItem.getEnchantLevel());
14921 sm.addItemName(equippedItem);
14922 }
14923 else
14924 {
14925 sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISARMED);
14926 sm.addItemName(equippedItem);
14927 }
14928 sendPacket(sm);
14929 }
14930 }
14931 }
14932
14933 public void setTransformAllowedSkills(int[] ids)
14934 {
14935 _transformAllowedSkills = ids;
14936 }
14937
14938 public boolean containsAllowedTransformSkill(int id)
14939 {
14940 for (int _transformAllowedSkill : _transformAllowedSkills)
14941 {
14942 if (_transformAllowedSkill == id)
14943 {
14944 return true;
14945 }
14946 }
14947 return false;
14948 }
14949
14950 /** Section for mounted pets */
14951 protected class FeedTask implements Runnable
14952 {
14953 @Override
14954 public void run()
14955 {
14956 try
14957 {
14958 if (!isMounted())
14959 {
14960 stopFeed();
14961 return;
14962 }
14963
14964 if (getCurrentFeed() > getFeedConsume())
14965 {
14966 // eat
14967 setCurrentFeed(getCurrentFeed() - getFeedConsume());
14968 }
14969 else
14970 {
14971 // go back to pet control item, or simply said, unsummon it
14972 setCurrentFeed(0);
14973 stopFeed();
14974 dismount();
14975 sendPacket(SystemMessageId.OUT_OF_FEED_MOUNT_CANCELED);
14976 }
14977
14978 List<Integer> foodIds = getPetData(getMountNpcId()).getFood();
14979 if (foodIds.isEmpty())
14980 {
14981 return;
14982 }
14983 L2ItemInstance food = null;
14984 for (int id : foodIds)
14985 {
14986 // TODO: possibly pet inv?
14987 food = getInventory().getItemByItemId(id);
14988 if (food != null)
14989 {
14990 break;
14991 }
14992 }
14993
14994 if ((food != null) && isHungry())
14995 {
14996 IItemHandler handler = ItemHandler.getInstance().getHandler(food.getEtcItem());
14997 if (handler != null)
14998 {
14999 handler.useItem(L2PcInstance.this, food, false);
15000 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.PET_TOOK_S1_BECAUSE_HE_WAS_HUNGRY);
15001 sm.addItemName(food.getItemId());
15002 sendPacket(sm);
15003 }
15004 }
15005 }
15006 catch (Exception e)
15007 {
15008 _log.log(Level.SEVERE, "Mounted Pet [NpcId: " + getMountNpcId() + "] a feed task error has occurred", e);
15009 }
15010 }
15011 }
15012
15013 protected synchronized void startFeed(int npcId)
15014 {
15015 _canFeed = npcId > 0;
15016 if (!isMounted())
15017 {
15018 return;
15019 }
15020 if (hasSummon())
15021 {
15022 setCurrentFeed(((L2PetInstance) getSummon()).getCurrentFed());
15023 _controlItemId = getSummon().getControlObjectId();
15024 sendPacket(new SetupGauge(3, (getCurrentFeed() * 10000) / getFeedConsume(), (getMaxFeed() * 10000) / getFeedConsume()));
15025 if (!isDead())
15026 {
15027 _mountFeedTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FeedTask(), 10000, 10000);
15028 }
15029 }
15030 else if (_canFeed)
15031 {
15032 setCurrentFeed(getMaxFeed());
15033 SetupGauge sg = new SetupGauge(3, (getCurrentFeed() * 10000) / getFeedConsume(), (getMaxFeed() * 10000) / getFeedConsume());
15034 sendPacket(sg);
15035 if (!isDead())
15036 {
15037 _mountFeedTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FeedTask(), 10000, 10000);
15038 }
15039 }
15040 }
15041
15042 protected synchronized void stopFeed()
15043 {
15044 if (_mountFeedTask != null)
15045 {
15046 _mountFeedTask.cancel(false);
15047 _mountFeedTask = null;
15048 }
15049 }
15050
15051 private final void clearPetData()
15052 {
15053 _data = null;
15054 }
15055
15056 protected final L2PetData getPetData(int npcId)
15057 {
15058 if (_data == null)
15059 {
15060 _data = PetDataTable.getInstance().getPetData(npcId);
15061 }
15062 return _data;
15063 }
15064
15065 private final L2PetLevelData getPetLevelData(int npcId)
15066 {
15067 if (_leveldata == null)
15068 {
15069 _leveldata = PetDataTable.getInstance().getPetData(npcId).getPetLevelData(getMountLevel());
15070 }
15071 return _leveldata;
15072 }
15073
15074 public int getCurrentFeed()
15075 {
15076 return _curFeed;
15077 }
15078
15079 protected int getFeedConsume()
15080 {
15081 // if pet is attacking
15082 if (isAttackingNow())
15083 {
15084 return getPetLevelData(_mountNpcId).getPetFeedBattle();
15085 }
15086 return getPetLevelData(_mountNpcId).getPetFeedNormal();
15087 }
15088
15089 public void setCurrentFeed(int num)
15090 {
15091 _curFeed = num > getMaxFeed() ? getMaxFeed() : num;
15092 SetupGauge sg = new SetupGauge(3, (getCurrentFeed() * 10000) / getFeedConsume(), (getMaxFeed() * 10000) / getFeedConsume());
15093 sendPacket(sg);
15094 }
15095
15096 private int getMaxFeed()
15097 {
15098 return getPetLevelData(_mountNpcId).getPetMaxFeed();
15099 }
15100
15101 protected boolean isHungry()
15102 {
15103 return _canFeed ? (getCurrentFeed() < ((getPetData(getMountNpcId()).getHungryLimit() / 100f) * getPetLevelData(getMountNpcId()).getPetMaxFeed())) : false;
15104 }
15105
15106 protected class Dismount implements Runnable
15107 {
15108 @Override
15109 public void run()
15110 {
15111 try
15112 {
15113 dismount();
15114 }
15115 catch (Exception e)
15116 {
15117 _log.log(Level.WARNING, "Exception on dismount(): " + e.getMessage(), e);
15118 }
15119 }
15120 }
15121
15122 public void enteredNoLanding(int delay)
15123 {
15124 _dismountTask = ThreadPoolManager.getInstance().scheduleGeneral(new Dismount(), delay * 1000);
15125 }
15126
15127 public void exitedNoLanding()
15128 {
15129 if (_dismountTask != null)
15130 {
15131 _dismountTask.cancel(true);
15132 _dismountTask = null;
15133 }
15134 }
15135
15136 public void storePetFood(int petId)
15137 {
15138 if ((_controlItemId != 0) && (petId != 0))
15139 {
15140 String req;
15141 req = "UPDATE pets SET fed=? WHERE item_obj_id = ?";
15142 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
15143 PreparedStatement statement = con.prepareStatement(req))
15144 {
15145 statement.setInt(1, getCurrentFeed());
15146 statement.setInt(2, _controlItemId);
15147 statement.executeUpdate();
15148 _controlItemId = 0;
15149 }
15150 catch (Exception e)
15151 {
15152 _log.log(Level.SEVERE, "Failed to store Pet [NpcId: " + petId + "] data", e);
15153 }
15154 }
15155 }
15156
15157 /** End of section for mounted pets */
15158
15159 /**
15160 * @return event effect id
15161 */
15162 public int getEventEffectId()
15163 {
15164 return _eventEffectId;
15165 }
15166
15167 public void startEventEffect(AbnormalEffect mask)
15168 {
15169 _eventEffectId |= mask.getMask();
15170 broadcastUserInfo();
15171 }
15172
15173 public void stopEventEffect(AbnormalEffect mask)
15174 {
15175 _eventEffectId &= ~mask.getMask();
15176 broadcastUserInfo();
15177 }
15178
15179 public void setIsInSiege(boolean b)
15180 {
15181 _isInSiege = b;
15182 }
15183
15184 public boolean isInSiege()
15185 {
15186 return _isInSiege;
15187 }
15188
15189 /**
15190 * @param isInHideoutSiege sets the value of {@link #_isInHideoutSiege}.
15191 */
15192 public void setIsInHideoutSiege(boolean isInHideoutSiege)
15193 {
15194 _isInHideoutSiege = isInHideoutSiege;
15195 }
15196
15197 /**
15198 * @return the value of {@link #_isInHideoutSiege}, {@code true} if the player is participing on a Hideout Siege, otherwise {@code false}.
15199 */
15200 public boolean isInHideoutSiege()
15201 {
15202 return _isInHideoutSiege;
15203 }
15204
15205 public FloodProtectors getFloodProtectors()
15206 {
15207 return getClient().getFloodProtectors();
15208 }
15209
15210 public boolean isFlyingMounted()
15211 {
15212 return _isFlyingMounted;
15213 }
15214
15215 public void setIsFlyingMounted(boolean val)
15216 {
15217 _isFlyingMounted = val;
15218 setIsFlying(val);
15219 }
15220
15221 /**
15222 * Returns the Number of Charges this L2PcInstance got.
15223 * @return
15224 */
15225 public int getCharges()
15226 {
15227 return _charges.get();
15228 }
15229
15230 public synchronized void increaseCharges(int count, int max)
15231 {
15232 if (_charges.get() >= max)
15233 {
15234 sendPacket(SystemMessageId.FORCE_MAXLEVEL_REACHED);
15235 return;
15236 }
15237
15238 // Charge clear task should be reset every time a charge is increased.
15239 restartChargeTask();
15240
15241 if (_charges.addAndGet(count) >= max)
15242 {
15243 _charges.set(max);
15244 sendPacket(SystemMessageId.FORCE_MAXLEVEL_REACHED);
15245 }
15246 else
15247 {
15248 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.FORCE_INCREASED_TO_S1);
15249 sm.addNumber(_charges.get());
15250 sendPacket(sm);
15251 }
15252
15253 sendPacket(new EtcStatusUpdate(this));
15254 }
15255
15256 public synchronized boolean decreaseCharges(int count)
15257 {
15258 if (_charges.get() < count)
15259 {
15260 return false;
15261 }
15262
15263 // Charge clear task should be reset every time a charge is decreased and stopped when charges become 0.
15264 if (_charges.addAndGet(-count) == 0)
15265 {
15266 stopChargeTask();
15267 }
15268 else
15269 {
15270 restartChargeTask();
15271 }
15272
15273 sendPacket(new EtcStatusUpdate(this));
15274 return true;
15275 }
15276
15277 public void clearCharges()
15278 {
15279 _charges.set(0);
15280 sendPacket(new EtcStatusUpdate(this));
15281 }
15282
15283 /**
15284 * Starts/Restarts the ChargeTask to Clear Charges after 10 Mins.
15285 */
15286 private void restartChargeTask()
15287 {
15288 if (_chargeTask != null)
15289 {
15290 _chargeTask.cancel(false);
15291 _chargeTask = null;
15292 }
15293 _chargeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ChargeTask(), 600000);
15294 }
15295
15296 /**
15297 * Stops the Charges Clearing Task.
15298 */
15299 public void stopChargeTask()
15300 {
15301 if (_chargeTask != null)
15302 {
15303 _chargeTask.cancel(false);
15304 // ThreadPoolManager.getInstance().removeGeneral((Runnable)_chargeTask);
15305 _chargeTask = null;
15306 }
15307 }
15308
15309 protected class ChargeTask implements Runnable
15310 {
15311 @Override
15312 public void run()
15313 {
15314 clearCharges();
15315 }
15316 }
15317
15318 public static class TeleportBookmark
15319 {
15320 public int _id, _x, _y, _z, _icon;
15321 public String _name, _tag;
15322
15323 TeleportBookmark(int id, int x, int y, int z, int icon, String tag, String name)
15324 {
15325 _id = id;
15326 _x = x;
15327 _y = y;
15328 _z = z;
15329 _icon = icon;
15330 _name = name;
15331 _tag = tag;
15332 }
15333
15334 }
15335
15336 public void teleportBookmarkModify(int Id, int icon, String tag, String name)
15337 {
15338 int count = 0;
15339 int size = tpbookmark.size();
15340 while (size > count)
15341 {
15342 if (tpbookmark.get(count)._id == Id)
15343 {
15344 tpbookmark.get(count)._icon = icon;
15345 tpbookmark.get(count)._tag = tag;
15346 tpbookmark.get(count)._name = name;
15347
15348 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
15349 PreparedStatement statement = con.prepareStatement(UPDATE_TP_BOOKMARK))
15350 {
15351 statement.setInt(1, icon);
15352 statement.setString(2, tag);
15353 statement.setString(3, name);
15354 statement.setInt(4, getObjectId());
15355 statement.setInt(5, Id);
15356 statement.execute();
15357 }
15358 catch (Exception e)
15359 {
15360 _log.log(Level.WARNING, "Could not update character teleport bookmark data: " + e.getMessage(), e);
15361 }
15362 }
15363 count++;
15364 }
15365
15366 sendPacket(new ExGetBookMarkInfoPacket(this));
15367
15368 }
15369
15370 public void teleportBookmarkDelete(int Id)
15371 {
15372 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
15373 PreparedStatement statement = con.prepareStatement(DELETE_TP_BOOKMARK))
15374 {
15375 statement.setInt(1, getObjectId());
15376 statement.setInt(2, Id);
15377 statement.execute();
15378 }
15379 catch (Exception e)
15380 {
15381 _log.log(Level.WARNING, "Could not delete character teleport bookmark data: " + e.getMessage(), e);
15382 }
15383
15384 int count = 0;
15385 int size = tpbookmark.size();
15386
15387 while (size > count)
15388 {
15389 if (tpbookmark.get(count)._id == Id)
15390 {
15391 tpbookmark.remove(count);
15392 break;
15393 }
15394 count++;
15395 }
15396
15397 sendPacket(new ExGetBookMarkInfoPacket(this));
15398 }
15399
15400 public void teleportBookmarkGo(int Id)
15401 {
15402 if (!teleportBookmarkCondition(0) || (this == null))
15403 {
15404 return;
15405 }
15406 if (getInventory().getInventoryItemCount(13016, 0) == 0)
15407 {
15408 sendPacket(SystemMessageId.YOU_CANNOT_TELEPORT_BECAUSE_YOU_DO_NOT_HAVE_A_TELEPORT_ITEM);
15409 return;
15410 }
15411 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
15412 sm.addItemName(13016);
15413 sendPacket(sm);
15414 int count = 0;
15415 int size = tpbookmark.size();
15416 while (size > count)
15417 {
15418 if (tpbookmark.get(count)._id == Id)
15419 {
15420 destroyItem("Consume", getInventory().getItemByItemId(13016).getObjectId(), 1, null, false);
15421 teleToLocation(tpbookmark.get(count)._x, tpbookmark.get(count)._y, tpbookmark.get(count)._z);
15422 break;
15423 }
15424 count++;
15425 }
15426 sendPacket(new ExGetBookMarkInfoPacket(this));
15427 }
15428
15429 public boolean teleportBookmarkCondition(int type)
15430 {
15431 if (isInCombat())
15432 {
15433 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_DURING_A_BATTLE);
15434 return false;
15435 }
15436 else if (isInSiege() || (getSiegeState() != 0))
15437 {
15438 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_PARTICIPATING);
15439 return false;
15440 }
15441 else if (isInDuel())
15442 {
15443 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_DURING_A_DUEL);
15444 return false;
15445 }
15446 else if (isFlying())
15447 {
15448 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_FLYING);
15449 return false;
15450 }
15451 else if (isInOlympiadMode())
15452 {
15453 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_PARTICIPATING_IN_AN_OLYMPIAD_MATCH);
15454 return false;
15455 }
15456 else if (isParalyzed())
15457 {
15458 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_YOU_ARE_PARALYZED);
15459 return false;
15460 }
15461 else if (isDead())
15462 {
15463 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_YOU_ARE_DEAD);
15464 return false;
15465 }
15466 else if ((type == 1) && (isIn7sDungeon() || (isInParty() && getParty().isInDimensionalRift())))
15467 {
15468 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_TO_REACH_THIS_AREA);
15469 return false;
15470 }
15471 else if (isInWater())
15472 {
15473 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_UNDERWATER);
15474 return false;
15475 }
15476 else if ((type == 1) && (isInsideZone(ZoneId.SIEGE) || isInsideZone(ZoneId.CLAN_HALL) || isInsideZone(ZoneId.JAIL) || isInsideZone(ZoneId.CASTLE) || isInsideZone(ZoneId.NO_SUMMON_FRIEND) || isInsideZone(ZoneId.FORT)))
15477 {
15478 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_TO_REACH_THIS_AREA);
15479 return false;
15480 }
15481 else if (isInsideZone(ZoneId.NO_BOOKMARK) || isInBoat() || isInAirShip())
15482 {
15483 if (type == 0)
15484 {
15485 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_IN_THIS_AREA);
15486 }
15487 else if (type == 1)
15488 {
15489 sendPacket(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_TO_REACH_THIS_AREA);
15490 }
15491 return false;
15492 }
15493 /*
15494 * TODO: Instant Zone still not implemented else if (isInsideZone(ZoneId.INSTANT)) { sendPacket(SystemMessage.getSystemMessage(2357)); return; }
15495 */
15496 else
15497 {
15498 return true;
15499 }
15500 }
15501
15502 public void teleportBookmarkAdd(int x, int y, int z, int icon, String tag, String name)
15503 {
15504 if (this == null)
15505 {
15506 return;
15507 }
15508
15509 if (!teleportBookmarkCondition(1))
15510 {
15511 return;
15512 }
15513
15514 if (tpbookmark.size() >= _bookmarkslot)
15515 {
15516 sendPacket(SystemMessageId.YOU_HAVE_NO_SPACE_TO_SAVE_THE_TELEPORT_LOCATION);
15517 return;
15518 }
15519
15520 if (getInventory().getInventoryItemCount(20033, 0) == 0)
15521 {
15522 sendPacket(SystemMessageId.YOU_CANNOT_BOOKMARK_THIS_LOCATION_BECAUSE_YOU_DO_NOT_HAVE_A_MY_TELEPORT_FLAG);
15523 return;
15524 }
15525
15526 int count = 0;
15527 int id = 1;
15528 FastList<Integer> idlist = new FastList<>();
15529
15530 int size = tpbookmark.size();
15531
15532 while (size > count)
15533 {
15534 idlist.add(tpbookmark.get(count)._id);
15535 count++;
15536 }
15537
15538 for (int i = 1; i < 10; i++)
15539 {
15540 if (!idlist.contains(i))
15541 {
15542 id = i;
15543 break;
15544 }
15545 }
15546
15547 tpbookmark.add(new TeleportBookmark(id, x, y, z, icon, tag, name));
15548
15549 destroyItem("Consume", getInventory().getItemByItemId(20033).getObjectId(), 1, null, false);
15550
15551 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
15552 sm.addItemName(20033);
15553 sendPacket(sm);
15554
15555 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
15556 PreparedStatement statement = con.prepareStatement(INSERT_TP_BOOKMARK))
15557 {
15558 statement.setInt(1, getObjectId());
15559 statement.setInt(2, id);
15560 statement.setInt(3, x);
15561 statement.setInt(4, y);
15562 statement.setInt(5, z);
15563 statement.setInt(6, icon);
15564 statement.setString(7, tag);
15565 statement.setString(8, name);
15566 statement.execute();
15567 }
15568 catch (Exception e)
15569 {
15570 _log.log(Level.WARNING, "Could not insert character teleport bookmark data: " + e.getMessage(), e);
15571 }
15572 sendPacket(new ExGetBookMarkInfoPacket(this));
15573 }
15574
15575 public void restoreTeleportBookmark()
15576 {
15577 if (tpbookmark == null)
15578 {
15579 tpbookmark = new FastList<>();
15580 }
15581
15582 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
15583 {
15584 PreparedStatement statement = con.prepareStatement(RESTORE_TP_BOOKMARK);
15585 statement.setInt(1, getObjectId());
15586 ResultSet rset = statement.executeQuery();
15587
15588 while (rset.next())
15589 {
15590 tpbookmark.add(new TeleportBookmark(rset.getInt("Id"), rset.getInt("x"), rset.getInt("y"), rset.getInt("z"), rset.getInt("icon"), rset.getString("tag"), rset.getString("name")));
15591 }
15592
15593 rset.close();
15594 statement.close();
15595 }
15596 catch (Exception e)
15597 {
15598 _log.log(Level.SEVERE, "Failed restoing character teleport bookmark.", e);
15599 }
15600 }
15601
15602 @Override
15603 public void sendInfo(L2PcInstance activeChar)
15604 {
15605 if (isInBoat())
15606 {
15607 getPosition().setWorldPosition(getBoat().getPosition().getWorldPosition());
15608
15609 activeChar.sendPacket(new CharInfo(this));
15610 activeChar.sendPacket(new ExBrExtraUserInfo(this));
15611 int relation1 = getRelation(activeChar);
15612 int relation2 = activeChar.getRelation(this);
15613 Integer oldrelation = getKnownList().getKnownRelations().get(activeChar.getObjectId());
15614 if ((oldrelation != null) && (oldrelation != relation1))
15615 {
15616 activeChar.sendPacket(new RelationChanged(this, relation1, isAutoAttackable(activeChar)));
15617 if (hasSummon())
15618 {
15619 activeChar.sendPacket(new RelationChanged(getSummon(), relation1, isAutoAttackable(activeChar)));
15620 }
15621 }
15622 oldrelation = activeChar.getKnownList().getKnownRelations().get(getObjectId());
15623 if ((oldrelation != null) && (oldrelation != relation2))
15624 {
15625 sendPacket(new RelationChanged(activeChar, relation2, activeChar.isAutoAttackable(this)));
15626 if (activeChar.hasSummon())
15627 {
15628 sendPacket(new RelationChanged(activeChar.getSummon(), relation2, activeChar.isAutoAttackable(this)));
15629 }
15630 }
15631 activeChar.sendPacket(new GetOnVehicle(getObjectId(), getBoat().getObjectId(), getInVehiclePosition()));
15632 }
15633 else if (isInAirShip())
15634 {
15635 getPosition().setWorldPosition(getAirShip().getPosition().getWorldPosition());
15636
15637 activeChar.sendPacket(new CharInfo(this));
15638 activeChar.sendPacket(new ExBrExtraUserInfo(this));
15639 int relation1 = getRelation(activeChar);
15640 int relation2 = activeChar.getRelation(this);
15641 Integer oldrelation = getKnownList().getKnownRelations().get(activeChar.getObjectId());
15642 if ((oldrelation != null) && (oldrelation != relation1))
15643 {
15644 activeChar.sendPacket(new RelationChanged(this, relation1, isAutoAttackable(activeChar)));
15645 if (hasSummon())
15646 {
15647 activeChar.sendPacket(new RelationChanged(getSummon(), relation1, isAutoAttackable(activeChar)));
15648 }
15649 }
15650 oldrelation = activeChar.getKnownList().getKnownRelations().get(getObjectId());
15651 if ((oldrelation != null) && (oldrelation != relation2))
15652 {
15653 sendPacket(new RelationChanged(activeChar, relation2, activeChar.isAutoAttackable(this)));
15654 if (activeChar.hasSummon())
15655 {
15656 sendPacket(new RelationChanged(activeChar.getSummon(), relation2, activeChar.isAutoAttackable(this)));
15657 }
15658 }
15659 activeChar.sendPacket(new ExGetOnAirShip(this, getAirShip()));
15660 }
15661 else
15662 {
15663 activeChar.sendPacket(new CharInfo(this));
15664 activeChar.sendPacket(new ExBrExtraUserInfo(this));
15665 int relation1 = getRelation(activeChar);
15666 int relation2 = activeChar.getRelation(this);
15667 Integer oldrelation = getKnownList().getKnownRelations().get(activeChar.getObjectId());
15668 if ((oldrelation != null) && (oldrelation != relation1))
15669 {
15670 activeChar.sendPacket(new RelationChanged(this, relation1, isAutoAttackable(activeChar)));
15671 if (hasSummon())
15672 {
15673 activeChar.sendPacket(new RelationChanged(getSummon(), relation1, isAutoAttackable(activeChar)));
15674 }
15675 }
15676 oldrelation = activeChar.getKnownList().getKnownRelations().get(getObjectId());
15677 if ((oldrelation != null) && (oldrelation != relation2))
15678 {
15679 sendPacket(new RelationChanged(activeChar, relation2, activeChar.isAutoAttackable(this)));
15680 if (activeChar.hasSummon())
15681 {
15682 sendPacket(new RelationChanged(activeChar.getSummon(), relation2, activeChar.isAutoAttackable(this)));
15683 }
15684 }
15685 }
15686 if (getMountType() == 4)
15687 {
15688 // TODO: Remove when horse mounts fixed
15689 activeChar.sendPacket(new Ride(this, false, 0));
15690 activeChar.sendPacket(new Ride(this, true, getMountNpcId()));
15691 }
15692
15693 switch (getPrivateStoreType())
15694 {
15695 case L2PcInstance.STORE_PRIVATE_SELL:
15696 activeChar.sendPacket(new PrivateStoreMsgSell(this));
15697 break;
15698 case L2PcInstance.STORE_PRIVATE_PACKAGE_SELL:
15699 activeChar.sendPacket(new ExPrivateStoreSetWholeMsg(this));
15700 break;
15701 case L2PcInstance.STORE_PRIVATE_BUY:
15702 activeChar.sendPacket(new PrivateStoreMsgBuy(this));
15703 break;
15704 case L2PcInstance.STORE_PRIVATE_MANUFACTURE:
15705 activeChar.sendPacket(new RecipeShopMsg(this));
15706 break;
15707 }
15708 }
15709
15710 public void showQuestMovie(int id)
15711 {
15712 if (_movieId > 0)
15713 {
15714 return;
15715 }
15716 abortAttack();
15717 abortCast();
15718 stopMove(null);
15719 _movieId = id;
15720 sendPacket(new ExStartScenePlayer(id));
15721 }
15722
15723 public boolean isAllowedToEnchantSkills()
15724 {
15725 if (isLocked())
15726 {
15727 return false;
15728 }
15729 if (isTransformed() || isInStance())
15730 {
15731 return false;
15732 }
15733 if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(this))
15734 {
15735 return false;
15736 }
15737 if (isCastingNow() || isCastingSimultaneouslyNow())
15738 {
15739 return false;
15740 }
15741 if (isInBoat() || isInAirShip())
15742 {
15743 return false;
15744 }
15745 return true;
15746 }
15747
15748 /**
15749 * Set the _createDate of the L2PcInstance.
15750 * @param createDate
15751 */
15752 public void setCreateDate(Calendar createDate)
15753 {
15754 _createDate = createDate;
15755 }
15756
15757 /**
15758 * @return the _createDate of the L2PcInstance.
15759 */
15760 public Calendar getCreateDate()
15761 {
15762 return _createDate;
15763 }
15764
15765 /**
15766 * @return number of days to char birthday.
15767 */
15768 public int checkBirthDay()
15769 {
15770 Calendar now = Calendar.getInstance();
15771
15772 // "Characters with a February 29 creation date will receive a gift on February 28."
15773 if ((_createDate.get(Calendar.DAY_OF_MONTH) == 29) && (_createDate.get(Calendar.MONTH) == 1))
15774 {
15775 _createDate.add(Calendar.HOUR_OF_DAY, -24);
15776 }
15777
15778 if ((now.get(Calendar.MONTH) == _createDate.get(Calendar.MONTH)) && (now.get(Calendar.DAY_OF_MONTH) == _createDate.get(Calendar.DAY_OF_MONTH)) && (now.get(Calendar.YEAR) != _createDate.get(Calendar.YEAR)))
15779 {
15780 return 0;
15781 }
15782
15783 int i;
15784 for (i = 1; i < 6; i++)
15785 {
15786 now.add(Calendar.HOUR_OF_DAY, 24);
15787 if ((now.get(Calendar.MONTH) == _createDate.get(Calendar.MONTH)) && (now.get(Calendar.DAY_OF_MONTH) == _createDate.get(Calendar.DAY_OF_MONTH)) && (now.get(Calendar.YEAR) != _createDate.get(Calendar.YEAR)))
15788 {
15789 return i;
15790 }
15791 }
15792 return -1;
15793 }
15794
15795 /**
15796 * list of character friends
15797 */
15798 private final List<Integer> _friendList = new FastList<>();
15799
15800 public List<Integer> getFriendList()
15801 {
15802 return _friendList;
15803 }
15804
15805 public void restoreFriendList()
15806 {
15807 _friendList.clear();
15808
15809 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
15810 {
15811 String sqlQuery = "SELECT friendId FROM character_friends WHERE charId=? AND relation=0";
15812 PreparedStatement statement = con.prepareStatement(sqlQuery);
15813 statement.setInt(1, getObjectId());
15814 ResultSet rset = statement.executeQuery();
15815
15816 int friendId;
15817 while (rset.next())
15818 {
15819 friendId = rset.getInt("friendId");
15820 if (friendId == getObjectId())
15821 {
15822 continue;
15823 }
15824 _friendList.add(friendId);
15825 }
15826
15827 rset.close();
15828 statement.close();
15829 }
15830 catch (Exception e)
15831 {
15832 _log.log(Level.WARNING, "Error found in " + getName() + "'s FriendList: " + e.getMessage(), e);
15833 }
15834 }
15835
15836 /**
15837 *
15838 */
15839 private void notifyFriends()
15840 {
15841 FriendStatusPacket pkt = new FriendStatusPacket(getObjectId());
15842 for (int id : _friendList)
15843 {
15844 L2PcInstance friend = L2World.getInstance().getPlayer(id);
15845 if (friend != null)
15846 {
15847 friend.sendPacket(pkt);
15848 }
15849 }
15850 }
15851
15852 /**
15853 * @return the _silenceMode
15854 */
15855 public boolean isSilenceMode()
15856 {
15857 return _silenceMode;
15858 }
15859
15860 /**
15861 * While at silenceMode, checks if this PC Instance blocks PMs for this user
15862 * @param objId
15863 * @return
15864 */
15865 public boolean isSilenceMode(int objId)
15866 {
15867 if (Config.SILENCE_MODE_EXCLUDE && _silenceMode)
15868 {
15869 return !_silenceModeExcluded.contains(objId);
15870 }
15871
15872 return _silenceMode;
15873 }
15874
15875 /**
15876 * @param mode the _silenceMode to set
15877 */
15878 public void setSilenceMode(boolean mode)
15879 {
15880 _silenceMode = mode;
15881 _silenceModeExcluded.clear(); // Clear the excluded list on each setSilenceMode
15882 sendPacket(new EtcStatusUpdate(this));
15883 }
15884
15885 public void addSilenceModeExcluded(int playerObjId)
15886 {
15887 _silenceModeExcluded.add(playerObjId);
15888 }
15889
15890 private void storeRecipeShopList()
15891 {
15892 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
15893 {
15894 PreparedStatement statement;
15895 L2ManufactureList list = getCreateList();
15896
15897 if ((list != null) && (list.size() > 0))
15898 {
15899 int _position = 1;
15900 statement = con.prepareStatement("DELETE FROM character_recipeshoplist WHERE charId=? ");
15901 statement.setInt(1, getObjectId());
15902 statement.execute();
15903 statement.close();
15904
15905 PreparedStatement statement2 = con.prepareStatement("INSERT INTO character_recipeshoplist (charId, Recipeid, Price, Pos) VALUES (?, ?, ?, ?)");
15906 for (L2ManufactureItem item : list.getList())
15907 {
15908 statement2.setInt(1, getObjectId());
15909 statement2.setInt(2, item.getRecipeId());
15910 statement2.setLong(3, item.getCost());
15911 statement2.setInt(4, _position);
15912 statement2.execute();
15913 statement2.clearParameters();
15914 _position++;
15915 }
15916 statement2.close();
15917 }
15918 }
15919 catch (Exception e)
15920 {
15921 _log.log(Level.SEVERE, "Could not store recipe shop for playerID " + getObjectId() + ": ", e);
15922 }
15923 }
15924
15925 private void restoreRecipeShopList()
15926 {
15927 try (Connection con = L2DatabaseFactory.getInstance().getConnection())
15928 {
15929 PreparedStatement statement = con.prepareStatement("SELECT Recipeid,Price FROM character_recipeshoplist WHERE charId=? ORDER BY Pos ASC");
15930 statement.setInt(1, getObjectId());
15931 ResultSet rset = statement.executeQuery();
15932 L2ManufactureList createList = new L2ManufactureList();
15933 while (rset.next())
15934 {
15935 createList.add(new L2ManufactureItem(rset.getInt("Recipeid"), rset.getLong("Price")));
15936 }
15937 setCreateList(createList);
15938 rset.close();
15939 statement.close();
15940 }
15941 catch (Exception e)
15942 {
15943 _log.log(Level.SEVERE, "Could not restore recipe shop list data for playerId: " + getObjectId(), e);
15944 }
15945 }
15946
15947 public double getCollisionRadius()
15948 {
15949 return getMountType() != 0 ? (NpcTable.getInstance().getTemplate(getMountNpcId()).getfCollisionRadius()) : (isTransformed() && !getTransformation().isStance() ? getTransformation().getCollisionRadius() : (getAppearance().getSex() ? getBaseTemplate().getFCollisionRadiusFemale() : getBaseTemplate().getfCollisionRadius()));
15950 }
15951
15952 public double getCollisionHeight()
15953 {
15954 return getMountType() != 0 ? (NpcTable.getInstance().getTemplate(getMountNpcId()).getfCollisionHeight()) : (isTransformed() && !getTransformation().isStance() ? getTransformation().getCollisionHeight() : (getAppearance().getSex() ? getBaseTemplate().getFCollisionHeightFemale() : getBaseTemplate().getfCollisionHeight()));
15955 }
15956
15957 public final int getClientX()
15958 {
15959 return _clientX;
15960 }
15961
15962 public final int getClientY()
15963 {
15964 return _clientY;
15965 }
15966
15967 public final int getClientZ()
15968 {
15969 return _clientZ;
15970 }
15971
15972 public final int getClientHeading()
15973 {
15974 return _clientHeading;
15975 }
15976
15977 public final void setClientX(int val)
15978 {
15979 _clientX = val;
15980 }
15981
15982 public final void setClientY(int val)
15983 {
15984 _clientY = val;
15985 }
15986
15987 public final void setClientZ(int val)
15988 {
15989 _clientZ = val;
15990 }
15991
15992 public final void setClientHeading(int val)
15993 {
15994 _clientHeading = val;
15995 }
15996
15997 /**
15998 * @param z
15999 * @return true if character falling now on the start of fall return false for correct coord sync!
16000 */
16001 public final boolean isFalling(int z)
16002 {
16003 if (isDead() || isFlying() || isFlyingMounted() || isInsideZone(ZoneId.WATER))
16004 {
16005 return false;
16006 }
16007
16008 if (System.currentTimeMillis() < _fallingTimestamp)
16009 {
16010 return true;
16011 }
16012
16013 final int deltaZ = getZ() - z;
16014 if (deltaZ <= getBaseTemplate().getFallHeight())
16015 {
16016 return false;
16017 }
16018
16019 final int damage = (int) Formulas.calcFallDam(this, deltaZ);
16020 if (damage > 0)
16021 {
16022 reduceCurrentHp(Math.min(damage, getCurrentHp() - 1), null, false, true, null);
16023 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.FALL_DAMAGE_S1);
16024 sm.addNumber(damage);
16025 sendPacket(sm);
16026 }
16027
16028 setFalling();
16029
16030 return false;
16031 }
16032
16033 /**
16034 * Set falling timestamp
16035 */
16036 public final void setFalling()
16037 {
16038 _fallingTimestamp = System.currentTimeMillis() + FALLING_VALIDATION_DELAY;
16039 }
16040
16041 /**
16042 * @return the _movieId
16043 */
16044 public int getMovieId()
16045 {
16046 return _movieId;
16047 }
16048
16049 public void setMovieId(int id)
16050 {
16051 _movieId = id;
16052 }
16053
16054 /**
16055 * Update last item auction request timestamp to current
16056 */
16057 public void updateLastItemAuctionRequest()
16058 {
16059 _lastItemAuctionInfoRequest = System.currentTimeMillis();
16060 }
16061
16062 /**
16063 * @return true if receiving item auction requests<br>
16064 * (last request was in 2 seconds before)
16065 */
16066 public boolean isItemAuctionPolling()
16067 {
16068 return (System.currentTimeMillis() - _lastItemAuctionInfoRequest) < 2000;
16069 }
16070
16071 @Override
16072 public boolean isMovementDisabled()
16073 {
16074 return super.isMovementDisabled() || (_movieId > 0);
16075 }
16076
16077 private void restoreUISettings()
16078 {
16079 _uiKeySettings = new L2UIKeysSettings(this);
16080 }
16081
16082 private void storeUISettings()
16083 {
16084 if (_uiKeySettings == null)
16085 {
16086 return;
16087 }
16088
16089 if (!_uiKeySettings.isSaved())
16090 {
16091 _uiKeySettings.saveInDB();
16092 }
16093 }
16094
16095 public long getGamePoints()
16096 {
16097 return _gamePoints;
16098 }
16099
16100 public void setGamePoints(long gamePoints)
16101 {
16102 _gamePoints = gamePoints;
16103 }
16104
16105 public L2UIKeysSettings getUISettings()
16106 {
16107 return _uiKeySettings;
16108 }
16109
16110 /**
16111 * Initializes his _botPunish object with the specified punish and for the specified time
16112 * @param punishType
16113 * @param minsOfPunish
16114 */
16115 public synchronized void setPunishDueBotting(BotPunish.Punish punishType, int minsOfPunish)
16116 {
16117 if (_botPunish == null)
16118 {
16119 _botPunish = new BotPunish(punishType, minsOfPunish);
16120 }
16121 }
16122
16123 /**
16124 * Returns the current object-representative player punish
16125 * @return
16126 */
16127 public BotPunish getPlayerPunish()
16128 {
16129 return _botPunish;
16130 }
16131
16132 /**
16133 * Returns the type of punish being applied
16134 * @return
16135 */
16136 public BotPunish.Punish getBotPunishType()
16137 {
16138 return _botPunish.getBotPunishType();
16139 }
16140
16141 /**
16142 * Will return true if the player has any bot punishment active
16143 * @return
16144 */
16145 public boolean isBeingPunished()
16146 {
16147 return _botPunish != null;
16148 }
16149
16150 /**
16151 * Will end the punishment once a player attempt to perform any forbid action and his punishment has expired
16152 */
16153 public void endPunishment()
16154 {
16155 Connection con = null;
16156 try
16157 {
16158 con = L2DatabaseFactory.getInstance().getConnection();
16159 PreparedStatement statement = con.prepareStatement("DELETE FROM bot_reported_punish WHERE charId = ?");
16160 statement.setInt(1, getObjectId());
16161 statement.execute();
16162 statement.close();
16163 }
16164 catch (SQLException sqle)
16165 {
16166 sqle.printStackTrace();
16167 }
16168 finally
16169 {
16170 try
16171 {
16172 con.close();
16173 }
16174 catch (SQLException sqle)
16175 {
16176 }
16177 }
16178 _botPunish = null;
16179 this.sendMessage("Your punishment has expired. Do not bot again!");
16180 }
16181
16182 public String getHtmlPrefix()
16183 {
16184 if (!Config.L2JMOD_MULTILANG_ENABLE)
16185 {
16186 return null;
16187 }
16188
16189 return _htmlPrefix;
16190 }
16191
16192 public String getLang()
16193 {
16194 return _lang;
16195 }
16196
16197 public boolean setLang(String lang)
16198 {
16199 boolean result = false;
16200 if (Config.L2JMOD_MULTILANG_ENABLE)
16201 {
16202 if (Config.L2JMOD_MULTILANG_ALLOWED.contains(lang))
16203 {
16204 _lang = lang;
16205 result = true;
16206 }
16207 else
16208 {
16209 _lang = Config.L2JMOD_MULTILANG_DEFAULT;
16210 }
16211
16212 _htmlPrefix = "data/lang/" + _lang + "/";
16213 }
16214 else
16215 {
16216 _lang = null;
16217 _htmlPrefix = null;
16218 }
16219
16220 return result;
16221 }
16222
16223 public long getOfflineStartTime()
16224 {
16225 return _offlineShopStart;
16226 }
16227
16228 public void setOfflineStartTime(long time)
16229 {
16230 _offlineShopStart = time;
16231 }
16232
16233 public int getPcBangPoints()
16234 {
16235 return _pcBangPoints;
16236
16237 }
16238
16239 public void setPcBangPoints(final int i)
16240 {
16241 if (i < 200000)
16242 {
16243 _pcBangPoints = i;
16244 }
16245 else
16246 {
16247 _pcBangPoints = 200000;
16248 }
16249 }
16250
16251 /**
16252 * Remove player from BossZones (used on char logout/exit)
16253 */
16254 public void removeFromBossZone()
16255 {
16256 try
16257 {
16258 for (L2BossZone _zone : GrandBossManager.getInstance().getZones())
16259 {
16260 _zone.removePlayer(this);
16261 }
16262 }
16263 catch (Exception e)
16264 {
16265 _log.log(Level.WARNING, "Exception on removeFromBossZone(): " + e.getMessage(), e);
16266 }
16267 }
16268
16269 /**
16270 * Check all player skills for skill level. If player level is lower than skill learn level - 9, skill level is decreased to next possible level.
16271 */
16272 public void checkPlayerSkills()
16273 {
16274 for (int id : getSkills().keySet())
16275 {
16276 int level = getSkillLevel(id);
16277 if (level >= 100)
16278 {
16279 level = SkillTable.getInstance().getMaxLevel(id);
16280 }
16281 final L2SkillLearn learn = SkillTreesData.getInstance().getClassSkill(id, level, getClassId());
16282 // not found - not a learn skill?
16283 if (learn == null)
16284 {
16285 continue;
16286 }
16287 // player level is too low for such skill level
16288 if (getLevel() < (learn.getGetLevel() - 9))
16289 {
16290 deacreaseSkillLevel(id);
16291 }
16292 }
16293 }
16294
16295 private void deacreaseSkillLevel(int id)
16296 {
16297 int nextLevel = -1;
16298 final Map<Integer, L2SkillLearn> skillTree = SkillTreesData.getInstance().getCompleteClassSkillTree(getClassId());
16299 for (L2SkillLearn sl : skillTree.values())
16300 {
16301 if ((sl.getSkillId() == id) && (nextLevel < sl.getSkillLevel()) && (getLevel() >= (sl.getGetLevel() - 9)))
16302 {
16303 // next possible skill level
16304 nextLevel = sl.getSkillLevel();
16305 }
16306 }
16307
16308 if (nextLevel == -1) // there is no lower skill
16309 {
16310 _log.info("Removing skill id " + id + " level " + getSkillLevel(id) + " from player " + this);
16311 removeSkill(getSkills().get(id), true);
16312 }
16313 else
16314 // replace with lower one
16315 {
16316 _log.info("Decreasing skill id " + id + " from " + getSkillLevel(id) + " to " + nextLevel + " for " + this);
16317 addSkill(SkillTable.getInstance().getInfo(id, nextLevel), true);
16318 }
16319 }
16320
16321 public boolean canMakeSocialAction()
16322 {
16323 if ((getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_NONE) && (getActiveRequester() == null) && !isAlikeDead() && (!isAllSkillsDisabled() || isInDuel()) && !isCastingNow() && !isCastingSimultaneouslyNow() && (getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE) && !AttackStanceTaskManager.getInstance().hasAttackStanceTask(this) && !isInOlympiadMode())
16324 {
16325 return true;
16326 }
16327 return false;
16328 }
16329
16330 public void setMultiSocialAction(int id, int targetId)
16331 {
16332 _multiSociaAction = id;
16333 _multiSocialTarget = targetId;
16334 }
16335
16336 public int getMultiSociaAction()
16337 {
16338 return _multiSociaAction;
16339 }
16340
16341 public int getMultiSocialTarget()
16342 {
16343 return _multiSocialTarget;
16344 }
16345
16346 public List<TeleportBookmark> getTpbookmark()
16347 {
16348 return tpbookmark;
16349 }
16350
16351 public int getBookmarkslot()
16352 {
16353 return _bookmarkslot;
16354 }
16355
16356 /**
16357 * @return
16358 */
16359 public int getQuestInventoryLimit()
16360 {
16361 return Config.INVENTORY_MAXIMUM_QUEST_ITEMS;
16362 }
16363
16364 public boolean canAttackCharacter(L2Character cha)
16365 {
16366 if (cha instanceof L2Attackable)
16367 {
16368 return true;
16369 }
16370 else if (cha instanceof L2Playable)
16371 {
16372 if (cha.isInsideZone(ZoneId.PVP) && !cha.isInsideZone(ZoneId.SIEGE))
16373 {
16374 return true;
16375 }
16376
16377 L2PcInstance target;
16378 if (cha instanceof L2Summon)
16379 {
16380 target = ((L2Summon) cha).getOwner();
16381 }
16382 else
16383 {
16384 target = (L2PcInstance) cha;
16385 }
16386
16387 if (isInDuel() && target.isInDuel() && (target.getDuelId() == getDuelId()))
16388 {
16389 return true;
16390 }
16391 else if (isInParty() && target.isInParty())
16392 {
16393 if (getParty() == target.getParty())
16394 {
16395 return false;
16396 }
16397 if (((getParty().getCommandChannel() != null) || (target.getParty().getCommandChannel() != null)) && (getParty().getCommandChannel() == target.getParty().getCommandChannel()))
16398 {
16399 return false;
16400 }
16401 }
16402 else if ((getClan() != null) && (target.getClan() != null))
16403 {
16404 if (getClanId() == target.getClanId())
16405 {
16406 return false;
16407 }
16408 if (((getAllyId() > 0) || (target.getAllyId() > 0)) && (getAllyId() == target.getAllyId()))
16409 {
16410 return false;
16411 }
16412 if (getClan().isAtWarWith(target.getClan().getClanId()) && target.getClan().isAtWarWith(getClan().getClanId()))
16413 {
16414 return true;
16415 }
16416 }
16417 else if ((getClan() == null) || (target.getClan() == null))
16418 {
16419 if ((target.getPvpFlag() == 0) && (target.getKarma() == 0))
16420 {
16421 return false;
16422 }
16423 }
16424 }
16425 return true;
16426 }
16427
16428 /**
16429 * Test if player inventory is under 90% capaity
16430 * @param includeQuestInv check also quest inventory
16431 * @return
16432 */
16433 public boolean isInventoryUnder90(boolean includeQuestInv)
16434 {
16435 return (getInventory().getSize(includeQuestInv) <= (getInventoryLimit() * 0.9));
16436 }
16437
16438 public boolean havePetInvItems()
16439 {
16440 return _petItems;
16441 }
16442
16443 public void setPetInvItems(boolean haveit)
16444 {
16445 _petItems = haveit;
16446 }
16447
16448 /**
16449 * Restore Pet's inventory items from database.
16450 */
16451 private void restorePetInventoryItems()
16452 {
16453 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
16454 PreparedStatement statement = con.prepareStatement("SELECT object_id FROM `items` WHERE `owner_id`=? AND (`loc`='PET' OR `loc`='PET_EQUIP') LIMIT 1;"))
16455 {
16456 statement.setInt(1, getObjectId());
16457 try (ResultSet rset = statement.executeQuery())
16458 {
16459 if (rset.next() && (rset.getInt("object_id") > 0))
16460 {
16461 setPetInvItems(true);
16462 }
16463 else
16464 {
16465 setPetInvItems(false);
16466 }
16467 }
16468 }
16469 catch (Exception e)
16470 {
16471 _log.log(Level.SEVERE, "Could not check Items in Pet Inventory for playerId: " + getObjectId(), e);
16472 }
16473 }
16474
16475 public String getAdminConfirmCmd()
16476 {
16477 return _adminConfirmCmd;
16478 }
16479
16480 public void setAdminConfirmCmd(String adminConfirmCmd)
16481 {
16482 _adminConfirmCmd = adminConfirmCmd;
16483 }
16484
16485 public DialogId getDialogId()
16486 {
16487 return _currentDialogId;
16488 }
16489
16490 public void setDialogId(DialogId id)
16491 {
16492 _currentDialogId = id;
16493 }
16494
16495 public void setBlockCheckerArena(byte arena)
16496 {
16497 _handysBlockCheckerEventArena = arena;
16498 }
16499
16500 public int getBlockCheckerArena()
16501 {
16502 return _handysBlockCheckerEventArena;
16503 }
16504
16505 /**
16506 * Load L2PcInstance Recommendations data.
16507 * @return
16508 */
16509 private long loadRecommendations()
16510 {
16511 long _time_left = 0;
16512 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
16513 PreparedStatement statement = con.prepareStatement("SELECT rec_have,rec_left,time_left FROM character_reco_bonus WHERE charId=? LIMIT 1"))
16514 {
16515 statement.setInt(1, getObjectId());
16516 try (ResultSet rset = statement.executeQuery())
16517 {
16518 if (rset.next())
16519 {
16520 setRecomHave(rset.getInt("rec_have"));
16521 setRecomLeft(rset.getInt("rec_left"));
16522 _time_left = rset.getLong("time_left");
16523 }
16524 else
16525 {
16526 _time_left = 3600000;
16527 }
16528 }
16529 }
16530 catch (Exception e)
16531 {
16532 _log.log(Level.SEVERE, "Could not restore Recommendations for player: " + getObjectId(), e);
16533 }
16534 return _time_left;
16535 }
16536
16537 /**
16538 * Update L2PcInstance Recommendations data.
16539 */
16540 public void storeRecommendations()
16541 {
16542 long _recoTaskEnd = 0;
16543 if (_recoBonusTask != null)
16544 {
16545 _recoTaskEnd = Math.max(0, _recoBonusTask.getDelay(TimeUnit.MILLISECONDS));
16546 }
16547
16548 try (Connection con = L2DatabaseFactory.getInstance().getConnection();
16549 PreparedStatement statement = con.prepareStatement("INSERT INTO character_reco_bonus (charId,rec_have,rec_left,time_left) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE rec_have=?, rec_left=?, time_left=?"))
16550 {
16551 statement.setInt(1, getObjectId());
16552 statement.setInt(2, getRecomHave());
16553 statement.setInt(3, getRecomLeft());
16554 statement.setLong(4, _recoTaskEnd);
16555 // Update part
16556 statement.setInt(5, getRecomHave());
16557 statement.setInt(6, getRecomLeft());
16558 statement.setLong(7, _recoTaskEnd);
16559 statement.execute();
16560 }
16561 catch (Exception e)
16562 {
16563 _log.log(Level.SEVERE, "Could not update Recommendations for player: " + getObjectId(), e);
16564 }
16565 }
16566
16567 public boolean RecoBonusActive()
16568 {
16569 return _isRecoBonusActive;
16570 }
16571
16572 public void setRecoBonusActive(boolean mode)
16573 {
16574 _isRecoBonusActive = mode;
16575 sendPacket(new ExVoteSystemInfo(this));
16576 }
16577
16578 public void checkRecoBonusTask()
16579 {
16580 // Load data
16581 long _task_time = loadRecommendations();
16582
16583 if (_task_time > 0)
16584 {
16585 // Add 20 recos on first login
16586 if (_task_time == 3600000)
16587 {
16588 setRecomLeft(getRecomLeft() + 20);
16589 }
16590 // If player have some timeleft, start bonus task
16591 _recoBonusTask = ThreadPoolManager.getInstance().scheduleGeneral(new RecoBonusTaskEnd(), _task_time);
16592 setRecoBonusActive(true);
16593 }
16594 // Create task to give new recommendations
16595 _recoGiveTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new RecoGiveTask(), 7200000, 3600000);
16596 // Store new data
16597 storeRecommendations();
16598 }
16599
16600 public void stopRecoBonusTask()
16601 {
16602 if (_recoBonusTask != null)
16603 {
16604 _recoBonusTask.cancel(false);
16605 _recoBonusTask = null;
16606 }
16607 }
16608
16609 public void stopRecoGiveTask()
16610 {
16611 if (_recoGiveTask != null)
16612 {
16613 _recoGiveTask.cancel(false);
16614 _recoGiveTask = null;
16615 }
16616 }
16617
16618 protected class RecoGiveTask implements Runnable
16619 {
16620 @Override
16621 public void run()
16622 {
16623 if (L2PcInstance.this == null)
16624 {
16625 // stopRecoGiveTask(); why is this here? it will lead to NPE
16626 return;
16627 }
16628 int reco_to_give;
16629 // 10 recommendations to give out after 2 hours of being logged in
16630 // 1 more recommendation to give out every hour after that.
16631 if (_recoTwoHoursGiven)
16632 {
16633 reco_to_give = 1;
16634 }
16635 else
16636 {
16637 reco_to_give = 10;
16638 }
16639
16640 _recoTwoHoursGiven = true;
16641
16642 setRecomLeft(getRecomLeft() + reco_to_give);
16643
16644 SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_OBTAINED_S1_RECOMMENDATIONS);
16645 sm.addNumber(reco_to_give);
16646 L2PcInstance.this.sendPacket(sm);
16647 L2PcInstance.this.sendPacket(new UserInfo(L2PcInstance.this));
16648 }
16649 }
16650
16651 protected class RecoBonusTaskEnd implements Runnable
16652 {
16653 @Override
16654 public void run()
16655 {
16656 if (L2PcInstance.this == null)
16657 {
16658 return;
16659 }
16660
16661 L2PcInstance.this.setRecoBonusActive(false);
16662 }
16663 }
16664
16665 public int getRecomBonusTime()
16666 {
16667 if (_recoBonusTask != null)
16668 {
16669 return (int) Math.max(0, _recoBonusTask.getDelay(TimeUnit.SECONDS));
16670 }
16671
16672 return 0;
16673 }
16674
16675 public int getRecomBonusType()
16676 {
16677 // Maintain = 1, nomal 0
16678 return _recoBonusMode;
16679 }
16680
16681 public short getScore()
16682 {
16683 return points;
16684 }
16685
16686 public void increaseScore()
16687 {
16688 points++;
16689 }
16690
16691 public void clearPoints()
16692 {
16693 points = 0;
16694 }
16695
16696 public boolean allowPeaceAttack()
16697 {
16698 if (!getAccessLevel().allowPeaceAttack() && (getTarget() != null) && (getTarget() instanceof L2Npc))
16699 {
16700 return Config.ALT_ATTACKABLE_NPCS;
16701 }
16702 if ((getTarget() != null) && (getTarget() instanceof L2PcInstance))
16703 {
16704 L2PcInstance target = (L2PcInstance) getTarget();
16705 return ((isInTownWarEvent() && !target.getClient().isDetached()) || getAccessLevel().allowPeaceAttack());
16706 }
16707 else
16708 {
16709 return (isInTownWarEvent() || getAccessLevel().allowPeaceAttack());
16710 }
16711 }
16712
16713 public void setLastPetitionGmName(String gmName)
16714 {
16715 _lastPetitionGmName = gmName;
16716 }
16717
16718 public String getLastPetitionGmName()
16719 {
16720 return _lastPetitionGmName;
16721 }
16722
16723 public L2ContactList getContactList()
16724 {
16725 return _contactList;
16726 }
16727
16728 public void setEventStatus()
16729 {
16730 eventStatus = new PlayerEventStatus(this);
16731 }
16732
16733 public void setEventStatus(PlayerEventStatus pes)
16734 {
16735 eventStatus = pes;
16736 }
16737
16738 public PlayerEventStatus getEventStatus()
16739 {
16740 return eventStatus;
16741 }
16742
16743 public L2PcInstance setRecomBonusType(int mode)
16744 {
16745 // Maintain = 1, normal 0
16746 _recoBonusMode = mode;
16747 return this;
16748 }
16749
16750 public long getNotMoveUntil()
16751 {
16752 return _notMoveUntil;
16753 }
16754
16755 public void updateNotMoveUntil()
16756 {
16757 _notMoveUntil = System.currentTimeMillis() + Config.PLAYER_MOVEMENT_BLOCK_TIME;
16758 }
16759
16760 @Override
16761 public boolean isPlayer()
16762 {
16763 return true;
16764 }
16765
16766 @Override
16767 public boolean isChargedShot(ShotType type)
16768 {
16769 L2ItemInstance weapon = getActiveWeaponInstance();
16770 return (weapon != null) && weapon.isChargedShot(type);
16771 }
16772
16773 @Override
16774 public void setChargedShot(ShotType type, boolean charged)
16775 {
16776 L2ItemInstance weapon = getActiveWeaponInstance();
16777 if (weapon != null)
16778 {
16779 weapon.setChargedShot(type, charged);
16780 }
16781 }
16782
16783 // LISTENERS
16784 /**
16785 * Fires all the equipment listeners, if any.<br>
16786 * Action is cancelled if it returns false.
16787 * @param isEquiped
16788 * @param item
16789 * @return
16790 */
16791 private boolean fireEquipmentListeners(boolean isEquiped, L2ItemInstance item)
16792 {
16793 if (item != null)
16794 {
16795 EquipmentEvent event = new EquipmentEvent();
16796 event.setEquipped(!isEquiped);
16797 event.setItem(item);
16798 for (EquipmentListener listener : equipmentListeners)
16799 {
16800 if (!listener.onEquip(event))
16801 {
16802 return false;
16803 }
16804 }
16805 for (EquipmentListener listener : globalEquipmentListeners)
16806 {
16807 if (!listener.onEquip(event))
16808 {
16809 return false;
16810 }
16811 }
16812 }
16813 return true;
16814 }
16815
16816 /**
16817 * Fires all the transformation listeners, if any.<br>
16818 * If it returns false, the action is cancelled.<br>
16819 * @param transformation
16820 * @param isTransforming
16821 * @return
16822 */
16823 private boolean fireTransformListeners(L2Transformation transformation, boolean isTransforming)
16824 {
16825 if ((transformation != null) && !transformListeners.isEmpty())
16826 {
16827 TransformEvent event = new TransformEvent();
16828 event.setTransformation(transformation);
16829 event.setTransforming(isTransforming);
16830 for (TransformListener listener : transformListeners)
16831 {
16832 if (!listener.onTransform(event))
16833 {
16834 return false;
16835 }
16836 }
16837 }
16838 return true;
16839 }
16840
16841 /**
16842 * Fires all the henna listeners, if any.<br>
16843 * The action is cancelled if it returns false
16844 * @param henna
16845 * @param isAdding
16846 * @return
16847 */
16848 private boolean fireHennaListeners(L2Henna henna, boolean isAdding)
16849 {
16850 if ((henna != null) && !hennaListeners.isEmpty())
16851 {
16852 HennaEvent event = new HennaEvent();
16853 event.setAdd(isAdding);
16854 event.setHenna(henna);
16855 event.setPlayer(this);
16856 for (HennaListener listener : hennaListeners)
16857 {
16858 if (!listener.onRemoveHenna(event))
16859 {
16860 return false;
16861 }
16862 }
16863 }
16864 return true;
16865 }
16866
16867 /**
16868 * Fires all the profession change listeners
16869 * @param t
16870 */
16871 private void fireProfessionChangeListeners(L2PcTemplate t)
16872 {
16873 if (!professionChangeListeners.isEmpty() || !globalProfessionChangeListeners.isEmpty())
16874 {
16875 ProfessionChangeEvent event = null;
16876 event = new ProfessionChangeEvent();
16877 event.setPlayer(this);
16878 event.setSubClass(isSubClassActive());
16879 event.setTemplate(t);
16880 for (ProfessionChangeListener listener : professionChangeListeners)
16881 {
16882 listener.professionChanged(event);
16883 }
16884 for (ProfessionChangeListener listener : globalProfessionChangeListeners)
16885 {
16886 listener.professionChanged(event);
16887 }
16888 }
16889 }
16890
16891 /**
16892 * Adds a despawn listener
16893 * @param listener
16894 */
16895 public static void addDespawnListener(PlayerDespawnListener listener)
16896 {
16897 if (!despawnListeners.contains(listener))
16898 {
16899 despawnListeners.add(listener);
16900 }
16901 }
16902
16903 /**
16904 * Removes a despawn listener
16905 * @param listener
16906 */
16907 public static void removeDespawnListener(PlayerDespawnListener listener)
16908 {
16909 despawnListeners.remove(listener);
16910 }
16911
16912 /**
16913 * Adds a henna listener
16914 * @param listener
16915 */
16916 public static void addHennaListener(HennaListener listener)
16917 {
16918 if (!hennaListeners.contains(listener))
16919 {
16920 hennaListeners.add(listener);
16921 }
16922 }
16923
16924 /**
16925 * Removes a henna listener
16926 * @param listener
16927 */
16928 public static void removeHennaListener(HennaListener listener)
16929 {
16930 hennaListeners.remove(listener);
16931 }
16932
16933 /**
16934 * Adds an equipment listener
16935 * @param listener
16936 */
16937 public void addEquipmentListener(EquipmentListener listener)
16938 {
16939 if (!equipmentListeners.contains(listener))
16940 {
16941 equipmentListeners.add(listener);
16942 }
16943 }
16944
16945 /**
16946 * Removes an equipment listener
16947 * @param listener
16948 */
16949 public void removeEquipmentListener(EquipmentListener listener)
16950 {
16951 equipmentListeners.remove(listener);
16952 }
16953
16954 /**
16955 * Adds an equipment listener
16956 * @param listener
16957 */
16958 public static void addGlobalEquipmentListener(EquipmentListener listener)
16959 {
16960 if (!globalEquipmentListeners.contains(listener))
16961 {
16962 globalEquipmentListeners.add(listener);
16963 }
16964 }
16965
16966 /**
16967 * Removes an equipment listener
16968 * @param listener
16969 */
16970 public static void removeGlobalEquipmentListener(EquipmentListener listener)
16971 {
16972 globalEquipmentListeners.remove(listener);
16973 }
16974
16975 /**
16976 * Adds a transformation listener
16977 * @param listener
16978 */
16979 public void addTransformListener(TransformListener listener)
16980 {
16981 if (!transformListeners.contains(listener))
16982 {
16983 transformListeners.add(listener);
16984 }
16985 }
16986
16987 /**
16988 * Remove a transformation listener
16989 * @param listener
16990 */
16991 public void removeTransformListener(TransformListener listener)
16992 {
16993 transformListeners.remove(listener);
16994 }
16995
16996 /**
16997 * Adds a profession change listener
16998 * @param listener
16999 */
17000 public void addProfessionChangeListener(ProfessionChangeListener listener)
17001 {
17002 if (!professionChangeListeners.contains(listener))
17003 {
17004 professionChangeListeners.add(listener);
17005 }
17006 }
17007
17008 /**
17009 * Removes a profession change listener
17010 * @param listener
17011 */
17012 public void removeProfessionChangeListener(ProfessionChangeListener listener)
17013 {
17014 professionChangeListeners.remove(listener);
17015 }
17016
17017 /**
17018 * Adds a global profession change listener
17019 * @param listener
17020 */
17021 public static void addGlobalProfessionChangeListener(ProfessionChangeListener listener)
17022 {
17023 if (!globalProfessionChangeListeners.contains(listener))
17024 {
17025 globalProfessionChangeListeners.add(listener);
17026 }
17027 }
17028
17029 /**
17030 * Removes a global profession change listener
17031 * @param listener
17032 */
17033 public static void removeGlobalProfessionChangeListener(ProfessionChangeListener listener)
17034 {
17035 globalProfessionChangeListeners.remove(listener);
17036 }
17037
17038 /**
17039 * @return {@code true} if premium service is registered for player, {@code false} otherwise
17040 */
17041 public boolean hasPremium()
17042 {
17043 return ExpirableServicesManager.getInstance().hasService(ServiceType.PREMIUM, this);
17044 }
17045
17046 /**
17047 * @param rateType type of rate to check
17048 * @param itemId item id to check
17049 * @param isRaid {@code true} if rate should be calculated against Raid boss
17050 * @return rate value for given rate type and item id
17051 */
17052 public float getRate(Rates rateType, int itemId, boolean isRaid)
17053 {
17054 switch (rateType)
17055 {
17056 case PREMIUM_BONUS_EXP:
17057 return hasPremium() ? PremiumTable.PREMIUM_BONUS_EXP : 1;
17058 case PREMIUM_BONUS_SP:
17059 return hasPremium() ? PremiumTable.PREMIUM_BONUS_SP : 1;
17060 case SPOIL:
17061 case DROP_ITEM:
17062 // check for premium owner in party, if enabled by config
17063 boolean hasPremium = false;
17064 if (Config.PREMIUM_PARTY_DROPSPOIL && !hasPremium() && isInParty())
17065 {
17066 for (L2PcInstance pl : getParty().getMembers())
17067 {
17068 if (pl.hasPremium() && Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, pl, true))
17069 {
17070 hasPremium = true;
17071 break;
17072 }
17073 }
17074 }
17075 else
17076 {
17077 hasPremium = hasPremium();
17078 }
17079
17080 switch (rateType)
17081 {
17082 case SPOIL:
17083 if (hasPremium)
17084 {
17085 if (Config.PREMIUM_RATE_DROP_ITEMS_ID.containsKey(itemId)) // check for overriden rate in premium list first
17086 {
17087 return Config.PREMIUM_RATE_DROP_ITEMS_ID.get(itemId);
17088 }
17089 else if (Config.RATE_DROP_ITEMS_ID.containsKey(itemId)) // then check for overriden rate in general list
17090 {
17091 return Config.RATE_DROP_ITEMS_ID.get(itemId);
17092 }
17093 else
17094 // return common premium rate, if it isn't overriden anywhere
17095 {
17096 return Config.PREMIUM_RATE_SPOIL;
17097 }
17098 }
17099 else
17100 {
17101 return Config.RATE_DROP_ITEMS_ID.containsKey(itemId) ? Config.RATE_DROP_ITEMS_ID.get(itemId) : Config.RATE_DROP_SPOIL;
17102 }
17103 case DROP_ITEM:
17104 if (hasPremium)
17105 {
17106 if (Config.PREMIUM_RATE_DROP_ITEMS_ID.containsKey(itemId)) // check for overriden rate in premium list first
17107 {
17108 return Config.PREMIUM_RATE_DROP_ITEMS_ID.get(itemId);
17109 }
17110 else if (Config.RATE_DROP_ITEMS_ID.containsKey(itemId)) // then check for overriden rate in general list
17111 {
17112 return Config.RATE_DROP_ITEMS_ID.get(itemId);
17113 }
17114 else
17115 // return premium rate, either for raid, or normal mob, if it isn't overriden anywhere
17116 {
17117 return isRaid ? Config.PREMIUM_RATE_DROP_ITEMS_BY_RAID : Config.PREMIUM_RATE_DROP_ITEMS;
17118 }
17119 }
17120 else
17121 {
17122 if (Config.RATE_DROP_ITEMS_ID.containsKey(itemId)) // check for overriden rate in general list first
17123 {
17124 return Config.RATE_DROP_ITEMS_ID.get(itemId);
17125 }
17126 else
17127 // return general rate, either for raid, or normal mob, if it isn't overriden anywhere
17128 {
17129 return isRaid ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
17130 }
17131 }
17132 }
17133 }
17134
17135 return 0;
17136 }
17137
17138 /**
17139 * @param rateType type of rate to check
17140 * @return rate value for given rate type
17141 */
17142 public float getRate(Rates rateType)
17143 {
17144 return getRate(rateType, -1, false);
17145 }
17146
17147 private boolean _isRefusingBuff = false;
17148
17149 public void setisRefusingBuff(boolean value)
17150 {
17151 _isRefusingBuff = value;
17152 }
17153
17154 public boolean isRefusingBuff()
17155 {
17156 return _isRefusingBuff;
17157 }
17158
17159 /** Advent 4h task **/
17160 private ScheduledFuture<?> _adventBonusTask;
17161 /** Advent Blessing task **/
17162 private ScheduledFuture<?> _adventBlessingTask;
17163
17164 public void stopAdventBlessingTask()
17165 {
17166 if (_adventBlessingTask != null)
17167 {
17168 _adventBlessingTask.cancel(false);
17169 _adventBlessingTask = null;
17170 }
17171 }
17172
17173 public void stopAdventBonusTask()
17174 {
17175 if (_adventBonusTask != null)
17176 {
17177 _adventBonusTask.cancel(false);
17178 _adventBonusTask = null;
17179 }
17180 }
17181
17182 private class AdventPoints implements Runnable
17183 {
17184 @Override
17185 public void run()
17186 {
17187 L2PcInstance.this.incAdventPoints(Config.BODY_ZA_MINUTU, true);
17188 }
17189 }
17190
17191 public void startAdventTask()
17192 {
17193 if (_adventBonusTask == null)
17194 {
17195 int advent_time = LovecTable.getInstance().getAdventTime(getObjectId());
17196 if (advent_time < 14400)
17197 {
17198 _adventBonusTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new AdventPoints(), 60000, 60000);
17199 sendPacket(new ExNevitAdventTimeChange(getAdventTime(), true));
17200 }
17201 }
17202 }
17203
17204 private class AdventBlessingEnd implements Runnable
17205 {
17206 @Override
17207 public void run()
17208 {
17209 L2PcInstance.this.stopSpecialEffect(AbnormalEffect.AVE_ADVENT_BLESSING);
17210 L2PcInstance.this.sendPacket(new ExNevitAdventEffect(0));
17211 L2PcInstance.this.sendPacket(new ExNevitAdventPointInfoPacket(L2PcInstance.this));
17212 L2PcInstance.this.sendPacket(SystemMessageId.NEVITS_ADVENT_BLESSING_HAS_ENDED);
17213
17214 _adventBlessingTask = null;
17215 }
17216 }
17217
17218 public boolean isAdventBlessingActive()
17219 {
17220 return ((_adventBlessingTask != null) && (_adventBlessingTask.getDelay(TimeUnit.MILLISECONDS) > 0));
17221 }
17222
17223 public int getAdventTime()
17224 {
17225 return LovecTable.getInstance().getAdventTime(getObjectId());
17226 }
17227
17228 public void incAdventPoints(int value, boolean decreasetime)
17229 {
17230 int adventPoints = LovecTable.getInstance().getAdventPoints(getObjectId());
17231 int adventTime = LovecTable.getInstance().getAdventTime(getObjectId());
17232
17233 if (decreasetime)
17234 {
17235 adventTime = adventTime + 60;
17236 if (adventTime >= 14400)
17237 {
17238 // To have 'Quit' on wings
17239 adventTime = 15000;
17240 // All 4h time used, stop task
17241 stopAdventBonusTask();
17242 // To be sure
17243 _adventBonusTask = null;
17244 }
17245 // Store new time
17246 LovecTable.getInstance().setAdventTime(getObjectId(), adventTime, true);
17247 }
17248 if (_adventBonusTask != null)
17249 {
17250 if ((adventPoints + value) >= 7200)
17251 {
17252 adventPoints = 0;
17253
17254 if (!isAdventBlessingActive())
17255 {
17256 // Abnormal
17257 startSpecialEffect(AbnormalEffect.AVE_ADVENT_BLESSING);
17258 // Start 3 min Advent Blessing
17259 _adventBlessingTask = ThreadPoolManager.getInstance().scheduleGeneral(new AdventBlessingEnd(), 180000);
17260 // Display Sysmsg
17261 sendPacket(SystemMessageId.THE_ANGEL_NEVIT_HAS_BLESSED_YOU_FROM_ABOVE);
17262 // Show counter for player
17263 L2PcInstance.this.sendPacket(new ExNevitAdventEffect(180));
17264 }
17265 }
17266 else
17267 {
17268 adventPoints = adventPoints + value;
17269 }
17270 }
17271 // Store
17272 LovecTable.getInstance().setAdventPoints(getObjectId(), adventPoints, true);
17273 // Show Points
17274 sendPacket(new ExNevitAdventPointInfoPacket(this));
17275 // Show state
17276 sendPacket(new ExNevitAdventTimeChange(getAdventTime(), _adventBonusTask != null));
17277 }
17278
17279 public void sendAdventPointMsg()
17280 {
17281 int adventPoints = LovecTable.getInstance().getAdventPoints(getObjectId());
17282 if (adventPoints >= 5760)
17283 {
17284 sendPacket(SystemMessageId.NEVITS_ADVENT_BLESSING_SHINES_STRONGLY_FROM_ABOVE);
17285 }
17286 else if (adventPoints >= 3600)
17287 {
17288 sendPacket(SystemMessageId.YOU_ARE_FURTHER_INFUSED_WITH_THE_BLESSINGS_OF_NEVIT);
17289 }
17290 else if (adventPoints >= 1440)
17291 {
17292 sendPacket(SystemMessageId.YOU_ARE_STARTING_TO_FEEL_THE_EFFECTS_OF_NEVITS_ADVENT_BLESSING);
17293 }
17294 }
17295
17296 public void setGainXp(boolean b)
17297 {
17298 _addXpSp = b;
17299 }
17300}