Bläddra i källkod

Merge remote-tracking branch 'origin/master' into
feature/ConnectionFactory

Conflicts:
L2J_Server/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java
L2J_Server/java/com/l2jserver/gameserver/taskmanager/tasks/TaskBirthday.java

Zoey76 9 år sedan
förälder
incheckning
705a25d5b2
31 ändrade filer med 382 tillägg och 447 borttagningar
  1. 1 1
      L2J_Server/java/com/l2jserver/gameserver/data/sql/impl/OfflineTradersTable.java
  2. 33 20
      L2J_Server/java/com/l2jserver/gameserver/data/xml/impl/SkillTreesData.java
  3. 24 93
      L2J_Server/java/com/l2jserver/gameserver/instancemanager/GrandBossManager.java
  4. 18 17
      L2J_Server/java/com/l2jserver/gameserver/model/L2Clan.java
  5. 3 7
      L2J_Server/java/com/l2jserver/gameserver/model/L2ClanMember.java
  6. 32 26
      L2J_Server/java/com/l2jserver/gameserver/model/L2Party.java
  7. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/actor/L2Attackable.java
  8. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/actor/L2Character.java
  9. 27 28
      L2J_Server/java/com/l2jserver/gameserver/model/actor/instance/L2CubicInstance.java
  10. 48 26
      L2J_Server/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java
  11. 74 72
      L2J_Server/java/com/l2jserver/gameserver/model/actor/tasks/cubics/CubicAction.java
  12. 11 22
      L2J_Server/java/com/l2jserver/gameserver/model/actor/tasks/cubics/CubicHeal.java
  13. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IAmountMultiplierStrategy.java
  14. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IChanceMultiplierStrategy.java
  15. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IDropCalculationStrategy.java
  16. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IGroupedItemDropCalculationStrategy.java
  17. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IKillerChanceModifierStrategy.java
  18. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/INonGroupedKillerChanceModifierStrategy.java
  19. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IPreciseDeterminationStrategy.java
  20. 1 1
      L2J_Server/java/com/l2jserver/gameserver/model/entity/TvTEventTeam.java
  21. 1 6
      L2J_Server/java/com/l2jserver/gameserver/model/itemcontainer/Inventory.java
  22. 7 13
      L2J_Server/java/com/l2jserver/gameserver/model/items/L2Weapon.java
  23. 2 2
      L2J_Server/java/com/l2jserver/gameserver/model/quest/QuestState.java
  24. 38 15
      L2J_Server/java/com/l2jserver/gameserver/model/skills/Skill.java
  25. 6 5
      L2J_Server/java/com/l2jserver/gameserver/model/stats/functions/formulas/FuncAtkEvasion.java
  26. 6 5
      L2J_Server/java/com/l2jserver/gameserver/network/clientpackets/EnterWorld.java
  27. 1 1
      L2J_Server/java/com/l2jserver/gameserver/network/clientpackets/RequestAnswerJoinPledge.java
  28. 4 2
      L2J_Server/java/com/l2jserver/gameserver/network/clientpackets/RequestOustPledgeMember.java
  29. 3 1
      L2J_Server/java/com/l2jserver/gameserver/network/clientpackets/RequestWithdrawalPledge.java
  30. 22 72
      L2J_Server/java/com/l2jserver/gameserver/taskmanager/tasks/TaskBirthday.java
  31. 11 3
      L2J_Server/java/com/l2jserver/util/IPv4Filter.java

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/data/sql/impl/OfflineTradersTable.java

