Explorar o código

Fixed a bug where current CP/HP/MP was not correctly restored.

Jewels which adjust max MP are still affected. It needs to be
investigated where thoose effects are applied.
HorridoJoho %!s(int64=2) %!d(string=hai) anos
pai
achega
70fa070978

+ 19 - 1
src/main/java/com/l2jserver/gameserver/model/CharSelectInfoPackage.java

@@ -1,5 +1,5 @@
 /*
- * Copyright © 2004-2021 L2J Server
+ * Copyright © 2004-2022 L2J Server
  * 
  * This file is part of L2J Server.
  * 
@@ -42,6 +42,8 @@ public class CharSelectInfoPackage {
 	private int _hairColor = 0;
 	private int _sex = 0;
 	private int _level = 1;
+	private int _maxCp = 0;
+	private double _currentCp = 0;
 	private int _maxHp = 0;
 	private double _currentHp = 0;
 	private int _maxMp = 0;
@@ -118,6 +120,14 @@ public class CharSelectInfoPackage {
 		_baseClassId = baseClassId;
 	}
 	
+	public double getCurrentCp() {
+		return _currentCp;
+	}
+	
+	public void setCurrentCp(double currentCp) {
+		_currentCp = currentCp;
+	}
+	
 	public double getCurrentHp() {
 		return _currentHp;
 	}
@@ -198,6 +208,14 @@ public class CharSelectInfoPackage {
 		_level = level;
 	}
 	
+	public int getMaxCp() {
+		return _maxCp;
+	}
+	
+	public void setMaxCp(int maxCp) {
+		_maxCp = maxCp;
+	}
+	
 	public int getMaxHp() {
 		return _maxHp;
 	}

+ 7 - 1
src/main/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java

@@ -1,5 +1,5 @@
 /*
- * Copyright © 2004-2021 L2J Server
+ * Copyright © 2004-2022 L2J Server
  * 
  * This file is part of L2J Server.
  * 
@@ -832,6 +832,12 @@ public final class L2PcInstance extends L2Playable {
 		return null;
 	}
 	
+	public void restoreStatusFromLoadedValues() {
+		setCurrentCp(getClient().getCharSelection().getCurrentCp());
+		setCurrentHp(getClient().getCharSelection().getCurrentHp());
+		setCurrentMp(getClient().getCharSelection().getCurrentMp());
+	}
+	
 	public boolean isSpawnProtected() {
 		return _protectEndTime > GameTimeController.getInstance().getGameTicks();
 	}

+ 73 - 533
src/main/java/com/l2jserver/gameserver/model/itemcontainer/Inventory.java

@@ -1,5 +1,5 @@
 /*
- * Copyright © 2004-2021 L2J Server
+ * Copyright © 2004-2022 L2J Server
  * 
  * This file is part of L2J Server.
  * 
@@ -26,21 +26,16 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.l2jserver.commons.database.ConnectionFactory;
-import com.l2jserver.gameserver.data.xml.impl.ArmorSetsData;
 import com.l2jserver.gameserver.datatables.ItemTable;
 import com.l2jserver.gameserver.enums.ItemLocation;
 import com.l2jserver.gameserver.enums.PrivateStoreType;
-import com.l2jserver.gameserver.model.L2ArmorSet;
 import com.l2jserver.gameserver.model.L2World;
 import com.l2jserver.gameserver.model.PcCondOverride;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
-import com.l2jserver.gameserver.model.holders.SkillHolder;
 import com.l2jserver.gameserver.model.items.L2Item;
 import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
 import com.l2jserver.gameserver.model.items.type.EtcItemType;
 import com.l2jserver.gameserver.model.items.type.WeaponType;
-import com.l2jserver.gameserver.model.skills.Skill;
-import com.l2jserver.gameserver.network.serverpackets.SkillCoolTime;
 import com.l2jserver.gameserver.util.StringUtil;
 
 /**
@@ -52,12 +47,6 @@ public abstract class Inventory extends ItemContainer {
 	
 	private static final Logger _log = Logger.getLogger(Inventory.class.getName());
 	
-	public interface PaperdollListener {
-		void notifyEquiped(int slot, L2ItemInstance inst, Inventory inventory);
-		
-		void notifyUnequiped(int slot, L2ItemInstance inst, Inventory inventory);
-	}
-	
 	// Common Items
 	public static final int ADENA_ID = 57;
 	public static final int ANCIENT_ADENA_ID = 5575;
@@ -101,520 +90,6 @@ public abstract class Inventory extends ItemContainer {
 	// used to quickly check for using of items of special type
 	private int _wearedMask;
 	
-	// Recorder of alterations in inventory
-	private static final class ChangeRecorder implements PaperdollListener {
-		private final List<L2ItemInstance> _changed;
-		
-		/**
-		 * Constructor of the ChangeRecorder
-		 * @param inventory
-		 */
-		ChangeRecorder(Inventory inventory) {
-			_changed = new ArrayList<>();
-			inventory.addPaperdollListener(this);
-		}
-		
-		/**
-		 * Add alteration in inventory when item equipped
-		 * @param slot
-		 * @param item
-		 * @param inventory
-		 */
-		@Override
-		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
-			if (!_changed.contains(item)) {
-				_changed.add(item);
-			}
-		}
-		
-		/**
-		 * Add alteration in inventory when item unequipped
-		 * @param slot
-		 * @param item
-		 * @param inventory
-		 */
-		@Override
-		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
-			if (!_changed.contains(item)) {
-				_changed.add(item);
-			}
-		}
-		
-		/**
-		 * Returns alterations in inventory
-		 * @return L2ItemInstance[] : array of altered items
-		 */
-		public L2ItemInstance[] getChangedItems() {
-			return _changed.toArray(new L2ItemInstance[_changed.size()]);
-		}
-	}
-	
-	private static final class BowCrossRodListener implements PaperdollListener {
-		private static final BowCrossRodListener instance = new BowCrossRodListener();
-		
-		public static BowCrossRodListener getInstance() {
-			return instance;
-		}
-		
-		@Override
-		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
-			if (slot != PAPERDOLL_RHAND) {
-				return;
-			}
-			
-			if (item.getItemType() == WeaponType.BOW) {
-				L2ItemInstance arrow = inventory.getPaperdollItem(PAPERDOLL_LHAND);
-				
-				if (arrow != null) {
-					inventory.setPaperdollItem(PAPERDOLL_LHAND, null);
-				}
-			} else if (item.getItemType() == WeaponType.CROSSBOW) {
-				L2ItemInstance bolts = inventory.getPaperdollItem(PAPERDOLL_LHAND);
-				
-				if (bolts != null) {
-					inventory.setPaperdollItem(PAPERDOLL_LHAND, null);
-				}
-			} else if (item.getItemType() == WeaponType.FISHINGROD) {
-				L2ItemInstance lure = inventory.getPaperdollItem(PAPERDOLL_LHAND);
-				
-				if (lure != null) {
-					inventory.setPaperdollItem(PAPERDOLL_LHAND, null);
-				}
-			}
-		}
-		
-		@Override
-		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
-			if (slot != PAPERDOLL_RHAND) {
-				return;
-			}
-			
-			if (item.getItemType() == WeaponType.BOW) {
-				L2ItemInstance arrow = inventory.findArrowForBow(item.getItem());
-				
-				if (arrow != null) {
-					inventory.setPaperdollItem(PAPERDOLL_LHAND, arrow);
-				}
-			} else if (item.getItemType() == WeaponType.CROSSBOW) {
-				L2ItemInstance bolts = inventory.findBoltForCrossBow(item.getItem());
-				
-				if (bolts != null) {
-					inventory.setPaperdollItem(PAPERDOLL_LHAND, bolts);
-				}
-			}
-		}
-	}
-	
-	private static final class StatsListener implements PaperdollListener {
-		private static final StatsListener instance = new StatsListener();
-		
-		public static StatsListener getInstance() {
-			return instance;
-		}
-		
-		@Override
-		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
-			inventory.getOwner().removeStatsOwner(item);
-		}
-		
-		@Override
-		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
-			inventory.getOwner().addStatFuncs(item.getStatFuncs(inventory.getOwner()));
-		}
-	}
-	
-	private static final class ItemSkillsListener implements PaperdollListener {
-		private static final ItemSkillsListener instance = new ItemSkillsListener();
-		
-		public static ItemSkillsListener getInstance() {
-			return instance;
-		}
-		
-		@Override
-		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
-			if (!(inventory.getOwner() instanceof L2PcInstance)) {
-				return;
-			}
-			final L2PcInstance player = (L2PcInstance) inventory.getOwner();
-			
-			Skill enchant4Skill, itemSkill;
-			L2Item it = item.getItem();
-			boolean update = false;
-			boolean updateTimeStamp = false;
-			
-			// Remove augmentation bonuses on unequip
-			if (item.isAugmented()) {
-				item.getAugmentation().removeBonus(player);
-			}
-			
-			item.unChargeAllShots();
-			item.removeElementAttrBonus(player);
-			
-			// Remove skills bestowed from +4 armor
-			if (item.getEnchantLevel() >= 4) {
-				enchant4Skill = it.getEnchant4Skill();
-				
-				if (enchant4Skill != null) {
-					player.removeSkill(enchant4Skill, false, enchant4Skill.isPassive());
-					update = true;
-				}
-			}
-			
-			item.clearEnchantStats();
-			
-			final SkillHolder[] skills = it.getSkills();
-			
-			if (skills != null) {
-				for (SkillHolder skillInfo : skills) {
-					if (skillInfo == null) {
-						continue;
-					}
-					
-					itemSkill = skillInfo.getSkill();
-					
-					if (itemSkill != null) {
-						player.removeSkill(itemSkill, false, itemSkill.isPassive());
-						update = true;
-					} else {
-						_log.warning("Inventory.ItemSkillsListener.Weapon: Incorrect skill: " + skillInfo + ".");
-					}
-				}
-			}
-			
-			if (item.isArmor()) {
-				for (L2ItemInstance itm : inventory.getItems()) {
-					if (!itm.isEquipped() || (itm.getItem().getSkills() == null) || itm.equals(item)) {
-						continue;
-					}
-					for (SkillHolder sk : itm.getItem().getSkills()) {
-						if (player.getSkillLevel(sk.getSkillId()) != -1) {
-							continue;
-						}
-						
-						itemSkill = sk.getSkill();
-						
-						if (itemSkill != null) {
-							player.addSkill(itemSkill, false);
-							
-							if (itemSkill.isActive()) {
-								if (!player.hasSkillReuse(itemSkill.getReuseHashCode())) {
-									int equipDelay = item.getEquipReuseDelay();
-									if (equipDelay > 0) {
-										player.addTimeStamp(itemSkill, equipDelay);
-										player.disableSkill(itemSkill, equipDelay);
-									}
-								}
-								updateTimeStamp = true;
-							}
-							update = true;
-						}
-					}
-				}
-			}
-			
-			// Apply skill, if weapon have "skills on unequip"
-			Skill unequipSkill = it.getUnequipSkill();
-			if (unequipSkill != null) {
-				unequipSkill.activateSkill(player, player);
-			}
-			
-			if (update) {
-				player.sendSkillList();
-				
-				if (updateTimeStamp) {
-					player.sendPacket(new SkillCoolTime(player));
-				}
-			}
-		}
-		
-		@Override
-		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
-			if (!(inventory.getOwner() instanceof L2PcInstance)) {
-				return;
-			}
-			
-			final L2PcInstance player = (L2PcInstance) inventory.getOwner();
-			
-			Skill enchant4Skill, itemSkill;
-			L2Item it = item.getItem();
-			boolean update = false;
-			boolean updateTimeStamp = false;
-			
-			// Apply augmentation bonuses on equip
-			if (item.isAugmented()) {
-				item.getAugmentation().applyBonus(player);
-			}
-			item.rechargeShots(true, true);
-			item.updateElementAttrBonus(player);
-			
-			// Add skills bestowed from +4 armor
-			if (item.getEnchantLevel() >= 4) {
-				enchant4Skill = it.getEnchant4Skill();
-				
-				if (enchant4Skill != null) {
-					player.addSkill(enchant4Skill, false);
-					update = true;
-				}
-			}
-			
-			item.applyEnchantStats();
-			
-			final SkillHolder[] skills = it.getSkills();
-			
-			if (skills != null) {
-				for (SkillHolder skillInfo : skills) {
-					if (skillInfo == null) {
-						continue;
-					}
-					
-					itemSkill = skillInfo.getSkill();
-					
-					if (itemSkill != null) {
-						itemSkill.setReferenceItemId(item.getId());
-						player.addSkill(itemSkill, false);
-						
-						if (itemSkill.isActive()) {
-							if (!player.hasSkillReuse(itemSkill.getReuseHashCode())) {
-								int equipDelay = item.getEquipReuseDelay();
-								if (equipDelay > 0) {
-									player.addTimeStamp(itemSkill, equipDelay);
-									player.disableSkill(itemSkill, equipDelay);
-								}
-							}
-							updateTimeStamp = true;
-						}
-						update = true;
-					} else {
-						_log.warning("Inventory.ItemSkillsListener.Weapon: Incorrect skill: " + skillInfo + ".");
-					}
-				}
-			}
-			
-			if (update) {
-				player.sendSkillList();
-				
-				if (updateTimeStamp) {
-					player.sendPacket(new SkillCoolTime(player));
-				}
-			}
-		}
-	}
-	
-	private static final class ArmorSetListener implements PaperdollListener {
-		private static final ArmorSetListener instance = new ArmorSetListener();
-		
-		public static ArmorSetListener getInstance() {
-			return instance;
-		}
-		
-		@Override
-		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
-			if (!(inventory.getOwner() instanceof L2PcInstance)) {
-				return;
-			}
-			
-			final L2PcInstance player = (L2PcInstance) inventory.getOwner();
-			
-			// Checks if player is wearing a chest item
-			final L2ItemInstance chestItem = inventory.getPaperdollItem(PAPERDOLL_CHEST);
-			
-			if (chestItem == null) {
-				return;
-			}
-			
-			// Checks for armor set for the equipped chest.
-			if (!ArmorSetsData.getInstance().isArmorSet(chestItem.getId())) {
-				return;
-			}
-			final L2ArmorSet armorSet = ArmorSetsData.getInstance().getSet(chestItem.getId());
-			boolean update = false;
-			boolean updateTimeStamp = false;
-			// Checks if equipped item is part of set
-			if (armorSet.containItem(slot, item.getId())) {
-				if (armorSet.containAll(player)) {
-					Skill itemSkill;
-					final List<SkillHolder> skills = armorSet.getSkills();
-					
-					if (skills != null) {
-						for (SkillHolder holder : skills) {
-							
-							itemSkill = holder.getSkill();
-							if (itemSkill != null) {
-								player.addSkill(itemSkill, false);
-								
-								if (itemSkill.isActive()) {
-									if (!player.hasSkillReuse(itemSkill.getReuseHashCode())) {
-										int equipDelay = item.getEquipReuseDelay();
-										if (equipDelay > 0) {
-											player.addTimeStamp(itemSkill, equipDelay);
-											player.disableSkill(itemSkill, equipDelay);
-										}
-									}
-									updateTimeStamp = true;
-								}
-								update = true;
-							} else {
-								_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
-							}
-						}
-					}
-					
-					if (armorSet.containShield(player)) // has shield from set
-					{
-						for (SkillHolder holder : armorSet.getShieldSkillId()) {
-							if (holder.getSkill() != null) {
-								player.addSkill(holder.getSkill(), false);
-								update = true;
-							} else {
-								_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
-							}
-						}
-					}
-					
-					if (armorSet.isEnchanted6(player)) // has all parts of set enchanted to 6 or more
-					{
-						for (SkillHolder holder : armorSet.getEnchant6skillId()) {
-							if (holder.getSkill() != null) {
-								player.addSkill(holder.getSkill(), false);
-								update = true;
-							} else {
-								_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
-							}
-						}
-					}
-				}
-			} else if (armorSet.containShield(item.getId())) {
-				for (SkillHolder holder : armorSet.getShieldSkillId()) {
-					if (holder.getSkill() != null) {
-						player.addSkill(holder.getSkill(), false);
-						update = true;
-					} else {
-						_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
-					}
-				}
-			}
-			
-			if (update) {
-				player.sendSkillList();
-				
-				if (updateTimeStamp) {
-					player.sendPacket(new SkillCoolTime(player));
-				}
-			}
-		}
-		
-		@Override
-		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
-			if (!(inventory.getOwner() instanceof L2PcInstance)) {
-				return;
-			}
-			
-			final L2PcInstance player = (L2PcInstance) inventory.getOwner();
-			
-			boolean remove = false;
-			Skill itemSkill;
-			List<SkillHolder> skills = null;
-			List<SkillHolder> shieldSkill = null; // shield skill
-			List<SkillHolder> skillId6 = null; // enchant +6 skill
-			
-			if (slot == PAPERDOLL_CHEST) {
-				if (!ArmorSetsData.getInstance().isArmorSet(item.getId())) {
-					return;
-				}
-				final L2ArmorSet armorSet = ArmorSetsData.getInstance().getSet(item.getId());
-				remove = true;
-				skills = armorSet.getSkills();
-				shieldSkill = armorSet.getShieldSkillId();
-				skillId6 = armorSet.getEnchant6skillId();
-			} else {
-				L2ItemInstance chestItem = inventory.getPaperdollItem(PAPERDOLL_CHEST);
-				if (chestItem == null) {
-					return;
-				}
-				
-				L2ArmorSet armorSet = ArmorSetsData.getInstance().getSet(chestItem.getId());
-				if (armorSet == null) {
-					return;
-				}
-				
-				if (armorSet.containItem(slot, item.getId())) // removed part of set
-				{
-					remove = true;
-					skills = armorSet.getSkills();
-					shieldSkill = armorSet.getShieldSkillId();
-					skillId6 = armorSet.getEnchant6skillId();
-				} else if (armorSet.containShield(item.getId())) // removed shield
-				{
-					remove = true;
-					shieldSkill = armorSet.getShieldSkillId();
-				}
-			}
-			
-			if (remove) {
-				if (skills != null) {
-					for (SkillHolder holder : skills) {
-						itemSkill = holder.getSkill();
-						if (itemSkill != null) {
-							player.removeSkill(itemSkill, false, itemSkill.isPassive());
-						} else {
-							_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
-						}
-					}
-				}
-				
-				if (shieldSkill != null) {
-					for (SkillHolder holder : shieldSkill) {
-						itemSkill = holder.getSkill();
-						if (itemSkill != null) {
-							player.removeSkill(itemSkill, false, itemSkill.isPassive());
-						} else {
-							_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
-						}
-					}
-				}
-				
-				if (skillId6 != null) {
-					for (SkillHolder holder : skillId6) {
-						itemSkill = holder.getSkill();
-						if (itemSkill != null) {
-							player.removeSkill(itemSkill, false, itemSkill.isPassive());
-						} else {
-							_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
-						}
-					}
-				}
-				
-				player.checkItemRestriction();
-				player.sendSkillList();
-			}
-		}
-	}
-	
-	private static final class BraceletListener implements PaperdollListener {
-		private static final BraceletListener instance = new BraceletListener();
-		
-		public static BraceletListener getInstance() {
-			return instance;
-		}
-		
-		@Override
-		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
-			if (item.getItem().getBodyPart() == L2Item.SLOT_R_BRACELET) {
-				inventory.unEquipItemInSlot(PAPERDOLL_DECO1);
-				inventory.unEquipItemInSlot(PAPERDOLL_DECO2);
-				inventory.unEquipItemInSlot(PAPERDOLL_DECO3);
-				inventory.unEquipItemInSlot(PAPERDOLL_DECO4);
-				inventory.unEquipItemInSlot(PAPERDOLL_DECO5);
-				inventory.unEquipItemInSlot(PAPERDOLL_DECO6);
-			}
-		}
-		
-		// Note (April 3, 2009): Currently on equip, talismans do not display properly, do we need checks here to fix this?
-		@Override
-		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
-		}
-	}
-	
 	/**
 	 * Constructor of the inventory
 	 */