@@ -65,7 +65,7 @@ public class OfflineTradersTable
 			{
 				try
 				{
-					if ((pc.getPrivateStoreType() != PrivateStoreType.NONE) && ((pc.getClient() == null) || pc.getClient().isDetached()))
+					if ((pc.getPrivateStoreType() != PrivateStoreType.NONE) && pc.isInOfflineMode())
 					{
 						stm3.setInt(1, pc.getObjectId()); // Char Id
 						stm3.setLong(2, pc.getOfflineStartTime());

+ 33 - 20
L2J_Server/java/com/l2jserver/gameserver/data/xml/impl/SkillTreesData.java

@@ -22,6 +22,8 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -74,22 +76,22 @@ import com.l2jserver.util.data.xml.IXmlReader;
  */
 public final class SkillTreesData implements IXmlReader
 {
-	// ClassId, FastMap of Skill Hash Code, L2SkillLearn
-	private final Map<ClassId, Map<Integer, L2SkillLearn>> _classSkillTrees = new HashMap<>();
-	private final Map<ClassId, Map<Integer, L2SkillLearn>> _transferSkillTrees = new HashMap<>();
+	// ClassId, Map of Skill Hash Code, L2SkillLearn
+	private final Map<ClassId, Map<Integer, L2SkillLearn>> _classSkillTrees = new LinkedHashMap<>();
+	private final Map<ClassId, Map<Integer, L2SkillLearn>> _transferSkillTrees = new LinkedHashMap<>();
 	// Skill Hash Code, L2SkillLearn
-	private final Map<Integer, L2SkillLearn> _collectSkillTree = new HashMap<>();
-	private final Map<Integer, L2SkillLearn> _fishingSkillTree = new HashMap<>();
-	private final Map<Integer, L2SkillLearn> _pledgeSkillTree = new HashMap<>();
-	private final Map<Integer, L2SkillLearn> _subClassSkillTree = new HashMap<>();
-	private final Map<Integer, L2SkillLearn> _subPledgeSkillTree = new HashMap<>();
-	private final Map<Integer, L2SkillLearn> _transformSkillTree = new HashMap<>();
-	private final Map<Integer, L2SkillLearn> _commonSkillTree = new HashMap<>();
+	private final Map<Integer, L2SkillLearn> _collectSkillTree = new LinkedHashMap<>();
+	private final Map<Integer, L2SkillLearn> _fishingSkillTree = new LinkedHashMap<>();
+	private final Map<Integer, L2SkillLearn> _pledgeSkillTree = new LinkedHashMap<>();
+	private final Map<Integer, L2SkillLearn> _subClassSkillTree = new LinkedHashMap<>();
+	private final Map<Integer, L2SkillLearn> _subPledgeSkillTree = new LinkedHashMap<>();
+	private final Map<Integer, L2SkillLearn> _transformSkillTree = new LinkedHashMap<>();
+	private final Map<Integer, L2SkillLearn> _commonSkillTree = new LinkedHashMap<>();
 	// Other skill trees
-	private final Map<Integer, L2SkillLearn> _nobleSkillTree = new HashMap<>();
-	private final Map<Integer, L2SkillLearn> _heroSkillTree = new HashMap<>();
-	private final Map<Integer, L2SkillLearn> _gameMasterSkillTree = new HashMap<>();
-	private final Map<Integer, L2SkillLearn> _gameMasterAuraSkillTree = new HashMap<>();
+	private final Map<Integer, L2SkillLearn> _nobleSkillTree = new LinkedHashMap<>();
+	private final Map<Integer, L2SkillLearn> _heroSkillTree = new LinkedHashMap<>();
+	private final Map<Integer, L2SkillLearn> _gameMasterSkillTree = new LinkedHashMap<>();
+	private final Map<Integer, L2SkillLearn> _gameMasterAuraSkillTree = new LinkedHashMap<>();
 	
 	// Checker, sorted arrays of hash codes
 	private Map<Integer, int[]> _skillsByClassIdHashCodes; // Occupation skills
@@ -98,8 +100,8 @@ public final class SkillTreesData implements IXmlReader
 	
 	private boolean _loading = true;
 	
-	/** Parent class Ids are read from XML and stored in this map, to allow easy customization. */
-	private final Map<ClassId, ClassId> _parentClassMap = new HashMap<>();
+	/** Parent class IDs are read from XML and stored in this map, to allow easy customization. */
+	private final Map<ClassId, ClassId> _parentClassMap = new LinkedHashMap<>();
 	
 	/**
 	 * Instantiates a new skill trees data.
@@ -325,14 +327,25 @@ public final class SkillTreesData implements IXmlReader
 	 */
 	public Map<Integer, L2SkillLearn> getCompleteClassSkillTree(ClassId classId)
 	{
-		final Map<Integer, L2SkillLearn> skillTree = new HashMap<>();
+		final Map<Integer, L2SkillLearn> skillTree = new LinkedHashMap<>();
 		// Add all skills that belong to all classes.
 		skillTree.putAll(_commonSkillTree);
-		while ((classId != null) && (_classSkillTrees.get(classId) != null))
+		
+		final LinkedList<ClassId> classSequence = new LinkedList<>();
+		while (classId != null)
 		{
-			skillTree.putAll(_classSkillTrees.get(classId));
+			classSequence.addFirst(classId);
 			classId = _parentClassMap.get(classId);
 		}
+		
+		for (ClassId cid : classSequence)
+		{
+			final Map<Integer, L2SkillLearn> classSkillTree = _classSkillTrees.get(cid);
+			if (classSkillTree != null)
+			{
+				skillTree.putAll(classSkillTree);
+			}
+		}
 		return skillTree;
 	}
 	
@@ -735,7 +748,7 @@ public final class SkillTreesData implements IXmlReader
 				final Skill oldSkill = clan.getSkills().get(skill.getSkillId());
 				if (oldSkill != null)
 				{
-					if (oldSkill.getLevel() < skill.getSkillLevel())
+					if ((oldSkill.getLevel() + 1) == skill.getSkillLevel())
 					{
 						result.add(skill);
 					}

+ 24 - 93
L2J_Server/java/com/l2jserver/gameserver/instancemanager/GrandBossManager.java

@@ -30,7 +30,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -65,9 +64,9 @@ public final class GrandBossManager implements IStorable
 	
 	protected static Map<Integer, StatsSet> _storedInfo = new HashMap<>();
 	
-	private final Map<Integer, Integer> _bossStatus = new HashMap<>();
+	private final Map<Integer, Integer> _bossStatus = new ConcurrentHashMap<>();
 	
-	private final List<L2BossZone> _zones = new CopyOnWriteArrayList<>();
+	private final Map<Integer, L2BossZone> _zones = new ConcurrentHashMap<>();
 	
 	protected GrandBossManager()
 	{
@@ -124,21 +123,10 @@ public final class GrandBossManager implements IStorable
 	 */
 	public void initZones()
 	{
-		Map<Integer, List<Integer>> zones = new HashMap<>();
-		
-		if (_zones == null)
-		{
-			_log.warning(getClass().getSimpleName() + ": Could not read Grand Boss zone data");
-			return;
-		}
-		
-		for (L2BossZone zone : _zones)
+		final Map<Integer, List<Integer>> zones = new HashMap<>();
+		for (Integer zoneId : _zones.keySet())
 		{
-			if (zone == null)
-			{
-				continue;
-			}
-			zones.put(zone.getId(), new ArrayList<>());
+			zones.put(zoneId, new ArrayList<>());
 		}
 		
 		try (Connection con = ConnectionFactory.getInstance().getConnection();
@@ -148,8 +136,8 @@ public final class GrandBossManager implements IStorable
 			while (rs.next())
 			{
 				int id = rs.getInt("player_id");
-				int zone_id = rs.getInt("zone");
-				zones.get(zone_id).add(id);
+				int zoneId = rs.getInt("zone");
+				zones.get(zoneId).add(id);
 			}
 			_log.info(getClass().getSimpleName() + ": Initialized " + _zones.size() + " Grand Boss Zones");
 		}
@@ -162,13 +150,9 @@ public final class GrandBossManager implements IStorable
 			_log.log(Level.WARNING, "Error while initializing GrandBoss zones: " + e.getMessage(), e);
 		}
 		
-		for (L2BossZone zone : _zones)
+		for (Entry<Integer, L2BossZone> e : _zones.entrySet())
 		{
-			if (zone == null)
-			{
-				continue;
-			}
-			zone.setAllowedPlayers(zones.get(zone.getId()));
+			e.getValue().setAllowedPlayers(zones.get(e.getKey()));
 		}
 		
 		zones.clear();
@@ -176,86 +160,38 @@ public final class GrandBossManager implements IStorable
 	
 	public void addZone(L2BossZone zone)
 	{
-		if (_zones != null)
-		{
-			_zones.add(zone);
-		}
+		_zones.put(zone.getId(), zone);
 	}
 	
-	public final L2BossZone getZone(int zoneId)
+	public L2BossZone getZone(int zoneId)
 	{
-		if (_zones != null)
-		{
-			for (L2BossZone temp : _zones)
-			{
-				if (temp.getId() == zoneId)
-				{
-					return temp;
-				}
-			}
-		}
-		return null;
+		return _zones.get(zoneId);
 	}
 	
-	public final L2BossZone getZone(L2Character character)
+	public L2BossZone getZone(L2Character character)
 	{
-		if (_zones != null)
-		{
-			for (L2BossZone temp : _zones)
-			{
-				if (temp.isCharacterInZone(character))
-				{
-					return temp;
-				}
-			}
-		}
-		return null;
+		return _zones.values().stream().filter(z -> z.isCharacterInZone(character)).findFirst().orElse(null);
 	}
 	
-	public final L2BossZone getZone(Location loc)
+	public L2BossZone getZone(Location loc)
 	{
 		return getZone(loc.getX(), loc.getY(), loc.getZ());
 	}
 	
-	public final L2BossZone getZone(int x, int y, int z)
+	public L2BossZone getZone(int x, int y, int z)
 	{
-		if (_zones != null)
-		{
-			for (L2BossZone temp : _zones)
-			{
-				if (temp.isInsideZone(x, y, z))
-				{
-					return temp;
-				}
-			}
-		}
-		return null;
+		return _zones.values().stream().filter(zone -> zone.isInsideZone(x, y, z)).findFirst().orElse(null);
 	}
 	
 	public boolean checkIfInZone(String zoneType, L2Object obj)
 	{
-		L2BossZone temp = getZone(obj.getX(), obj.getY(), obj.getZ());
-		if (temp == null)
-		{
-			return false;
-		}
-		
-		return temp.getName().equalsIgnoreCase(zoneType);
+		final L2BossZone temp = getZone(obj.getX(), obj.getY(), obj.getZ());
+		return (temp != null) && temp.getName().equalsIgnoreCase(zoneType);
 	}
 	
 	public boolean checkIfInZone(L2PcInstance player)
 	{
-		if (player == null)
-		{
-			return false;
-		}
-		L2BossZone temp = getZone(player.getX(), player.getY(), player.getZ());
-		if (temp == null)
-		{
-			return false;
-		}
-		
-		return true;
+		return (player != null) && (getZone(player.getX(), player.getY(), player.getZ()) != null);
 	}
 	
 	public int getBossStatus(int bossId)
@@ -308,14 +244,9 @@ public final class GrandBossManager implements IStorable
 			
 			try (PreparedStatement insert = con.prepareStatement(INSERT_GRAND_BOSS_LIST))
 			{
-				for (L2BossZone zone : _zones)
+				for (Entry<Integer, L2BossZone> e : _zones.entrySet())
 				{
-					if (zone == null)
-					{
-						continue;
-					}
-					Integer id = zone.getId();
-					List<Integer> list = zone.getAllowedPlayers();
+					List<Integer> list = e.getValue().getAllowedPlayers();
 					if ((list == null) || list.isEmpty())
 					{
 						continue;
@@ -323,7 +254,7 @@ public final class GrandBossManager implements IStorable
 					for (Integer player : list)
 					{
 						insert.setInt(1, player);
-						insert.setInt(2, id);
+						insert.setInt(2, e.getKey());
 						insert.executeUpdate();
 						insert.clearParameters();
 					}
@@ -436,7 +367,7 @@ public final class GrandBossManager implements IStorable
 		_zones.clear();
 	}
 	
-	public List<L2BossZone> getZones()
+	public Map<Integer, L2BossZone> getZones()
 	{
 		return _zones;
 	}

+ 18 - 17
L2J_Server/java/com/l2jserver/gameserver/model/L2Clan.java

@@ -30,6 +30,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -356,13 +357,14 @@ public class L2Clan implements IIdentifiable, INamable
 	public void addClanMember(L2PcInstance player)
 	{
 		final L2ClanMember member = new L2ClanMember(this, player);
-		// store in memory
-		addClanMember(member);
 		member.setPlayerInstance(player);
+		addClanMember(member);
+		
 		player.setClan(this);
 		player.setPledgeClass(L2ClanMember.calculatePledgeClass(player));
 		player.sendPacket(new PledgeShowMemberListUpdate(player));
 		player.sendPacket(new PledgeSkillList(this));
+		
 		addSkillEffects(player);
 		
 		// Notify to scripts
@@ -469,9 +471,10 @@ public class L2Clan implements IIdentifiable, INamable
 		{
 			CastleManager.getInstance().removeCirclet(exMember, getCastleId());
 		}
-		if (exMember.isOnline())
+		
+		final L2PcInstance player = exMember.getPlayerInstance();
+		if (player != null)
 		{
-			L2PcInstance player = exMember.getPlayerInstance();
 			if (!player.isNoble())
 			{
 				player.setTitle("");
@@ -482,7 +485,7 @@ public class L2Clan implements IIdentifiable, INamable
 			if (player.isClanLeader())
 			{
 				SiegeManager.getInstance().removeSiegeSkills(player);
-				player.setClanCreateExpiryTime(System.currentTimeMillis() + (Config.ALT_CLAN_CREATE_DAYS * 86400000L)); // 24*60*60*1000 = 86400000
+				player.setClanCreateExpiryTime(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(Config.ALT_CLAN_CREATE_DAYS));
 			}
 			// remove Clan skills from Player
 			removeSkillEffects(player);
@@ -513,7 +516,7 @@ public class L2Clan implements IIdentifiable, INamable
 		}
 		else
 		{
-			removeMemberInDatabase(exMember, clanJoinExpiryTime, getLeaderId() == objectId ? System.currentTimeMillis() + (Config.ALT_CLAN_CREATE_DAYS * 86400000L) : 0);
+			removeMemberInDatabase(exMember.getObjectId(), clanJoinExpiryTime, getLeaderId() == objectId ? System.currentTimeMillis() + TimeUnit.DAYS.toMillis(Config.ALT_CLAN_CREATE_DAYS) : 0);
 		}
 		
 		// Notify to scripts
@@ -1004,31 +1007,29 @@ public class L2Clan implements IIdentifiable, INamable
 	}
 	
 	/**
-	 * @param member the clan member to be removed.
-	 * @param clanJoinExpiryTime
-	 * @param clanCreateExpiryTime
+	 * Removes a clan member from this clan.
+	 * @param playerId the clan member object ID to be removed
+	 * @param clanJoinExpiryTime the time penalty for the player to join a new clan
+	 * @param clanCreateExpiryTime the time penalty for the player to create a new clan
 	 */
-	private void removeMemberInDatabase(L2ClanMember member, long clanJoinExpiryTime, long clanCreateExpiryTime)
+	private void removeMemberInDatabase(int playerId, long clanJoinExpiryTime, long clanCreateExpiryTime)
 	{
 		try (Connection con = ConnectionFactory.getInstance().getConnection();
 			PreparedStatement ps1 = con.prepareStatement("UPDATE characters SET clanid=0, title=?, clan_join_expiry_time=?, clan_create_expiry_time=?, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0 WHERE charId=?");
 			PreparedStatement ps2 = con.prepareStatement("UPDATE characters SET apprentice=0 WHERE apprentice=?");
 			PreparedStatement ps3 = con.prepareStatement("UPDATE characters SET sponsor=0 WHERE sponsor=?"))
 		{
+			// Remove clan member.
 			ps1.setString(1, "");
 			ps1.setLong(2, clanJoinExpiryTime);
 			ps1.setLong(3, clanCreateExpiryTime);
-			ps1.setInt(4, member.getObjectId());
+			ps1.setInt(4, playerId);
 			ps1.execute();
-			if (Config.DEBUG)
-			{
-				_log.fine("clan member removed in db: " + getId());
-			}
 			// Remove apprentice.
-			ps2.setInt(1, member.getObjectId());
+			ps2.setInt(1, playerId);
 			ps2.execute();
 			// Remove sponsor.
-			ps3.setInt(1, member.getObjectId());
+			ps3.setInt(1, playerId);
 			ps3.execute();
 		}
 		catch (Exception e)

+ 3 - 7
L2J_Server/java/com/l2jserver/gameserver/model/L2ClanMember.java

@@ -149,8 +149,8 @@ public class L2ClanMember
 	}
 	
 	/**
-	 * Checks if is online.
-	 * @return true, if is online
+	 * Verifies if the clan member is online.
+	 * @return {@code true} if is online
 	 */
 	public boolean isOnline()
 	{
@@ -158,11 +158,7 @@ public class L2ClanMember
 		{
 			return false;
 		}
-		if (_player.getClient() == null)
-		{
-			return false;
-		}
-		if (_player.getClient().isDetached())
+		if (_player.isInOfflineMode())
 		{
 			return false;
 		}

+ 32 - 26
L2J_Server/java/com/l2jserver/gameserver/model/L2Party.java

@@ -618,20 +618,23 @@ public class L2Party extends AbstractPlayerGroup
 		target.addItem("Party", item, player, true);
 		
 		// Send messages to other party members about reward
-		if (item.getCount() > 1)
+		if (item.getCount() > 0)
 		{
-			SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_OBTAINED_S3_S2);
-			msg.addString(target.getName());
-			msg.addItemName(item);
-			msg.addLong(item.getCount());
-			broadcastToPartyMembers(target, msg);
-		}
-		else
-		{
-			SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_OBTAINED_S2);
-			msg.addString(target.getName());
-			msg.addItemName(item);
-			broadcastToPartyMembers(target, msg);
+			if (item.getCount() > 1)
+			{
+				SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_OBTAINED_S3_S2);
+				msg.addString(target.getName());
+				msg.addItemName(item);
+				msg.addLong(item.getCount());
+				broadcastToPartyMembers(target, msg);
+			}
+			else
+			{
+				SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_OBTAINED_S2);
+				msg.addString(target.getName());
+				msg.addItemName(item);
+				broadcastToPartyMembers(target, msg);
+			}
 		}
 	}
 	
@@ -656,20 +659,23 @@ public class L2Party extends AbstractPlayerGroup
 		looter.addItem(spoil ? "Sweeper Party" : "Party", itemId, itemCount, target, true);
 		
 		// Send messages to other party members about reward
-		if (itemCount > 1)
+		if (itemCount > 0)
 		{
-			SystemMessage msg = spoil ? SystemMessage.getSystemMessage(SystemMessageId.C1_SWEEPED_UP_S3_S2) : SystemMessage.getSystemMessage(SystemMessageId.C1_OBTAINED_S3_S2);
-			msg.addString(looter.getName());
-			msg.addItemName(itemId);
-			msg.addLong(itemCount);
-			broadcastToPartyMembers(looter, msg);
-		}
-		else
-		{
-			SystemMessage msg = spoil ? SystemMessage.getSystemMessage(SystemMessageId.C1_SWEEPED_UP_S2) : SystemMessage.getSystemMessage(SystemMessageId.C1_OBTAINED_S2);
-			msg.addString(looter.getName());
-			msg.addItemName(itemId);
-			broadcastToPartyMembers(looter, msg);
+			if (itemCount > 1)
+			{
+				SystemMessage msg = spoil ? SystemMessage.getSystemMessage(SystemMessageId.C1_SWEEPED_UP_S3_S2) : SystemMessage.getSystemMessage(SystemMessageId.C1_OBTAINED_S3_S2);
+				msg.addString(looter.getName());
+				msg.addItemName(itemId);
+				msg.addLong(itemCount);
+				broadcastToPartyMembers(looter, msg);
+			}
+			else
+			{
+				SystemMessage msg = spoil ? SystemMessage.getSystemMessage(SystemMessageId.C1_SWEEPED_UP_S2) : SystemMessage.getSystemMessage(SystemMessageId.C1_OBTAINED_S2);
+				msg.addString(looter.getName());
+				msg.addItemName(itemId);
+				broadcastToPartyMembers(looter, msg);
+			}
 		}
 	}
 	

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/actor/L2Attackable.java

@@ -989,7 +989,7 @@ public class L2Attackable extends L2Npc
 				}
 				
 				// Broadcast message if RaidBoss was defeated
-				if (isRaid() && !isRaidMinion())
+				if (isRaid() && !isRaidMinion() && drop.getCount() > 0)
 				{
 					final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_DIED_DROPPED_S3_S2);
 					sm.addCharName(this);

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/actor/L2Character.java

@@ -5287,7 +5287,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 			
 			if (newSkill.isPassive())
 			{
-				newSkill.applyEffects(this, null, this, false, true, false, 0);
+				newSkill.applyEffects(this, this, false, true, false, 0);
 			}
 		}
 		return oldSkill;

+ 27 - 28
L2J_Server/java/com/l2jserver/gameserver/model/actor/instance/L2CubicInstance.java

@@ -33,7 +33,6 @@ import com.l2jserver.gameserver.model.L2Object;
 import com.l2jserver.gameserver.model.L2Party;
 import com.l2jserver.gameserver.model.actor.L2Attackable;
 import com.l2jserver.gameserver.model.actor.L2Character;
-import com.l2jserver.gameserver.model.actor.L2Playable;
 import com.l2jserver.gameserver.model.actor.tasks.cubics.CubicAction;
 import com.l2jserver.gameserver.model.actor.tasks.cubics.CubicDisappear;
 import com.l2jserver.gameserver.model.actor.tasks.cubics.CubicHeal;
@@ -355,7 +354,7 @@ public final class L2CubicInstance implements IIdentifiable
 			{
 				if (_owner.isOlympiadStart())
 				{
-					if (ownerTarget instanceof L2Playable)
+					if (ownerTarget.isPlayable())
 					{
 						final L2PcInstance targetPlayer = ownerTarget.getActingPlayer();
 						if ((targetPlayer != null) && (targetPlayer.getOlympiadGameId() == _owner.getOlympiadGameId()) && (targetPlayer.getOlympiadSide() != _owner.getOlympiadSide()))
@@ -367,19 +366,20 @@ public final class L2CubicInstance implements IIdentifiable
 				return;
 			}
 			// test owners target if it is valid then use it
-			if ((ownerTarget instanceof L2Character) && (ownerTarget != _owner.getSummon()) && (ownerTarget != _owner))
+			if (ownerTarget.isCharacter() && (ownerTarget != _owner.getSummon()) && (ownerTarget != _owner))
 			{
 				// target mob which has aggro on you or your summon
-				if (ownerTarget instanceof L2Attackable)
+				if (ownerTarget.isAttackable())
 				{
-					if ((((L2Attackable) ownerTarget).getAggroList().get(_owner) != null) && !((L2Attackable) ownerTarget).isDead())
+					final L2Attackable attackable = (L2Attackable) ownerTarget;
+					if ((attackable.getAggroList().get(_owner) != null) && !attackable.isDead())
 					{
 						_target = (L2Character) ownerTarget;
 						return;
 					}
 					if (_owner.hasSummon())
 					{
-						if ((((L2Attackable) ownerTarget).getAggroList().get(_owner.getSummon()) != null) && !((L2Attackable) ownerTarget).isDead())
+						if ((attackable.getAggroList().get(_owner.getSummon()) != null) && !attackable.isDead())
 						{
 							_target = (L2Character) ownerTarget;
 							return;
@@ -472,21 +472,21 @@ public final class L2CubicInstance implements IIdentifiable
 			
 			if (skill.isBad())
 			{
-				byte shld = Formulas.calcShldUse(getOwner(), target, skill);
+				byte shld = Formulas.calcShldUse(_owner, target, skill);
 				boolean acted = Formulas.calcCubicSkillSuccess(this, target, skill, shld);
 				if (!acted)
 				{
-					getOwner().sendPacket(SystemMessageId.ATTACK_FAILED);
+					_owner.sendPacket(SystemMessageId.ATTACK_FAILED);
 					continue;
 				}
 				
 			}
 			
 			// Apply effects
-			skill.applyEffects(getOwner(), this, target, false, false, true, 0);
+			skill.applyEffects(_owner, target, false, false, true, 0);
 			
 			// If this is a bad skill notify the duel manager, so it can be removed after the duel (player & target must be in the same duel).
-			if (target.isPlayer() && target.getActingPlayer().isInDuel() && skill.isBad() && (getOwner().getDuelId() == target.getActingPlayer().getDuelId()))
+			if (target.isPlayer() && target.getActingPlayer().isInDuel() && skill.isBad() && (_owner.getDuelId() == target.getActingPlayer().getDuelId()))
 			{
 				DuelManager.getInstance().onBuff(target.getActingPlayer(), skill);
 			}
@@ -494,11 +494,10 @@ public final class L2CubicInstance implements IIdentifiable
 	}
 	
 	/**
-	 * @param activeCubic
 	 * @param skill
 	 * @param targets
 	 */
-	public void useCubicMdam(L2CubicInstance activeCubic, Skill skill, L2Object[] targets)
+	public void useCubicMdam(Skill skill, L2Object[] targets)
 	{
 		for (L2Character target : (L2Character[]) targets)
 		{
@@ -519,9 +518,9 @@ public final class L2CubicInstance implements IIdentifiable
 				}
 			}
 			
-			boolean mcrit = Formulas.calcMCrit(activeCubic.getOwner().getMCriticalHit(target, skill));
-			byte shld = Formulas.calcShldUse(activeCubic.getOwner(), target, skill);
-			int damage = (int) Formulas.calcMagicDam(activeCubic, target, skill, mcrit, shld);
+			boolean mcrit = Formulas.calcMCrit(_owner.getMCriticalHit(target, skill));
+			byte shld = Formulas.calcShldUse(_owner, target, skill);
+			int damage = (int) Formulas.calcMagicDam(this, target, skill, mcrit, shld);
 			
 			if (Config.DEBUG)
 			{
@@ -544,14 +543,14 @@ public final class L2CubicInstance implements IIdentifiable
 				}
 				else
 				{
-					activeCubic.getOwner().sendDamageMessage(target, damage, mcrit, false, false);
-					target.reduceCurrentHp(damage, activeCubic.getOwner(), skill);
+					_owner.sendDamageMessage(target, damage, mcrit, false, false);
+					target.reduceCurrentHp(damage, _owner, skill);
 				}
 			}
 		}
 	}
 	
-	public void useCubicDrain(L2CubicInstance activeCubic, Skill skill, L2Object[] targets)
+	public void useCubicDrain(Skill skill, L2Object[] targets)
 	{
 		if (Config.DEBUG)
 		{
@@ -565,10 +564,10 @@ public final class L2CubicInstance implements IIdentifiable
 				continue;
 			}
 			
-			boolean mcrit = Formulas.calcMCrit(activeCubic.getOwner().getMCriticalHit(target, skill));
-			byte shld = Formulas.calcShldUse(activeCubic.getOwner(), target, skill);
+			boolean mcrit = Formulas.calcMCrit(_owner.getMCriticalHit(target, skill));
+			byte shld = Formulas.calcShldUse(_owner, target, skill);
 			
-			int damage = (int) Formulas.calcMagicDam(activeCubic, target, skill, mcrit, shld);
+			int damage = (int) Formulas.calcMagicDam(this, target, skill, mcrit, shld);
 			if (Config.DEBUG)
 			{
 				_log.info("L2SkillDrain: useCubicSkill() -> damage = " + damage);
@@ -576,7 +575,7 @@ public final class L2CubicInstance implements IIdentifiable
 			
 			// TODO: Unhardcode fixed value
 			double hpAdd = (0.4 * damage);
-			L2PcInstance owner = activeCubic.getOwner();
+			L2PcInstance owner = _owner;
 			double hp = ((owner.getCurrentHp() + hpAdd) > owner.getMaxHp() ? owner.getMaxHp() : (owner.getCurrentHp() + hpAdd));
 			
 			owner.setCurrentHp(hp);
@@ -584,7 +583,7 @@ public final class L2CubicInstance implements IIdentifiable
 			// Check to see if we should damage the target
 			if ((damage > 0) && !target.isDead())
 			{
-				target.reduceCurrentHp(damage, activeCubic.getOwner(), skill);
+				target.reduceCurrentHp(damage, _owner, skill);
 				
 				// Manage attack or cast break of the target (calculating rate, sending message...)
 				if (!target.isRaid() && Formulas.calcAtkBreak(target, damage))
@@ -611,17 +610,17 @@ public final class L2CubicInstance implements IIdentifiable
 				continue;
 			}
 			
-			byte shld = Formulas.calcShldUse(getOwner(), target, skill);
+			byte shld = Formulas.calcShldUse(_owner, target, skill);
 			
 			if (skill.hasEffectType(L2EffectType.STUN, L2EffectType.PARALYZE, L2EffectType.ROOT))
 			{
 				if (Formulas.calcCubicSkillSuccess(this, target, skill, shld))
 				{
 					// Apply effects
-					skill.applyEffects(getOwner(), this, target, false, false, true, 0);
+					skill.applyEffects(_owner, target, false, false, true, 0);
 					
 					// If this is a bad skill notify the duel manager, so it can be removed after the duel (player & target must be in the same duel).
-					if (target.isPlayer() && target.getActingPlayer().isInDuel() && skill.isBad() && (getOwner().getDuelId() == target.getActingPlayer().getDuelId()))
+					if (target.isPlayer() && target.getActingPlayer().isInDuel() && skill.isBad() && (_owner.getDuelId() == target.getActingPlayer().getDuelId()))
 					{
 						DuelManager.getInstance().onBuff(target.getActingPlayer(), skill);
 					}
@@ -646,11 +645,11 @@ public final class L2CubicInstance implements IIdentifiable
 				{
 					if (target.isAttackable())
 					{
-						target.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getOwner(), (int) ((150 * skill.getPower()) / (target.getLevel() + 7)));
+						target.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, _owner, (int) ((150 * skill.getPower()) / (target.getLevel() + 7)));
 					}
 					
 					// Apply effects
-					skill.applyEffects(getOwner(), this, target, false, false, true, 0);
+					skill.applyEffects(_owner, target, false, false, true, 0);
 					
 					if (Config.DEBUG)
 					{

+ 48 - 26
L2J_Server/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java

@@ -19,10 +19,10 @@
 package com.l2jserver.gameserver.model.actor.instance;
 
 import java.sql.Connection;
-import java.sql.Date;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -640,7 +640,7 @@ public final class L2PcInstance extends L2Playable
 	
 	// charges
 	private final AtomicInteger _charges = new AtomicInteger();
-	private ScheduledFuture<?> _chargeTask = null;
+	private volatile ScheduledFuture<?> _chargeTask = null;
 	
 	// Absorbed Souls
 	private int _souls = 0;
@@ -4424,7 +4424,7 @@ public final class L2PcInstance extends L2Playable
 		getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
 		
 		// Check if the L2Object to pick up is a L2ItemInstance
-		if (!(object instanceof L2ItemInstance))
+		if (!(object.isItem()))
 		{
 			// dont try to pickup anything that is not an item :)
 			_log.warning(this + " trying to pickup wrong target." + getTarget());
@@ -4433,12 +4433,7 @@ public final class L2PcInstance extends L2Playable
 		
 		L2ItemInstance target = (L2ItemInstance) object;
 		
-		// Send a Server->Client packet ActionFailed to this L2PcInstance
-		sendPacket(ActionFailed.STATIC_PACKET);
-		
-		// Send a Server->Client packet StopMove to this L2PcInstance
-		StopMove sm = new StopMove(this);
-		sendPacket(sm);
+		sendPacket(new StopMove(this));
 		
 		SystemMessage smsg = null;
 		synchronized (target)
@@ -4467,12 +4462,8 @@ public final class L2PcInstance extends L2Playable
 				return;
 			}
 			
-			if (isInvul() && !canOverrideCond(PcCondOverride.ITEM_CONDITIONS))
+			if (isInvisible() && !canOverrideCond(PcCondOverride.ITEM_CONDITIONS))
 			{
-				sendPacket(ActionFailed.STATIC_PACKET);
-				smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
-				smsg.addItemName(target);
-				sendPacket(smsg);
 				return;
 			}
 			
@@ -6738,7 +6729,7 @@ public final class L2PcInstance extends L2Playable
 			ps.setInt(34, getNewbie());
 			ps.setInt(35, isNoble() ? 1 : 0);
 			ps.setLong(36, 0);
-			ps.setDate(37, new Date(getCreateDate().getTimeInMillis()));
+			ps.setTimestamp(37, new Timestamp(getCreateDate().getTimeInMillis()));
 			ps.executeUpdate();
 		}
 		catch (Exception e)
@@ -6923,7 +6914,7 @@ public final class L2PcInstance extends L2Playable
 					player.setBookMarkSlot(rset.getInt("BookmarkSlot"));
 					
 					// character creation Time
-					player.getCreateDate().setTime(rset.getDate("createDate"));
+					player.getCreateDate().setTimeInMillis(rset.getTimestamp("createDate").getTime());
 					
 					// Language
 					player.setLang(rset.getString("language"));
@@ -7555,13 +7546,25 @@ public final class L2PcInstance extends L2Playable
 	
 	public int isOnlineInt()
 	{
-		if (_isOnline && (getClient() != null))
+		if (_isOnline && (_client != null))
 		{
-			return getClient().isDetached() ? 2 : 1;
+			return _client.isDetached() ? 2 : 1;
 		}
 		return 0;
 	}
 	
+	/**
+	 * Verifies if the player is in offline mode.<br>
+	 * The offline mode may happen for different reasons:<br>
+	 * Abnormally: Player gets abrouptaly disconnected from server.<br>
+	 * Normally: The player gets into offline shop mode, only avaiable by enabling the offline shop mod.
+	 * @return {@code true} if the player is in offline mode, {@code false} otherwise
+	 */
+	public boolean isInOfflineMode()
+	{
+		return (_client == null) || _client.isDetached();
+	}
+	
 	public boolean isIn7sDungeon()
 	{
 		return _isIn7sDungeon;
@@ -10334,6 +10337,13 @@ public final class L2PcInstance extends L2Playable
 			sendPacket(new SkillCoolTime(this));
 			sendPacket(new ExStorageMaxCount(this));
 			
+			if (Config.ALTERNATE_CLASS_MASTER)
+			{
+				if (Config.CLASS_MASTER_SETTINGS.isAllowed(getClassId().level() + 1) && Config.ALTERNATE_CLASS_MASTER && (((this.getClassId().level() == 1) && (this.getLevel() >= 40)) || ((this.getClassId().level() == 2) && (this.getLevel() >= 76))))
+				{
+					L2ClassMasterInstance.showQuestionMark(this);
+				}
+			}
 			return true;
 		}
 		finally
@@ -12565,7 +12575,7 @@ public final class L2PcInstance extends L2Playable
 			{
 				if (_transformSkills == null)
 				{
-					_transformSkills = new HashMap<>();
+					_transformSkills = new ConcurrentHashMap<>();
 				}
 			}
 		}
@@ -12574,15 +12584,23 @@ public final class L2PcInstance extends L2Playable
 	
 	public Skill getTransformSkill(int id)
 	{
+		if (_transformSkills == null)
+		{
+			return null;
+		}
 		return _transformSkills.get(id);
 	}
 	
 	public boolean hasTransformSkill(int id)
 	{
+		if (_transformSkills == null)
+		{
+			return false;
+		}
 		return _transformSkills.containsKey(id);
 	}
 	
-	public synchronized void removeAllTransformSkills()
+	public void removeAllTransformSkills()
 	{
 		_transformSkills = null;
 	}
@@ -12825,8 +12843,13 @@ public final class L2PcInstance extends L2Playable
 	{
 		if (_chargeTask != null)
 		{
-			_chargeTask.cancel(false);
-			_chargeTask = null;
+			synchronized (this)
+			{
+				if (_chargeTask != null)
+				{
+					_chargeTask.cancel(false);
+				}
+			}
 		}
 		_chargeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ResetChargesTask(this), 600000);
 	}
@@ -13644,9 +13667,9 @@ public final class L2PcInstance extends L2Playable
 	{
 		try
 		{
-			for (L2BossZone _zone : GrandBossManager.getInstance().getZones())
+			for (L2BossZone zone : GrandBossManager.getInstance().getZones().values())
 			{
-				_zone.removePlayer(this);
+				zone.removePlayer(this);
 			}
 		}
 		catch (Exception e)
@@ -13660,10 +13683,9 @@ public final class L2PcInstance extends L2Playable
 	 */
 	public void checkPlayerSkills()
 	{
-		L2SkillLearn learn;
 		for (Entry<Integer, Skill> e : getSkills().entrySet())
 		{
-			learn = SkillTreesData.getInstance().getClassSkill(e.getKey(), e.getValue().getLevel() % 100, getClassId());
+			final L2SkillLearn learn = SkillTreesData.getInstance().getClassSkill(e.getKey(), e.getValue().getLevel() % 100, getClassId());
 			if (learn != null)
 			{
 				int lvlDiff = e.getKey() == CommonSkill.EXPERTISE.getId() ? 0 : 9;

+ 74 - 72
L2J_Server/java/com/l2jserver/gameserver/model/actor/tasks/cubics/CubicAction.java

@@ -117,100 +117,102 @@ public final class CubicAction implements Runnable
 			}
 			else if (Rnd.get(1, 100) < _chance)
 			{
-				Skill skill = _cubic.getSkills().get(Rnd.get(_cubic.getSkills().size()));
-				if (skill != null)
+				final Skill skill = _cubic.getSkills().get(Rnd.get(_cubic.getSkills().size()));
+				if (skill == null)
 				{
-					if (skill.getId() == L2CubicInstance.SKILL_CUBIC_HEAL)
+					return;
+				}
+				
+				if (skill.getId() == L2CubicInstance.SKILL_CUBIC_HEAL)
+				{
+					// friendly skill, so we look a target in owner's party
+					_cubic.cubicTargetForHeal();
+				}
+				else
+				{
+					// offensive skill, we look for an enemy target
+					_cubic.getCubicTarget();
+					if (!L2CubicInstance.isInCubicRange(_cubic.getOwner(), _cubic.getTarget()))
 					{
-						// friendly skill, so we look a target in owner's party
-						_cubic.cubicTargetForHeal();
+						_cubic.setTarget(null);
 					}
-					else
+				}
+				L2Character target = _cubic.getTarget();
+				if ((target != null) && !target.isDead())
+				{
+					if (Config.DEBUG)
 					{
-						// offensive skill, we look for an enemy target
-						_cubic.getCubicTarget();
-						if (!L2CubicInstance.isInCubicRange(_cubic.getOwner(), _cubic.getTarget()))
-						{
-							_cubic.setTarget(null);
-						}
+						_log.info("L2CubicInstance: Action.run();");
+						_log.info("Cubic ID: " + _cubic.getId() + " Target: " + target.getName() + " distance: " + target.calculateDistance(_cubic.getOwner(), true, false));
 					}
-					L2Character target = _cubic.getTarget();
-					if ((target != null) && !target.isDead())
+					
+					_cubic.getOwner().broadcastPacket(new MagicSkillUse(_cubic.getOwner(), target, skill.getId(), skill.getLevel(), 0, 0));
+					
+					L2Character[] targets =
+					{
+						target
+					};
+					
+					if (skill.isContinuous())
 					{
 						if (Config.DEBUG)
 						{
-							_log.info("L2CubicInstance: Action.run();");
-							_log.info("Cubic ID: " + _cubic.getId() + " Target: " + target.getName() + " distance: " + target.calculateDistance(_cubic.getOwner(), true, false));
+							_log.info("L2CubicInstance: Action.run() skill " + skill);
 						}
-						
-						_cubic.getOwner().broadcastPacket(new MagicSkillUse(_cubic.getOwner(), target, skill.getId(), skill.getLevel(), 0, 0));
-						
-						L2Character[] targets =
-						{
-							target
-						};
-						
-						if (skill.isContinuous())
-						{
-							if (Config.DEBUG)
-							{
-								_log.info("L2CubicInstance: Action.run() skill " + skill);
-							}
-							_cubic.useCubicContinuous(skill, targets);
-						}
-						else
+						_cubic.useCubicContinuous(skill, targets);
+					}
+					else
+					{
+						skill.activateSkill(_cubic, targets);
+						if (Config.DEBUG)
 						{
-							skill.activateSkill(_cubic.getOwner(), targets);
-							if (Config.DEBUG)
-							{
-								_log.info("L2CubicInstance: Action.run(); other handler");
-							}
+							_log.info("L2CubicInstance: Action.run(); other handler");
 						}
-						
-						if (skill.hasEffectType(L2EffectType.MAGICAL_ATTACK))
+					}
+					
+					if (skill.hasEffectType(L2EffectType.MAGICAL_ATTACK))
+					{
+						if (Config.DEBUG)
 						{
-							if (Config.DEBUG)
-							{
-								_log.info("L2CubicInstance: Action.run() skill " + skill);
-							}
-							_cubic.useCubicMdam(_cubic, skill, targets);
+							_log.info("L2CubicInstance: Action.run() skill " + skill);
 						}
-						else if (skill.hasEffectType(L2EffectType.HP_DRAIN))
+						_cubic.useCubicMdam(skill, targets);
+					}
+					else if (skill.hasEffectType(L2EffectType.HP_DRAIN))
+					{
+						if (Config.DEBUG)
 						{
-							if (Config.DEBUG)
-							{
-								_log.info("L2CubicInstance: Action.run() skill " + skill);
-							}
-							_cubic.useCubicDrain(_cubic, skill, targets);
+							_log.info("L2CubicInstance: Action.run() skill " + skill);
 						}
-						else if (skill.hasEffectType(L2EffectType.STUN, L2EffectType.ROOT, L2EffectType.PARALYZE))
+						_cubic.useCubicDrain(skill, targets);
+					}
+					else if (skill.hasEffectType(L2EffectType.STUN, L2EffectType.ROOT, L2EffectType.PARALYZE))
+					{
+						if (Config.DEBUG)
 						{
-							if (Config.DEBUG)
-							{
-								_log.info("L2CubicInstance: Action.run() skill " + skill);
-							}
-							_cubic.useCubicDisabler(skill, targets);
+							_log.info("L2CubicInstance: Action.run() skill " + skill);
 						}
-						else if (skill.hasEffectType(L2EffectType.DMG_OVER_TIME, L2EffectType.DMG_OVER_TIME_PERCENT))
+						_cubic.useCubicDisabler(skill, targets);
+					}
+					else if (skill.hasEffectType(L2EffectType.DMG_OVER_TIME, L2EffectType.DMG_OVER_TIME_PERCENT))
+					{
+						if (Config.DEBUG)
 						{
-							if (Config.DEBUG)
-							{
-								_log.info("L2CubicInstance: Action.run() skill " + skill);
-							}
-							_cubic.useCubicContinuous(skill, targets);
+							_log.info("L2CubicInstance: Action.run() skill " + skill);
 						}
-						else if (skill.hasEffectType(L2EffectType.AGGRESSION))
+						_cubic.useCubicContinuous(skill, targets);
+					}
+					else if (skill.hasEffectType(L2EffectType.AGGRESSION))
+					{
+						if (Config.DEBUG)
 						{
-							if (Config.DEBUG)
-							{
-								_log.info("L2CubicInstance: Action.run() skill " + skill);
-							}
-							_cubic.useCubicDisabler(skill, targets);
+							_log.info("L2CubicInstance: Action.run() skill " + skill);
 						}
-						
-						// The cubic has done an action, increase the current count
-						_currentCount.incrementAndGet();
+						_cubic.useCubicDisabler(skill, targets);
 					}
+					
+					// The cubic has done an action, increase the current count
+					_currentCount.incrementAndGet();
 				}
 			}
 		}

+ 11 - 22
L2J_Server/java/com/l2jserver/gameserver/model/actor/tasks/cubics/CubicHeal.java

@@ -56,35 +56,24 @@ public class CubicHeal implements Runnable
 			_cubic.cancelDisappear();
 			return;
 		}
+		
 		try
 		{
-			Skill skill = null;
-			for (Skill sk : _cubic.getSkills())
+			final Skill skill = _cubic.getSkills().stream().filter(s -> s.getId() == L2CubicInstance.SKILL_CUBIC_HEAL).findFirst().orElse(null);
+			if (skill == null)
 			{
-				if (sk.getId() == L2CubicInstance.SKILL_CUBIC_HEAL)
-				{
-					skill = sk;
-					break;
-				}
+				return;
 			}
 			
-			if (skill != null)
+			_cubic.cubicTargetForHeal();
+			final L2Character target = _cubic.getTarget();
+			if ((target != null) && !target.isDead())
 			{
-				_cubic.cubicTargetForHeal();
-				final L2Character target = _cubic.getTarget();
-				if ((target != null) && !target.isDead())
+				if ((target.getMaxHp() - target.getCurrentHp()) > skill.getPower())
 				{
-					if ((target.getMaxHp() - target.getCurrentHp()) > skill.getPower())
-					{
-						L2Character[] targets =
-						{
-							target
-						};
-						
-						skill.activateSkill(_cubic.getOwner(), targets);
-						
-						_cubic.getOwner().broadcastPacket(new MagicSkillUse(_cubic.getOwner(), target, skill.getId(), skill.getLevel(), 0, 0));
-					}
+					skill.activateSkill(_cubic, target);
+					
+					_cubic.getOwner().broadcastPacket(new MagicSkillUse(_cubic.getOwner(), target, skill.getId(), skill.getLevel(), 0, 0));
 				}
 			}
 		}

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IAmountMultiplierStrategy.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2014 L2J Server
+ * Copyright (C) 2004-2015 L2J Server
  * 
  * This file is part of L2J Server.
  * 

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IChanceMultiplierStrategy.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2014 L2J Server
+ * Copyright (C) 2004-2015 L2J Server
  * 
  * This file is part of L2J Server.
  * 

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IDropCalculationStrategy.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2014 L2J Server
+ * Copyright (C) 2004-2015 L2J Server
  * 
  * This file is part of L2J Server.
  * 

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IGroupedItemDropCalculationStrategy.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2014 L2J Server
+ * Copyright (C) 2004-2015 L2J Server
  *
  * This file is part of L2J Server.
  *

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IKillerChanceModifierStrategy.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2014 L2J Server
+ * Copyright (C) 2004-2015 L2J Server
  *
  * This file is part of L2J Server.
  *

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/INonGroupedKillerChanceModifierStrategy.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2014 L2J Server
+ * Copyright (C) 2004-2015 L2J Server
  * 
  * This file is part of L2J Server.
  * 

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/drops/strategy/IPreciseDeterminationStrategy.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2014 L2J Server
+ * Copyright (C) 2004-2015 L2J Server
  * 
  * This file is part of L2J Server.
  * 

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/model/entity/TvTEventTeam.java

@@ -135,7 +135,7 @@ public class TvTEventTeam
 	}
 	
 	/**
-	 * Returns name and instance of all participated players in FastMap<br>
+	 * Returns name and instance of all participated players in Map<br>
 	 * <br>
 	 * @return Map<String, L2PcInstance>: map of players in this team<br>
 	 */

+ 1 - 6
L2J_Server/java/com/l2jserver/gameserver/model/itemcontainer/Inventory.java

@@ -373,12 +373,7 @@ public abstract class Inventory extends ItemContainer
 			Skill unequipSkill = it.getUnequipSkill();
 			if (unequipSkill != null)
 			{
-				L2PcInstance[] targets =
-				{
-					player
-				};
-				
-				unequipSkill.activateSkill(player, targets);
+				unequipSkill.activateSkill(player, player);
 			}
 			
 			if (update)

+ 7 - 13
L2J_Server/java/com/l2jserver/gameserver/model/items/L2Weapon.java

@@ -364,13 +364,7 @@ public final class L2Weapon extends L2Item
 			// Skill condition not met
 			return;
 		}
-		
-		L2Character[] targets =
-		{
-			target
-		};
-		
-		onCritSkill.activateSkill(caster, targets);
+		onCritSkill.activateSkill(caster, target);
 	}
 	
 	/**
@@ -429,18 +423,18 @@ public final class L2Weapon extends L2Item
 			return;
 		}
 		
-		L2Character[] targets =
-		{
-			target
-		};
-		
 		// Launch the magic skill and calculate its effects
 		// Get the skill handler corresponding to the skill type
-		onMagicSkill.activateSkill(caster, targets);
+		onMagicSkill.activateSkill(caster, target);
 		
 		// notify quests of a skill use
 		if (caster instanceof L2PcInstance)
 		{
+			L2Character[] targets =
+			{
+				target
+			};
+			
 			//@formatter:off
 			caster.getKnownList().getKnownObjects().values().stream()
 				.filter(Objects::nonNull)

+ 2 - 2
L2J_Server/java/com/l2jserver/gameserver/model/quest/QuestState.java

@@ -222,8 +222,8 @@ public final class QuestState
 	 * <ul>
 	 * <li>Initialize class variable "vars" if is null.</li>
 	 * <li>Initialize parameter "val" if is null</li>
-	 * <li>Add/Update couple (var,val) in class variable FastMap "vars"</li>
-	 * <li>If the key represented by "var" exists in FastMap "vars", the couple (var,val) is updated in the database.<br>
+	 * <li>Add/Update couple (var,val) in class variable Map "vars"</li>
+	 * <li>If the key represented by "var" exists in Map "vars", the couple (var,val) is updated in the database.<br>
 	 * The key is known as existing if the preceding value of the key (given as result of function put()) is not null.<br>
 	 * If the key doesn't exist, the couple is added/created in the database</li>
 	 * <ul>

+ 38 - 15
L2J_Server/java/com/l2jserver/gameserver/model/skills/Skill.java

@@ -909,7 +909,7 @@ public final class Skill implements IIdentifiable
 	
 	public boolean useSoulShot()
 	{
-		return (hasEffectType(L2EffectType.PHYSICAL_ATTACK, L2EffectType.PHYSICAL_ATTACK_HP_LINK));
+		return hasEffectType(L2EffectType.PHYSICAL_ATTACK, L2EffectType.PHYSICAL_ATTACK_HP_LINK);
 	}
 	
 	public boolean useSpiritShot()
@@ -1329,18 +1329,18 @@ public final class Skill implements IIdentifiable
 	}
 	
 	/**
-	 * Method overload for {@link Skill#applyEffects(L2Character, L2CubicInstance, L2Character, boolean, boolean, boolean, int)}.<br>
+	 * Method overload for {@link Skill#applyEffects(L2Character, L2Character, boolean, boolean, boolean, int)}.<br>
 	 * Simplify the calls.
 	 * @param effector the caster of the skill
 	 * @param effected the target of the effect
 	 */
 	public void applyEffects(L2Character effector, L2Character effected)
 	{
-		applyEffects(effector, null, effected, false, false, true, 0);
+		applyEffects(effector, effected, false, false, true, 0);
 	}
 	
 	/**
-	 * Method overload for {@link Skill#applyEffects(L2Character, L2CubicInstance, L2Character, boolean, boolean, boolean, int)}.<br>
+	 * Method overload for {@link Skill#applyEffects(L2Character, L2Character, boolean, boolean, boolean, int)}.<br>
 	 * Simplify the calls, allowing abnormal time time customization.
 	 * @param effector the caster of the skill
 	 * @param effected the target of the effect
@@ -1349,20 +1349,19 @@ public final class Skill implements IIdentifiable
 	 */
 	public void applyEffects(L2Character effector, L2Character effected, boolean instant, int abnormalTime)
 	{
-		applyEffects(effector, null, effected, false, false, instant, abnormalTime);
+		applyEffects(effector, effected, false, false, instant, abnormalTime);
 	}
 	
 	/**
 	 * Applies the effects from this skill to the target.
 	 * @param effector the caster of the skill
-	 * @param cubic the cubic that cast the skill, can be {@code null}
 	 * @param effected the target of the effect
 	 * @param self if {@code true} self-effects will be casted on the caster
 	 * @param passive if {@code true} passive effects will be applied to the effector
 	 * @param instant if {@code true} instant effects will be applied to the effected
 	 * @param abnormalTime custom abnormal time, if equal or lesser than zero will be ignored
 	 */
-	public void applyEffects(L2Character effector, L2CubicInstance cubic, L2Character effected, boolean self, boolean passive, boolean instant, int abnormalTime)
+	public void applyEffects(L2Character effector, L2Character effected, boolean self, boolean passive, boolean instant, int abnormalTime)
 	{
 		// null targets cannot receive any effects.
 		if (effected == null)
@@ -1447,12 +1446,33 @@ public final class Skill implements IIdentifiable
 		}
 	}
 	
+	/**
+	 * Activates a skill for the given creature and targets.
+	 * @param caster the caster
+	 * @param targets the targets
+	 */
+	public void activateSkill(L2Character caster, L2Object... targets)
+	{
+		activateSkill(caster, null, targets);
+	}
+	
+	/**
+	 * Activates a skill for the given cubic and targets.
+	 * @param cubic the cubic
+	 * @param targets the targets
+	 */
+	public void activateSkill(L2CubicInstance cubic, L2Object... targets)
+	{
+		activateSkill(cubic.getOwner(), cubic, targets);
+	}
+	
 	/**
 	 * Activates the skill to the targets.
 	 * @param caster the caster
+	 * @param cubic the cubic, can be {@code null}
 	 * @param targets the targets
 	 */
-	public void activateSkill(L2Character caster, L2Object[] targets)
+	private void activateSkill(L2Character caster, L2CubicInstance cubic, L2Object... targets)
 	{
 		switch (getId())
 		{
@@ -1524,16 +1544,19 @@ public final class Skill implements IIdentifiable
 			{
 				caster.stopSkillEffects(true, getId());
 			}
-			applyEffects(caster, null, caster, true, false, true, 0);
+			applyEffects(caster, caster, true, false, true, 0);
 		}
 		
-		if (useSpiritShot())
-		{
-			caster.setChargedShot(caster.isChargedShot(ShotType.BLESSED_SPIRITSHOTS) ? ShotType.BLESSED_SPIRITSHOTS : ShotType.SPIRITSHOTS, false);
-		}
-		else if (useSoulShot())
+		if (cubic == null)
 		{
-			caster.setChargedShot(ShotType.SOULSHOTS, false);
+			if (useSpiritShot())
+			{
+				caster.setChargedShot(caster.isChargedShot(ShotType.BLESSED_SPIRITSHOTS) ? ShotType.BLESSED_SPIRITSHOTS : ShotType.SPIRITSHOTS, false);
+			}
+			else if (useSoulShot())
+			{
+				caster.setChargedShot(ShotType.SOULSHOTS, false);
+			}
 		}
 	}
 	

+ 6 - 5
L2J_Server/java/com/l2jserver/gameserver/model/stats/functions/formulas/FuncAtkEvasion.java

@@ -49,13 +49,14 @@ public class FuncAtkEvasion extends AbstractFunction
 		{
 			// [Square(DEX)] * 6 + lvl;
 			value += (Math.sqrt(effector.getDEX()) * 6) + level;
-			if (level > 77)
+			double diff = level - 69;
+			if (level >= 78)
 			{
-				value += level - 77;
+				diff *= 1.2;
 			}
-			if (level > 69)
+			if (level >= 70)
 			{
-				value += level - 69;
+				value += diff;
 			}
 		}
 		else
@@ -67,6 +68,6 @@ public class FuncAtkEvasion extends AbstractFunction
 				value += (level - 69) + 2;
 			}
 		}
-		return value;
+		return (int) value;
 	}
 }

+ 6 - 5
L2J_Server/java/com/l2jserver/gameserver/network/clientpackets/EnterWorld.java

@@ -61,6 +61,7 @@ import com.l2jserver.gameserver.model.quest.QuestState;
 import com.l2jserver.gameserver.model.skills.CommonSkill;
 import com.l2jserver.gameserver.model.zone.ZoneId;
 import com.l2jserver.gameserver.network.SystemMessageId;
+import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
 import com.l2jserver.gameserver.network.serverpackets.Die;
 import com.l2jserver.gameserver.network.serverpackets.EtcStatusUpdate;
 import com.l2jserver.gameserver.network.serverpackets.ExBasicActionList;
@@ -433,8 +434,8 @@ public class EnterWorld extends L2GameClientPacket
 		
 		activeChar.sendMessage(getText("VGhpcyBTZXJ2ZXIgdXNlcyBMMkosIGEgUHJvamVjdCBmb3VuZGVkIGJ5IEwyQ2hlZg=="));
 		activeChar.sendMessage(getText("YW5kIGRldmVsb3BlZCBieSBMMkogVGVhbSBhdCB3d3cubDJqc2VydmVyLmNvbQ=="));
-		activeChar.sendMessage(getText("Q29weXJpZ2h0IDIwMDQtMjAxNA=="));
-		activeChar.sendMessage(getText("VGhhbmsgeW91IGZvciAxMCB5ZWFycyE="));
+		activeChar.sendMessage(getText("Q29weXJpZ2h0IDIwMDQtMjAxNQ=="));
+		activeChar.sendMessage(getText("VGhhbmsgeW91IGZvciAxMSB5ZWFycyE="));
 		
 		SevenSigns.getInstance().sendCurrentPeriodMsg(activeChar);
 		AnnouncementsTable.getInstance().showAnnouncements(activeChar);