@@ -622,13 +97,6 @@ public abstract class Inventory extends ItemContainer {
 		_paperdoll = new L2ItemInstance[PAPERDOLL_TOTALSLOTS];
 		_paperdollListeners = new ArrayList<>();
 		
-		if (this instanceof PcInventory) {
-			addPaperdollListener(ArmorSetListener.getInstance());
-			addPaperdollListener(BowCrossRodListener.getInstance());
-			addPaperdollListener(ItemSkillsListener.getInstance());
-			addPaperdollListener(BraceletListener.getInstance());
-		}
-		
 		// common
 		addPaperdollListener(StatsListener.getInstance());
 		
@@ -1348,4 +816,76 @@ public abstract class Inventory extends ItemContainer {
 			}
 		}
 	}
+	
+	public interface PaperdollListener {
+		void notifyEquiped(int slot, L2ItemInstance inst, Inventory inventory);
+		
+		void notifyUnequiped(int slot, L2ItemInstance inst, Inventory inventory);
+	}
+
+	// Recorder of alterations in inventory
+	private static final class ChangeRecorder implements PaperdollListener {
+		private final List<L2ItemInstance> _changed;
+		
+		/**
+		 * Constructor of the ChangeRecorder
+		 * @param inventory
+		 */
+		ChangeRecorder(Inventory inventory) {
+			_changed = new ArrayList<>();
+			inventory.addPaperdollListener(this);
+		}
+		
+		/**
+		 * Add alteration in inventory when item equipped
+		 * @param slot
+		 * @param item
+		 * @param inventory
+		 */
+		@Override
+		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
+			if (!_changed.contains(item)) {
+				_changed.add(item);
+			}
+		}
+		
+		/**
+		 * Add alteration in inventory when item unequipped
+		 * @param slot
+		 * @param item
+		 * @param inventory
+		 */
+		@Override
+		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
+			if (!_changed.contains(item)) {
+				_changed.add(item);
+			}
+		}
+		
+		/**
+		 * Returns alterations in inventory
+		 * @return L2ItemInstance[] : array of altered items
+		 */
+		public L2ItemInstance[] getChangedItems() {
+			return _changed.toArray(new L2ItemInstance[_changed.size()]);
+		}
+	}
+
+	private static final class StatsListener implements PaperdollListener {
+		private static final StatsListener instance = new StatsListener();
+		
+		public static StatsListener getInstance() {
+			return instance;
+		}
+		
+		@Override
+		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
+			inventory.getOwner().removeStatsOwner(item);
+		}
+		
+		@Override
+		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
+			inventory.getOwner().addStatFuncs(item.getStatFuncs(inventory.getOwner()));
+		}
+	}
 }