@@ -564,11 +565,11 @@ public class EnterWorld extends L2GameClientPacket
 		{
 			activeChar.sendPacket(ExNotifyPremiumItem.STATIC_PACKET);
 		}
+		
+		// Unstuck players that had client open when server crashed.
+		activeChar.sendPacket(ActionFailed.STATIC_PACKET);
 	}
 	
-	/**
-	 * @param cha
-	 */
 	private void engage(L2PcInstance cha)
 	{
 		int chaId = cha.getObjectId();

+ 1 - 1
L2J_Server/java/com/l2jserver/gameserver/network/clientpackets/RequestAnswerJoinPledge.java

@@ -86,7 +86,7 @@ public final class RequestAnswerJoinPledge extends L2GameClientPacket
 				activeChar.setPledgeType(requestPacket.getPledgeType());
 				if (requestPacket.getPledgeType() == L2Clan.SUBUNIT_ACADEMY)
 				{
-					activeChar.setPowerGrade(9); // adademy
+					activeChar.setPowerGrade(9); // Academy
 					activeChar.setLvlJoinedAcademy(activeChar.getLevel());
 				}
 				else

+ 4 - 2
L2J_Server/java/com/l2jserver/gameserver/network/clientpackets/RequestOustPledgeMember.java

@@ -18,6 +18,8 @@
  */
 package com.l2jserver.gameserver.network.clientpackets;
 
+import java.util.concurrent.TimeUnit;
+
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.model.ClanPrivilege;
 import com.l2jserver.gameserver.model.L2Clan;
@@ -82,8 +84,8 @@ public final class RequestOustPledgeMember extends L2GameClientPacket
 		}
 		
 		// this also updates the database
-		clan.removeClanMember(member.getObjectId(), System.currentTimeMillis() + (Config.ALT_CLAN_JOIN_DAYS * 86400000L)); // 24*60*60*1000 = 86400000
-		clan.setCharPenaltyExpiryTime(System.currentTimeMillis() + (Config.ALT_CLAN_JOIN_DAYS * 86400000L)); // 24*60*60*1000 = 86400000
+		clan.removeClanMember(member.getObjectId(), System.currentTimeMillis() + TimeUnit.DAYS.toMillis(Config.ALT_CLAN_JOIN_DAYS));
+		clan.setCharPenaltyExpiryTime(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(Config.ALT_CLAN_JOIN_DAYS));
 		clan.updateClanInDB();
 		
 		SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.CLAN_MEMBER_S1_EXPELLED);

+ 3 - 1
L2J_Server/java/com/l2jserver/gameserver/network/clientpackets/RequestWithdrawalPledge.java

@@ -18,6 +18,8 @@
  */
 package com.l2jserver.gameserver.network.clientpackets;
 
+import java.util.concurrent.TimeUnit;
+
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.model.L2Clan;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
@@ -65,7 +67,7 @@ public final class RequestWithdrawalPledge extends L2GameClientPacket
 		
 		L2Clan clan = activeChar.getClan();
 		