+ 460 - 1
src/main/java/com/l2jserver/gameserver/model/itemcontainer/PcInventory.java

@@ -1,5 +1,5 @@
 /*
- * Copyright © 2004-2021 L2J Server
+ * Copyright © 2004-2022 L2J Server
  * 
  * This file is part of L2J Server.
  * 
@@ -26,8 +26,10 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.l2jserver.commons.database.ConnectionFactory;
+import com.l2jserver.gameserver.data.xml.impl.ArmorSetsData;
 import com.l2jserver.gameserver.datatables.ItemTable;
 import com.l2jserver.gameserver.enums.ItemLocation;
+import com.l2jserver.gameserver.model.L2ArmorSet;
 import com.l2jserver.gameserver.model.TradeItem;
 import com.l2jserver.gameserver.model.TradeList;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
@@ -36,11 +38,15 @@ import com.l2jserver.gameserver.model.events.impl.character.player.inventory.OnP
 import com.l2jserver.gameserver.model.events.impl.character.player.inventory.OnPlayerItemDestroy;
 import com.l2jserver.gameserver.model.events.impl.character.player.inventory.OnPlayerItemDrop;
 import com.l2jserver.gameserver.model.events.impl.character.player.inventory.OnPlayerItemTransfer;
+import com.l2jserver.gameserver.model.holders.SkillHolder;
 import com.l2jserver.gameserver.model.items.L2Item;
 import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
+import com.l2jserver.gameserver.model.items.type.WeaponType;
+import com.l2jserver.gameserver.model.skills.Skill;
 import com.l2jserver.gameserver.network.SystemMessageId;
 import com.l2jserver.gameserver.network.serverpackets.InventoryUpdate;
 import com.l2jserver.gameserver.network.serverpackets.ItemList;
+import com.l2jserver.gameserver.network.serverpackets.SkillCoolTime;
 import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
 import com.l2jserver.gameserver.util.Util;
 
@@ -71,6 +77,11 @@ public class PcInventory extends Inventory {
 	private int _blockMode = -1;
 	
 	public PcInventory(L2PcInstance owner) {
+		addPaperdollListener(ArmorSetListener.getInstance());
+		addPaperdollListener(BowCrossRodListener.getInstance());
+		addPaperdollListener(ItemSkillsListener.getInstance());
+		addPaperdollListener(BraceletListener.getInstance());
+
 		_owner = owner;
 		_lock = new Object();
 	}
@@ -871,4 +882,452 @@ public class PcInventory extends Inventory {
 			item.applyEnchantStats();
 		}
 	}
+
+	private static final class BowCrossRodListener implements PaperdollListener {
+		private static final BowCrossRodListener instance = new BowCrossRodListener();
+		
+		public static BowCrossRodListener getInstance() {
+			return instance;
+		}
+		
+		@Override
+		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
+			if (slot != PAPERDOLL_RHAND) {
+				return;
+			}
+			
+			if (item.getItemType() == WeaponType.BOW) {
+				L2ItemInstance arrow = inventory.getPaperdollItem(PAPERDOLL_LHAND);
+				
+				if (arrow != null) {
+					inventory.setPaperdollItem(PAPERDOLL_LHAND, null);
+				}
+			} else if (item.getItemType() == WeaponType.CROSSBOW) {
+				L2ItemInstance bolts = inventory.getPaperdollItem(PAPERDOLL_LHAND);
+				
+				if (bolts != null) {
+					inventory.setPaperdollItem(PAPERDOLL_LHAND, null);
+				}
+			} else if (item.getItemType() == WeaponType.FISHINGROD) {
+				L2ItemInstance lure = inventory.getPaperdollItem(PAPERDOLL_LHAND);
+				
+				if (lure != null) {
+					inventory.setPaperdollItem(PAPERDOLL_LHAND, null);
+				}
+			}
+		}
+		
+		@Override
+		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
+			if (slot != PAPERDOLL_RHAND) {
+				return;
+			}
+			
+			if (item.getItemType() == WeaponType.BOW) {
+				L2ItemInstance arrow = inventory.findArrowForBow(item.getItem());
+				
+				if (arrow != null) {
+					inventory.setPaperdollItem(PAPERDOLL_LHAND, arrow);
+				}
+			} else if (item.getItemType() == WeaponType.CROSSBOW) {
+				L2ItemInstance bolts = inventory.findBoltForCrossBow(item.getItem());
+				
+				if (bolts != null) {
+					inventory.setPaperdollItem(PAPERDOLL_LHAND, bolts);
+				}
+			}
+		}
+	}
+	
+	private static final class ItemSkillsListener implements PaperdollListener {
+		private static final ItemSkillsListener instance = new ItemSkillsListener();
+		
+		public static ItemSkillsListener getInstance() {
+			return instance;
+		}
+		
+		@Override
+		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
+			if (!(inventory.getOwner() instanceof L2PcInstance)) {
+				return;
+			}
+			final L2PcInstance player = (L2PcInstance) inventory.getOwner();
+			
+			Skill enchant4Skill, itemSkill;
+			L2Item it = item.getItem();
+			boolean update = false;
+			boolean updateTimeStamp = false;
+			
+			// Remove augmentation bonuses on unequip
+			if (item.isAugmented()) {
+				item.getAugmentation().removeBonus(player);
+			}
+			
+			item.unChargeAllShots();
+			item.removeElementAttrBonus(player);
+			
+			// Remove skills bestowed from +4 armor
+			if (item.getEnchantLevel() >= 4) {
+				enchant4Skill = it.getEnchant4Skill();
+				
+				if (enchant4Skill != null) {
+					player.removeSkill(enchant4Skill, false, enchant4Skill.isPassive());
+					update = true;
+				}
+			}
+			
+			item.clearEnchantStats();
+			
+			final SkillHolder[] skills = it.getSkills();
+			
+			if (skills != null) {
+				for (SkillHolder skillInfo : skills) {
+					if (skillInfo == null) {
+						continue;
+					}
+					
+					itemSkill = skillInfo.getSkill();
+					
+					if (itemSkill != null) {
+						player.removeSkill(itemSkill, false, itemSkill.isPassive());
+						update = true;
+					} else {
+						_log.warning("Inventory.ItemSkillsListener.Weapon: Incorrect skill: " + skillInfo + ".");
+					}
+				}
+			}
+			
+			if (item.isArmor()) {
+				for (L2ItemInstance itm : inventory.getItems()) {
+					if (!itm.isEquipped() || (itm.getItem().getSkills() == null) || itm.equals(item)) {
+						continue;
+					}
+					for (SkillHolder sk : itm.getItem().getSkills()) {
+						if (player.getSkillLevel(sk.getSkillId()) != -1) {
+							continue;
+						}
+						
+						itemSkill = sk.getSkill();
+						
+						if (itemSkill != null) {
+							player.addSkill(itemSkill, false);
+							
+							if (itemSkill.isActive()) {
+								if (!player.hasSkillReuse(itemSkill.getReuseHashCode())) {
+									int equipDelay = item.getEquipReuseDelay();
+									if (equipDelay > 0) {
+										player.addTimeStamp(itemSkill, equipDelay);
+										player.disableSkill(itemSkill, equipDelay);
+									}
+								}
+								updateTimeStamp = true;
+							}
+							update = true;
+						}
+					}
+				}
+			}
+			
+			// Apply skill, if weapon have "skills on unequip"
+			Skill unequipSkill = it.getUnequipSkill();
+			if (unequipSkill != null) {
+				unequipSkill.activateSkill(player, player);
+			}
+			
+			if (update) {
+				player.sendSkillList();
+				
+				if (updateTimeStamp) {
+					player.sendPacket(new SkillCoolTime(player));
+				}
+			}
+		}
+		
+		@Override
+		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
+			if (!(inventory.getOwner() instanceof L2PcInstance)) {
+				return;
+			}
+			
+			final L2PcInstance player = (L2PcInstance) inventory.getOwner();
+			
+			Skill enchant4Skill, itemSkill;
+			L2Item it = item.getItem();
+			boolean update = false;
+			boolean updateTimeStamp = false;
+			
+			// Apply augmentation bonuses on equip
+			if (item.isAugmented()) {
+				item.getAugmentation().applyBonus(player);
+			}
+			item.rechargeShots(true, true);
+			item.updateElementAttrBonus(player);
+			
+			// Add skills bestowed from +4 armor
+			if (item.getEnchantLevel() >= 4) {
+				enchant4Skill = it.getEnchant4Skill();
+				
+				if (enchant4Skill != null) {
+					player.addSkill(enchant4Skill, false);
+					update = true;
+				}
+			}
+			
+			item.applyEnchantStats();
+			
+			final SkillHolder[] skills = it.getSkills();
+			
+			if (skills != null) {
+				for (SkillHolder skillInfo : skills) {
+					if (skillInfo == null) {
+						continue;
+					}
+					
+					itemSkill = skillInfo.getSkill();
+					
+					if (itemSkill != null) {
+						itemSkill.setReferenceItemId(item.getId());
+						player.addSkill(itemSkill, false);
+						
+						if (itemSkill.isActive()) {
+							if (!player.hasSkillReuse(itemSkill.getReuseHashCode())) {
+								int equipDelay = item.getEquipReuseDelay();
+								if (equipDelay > 0) {
+									player.addTimeStamp(itemSkill, equipDelay);
+									player.disableSkill(itemSkill, equipDelay);
+								}
+							}
+							updateTimeStamp = true;
+						}
+						update = true;
+					} else {
+						_log.warning("Inventory.ItemSkillsListener.Weapon: Incorrect skill: " + skillInfo + ".");
+					}
+				}
+			}
+			
+			if (update) {
+				player.sendSkillList();
+				
+				if (updateTimeStamp) {
+					player.sendPacket(new SkillCoolTime(player));
+				}
+			}
+		}
+	}
+	
+	private static final class ArmorSetListener implements PaperdollListener {
+		private static final ArmorSetListener instance = new ArmorSetListener();
+		
+		public static ArmorSetListener getInstance() {
+			return instance;
+		}
+		
+		@Override
+		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
+			if (!(inventory.getOwner() instanceof L2PcInstance)) {
+				return;
+			}
+			
+			final L2PcInstance player = (L2PcInstance) inventory.getOwner();
+			
+			// Checks if player is wearing a chest item
+			final L2ItemInstance chestItem = inventory.getPaperdollItem(PAPERDOLL_CHEST);
+			
+			if (chestItem == null) {
+				return;
+			}
+			
+			// Checks for armor set for the equipped chest.
+			if (!ArmorSetsData.getInstance().isArmorSet(chestItem.getId())) {
+				return;
+			}
+			final L2ArmorSet armorSet = ArmorSetsData.getInstance().getSet(chestItem.getId());
+			boolean update = false;
+			boolean updateTimeStamp = false;
+			// Checks if equipped item is part of set
+			if (armorSet.containItem(slot, item.getId())) {
+				if (armorSet.containAll(player)) {
+					Skill itemSkill;
+					final List<SkillHolder> skills = armorSet.getSkills();
+					
+					if (skills != null) {
+						for (SkillHolder holder : skills) {
+							
+							itemSkill = holder.getSkill();
+							if (itemSkill != null) {
+								player.addSkill(itemSkill, false);
+								
+								if (itemSkill.isActive()) {
+									if (!player.hasSkillReuse(itemSkill.getReuseHashCode())) {
+										int equipDelay = item.getEquipReuseDelay();
+										if (equipDelay > 0) {
+											player.addTimeStamp(itemSkill, equipDelay);
+											player.disableSkill(itemSkill, equipDelay);
+										}
+									}
+									updateTimeStamp = true;
+								}
+								update = true;
+							} else {
+								_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
+							}
+						}
+					}
+					
+					if (armorSet.containShield(player)) // has shield from set
+					{
+						for (SkillHolder holder : armorSet.getShieldSkillId()) {
+							if (holder.getSkill() != null) {
+								player.addSkill(holder.getSkill(), false);
+								update = true;
+							} else {
+								_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
+							}
+						}
+					}
+					
+					if (armorSet.isEnchanted6(player)) // has all parts of set enchanted to 6 or more
+					{
+						for (SkillHolder holder : armorSet.getEnchant6skillId()) {
+							if (holder.getSkill() != null) {
+								player.addSkill(holder.getSkill(), false);
+								update = true;
+							} else {
+								_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
+							}
+						}
+					}
+				}
+			} else if (armorSet.containShield(item.getId())) {
+				for (SkillHolder holder : armorSet.getShieldSkillId()) {
+					if (holder.getSkill() != null) {
+						player.addSkill(holder.getSkill(), false);
+						update = true;
+					} else {
+						_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
+					}
+				}
+			}
+			
+			if (update) {
+				player.sendSkillList();
+				
+				if (updateTimeStamp) {
+					player.sendPacket(new SkillCoolTime(player));
+				}
+			}
+		}
+		
+		@Override
+		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
+			if (!(inventory.getOwner() instanceof L2PcInstance)) {
+				return;
+			}
+			
+			final L2PcInstance player = (L2PcInstance) inventory.getOwner();
+			
+			boolean remove = false;
+			Skill itemSkill;
+			List<SkillHolder> skills = null;
+			List<SkillHolder> shieldSkill = null; // shield skill
+			List<SkillHolder> skillId6 = null; // enchant +6 skill
+			
+			if (slot == PAPERDOLL_CHEST) {
+				if (!ArmorSetsData.getInstance().isArmorSet(item.getId())) {
+					return;
+				}
+				final L2ArmorSet armorSet = ArmorSetsData.getInstance().getSet(item.getId());
+				remove = true;
+				skills = armorSet.getSkills();
+				shieldSkill = armorSet.getShieldSkillId();
+				skillId6 = armorSet.getEnchant6skillId();
+			} else {
+				L2ItemInstance chestItem = inventory.getPaperdollItem(PAPERDOLL_CHEST);
+				if (chestItem == null) {
+					return;
+				}
+				
+				L2ArmorSet armorSet = ArmorSetsData.getInstance().getSet(chestItem.getId());
+				if (armorSet == null) {
+					return;
+				}
+				
+				if (armorSet.containItem(slot, item.getId())) // removed part of set
+				{
+					remove = true;
+					skills = armorSet.getSkills();
+					shieldSkill = armorSet.getShieldSkillId();
+					skillId6 = armorSet.getEnchant6skillId();
+				} else if (armorSet.containShield(item.getId())) // removed shield
+				{
+					remove = true;
+					shieldSkill = armorSet.getShieldSkillId();
+				}
+			}
+			
+			if (remove) {
+				if (skills != null) {
+					for (SkillHolder holder : skills) {
+						itemSkill = holder.getSkill();
+						if (itemSkill != null) {
+							player.removeSkill(itemSkill, false, itemSkill.isPassive());
+						} else {
+							_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
+						}
+					}
+				}
+				
+				if (shieldSkill != null) {
+					for (SkillHolder holder : shieldSkill) {
+						itemSkill = holder.getSkill();
+						if (itemSkill != null) {
+							player.removeSkill(itemSkill, false, itemSkill.isPassive());
+						} else {
+							_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
+						}
+					}
+				}
+				
+				if (skillId6 != null) {
+					for (SkillHolder holder : skillId6) {
+						itemSkill = holder.getSkill();
+						if (itemSkill != null) {
+							player.removeSkill(itemSkill, false, itemSkill.isPassive());
+						} else {
+							_log.warning("Inventory.ArmorSetListener: Incorrect skill: " + holder + ".");
+						}
+					}
+				}
+				
+				player.checkItemRestriction();
+				player.sendSkillList();
+			}
+		}
+	}
+	
+	private static final class BraceletListener implements PaperdollListener {
+		private static final BraceletListener instance = new BraceletListener();
+		
+		public static BraceletListener getInstance() {
+			return instance;
+		}
+		
+		@Override
+		public void notifyUnequiped(int slot, L2ItemInstance item, Inventory inventory) {
+			if (item.getItem().getBodyPart() == L2Item.SLOT_R_BRACELET) {
+				inventory.unEquipItemInSlot(PAPERDOLL_DECO1);
+				inventory.unEquipItemInSlot(PAPERDOLL_DECO2);
+				inventory.unEquipItemInSlot(PAPERDOLL_DECO3);
+				inventory.unEquipItemInSlot(PAPERDOLL_DECO4);
+				inventory.unEquipItemInSlot(PAPERDOLL_DECO5);
+				inventory.unEquipItemInSlot(PAPERDOLL_DECO6);
+			}
+		}
+		
+		// Note (April 3, 2009): Currently on equip, talismans do not display properly, do we need checks here to fix this?
+		@Override
+		public void notifyEquiped(int slot, L2ItemInstance item, Inventory inventory) {
+		}
+	}
 }

+ 10 - 1
src/main/java/com/l2jserver/gameserver/network/L2GameClient.java

@@ -1,5 +1,5 @@
 /*
- * Copyright © 2004-2021 L2J Server
+ * Copyright © 2004-2022 L2J Server
  * 
  * This file is part of L2J Server.
  * 
@@ -102,6 +102,7 @@ public final class L2GameClient extends MMOClient<MMOConnection<L2GameClient>> i
 	private boolean _isAuthedGG;
 	private final long _connectionStartTime;
 	private List<CharSelectInfoPackage> _charSlotMapping = null;
+	private int _charSlot = -1;
 	
 	// flood protectors
 	private final FloodProtectors _floodProtectors = new FloodProtectors(this);
@@ -524,6 +525,14 @@ public final class L2GameClient extends MMOClient<MMOConnection<L2GameClient>> i
 		_charSlotMapping = list;
 	}
 	
+	public void setCharSelectionSlot(int charSlot) {
+		_charSlot = charSlot;
+	}
+	
+	public CharSelectInfoPackage getCharSelection() {
+		return getCharSelection(_charSlot);
+	}
+	
 	public CharSelectInfoPackage getCharSelection(int charslot) {
 		if ((_charSlotMapping == null) || (charslot < 0) || (charslot >= _charSlotMapping.size())) {
 			return null;

+ 4 - 1
src/main/java/com/l2jserver/gameserver/network/clientpackets/CharacterSelect.java

@@ -1,5 +1,5 @@
 /*
- * Copyright © 2004-2021 L2J Server
+ * Copyright © 2004-2022 L2J Server
  * 
  * This file is part of L2J Server.
  * 
@@ -138,6 +138,9 @@ public class CharacterSelect extends L2GameClientPacket {
 						cha.deleteMe();
 						return;
 					}
+
+					client.setCharSelectionSlot(_charSlot);
+					cha.restoreStatusFromLoadedValues();
 					
 					sendPacket(new SSQInfo());
 					

+ 3 - 1
src/main/java/com/l2jserver/gameserver/network/serverpackets/CharSelectionInfo.java

@@ -1,5 +1,5 @@
 /*
- * Copyright © 2004-2021 L2J Server
+ * Copyright © 2004-2022 L2J Server
  * 
  * This file is part of L2J Server.
  * 
@@ -221,6 +221,8 @@ public class CharSelectionInfo extends L2GameServerPacket {
 		CharSelectInfoPackage charInfopackage = new CharSelectInfoPackage(objectId, name);
 		charInfopackage.setAccessLevel(chardata.getInt("accesslevel"));
 		charInfopackage.setLevel(chardata.getInt("level"));
+		charInfopackage.setMaxCp(chardata.getInt("maxCp"));
+		charInfopackage.setCurrentCp(chardata.getInt("curCp"));
 		charInfopackage.setMaxHp(chardata.getInt("maxhp"));
 		charInfopackage.setCurrentHp(chardata.getDouble("curhp"));
 		charInfopackage.setMaxMp(chardata.getInt("maxmp"));