-		clan.removeClanMember(activeChar.getObjectId(), System.currentTimeMillis() + (Config.ALT_CLAN_JOIN_DAYS * 86400000L)); // 24*60*60*1000 = 86400000
+		clan.removeClanMember(activeChar.getObjectId(), System.currentTimeMillis() + TimeUnit.DAYS.toMillis(Config.ALT_CLAN_JOIN_DAYS));
 		
 		SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_WITHDRAWN_FROM_THE_CLAN);
 		sm.addString(activeChar.getName());

+ 22 - 72
L2J_Server/java/com/l2jserver/gameserver/taskmanager/tasks/TaskBirthday.java

@@ -22,31 +22,27 @@ import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.logging.Level;
+import java.util.concurrent.TimeUnit;
 
 import com.l2jserver.Config;
 import com.l2jserver.commons.database.pool.impl.ConnectionFactory;
-import com.l2jserver.gameserver.data.sql.impl.CharNameTable;
 import com.l2jserver.gameserver.instancemanager.MailManager;
 import com.l2jserver.gameserver.model.entity.Message;
-import com.l2jserver.gameserver.model.itemcontainer.Mail;
 import com.l2jserver.gameserver.taskmanager.Task;
 import com.l2jserver.gameserver.taskmanager.TaskManager;
 import com.l2jserver.gameserver.taskmanager.TaskManager.ExecutedTask;
 import com.l2jserver.gameserver.taskmanager.TaskTypes;
-import com.l2jserver.gameserver.util.Util;
 
 /**
- * @author Nyaran
+ * Birthday Gift task.
+ * @author Zoey76
  */
 public class TaskBirthday extends Task
 {
 	private static final String NAME = "birthday";
-	private static final String QUERY = "SELECT charId, createDate FROM characters WHERE createDate LIKE ?";
-	private static final Calendar _today = Calendar.getInstance();
-	private int _count = 0;
+	/** Get all players that have had a birthday since last check. */
+	private static final String SELECT_PENDING_BIRTHDAY_GIFTS = "SELECT charId, char_name, createDate, (YEAR(NOW()) - YEAR(createDate)) AS age " //
+		+ "FROM characters WHERE (YEAR(NOW()) - YEAR(createDate) > 0) AND (DATE_FORMAT(createDate, '%m-%d') > DATE_FORMAT(FROM_UNIXTIME(?), '%m-%d'))";
 	
 	@Override
 	public String getName()
@@ -57,85 +53,39 @@ public class TaskBirthday extends Task
 	@Override
 	public void onTimeElapsed(ExecutedTask task)
 	{
-		Calendar lastExecDate = Calendar.getInstance();
-		long lastActivation = task.getLastActivation();
+		// TODO(Zoey76): Fix first run.
+		final int birthdayGiftCount = giveBirthdayGifts(task.getLastActivation());
 		
-		if (lastActivation > 0)
-		{
-			lastExecDate.setTimeInMillis(lastActivation);
-		}
-		
-		String rangeDate = "[" + Util.getDateString(lastExecDate.getTime()) + "] - [" + Util.getDateString(_today.getTime()) + "]";
-		
-		for (; !_today.before(lastExecDate); lastExecDate.add(Calendar.DATE, 1))
-		{
-			checkBirthday(lastExecDate.get(Calendar.YEAR), lastExecDate.get(Calendar.MONTH), lastExecDate.get(Calendar.DATE));
-		}
-		
-		_log.info("BirthdayManager: " + _count + " gifts sent. " + rangeDate);
+		_log.info("BirthdayManager: " + birthdayGiftCount + " gifts sent.");
 	}
 	
-	private void checkBirthday(int year, int month, int day)
+	private int giveBirthdayGifts(long lastActivation)
 	{
+		int birthdayGiftCount = 0;
 		try (Connection con = ConnectionFactory.getInstance().getConnection();
-			PreparedStatement statement = con.prepareStatement(QUERY))
+			PreparedStatement ps = con.prepareStatement(SELECT_PENDING_BIRTHDAY_GIFTS))
 		{
-			statement.setString(1, "%-" + getNum(month + 1) + "-" + getNum(day));
-			try (ResultSet rset = statement.executeQuery())
+			ps.setLong(1, TimeUnit.SECONDS.convert(lastActivation, TimeUnit.MILLISECONDS));
+			try (ResultSet rs = ps.executeQuery())
 			{
-				while (rset.next())
+				while (rs.next())
 				{
-					int playerId = rset.getInt("charId");
-					Calendar createDate = Calendar.getInstance();
-					createDate.setTime(rset.getDate("createDate"));
-					
-					int age = year - createDate.get(Calendar.YEAR);
-					if (age <= 0)
-					{
-						continue;
-					}
-					
 					String text = Config.ALT_BIRTHDAY_MAIL_TEXT;
+					text = text.replaceAll("$c1", rs.getString("char_name"));
+					text = text.replaceAll("$s1", Integer.toString(rs.getInt("age")));
 					
-					if (text.contains("$c1"))
-					{
-						text = text.replace("$c1", CharNameTable.getInstance().getNameById(playerId));
-					}
-					if (text.contains("$s1"))
-					{
-						text = text.replace("$s1", String.valueOf(age));
-					}
-					
-					Message msg = new Message(playerId, Config.ALT_BIRTHDAY_MAIL_SUBJECT, text, Message.SendBySystem.ALEGRIA);
-					
-					Mail attachments = msg.createAttachments();
-					attachments.addItem("Birthday", Config.ALT_BIRTHDAY_GIFT, 1, null, null);
-					
+					final Message msg = new Message(rs.getInt("charId"), Config.ALT_BIRTHDAY_MAIL_SUBJECT, text, Message.SendBySystem.ALEGRIA);
+					msg.createAttachments().addItem("Birthday", Config.ALT_BIRTHDAY_GIFT, 1, null, null);
 					MailManager.getInstance().sendMessage(msg);
-					_count++;
+					birthdayGiftCount++;
 				}
 			}
 		}
 		catch (SQLException e)
 		{
-			_log.log(Level.WARNING, "Error checking birthdays. ", e);
+			_log.warning("Error checking birthdays: " + e.getMessage());
 		}
-		
-		// If character birthday is 29-Feb and year isn't leap, send gift on 28-feb
-		GregorianCalendar calendar = new GregorianCalendar();
-		if ((month == Calendar.FEBRUARY) && (day == 28) && !calendar.isLeapYear(_today.get(Calendar.YEAR)))
-		{
-			checkBirthday(year, Calendar.FEBRUARY, 29);
-		}
-	}
-	
-	/**
-	 * @param num the number to format.
-	 * @return the formatted number starting with a 0 if it is lower or equal than 10.
-	 */
-	private String getNum(int num)
-	{
-		return (num <= 9) ? "0" + num : String.valueOf(num);
+		return birthdayGiftCount;
 	}
 	
 	@Override

+ 11 - 3
L2J_Server/java/com/l2jserver/util/IPv4Filter.java

@@ -18,20 +18,23 @@
  */
 package com.l2jserver.util;
 
+import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.nio.channels.SocketChannel;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map.Entry;
+import java.util.logging.Logger;
 
 import com.l2jserver.mmocore.IAcceptFilter;
 
 /**
  * IPv4 filter.
- * @author Forsaiken
+ * @author Forsaiken, Zoey76
  */
 public class IPv4Filter implements IAcceptFilter, Runnable
 {
+	private static final Logger LOG = Logger.getLogger(IPv4Filter.class.getName());
 	private final HashMap<Integer, Flood> _ipFloodMap;
 	private static final long SLEEP_TIME = 5000;
 	
@@ -67,9 +70,14 @@ public class IPv4Filter implements IAcceptFilter, Runnable
 	@Override
 	public boolean accept(SocketChannel sc)
 	{
-		InetAddress addr = sc.socket().getInetAddress();
-		int h = hash(addr.getAddress());
+		final InetAddress addr = sc.socket().getInetAddress();
+		if (!(addr instanceof Inet4Address))
+		{
+			LOG.info(IPv4Filter.class.getSimpleName() + ": Someone tried to connect from something other than IPv4: " + addr.getHostAddress());
+			return false;
+		}
 		
+		final int h = hash(addr.getAddress());
 		long current = System.currentTimeMillis();
 		Flood f;
 		synchronized (_ipFloodMap)