Browse Source

Enchant Skill Tree rework. Some parts created by JIV.

Gigiikun 15 năm trước cách đây
mục cha
commit
f1bb598dab
16 tập tin đã thay đổi với 533 bổ sung402 xóa
  1. 2 0
      L2_GameServer/java/com/l2jserver/gameserver/GameServer.java
  2. 238 0
      L2_GameServer/java/com/l2jserver/gameserver/datatables/EnchantGroupsTable.java
  3. 1 0
      L2_GameServer/java/com/l2jserver/gameserver/datatables/SkillTable.java
  4. 18 133
      L2_GameServer/java/com/l2jserver/gameserver/datatables/SkillTreeTable.java
  5. 106 0
      L2_GameServer/java/com/l2jserver/gameserver/model/L2EnchantSkillGroup.java
  6. 98 179
      L2_GameServer/java/com/l2jserver/gameserver/model/L2EnchantSkillLearn.java
  7. 2 1
      L2_GameServer/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java
  8. 7 7
      L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkill.java
  9. 2 2
      L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillInfo.java
  10. 2 2
      L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillInfoDetail.java
  11. 5 5
      L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillRouteChange.java
  12. 7 7
      L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillSafe.java
  13. 5 5
      L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillUntrain.java
  14. 11 19
      L2_GameServer/java/com/l2jserver/gameserver/network/serverpackets/ExEnchantSkillInfo.java
  15. 12 26
      L2_GameServer/java/com/l2jserver/gameserver/network/serverpackets/ExEnchantSkillInfoDetail.java
  16. 17 16
      L2_GameServer/java/com/l2jserver/gameserver/skills/DocumentSkill.java

+ 2 - 0
L2_GameServer/java/com/l2jserver/gameserver/GameServer.java

@@ -43,6 +43,7 @@ import com.l2jserver.gameserver.datatables.CharNameTable;
 import com.l2jserver.gameserver.datatables.CharTemplateTable;
 import com.l2jserver.gameserver.datatables.ClanTable;
 import com.l2jserver.gameserver.datatables.DoorTable;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.datatables.EnchantHPBonusData;
 import com.l2jserver.gameserver.datatables.EventDroplist;
 import com.l2jserver.gameserver.datatables.ExtractableItemsData;
@@ -198,6 +199,7 @@ public class GameServer
 		
 		// keep the references of Singletons to prevent garbage collection
 		CharNameTable.getInstance();
+		EnchantGroupsTable.getInstance();
 		SkillTable.getInstance();
 		
 		ItemTable.getInstance();

+ 238 - 0
L2_GameServer/java/com/l2jserver/gameserver/datatables/EnchantGroupsTable.java

@@ -0,0 +1,238 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.gameserver.datatables;
+
+import gnu.trove.TIntObjectHashMap;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.model.L2EnchantSkillGroup;
+import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.L2EnchantSkillGroup.EnchantSkillDetail;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * This class ...
+ *
+ * @version $Revision: 1.13.2.2.2.8 $ $Date: 2005/04/06 16:13:25 $
+ */
+public class EnchantGroupsTable
+{
+	public static final int NORMAL_ENCHANT_COST_MULTIPLIER = 1;
+	public static final int SAFE_ENCHANT_COST_MULTIPLIER = 5;
+	
+	public static final int NORMAL_ENCHANT_BOOK = 6622;
+	public static final int SAFE_ENCHANT_BOOK = 9627;
+	public static final int CHANGE_ENCHANT_BOOK = 9626;
+	public static final int UNTRAIN_ENCHANT_BOOK = 9625;
+	
+	private static Logger _log = Logger.getLogger(EnchantGroupsTable.class.getName());
+	
+	private TIntObjectHashMap<L2EnchantSkillGroup> _enchantSkillGroups; //enchant skill group
+	private TIntObjectHashMap<L2EnchantSkillLearn> _enchantSkillTrees; //enchant skill list
+	
+	public static EnchantGroupsTable getInstance()
+	{
+		return SingletonHolder._instance;
+	}
+	
+	
+	private EnchantGroupsTable()
+	{
+		load();
+	}
+	
+	private void load()
+	{
+		int count = 0;
+		Connection con = null;
+		
+		try
+		{
+			con = L2DatabaseFactory.getInstance().getConnection();
+			
+			try
+			{
+				_enchantSkillGroups = new TIntObjectHashMap<L2EnchantSkillGroup>();
+				_enchantSkillTrees = new TIntObjectHashMap<L2EnchantSkillLearn>();
+				
+				PreparedStatement statement = con.prepareStatement("SELECT group_id, level, adena, exp, sp, success_rate76, success_rate77, success_rate78, success_rate79, success_rate80, success_rate81, success_rate82, success_rate83, success_rate84, success_rate85 FROM enchant_skill_groups ORDER BY group_id, level");
+				ResultSet enchantGroups = statement.executeQuery();
+				
+				int prevGroupId = -1;
+				
+				while (enchantGroups.next())
+				{
+					int id = enchantGroups.getInt("group_id");
+					int lvl = enchantGroups.getInt("level");
+					int adena = enchantGroups.getInt("adena");
+					int exp = enchantGroups.getInt("exp");
+					int sp = enchantGroups.getInt("sp");
+					byte rate76 = enchantGroups.getByte("success_rate76");
+					byte rate77 = enchantGroups.getByte("success_rate77");
+					byte rate78 = enchantGroups.getByte("success_rate78");
+					byte rate79 = enchantGroups.getByte("success_rate79");
+					byte rate80 = enchantGroups.getByte("success_rate80");
+					byte rate81 = enchantGroups.getByte("success_rate81");
+					byte rate82 = enchantGroups.getByte("success_rate82");
+					byte rate83 = enchantGroups.getByte("success_rate83");
+					byte rate84 = enchantGroups.getByte("success_rate84");
+					byte rate85 = enchantGroups.getByte("success_rate85");
+					
+					if (prevGroupId != id)
+						prevGroupId = id;
+					
+					L2EnchantSkillGroup group = _enchantSkillGroups.get(id);
+					if (group == null)
+					{
+						group = new L2EnchantSkillGroup(id);
+						_enchantSkillGroups.put(id, group);
+						count++;
+					}
+					EnchantSkillDetail esd = new EnchantSkillDetail(lvl, adena, exp, sp, rate76, rate77, rate78, rate79, rate80, rate81, rate82, rate83, rate84, rate85);
+					group.addEnchantDetail(esd);
+				}
+				
+				enchantGroups.close();
+				statement.close();
+			}
+			catch (Exception e)
+			{
+				_log.log(Level.SEVERE, "Error while loading enchant skill groups ", e);
+			}
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "Error while loading enchant skill groups ", e);
+		}
+		finally
+		{
+			try
+			{
+				con.close();
+			}
+			catch (Exception e)
+			{
+			}
+		}
+		
+		_log.config("EnchantGroupsTable: Loaded " + count + " groups.");
+	}
+	
+	public int addNewRouteForSkill(int skillId, int maxLvL, int route, int group)
+	{
+		L2EnchantSkillLearn enchantableSkill = _enchantSkillTrees.get(skillId);
+		if (enchantableSkill == null)
+		{
+			enchantableSkill = new L2EnchantSkillLearn(skillId, maxLvL);
+			_enchantSkillTrees.put(skillId, enchantableSkill);
+		}
+		if (_enchantSkillGroups.containsKey(group))
+		{
+			enchantableSkill.addNewEnchantRoute(route, group);
+			
+			return _enchantSkillGroups.get(group).getEnchantGroupDetails().size();
+		}
+		_log.log(Level.SEVERE, "Error while loading generating enchant skill id: " + skillId + "; route: " + route + "; missing group: " + group);
+		return 0;
+	}
+	
+	public L2EnchantSkillLearn getSkillEnchantmentForSkill(L2Skill skill)
+	{
+		L2EnchantSkillLearn esl = this.getSkillEnchantmentBySkillId(skill.getId());
+		// there is enchantment for this skill and we have the required level of it
+		if (esl != null && skill.getLevel() >= esl.getBaseLevel())
+		{
+			return esl;
+		}
+		return null;
+	}
+	
+	public L2EnchantSkillLearn getSkillEnchantmentBySkillId(int skillId)
+	{
+		return _enchantSkillTrees.get(skillId);
+	}
+	
+	public int getEnchantSkillSpCost(L2Skill skill)
+	{
+		L2EnchantSkillLearn enchantSkillLearn = _enchantSkillTrees.get(skill.getId());
+		if (enchantSkillLearn != null)
+		{
+			
+			EnchantSkillDetail esd = enchantSkillLearn.getEnchantSkillDetail(skill.getLevel());
+			if (esd != null)
+			{
+				return esd.getSpCost();
+			}
+		}
+		
+		return Integer.MAX_VALUE;
+	}
+	
+	public int getEnchantSkillAdenaCost(L2Skill skill)
+	{
+		L2EnchantSkillLearn enchantSkillLearn = _enchantSkillTrees.get(skill.getId());
+		if (enchantSkillLearn != null)
+		{
+			EnchantSkillDetail esd = enchantSkillLearn.getEnchantSkillDetail(skill.getLevel());
+			if (esd != null)
+			{
+				return esd.getAdenaCost();
+			}
+		}
+		
+		return Integer.MAX_VALUE;
+	}
+	
+	public byte getEnchantSkillRate(L2PcInstance player, L2Skill skill)
+	{
+		L2EnchantSkillLearn enchantSkillLearn = _enchantSkillTrees.get(skill.getId());
+		if (enchantSkillLearn != null)
+		{
+			EnchantSkillDetail esd = enchantSkillLearn.getEnchantSkillDetail(skill.getLevel());
+			if (esd != null)
+			{
+				return esd.getRate(player);
+			}
+		}
+		
+		return 0;
+	}
+	
+	@SuppressWarnings("synthetic-access")
+	private static class SingletonHolder
+	{
+		protected static final EnchantGroupsTable _instance = new EnchantGroupsTable();
+	}
+
+	/**
+	 * @return L2EnchantSkillGroup
+	 */
+	public L2EnchantSkillGroup getEnchantSkillGroupById(int id)
+	{
+		return _enchantSkillGroups.get(id);
+	}
+	
+	public void reload()
+	{
+		load();
+	}
+}

+ 1 - 0
L2_GameServer/java/com/l2jserver/gameserver/datatables/SkillTable.java

@@ -53,6 +53,7 @@ public class SkillTable
 			if (skillLvl > maxLvl)
 				_skillMaxLevel.put(skillId, skillLvl);
 		}
+		//SkillTreeTable.getInstance().reload();
 		
 		// Reloading as well FrequentSkill enumeration values 
 		for (FrequentSkill sk : FrequentSkill.values())

+ 18 - 133
L2_GameServer/java/com/l2jserver/gameserver/datatables/SkillTreeTable.java

@@ -24,12 +24,10 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.l2jserver.L2DatabaseFactory;
-import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
 import com.l2jserver.gameserver.model.L2PledgeSkillLearn;
 import com.l2jserver.gameserver.model.L2Skill;
 import com.l2jserver.gameserver.model.L2SkillLearn;
 import com.l2jserver.gameserver.model.L2TransformSkillLearn;
-import com.l2jserver.gameserver.model.L2EnchantSkillLearn.EnchantSkillDetail;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 import com.l2jserver.gameserver.model.base.ClassId;
 
@@ -43,22 +41,12 @@ import javolution.util.FastMap;
  */
 public class SkillTreeTable
 {
-	public static final int NORMAL_ENCHANT_COST_MULTIPLIER = 1;
-	public static final int SAFE_ENCHANT_COST_MULTIPLIER = 5;
-	public static final int ADENA_XP_DIV = 3; //TODO magic number
-	
-	public static final int NORMAL_ENCHANT_BOOK = 6622;
-	public static final int SAFE_ENCHANT_BOOK = 9627;
-	public static final int CHANGE_ENCHANT_BOOK = 9626;
-	public static final int UNTRAIN_ENCHANT_BOOK = 9625;
-	
 	private static Logger _log = Logger.getLogger(SkillTreeTable.class.getName());
 	
 	private Map<ClassId, Map<Integer, L2SkillLearn>> _skillTrees;
 	private List<L2SkillLearn> _fishingSkillTrees; //all common skills (teached by Fisherman)
 	private List<L2SkillLearn> _expandDwarfCraftSkillTrees; //list of special skill for dwarf (expand dwarf craft) learned by class teacher
 	private List<L2PledgeSkillLearn> _pledgeSkillTrees; //pledge skill list
-	private Map<Integer, L2EnchantSkillLearn> _enchantSkillTrees; //enchant skill list
 	private List<L2TransformSkillLearn> _TransformSkillTrees; // Transform Skills (Test)
 	private FastList<L2SkillLearn> _specialSkillTrees;
 	
@@ -67,6 +55,12 @@ public class SkillTreeTable
 		return SingletonHolder._instance;
 	}
 	
+	
+	private SkillTreeTable()
+	{
+		load();
+	}
+	
 	/**
 	 * Return the minimum level needed to have this Expertise.<BR><BR>
 	 *
@@ -128,7 +122,7 @@ public class SkillTreeTable
 		return 0;
 	}
 	
-	private SkillTreeTable()
+	private void load()
 	{
 		int classId = 0;
 		int count = 0;
@@ -137,7 +131,6 @@ public class SkillTreeTable
 		int count4 = 0;
 		int count5 = 0;
 		int count6 = 0;
-		int count7 = 0;
 		Connection con = null;
 		
 		try
@@ -246,57 +239,6 @@ public class SkillTreeTable
 				_log.severe("Error while creating fishing skill table: " + e);
 			}
 			
-			try
-			{
-				_enchantSkillTrees = new FastMap<Integer, L2EnchantSkillLearn>();
-				
-				PreparedStatement statement = con.prepareStatement("SELECT skill_id, level, base_lvl, sp, min_skill_lvl, exp, success_rate76, success_rate77, success_rate78, success_rate79, success_rate80, success_rate81, success_rate82, success_rate83, success_rate84, success_rate85 FROM enchant_skill_trees ORDER BY skill_id, level");
-				ResultSet skilltree3 = statement.executeQuery();
-				
-				int prevSkillId = -1;
-				
-				while (skilltree3.next())
-				{
-					int id = skilltree3.getInt("skill_id");
-					int lvl = skilltree3.getInt("level");
-					int baseLvl = skilltree3.getInt("base_lvl");
-					int minSkillLvl = skilltree3.getInt("min_skill_lvl");
-					int sp = skilltree3.getInt("sp");
-					int exp = skilltree3.getInt("exp");
-					byte rate76 = skilltree3.getByte("success_rate76");
-					byte rate77 = skilltree3.getByte("success_rate77");
-					byte rate78 = skilltree3.getByte("success_rate78");
-					byte rate79 = skilltree3.getByte("success_rate79");
-					byte rate80 = skilltree3.getByte("success_rate80");
-					byte rate81 = skilltree3.getByte("success_rate81");
-					byte rate82 = skilltree3.getByte("success_rate82");
-					byte rate83 = skilltree3.getByte("success_rate83");
-					byte rate84 = skilltree3.getByte("success_rate84");
-					byte rate85 = skilltree3.getByte("success_rate85");
-					
-					if (prevSkillId != id)
-						prevSkillId = id;
-					
-					L2EnchantSkillLearn skill = _enchantSkillTrees.get(id);
-					if (skill == null)
-					{
-						skill = new L2EnchantSkillLearn(id, baseLvl);
-						_enchantSkillTrees.put(id, skill);
-					}
-					EnchantSkillDetail esd = new EnchantSkillDetail(lvl, minSkillLvl, sp, exp, rate76, rate77, rate78, rate79, rate80, rate81, rate82, rate83, rate84, rate85);
-					skill.addEnchantDetail(esd);
-				}
-				
-				skilltree3.close();
-				statement.close();
-				
-				count4 = _enchantSkillTrees.size();
-			}
-			catch (Exception e)
-			{
-				_log.log(Level.SEVERE, "Error while creating enchant skill table ", e);
-			}
-			
 			try
 			{
 				_pledgeSkillTrees = new FastList<L2PledgeSkillLearn>();
@@ -327,7 +269,7 @@ public class SkillTreeTable
 				skilltree4.close();
 				statement.close();
 				
-				count5 = _pledgeSkillTrees.size();
+				count4 = _pledgeSkillTrees.size();
 			}
 			catch (Exception e)
 			{
@@ -363,7 +305,7 @@ public class SkillTreeTable
 				skilltree5.close();
 				statement.close();
 				
-				count6 = _TransformSkillTrees.size();
+				count5 = _TransformSkillTrees.size();
 			}
 			catch (Exception e)
 			{
@@ -397,7 +339,7 @@ public class SkillTreeTable
 				skilltree6.close();
 				statement.close();
 				
-				count7 = _specialSkillTrees.size();
+				count6 = _specialSkillTrees.size();
 			}
 			catch (Exception e)
 			{
@@ -421,10 +363,9 @@ public class SkillTreeTable
 		
 		_log.config("FishingSkillTreeTable: Loaded " + count2 + " general skills.");
 		_log.config("DwarvenCraftSkillTreeTable: Loaded " + count3 + " dwarven skills.");
-		_log.config("EnchantSkillTreeTable: Loaded " + count4 + " enchant skills.");
-		_log.config("PledgeSkillTreeTable: Loaded " + count5 + " pledge skills");
-		_log.config("TransformSkillTreeTable: Loaded " + count6 + " transform skills");
-		_log.config("SpecialSkillTreeTable: Loaded " + count7 + " special skills");
+		_log.config("PledgeSkillTreeTable: Loaded " + count4 + " pledge skills");
+		_log.config("TransformSkillTreeTable: Loaded " + count5 + " transform skills");
+		_log.config("SpecialSkillTreeTable: Loaded " + count6 + " special skills");
 	}
 	
 	private Map<ClassId, Map<Integer, L2SkillLearn>> getSkillTrees()
@@ -576,22 +517,6 @@ public class SkillTreeTable
 		return result.toArray(new L2SkillLearn[result.size()]);
 	}
 	
-	public L2EnchantSkillLearn getSkillEnchantmentForSkill(L2Skill skill)
-	{
-		L2EnchantSkillLearn esl = this.getSkillEnchantmentBySkillId(skill.getId());
-		// there is enchantment for this skill and we have the required level of it
-		if (esl != null && skill.getLevel() >= esl.getBaseLevel())
-		{
-			return esl;
-		}
-		return null;
-	}
-	
-	public L2EnchantSkillLearn getSkillEnchantmentBySkillId(int skillId)
-	{
-		return _enchantSkillTrees.get(skillId);
-	}
-	
 	public L2TransformSkillLearn[] getAvailableTransformSkills(L2PcInstance cha)
 	{
 		List<L2TransformSkillLearn> result = new FastList<L2TransformSkillLearn>();
@@ -789,54 +714,14 @@ public class SkillTreeTable
 		return skillCost;
 	}
 	
-	public int getEnchantSkillSpCost(L2Skill skill)
-	{
-		L2EnchantSkillLearn enchantSkillLearn = _enchantSkillTrees.get(skill.getId());
-		if (enchantSkillLearn != null)
-		{
-			EnchantSkillDetail esd = enchantSkillLearn.getEnchantSkillDetail(skill.getLevel());
-			if (esd != null)
-			{
-				return esd.getSpCost();
-			}
-		}
-		
-		return Integer.MAX_VALUE;
-	}
-	
-	public int getEnchantSkillAdenaCost(L2Skill skill)
-	{
-		L2EnchantSkillLearn enchantSkillLearn = _enchantSkillTrees.get(skill.getId());
-		if (enchantSkillLearn != null)
-		{
-			EnchantSkillDetail esd = enchantSkillLearn.getEnchantSkillDetail(skill.getLevel());
-			if (esd != null)
-			{
-				return esd.getAdena();
-			}
-		}
-		
-		return Integer.MAX_VALUE;
-	}
-	
-	public byte getEnchantSkillRate(L2PcInstance player, L2Skill skill)
-	{
-		L2EnchantSkillLearn enchantSkillLearn = _enchantSkillTrees.get(skill.getId());
-		if (enchantSkillLearn != null)
-		{
-			EnchantSkillDetail esd = enchantSkillLearn.getEnchantSkillDetail(skill.getLevel());
-			if (esd != null)
-			{
-				return esd.getRate(player);
-			}
-		}
-		
-		return 0;
-	}
-	
 	@SuppressWarnings("synthetic-access")
 	private static class SingletonHolder
 	{
 		protected static final SkillTreeTable _instance = new SkillTreeTable();
 	}
+	
+	public void reload()
+	{
+		load();
+	}
 }

+ 106 - 0
L2_GameServer/java/com/l2jserver/gameserver/model/L2EnchantSkillGroup.java

@@ -0,0 +1,106 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.gameserver.model;
+
+import java.util.List;
+
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+import javolution.util.FastList;
+
+public final class L2EnchantSkillGroup
+{
+	private final int _id;
+	private List<EnchantSkillDetail> _enchantDetails = new FastList<EnchantSkillDetail>();
+
+	public L2EnchantSkillGroup(int id)
+	{
+		_id = id;
+	}
+
+	public void addEnchantDetail(EnchantSkillDetail detail)
+	{
+		_enchantDetails.add(detail);
+	}
+	
+	public int getId()
+	{
+		return _id;
+	}
+	
+	public List<EnchantSkillDetail> getEnchantGroupDetails()
+	{
+		return _enchantDetails;
+	}
+	
+	public static class EnchantSkillDetail
+	{
+		private final int _level;
+		private final int _adenaCost;
+		private final int _expCost;
+		private final int _spCost;
+		private final byte[] _rate;
+		
+		public EnchantSkillDetail(int lvl, int adena, int exp, int sp, byte rate76, byte rate77, byte rate78, byte rate79, byte rate80, byte rate81, byte rate82, byte rate83, byte rate84, byte rate85)
+		{
+			_level = lvl;
+			_adenaCost = adena;
+			_expCost = exp;
+			_spCost = sp;
+			_rate = new byte[10];
+			_rate[0] = rate76;
+			_rate[1] = rate77;
+			_rate[2] = rate78;
+			_rate[3] = rate79;
+			_rate[4] = rate80;
+			_rate[5] = rate81;
+			_rate[6] = rate82;
+			_rate[7] = rate83;
+			_rate[8] = rate84;
+			_rate[9] = rate85;
+		}
+		
+		/**
+		 * @return Returns the level.
+		 */
+		public int getLevel()
+		{
+			return _level;
+		}
+		
+		/**
+		 * @return Returns the spCost.
+		 */
+		public int getSpCost()
+		{
+			return _spCost;
+		}
+		public int getExpCost()
+		{
+			return _expCost;
+		}
+		public int getAdenaCost()
+		{
+			return _adenaCost;
+		}
+		
+		public byte getRate(L2PcInstance ply)
+		{
+			if (ply.getLevel() < 76)
+				return 0;
+			return _rate[ply.getLevel() - 76];
+		}
+	}
+}

+ 98 - 179
L2_GameServer/java/com/l2jserver/gameserver/model/L2EnchantSkillLearn.java

@@ -14,195 +14,114 @@
  */
 package com.l2jserver.gameserver.model;
 
-import java.util.List;
+import gnu.trove.TIntIntHashMap;
 
-import com.l2jserver.gameserver.datatables.SkillTreeTable;
-import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
-
-import javolution.util.FastTable;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
+import com.l2jserver.gameserver.model.L2EnchantSkillGroup.EnchantSkillDetail;
 
 /**
  * This class ...
  *
  * @version $Revision: 1.2.4.2 $ $Date: 2005/03/27 15:29:33 $
  */
-@SuppressWarnings("unchecked")
 public final class L2EnchantSkillLearn
 {
-    private final int _id;
-    private final int _baseLvl;
-    
-    private List<EnchantSkillDetail>[] _enchantDetails = new List[0];
-
-    public L2EnchantSkillLearn(int id, int baseLvl)
-    {
-        _id = id;
-        _baseLvl = baseLvl;
-    }
-
-    /**
-     * @return Returns the id.
-     */
-    public int getId()
-    {
-        return _id;
-    }
-
-    /**
-     * @return Returns the minLevel.
-     */
-    public int getBaseLevel()
-    {
-        return _baseLvl;
-    }
-    
-    public void addEnchantDetail(EnchantSkillDetail esd)
-    {
-        int enchantType = L2EnchantSkillLearn.getEnchantType(esd.getLevel());
-        
-        if (enchantType < 0)
-        {
-            throw new IllegalArgumentException("Skill enchantments should have level higher then 100");
-        }
-        else
-        {
-            if (enchantType >= _enchantDetails.length)
-            {
-                List<EnchantSkillDetail>[] newArray = new List[enchantType+1];
-                System.arraycopy(_enchantDetails, 0, newArray, 0, _enchantDetails.length);
-                _enchantDetails = newArray;
-                _enchantDetails[enchantType] = new FastTable<EnchantSkillDetail>();
-            }
-            int index = L2EnchantSkillLearn.getEnchantIndex(esd.getLevel());
-            _enchantDetails[enchantType].add(index, esd);
-        }
-    }
-    
-    public List<EnchantSkillDetail>[] getEnchantRoutes()
-    {
-        return _enchantDetails;
-    }
-    
-    public EnchantSkillDetail getEnchantSkillDetail(int level)
-    {
-        int enchantType = L2EnchantSkillLearn.getEnchantType(level);
-        if (enchantType < 0 || enchantType >= _enchantDetails.length)
-        {
-            return null;
-        }
-        int index = L2EnchantSkillLearn.getEnchantIndex(level);
-        if (index < 0 || index >= _enchantDetails[enchantType].size())
-        {
-            return null;
-        }
-        return _enchantDetails[enchantType].get(index);
-    }
-    
-    public static int getEnchantIndex(int level)
-    {
-        return (level % 100) - 1;
-    }
-    
-    public static int getEnchantType(int level)
-    {
-        return ((level - 1) / 100) - 1;
-    }
-    
-    public static class EnchantSkillDetail
-    {
-        private final int _level;
-        private final int _spCost;
-        private final int _minSkillLevel;
-        private final int _exp;
-        private final byte _rate76,_rate77,_rate78,_rate79,_rate80,_rate81,_rate82,_rate83,_rate84,_rate85;
+	private final int _id;
+	private final int _baseLvl;
+	private final TIntIntHashMap _enchantRoutes = new TIntIntHashMap();
 
-        
-        public EnchantSkillDetail(int lvl, int minSkillLvl, int cost, int exp, byte rate76, byte rate77, byte rate78, byte rate79, byte rate80, byte rate81, byte rate82, byte rate83, byte rate84, byte rate85)
-        {
-            _level = lvl;
-            _minSkillLevel = minSkillLvl;
-            _spCost = cost;
-            _exp = exp;
-            _rate76 = rate76;
-            _rate77 = rate77;
-            _rate78 = rate78;
-            _rate79 = rate79;
-            _rate80 = rate80;
-            _rate81 = rate81;
-            _rate82 = rate82;
-            _rate83 = rate83;
-            _rate84 = rate84;
-            _rate85 = rate85;
-        }
-        
-        /**
-         * @return Returns the level.
-         */
-        public int getLevel()
-        {
-            return _level;
-        }
-        
-        /**
-         * @return Returns the minSkillLevel.
-         */
-        public int getMinSkillLevel()
-        {
-            return _minSkillLevel;
-        }
+	public L2EnchantSkillLearn(int id, int baseLvl)
+	{
+		_id = id;
+		_baseLvl = baseLvl;
+	}
 
-        /**
-         * @return Returns the spCost.
-         */
-        public int getSpCost()
-        {
-            return _spCost;
-        }
-        public int getAdena()
-        {
-            return _exp / SkillTreeTable.ADENA_XP_DIV;
-        }
+	public void addNewEnchantRoute(int route, int group)
+	{
+		_enchantRoutes.put(route, group);
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public int getId()
+	{
+		return _id;
+	}
 
-        public byte getRate(L2PcInstance ply)
-        {
-            byte result;
-            switch (ply.getLevel())
-            {
-                case 76:
-                    result = _rate76;
-                    break;
-                case 77:
-                    result = _rate77;
-                    break;
-                case 78:
-                    result = _rate78;
-                    break;
-                case 79:
-                    result = _rate79;
-                    break;
-                case 80:
-                    result = _rate80;
-                    break;
-                case 81:
-                    result = _rate81;
-                    break;
-                case 82:
-                    result = _rate82;
-                    break;
-                case 83:
-                    result = _rate83;
-                    break;
-                case 84:
-                    result = _rate84;
-                    break;
-                case 85:
-                    result = _rate85;
-                    break;
-                default:
-                    result = _rate85;
-                break;
-            }
-            return result;
-        }
-    }
+	/**
+	 * @return Returns the minLevel.
+	 */
+	public int getBaseLevel()
+	{
+		return _baseLvl;
+	}
+	
+	public static int getEnchantRoute(int level)
+	{
+		return (int) Math.floor(level / 100);
+	}
+	
+	public static int getEnchantIndex(int level)
+	{
+		return (level % 100) - 1;
+	}
+	
+	public static int getEnchantType(int level)
+	{
+		return ((level - 1) / 100) - 1;
+	}
+	
+	public L2EnchantSkillGroup getFirstRouteGroup()
+	{
+		return EnchantGroupsTable.getInstance().getEnchantSkillGroupById(_enchantRoutes.getValues()[0]);
+	}
+	
+	public int[] getAllRoutes()
+	{
+		return _enchantRoutes.keys();
+	}
+	
+	public int getMinSkillLevel(int level)
+	{
+		if (level % 100 == 1)
+			return _baseLvl;
+		return level - 1;
+	}
+	
+	public boolean isMaxEnchant(int level)
+	{
+		int enchantType = L2EnchantSkillLearn.getEnchantRoute(level);
+		if (enchantType < 1 || !_enchantRoutes.contains(enchantType))
+		{
+			return false;
+		}
+		int index = L2EnchantSkillLearn.getEnchantIndex(level);
+		
+		if ((index + 1) >= EnchantGroupsTable.getInstance().getEnchantSkillGroupById(_enchantRoutes.get(enchantType)).getEnchantGroupDetails().size())
+		{
+			return true;
+		}
+		return false;
+	}
+	
+	public EnchantSkillDetail getEnchantSkillDetail(int level)
+	{
+		int enchantType = L2EnchantSkillLearn.getEnchantRoute(level);
+		if (enchantType < 1 || !_enchantRoutes.contains(enchantType))
+		{
+			return null;
+		}
+		int index = L2EnchantSkillLearn.getEnchantIndex(level);
+		L2EnchantSkillGroup group = EnchantGroupsTable.getInstance().getEnchantSkillGroupById(_enchantRoutes.get(enchantType));
+		
+		if (index < 0)
+		{
+			return group.getEnchantGroupDetails().get(0);
+		}
+		else if (index >= group.getEnchantGroupDetails().size())
+		{
+			return group.getEnchantGroupDetails().get(EnchantGroupsTable.getInstance().getEnchantSkillGroupById(_enchantRoutes.get(enchantType)).getEnchantGroupDetails().size() - 1);
+		}
+		return group.getEnchantGroupDetails().get(index);
+	}
 }

+ 2 - 1
L2_GameServer/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java

@@ -61,6 +61,7 @@ import com.l2jserver.gameserver.datatables.AdminCommandAccessRights;
 import com.l2jserver.gameserver.datatables.CharNameTable;
 import com.l2jserver.gameserver.datatables.CharTemplateTable;
 import com.l2jserver.gameserver.datatables.ClanTable;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.datatables.FishTable;
 import com.l2jserver.gameserver.datatables.HennaTable;
 import com.l2jserver.gameserver.datatables.HeroSkillTable;
@@ -10418,7 +10419,7 @@ public final class L2PcInstance extends L2Playable
 				boolean isEnchantable = skillMaxLevel > 100;
 				if (isEnchantable)
 				{
-					L2EnchantSkillLearn esl = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(s.getId());
+					L2EnchantSkillLearn esl = EnchantGroupsTable.getInstance().getSkillEnchantmentBySkillId(s.getId());
 					if (esl != null)
 					{
 						//if player dont have min level to enchant 

+ 7 - 7
L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkill.java

@@ -19,13 +19,13 @@ import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 
 import com.l2jserver.Config;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
-import com.l2jserver.gameserver.datatables.SkillTreeTable;
 import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
 import com.l2jserver.gameserver.model.L2ItemInstance;
 import com.l2jserver.gameserver.model.L2ShortCut;
 import com.l2jserver.gameserver.model.L2Skill;
-import com.l2jserver.gameserver.model.L2EnchantSkillLearn.EnchantSkillDetail;
+import com.l2jserver.gameserver.model.L2EnchantSkillGroup.EnchantSkillDetail;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 import com.l2jserver.gameserver.network.SystemMessageId;
 import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
@@ -97,22 +97,22 @@ public final class RequestExEnchantSkill extends L2GameClientPacket
             return;
         }
         
-        int costMultiplier = SkillTreeTable.NORMAL_ENCHANT_COST_MULTIPLIER;
-        int reqItemId = SkillTreeTable.NORMAL_ENCHANT_BOOK;
+        int costMultiplier = EnchantGroupsTable.NORMAL_ENCHANT_COST_MULTIPLIER;
+        int reqItemId = EnchantGroupsTable.NORMAL_ENCHANT_BOOK;
         
-        L2EnchantSkillLearn s = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
+        L2EnchantSkillLearn s = EnchantGroupsTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
         if (s == null)
         {
             return;
         }
         EnchantSkillDetail esd = s.getEnchantSkillDetail(_skillLvl);
-        if (player.getSkillLevel(_skillId) != esd.getMinSkillLevel())
+        if (player.getSkillLevel(_skillId) != s.getMinSkillLevel(_skillLvl))
         {
             return;
         }
         
         int requiredSp = esd.getSpCost() * costMultiplier;
-        int requireditems = (esd.getAdena() * costMultiplier);
+        int requireditems = (esd.getAdenaCost() * costMultiplier);
         int rate = esd.getRate(player);
         
         if (player.getSp() >= requiredSp)

+ 2 - 2
L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillInfo.java

@@ -14,8 +14,8 @@
  */
 package com.l2jserver.gameserver.network.clientpackets;
 
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
-import com.l2jserver.gameserver.datatables.SkillTreeTable;
 import com.l2jserver.gameserver.model.L2Skill;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 import com.l2jserver.gameserver.network.serverpackets.ExEnchantSkillInfo;
@@ -71,7 +71,7 @@ public final class RequestExEnchantSkillInfo extends L2GameClientPacket
             return;
         }
 
-        if ( SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(_skillId) == null)
+        if ( EnchantGroupsTable.getInstance().getSkillEnchantmentBySkillId(_skillId) == null)
         	return;
         
         int playerSkillLvl = activeChar.getSkillLevel(_skillId);

+ 2 - 2
L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillInfoDetail.java

@@ -16,7 +16,7 @@ package com.l2jserver.gameserver.network.clientpackets;
 
 import java.util.logging.Logger;
 
-import com.l2jserver.gameserver.datatables.SkillTreeTable;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 import com.l2jserver.gameserver.network.serverpackets.ExEnchantSkillInfoDetail;
@@ -75,7 +75,7 @@ public final class RequestExEnchantSkillInfoDetail extends L2GameClientPacket
 		// if reqlvl is 100,200,.. check base skill lvl enchant
 		if ((reqSkillLvl % 100) == 0)
 		{
-			L2EnchantSkillLearn esl = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
+			L2EnchantSkillLearn esl = EnchantGroupsTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
 			if (esl != null)
 			{
 				// if player dont have min level to enchant

+ 5 - 5
L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillRouteChange.java

@@ -19,13 +19,13 @@ import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 
 import com.l2jserver.Config;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
-import com.l2jserver.gameserver.datatables.SkillTreeTable;
 import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
 import com.l2jserver.gameserver.model.L2ItemInstance;
 import com.l2jserver.gameserver.model.L2ShortCut;
 import com.l2jserver.gameserver.model.L2Skill;
-import com.l2jserver.gameserver.model.L2EnchantSkillLearn.EnchantSkillDetail;
+import com.l2jserver.gameserver.model.L2EnchantSkillGroup.EnchantSkillDetail;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 import com.l2jserver.gameserver.network.SystemMessageId;
 import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
@@ -95,9 +95,9 @@ public final class RequestExEnchantSkillRouteChange extends L2GameClientPacket
 			return;
 		}
 
-		int reqItemId = SkillTreeTable.CHANGE_ENCHANT_BOOK;
+		int reqItemId = EnchantGroupsTable.CHANGE_ENCHANT_BOOK;
 
-		L2EnchantSkillLearn s = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
+		L2EnchantSkillLearn s = EnchantGroupsTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
 		if (s == null)
 		{
 			return;
@@ -119,7 +119,7 @@ public final class RequestExEnchantSkillRouteChange extends L2GameClientPacket
 		EnchantSkillDetail esd = s.getEnchantSkillDetail(_skillLvl);
 
 		int requiredSp = esd.getSpCost();
-		int requireditems = esd.getAdena();
+		int requireditems = esd.getAdenaCost();
 
 		if (player.getSp() >= requiredSp)
 		{

+ 7 - 7
L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillSafe.java

@@ -19,13 +19,13 @@ import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 
 import com.l2jserver.Config;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
-import com.l2jserver.gameserver.datatables.SkillTreeTable;
 import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
 import com.l2jserver.gameserver.model.L2ItemInstance;
 import com.l2jserver.gameserver.model.L2ShortCut;
 import com.l2jserver.gameserver.model.L2Skill;
-import com.l2jserver.gameserver.model.L2EnchantSkillLearn.EnchantSkillDetail;
+import com.l2jserver.gameserver.model.L2EnchantSkillGroup.EnchantSkillDetail;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 import com.l2jserver.gameserver.network.SystemMessageId;
 import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
@@ -95,22 +95,22 @@ public final class RequestExEnchantSkillSafe extends L2GameClientPacket
 			return;
 		}
 
-		int costMultiplier = SkillTreeTable.SAFE_ENCHANT_COST_MULTIPLIER;
-		int reqItemId = SkillTreeTable.SAFE_ENCHANT_BOOK;
+		int costMultiplier = EnchantGroupsTable.SAFE_ENCHANT_COST_MULTIPLIER;
+		int reqItemId = EnchantGroupsTable.SAFE_ENCHANT_BOOK;
 
-		L2EnchantSkillLearn s = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
+		L2EnchantSkillLearn s = EnchantGroupsTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
 		if (s == null)
 		{
 			return;
 		}
 		EnchantSkillDetail esd = s.getEnchantSkillDetail(_skillLvl);
-		if (player.getSkillLevel(_skillId) != esd.getMinSkillLevel())
+		if (player.getSkillLevel(_skillId) != s.getMinSkillLevel(_skillLvl))
 		{
 			return;
 		}
 
 		int requiredSp = esd.getSpCost() * costMultiplier;
-		int requireditems = esd.getAdena() * costMultiplier;
+		int requireditems = esd.getAdenaCost() * costMultiplier;
 		int rate = esd.getRate(player);
 
 		if (player.getSp() >= requiredSp)

+ 5 - 5
L2_GameServer/java/com/l2jserver/gameserver/network/clientpackets/RequestExEnchantSkillUntrain.java

@@ -19,13 +19,13 @@ import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 
 import com.l2jserver.Config;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
-import com.l2jserver.gameserver.datatables.SkillTreeTable;
 import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
 import com.l2jserver.gameserver.model.L2ItemInstance;
 import com.l2jserver.gameserver.model.L2ShortCut;
 import com.l2jserver.gameserver.model.L2Skill;
-import com.l2jserver.gameserver.model.L2EnchantSkillLearn.EnchantSkillDetail;
+import com.l2jserver.gameserver.model.L2EnchantSkillGroup.EnchantSkillDetail;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 import com.l2jserver.gameserver.network.SystemMessageId;
 import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
@@ -89,7 +89,7 @@ public final class RequestExEnchantSkillUntrain extends L2GameClientPacket
         	return;
         }
 
-		L2EnchantSkillLearn s = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
+		L2EnchantSkillLearn s = EnchantGroupsTable.getInstance().getSkillEnchantmentBySkillId(_skillId);
 		if (s == null)
 			return;
 		
@@ -102,7 +102,7 @@ public final class RequestExEnchantSkillUntrain extends L2GameClientPacket
 		if (skill == null)
 			return;
 		
-		int reqItemId = SkillTreeTable.UNTRAIN_ENCHANT_BOOK;
+		int reqItemId = EnchantGroupsTable.UNTRAIN_ENCHANT_BOOK;
 		
 		int currentLevel = player.getSkillLevel(_skillId);
 		if (currentLevel - 1 != _skillLvl && (currentLevel % 100 != 1 || _skillLvl != s.getBaseLevel()))
@@ -111,7 +111,7 @@ public final class RequestExEnchantSkillUntrain extends L2GameClientPacket
 		EnchantSkillDetail esd = s.getEnchantSkillDetail(currentLevel);
 		
 		int requiredSp = esd.getSpCost();
-		int requireditems = esd.getAdena();
+		int requireditems = esd.getAdenaCost();
 		
 		L2ItemInstance spb = player.getInventory().getItemByItemId(reqItemId);
 		if (Config.ES_SP_BOOK_NEEDED)

+ 11 - 19
L2_GameServer/java/com/l2jserver/gameserver/network/serverpackets/ExEnchantSkillInfo.java

@@ -14,11 +14,9 @@
  */
 package com.l2jserver.gameserver.network.serverpackets;
 
-import java.util.List;
-
-import com.l2jserver.gameserver.datatables.SkillTreeTable;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
-import com.l2jserver.gameserver.model.L2EnchantSkillLearn.EnchantSkillDetail;
+import com.l2jserver.gameserver.model.L2EnchantSkillGroup.EnchantSkillDetail;
 
 import javolution.util.FastList;
 
@@ -37,16 +35,14 @@ public final class ExEnchantSkillInfo extends L2GameServerPacket
 		_id = id;
 		_lvl = lvl;
 
-		L2EnchantSkillLearn enchantLearn = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(_id);
+		L2EnchantSkillLearn enchantLearn = EnchantGroupsTable.getInstance().getSkillEnchantmentBySkillId(_id);
 		// do we have this skill?
 		if (enchantLearn != null)
 		{
 			// skill already enchanted?
 			if (_lvl > 100)
 			{
-				int route = (_lvl / 100) -1;
-				if (_lvl % 100 >= enchantLearn.getEnchantRoutes()[route].size())
-					_maxEnchanted = true;
+				_maxEnchanted = enchantLearn.isMaxEnchant(_lvl);
 				
 				// get detail for next level
 				EnchantSkillDetail esd = enchantLearn.getEnchantSkillDetail(_lvl);
@@ -54,32 +50,28 @@ public final class ExEnchantSkillInfo extends L2GameServerPacket
 				// if it exists add it
 				if (esd != null)
 				{
-					_routes.add(esd.getLevel()); // current enchant add firts
+					_routes.add(_lvl); // current enchant add firts
 				}
 
-				int diff = (_lvl % 100) - 1; // indexed form 0
+				int skillLvL = (_lvl % 100);
 
-				for (List<EnchantSkillDetail> esd1 : enchantLearn.getEnchantRoutes())
+				for (int route : enchantLearn.getAllRoutes())
 				{
-					if (esd1 == null)
-						continue;
-					if (esd1.get(0).getLevel() == _lvl) // skip current
+					if ((route * 100 + skillLvL) == _lvl) // skip current
 						continue;
 					// add other levels of all routes - same lvl as enchanted
 					// lvl
-					_routes.add(esd1.get(diff).getLevel());
+					_routes.add(route * 100 + skillLvL);
 				}
 
 			}
 			else
 			// not already enchanted
 			{
-				for (List<EnchantSkillDetail> esd : enchantLearn.getEnchantRoutes())
+				for (int route : enchantLearn.getAllRoutes())
 				{
-					if (esd == null)
-						continue;
 					// add first level (+1) of all routes
-					_routes.add(esd.get(0).getLevel());
+					_routes.add(route * 100 + 1);
 				}
 			}
 		}

+ 12 - 26
L2_GameServer/java/com/l2jserver/gameserver/network/serverpackets/ExEnchantSkillInfoDetail.java

@@ -14,12 +14,10 @@
  */
 package com.l2jserver.gameserver.network.serverpackets;
 
-import java.util.List;
-
 import com.l2jserver.Config;
-import com.l2jserver.gameserver.datatables.SkillTreeTable;
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
-import com.l2jserver.gameserver.model.L2EnchantSkillLearn.EnchantSkillDetail;
+import com.l2jserver.gameserver.model.L2EnchantSkillGroup.EnchantSkillDetail;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 
 /**
@@ -46,43 +44,31 @@ public class ExEnchantSkillInfoDetail extends L2GameServerPacket
 	public ExEnchantSkillInfoDetail(int type, int skillid, int skilllvl, L2PcInstance ply)
 	{
 
-		L2EnchantSkillLearn enchantLearn = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(skillid);
+		L2EnchantSkillLearn enchantLearn = EnchantGroupsTable.getInstance().getSkillEnchantmentBySkillId(skillid);
 		EnchantSkillDetail esd = null;
 		// do we have this skill?
 		if (enchantLearn != null)
 		{
 			if (skilllvl > 100)
 			{
-				int route = (skilllvl / 100) -1;
-				if (skilllvl % 100 == 0)
-					esd = enchantLearn.getEnchantRoutes()[route].get(0);
-				else if (skilllvl % 100 >= enchantLearn.getEnchantRoutes()[route].size())
-					esd = enchantLearn.getEnchantRoutes()[route].get(enchantLearn.getEnchantRoutes()[route].size()-1);
-				else
-					esd = enchantLearn.getEnchantSkillDetail(skilllvl);
+				esd = enchantLearn.getEnchantSkillDetail(skilllvl);
 			}
 			else
-				//find first enchant route
-				for (List<EnchantSkillDetail> list : enchantLearn.getEnchantRoutes())
-					if (list != null)
-					{
-						esd = list.get(0);
-						break;
-					}
+				esd = enchantLearn.getFirstRouteGroup().getEnchantGroupDetails().get(0);
 		}
 
 		if (esd == null)
 			throw new IllegalArgumentException("Skill "+skillid + " dont have enchant data for level "+skilllvl);
 
 		if (type == 0)
-			multi = SkillTreeTable.NORMAL_ENCHANT_COST_MULTIPLIER;
+			multi = EnchantGroupsTable.NORMAL_ENCHANT_COST_MULTIPLIER;
 		else if (type == 1)
-			multi = SkillTreeTable.SAFE_ENCHANT_COST_MULTIPLIER;
+			multi = EnchantGroupsTable.SAFE_ENCHANT_COST_MULTIPLIER;
 		_chance = esd.getRate(ply);
 		_sp = esd.getSpCost();
 		if (type == TYPE_UNTRAIN_ENCHANT)
 			_sp = (int) (0.8 * _sp);
-		_adenacount = esd.getAdena() * multi;
+		_adenacount = esd.getAdenaCost() * multi;
 		_type = type;
 		_skillid = skillid;
 		_skilllvl = skilllvl;
@@ -90,19 +76,19 @@ public class ExEnchantSkillInfoDetail extends L2GameServerPacket
 		switch (type)
 		{
 		case TYPE_NORMAL_ENCHANT:
-			bookId = SkillTreeTable.NORMAL_ENCHANT_BOOK;
+			bookId = EnchantGroupsTable.NORMAL_ENCHANT_BOOK;
 			reqCount = ((_skilllvl % 100 > 1) ? 0 : 1) ;
 			break;
 		case TYPE_SAFE_ENCHANT:
-			bookId = SkillTreeTable.SAFE_ENCHANT_BOOK;
+			bookId = EnchantGroupsTable.SAFE_ENCHANT_BOOK;
 			reqCount = 1;
 			break;
 		case TYPE_UNTRAIN_ENCHANT:
-			bookId = SkillTreeTable.UNTRAIN_ENCHANT_BOOK;
+			bookId = EnchantGroupsTable.UNTRAIN_ENCHANT_BOOK;
 			reqCount = 1;
 			break;
 		case TYPE_CHANGE_ENCHANT:
-			bookId = SkillTreeTable.CHANGE_ENCHANT_BOOK;
+			bookId = EnchantGroupsTable.CHANGE_ENCHANT_BOOK;
 			reqCount = 1;
 			break;
 		default:

+ 17 - 16
L2_GameServer/java/com/l2jserver/gameserver/skills/DocumentSkill.java

@@ -24,6 +24,7 @@ import org.w3c.dom.Document;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 
+import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
 import com.l2jserver.gameserver.model.L2Skill;
 import com.l2jserver.gameserver.skills.conditions.Condition;
 import com.l2jserver.gameserver.templates.StatsSet;
@@ -149,22 +150,22 @@ class DocumentSkill extends DocumentBase {
 		String skillName = attrs.getNamedItem("name").getNodeValue();
 		String levels = attrs.getNamedItem("levels").getNodeValue();
 		int lastLvl = Integer.parseInt(levels);
-        if (attrs.getNamedItem("enchantLevels1") != null)
-            enchantLevels1 = Integer.parseInt(attrs.getNamedItem("enchantLevels1").getNodeValue());
-        if (attrs.getNamedItem("enchantLevels2") != null)
-            enchantLevels2 = Integer.parseInt(attrs.getNamedItem("enchantLevels2").getNodeValue());
-        if (attrs.getNamedItem("enchantLevels3") != null)
-            enchantLevels3 = Integer.parseInt(attrs.getNamedItem("enchantLevels3").getNodeValue());
-        if (attrs.getNamedItem("enchantLevels4") != null)
-            enchantLevels4 = Integer.parseInt(attrs.getNamedItem("enchantLevels4").getNodeValue());
-        if (attrs.getNamedItem("enchantLevels5") != null)
-            enchantLevels5 = Integer.parseInt(attrs.getNamedItem("enchantLevels5").getNodeValue());
-        if (attrs.getNamedItem("enchantLevels6") != null)
-            enchantLevels6 = Integer.parseInt(attrs.getNamedItem("enchantLevels6").getNodeValue());
-        if (attrs.getNamedItem("enchantLevels7") != null)
-            enchantLevels7 = Integer.parseInt(attrs.getNamedItem("enchantLevels7").getNodeValue());
-        if (attrs.getNamedItem("enchantLevels8") != null)
-            enchantLevels8 = Integer.parseInt(attrs.getNamedItem("enchantLevels8").getNodeValue());
+        if (attrs.getNamedItem("enchantGroup1") != null)
+            enchantLevels1 = EnchantGroupsTable.getInstance().addNewRouteForSkill(skillId, lastLvl, 1, Integer.parseInt(attrs.getNamedItem("enchantGroup1").getNodeValue()));
+        if (attrs.getNamedItem("enchantGroup2") != null)
+        	enchantLevels2 = EnchantGroupsTable.getInstance().addNewRouteForSkill(skillId, lastLvl, 2, Integer.parseInt(attrs.getNamedItem("enchantGroup2").getNodeValue()));
+        if (attrs.getNamedItem("enchantGroup3") != null)
+        	enchantLevels3 = EnchantGroupsTable.getInstance().addNewRouteForSkill(skillId, lastLvl, 3, Integer.parseInt(attrs.getNamedItem("enchantGroup3").getNodeValue()));
+        if (attrs.getNamedItem("enchantGroup4") != null)
+        	enchantLevels4 = EnchantGroupsTable.getInstance().addNewRouteForSkill(skillId, lastLvl, 4, Integer.parseInt(attrs.getNamedItem("enchantGroup4").getNodeValue()));
+        if (attrs.getNamedItem("enchantGroup5") != null)
+        	enchantLevels5 = EnchantGroupsTable.getInstance().addNewRouteForSkill(skillId, lastLvl, 5, Integer.parseInt(attrs.getNamedItem("enchantGroup5").getNodeValue()));
+        if (attrs.getNamedItem("enchantGroup6") != null)
+        	enchantLevels6 = EnchantGroupsTable.getInstance().addNewRouteForSkill(skillId, lastLvl, 6, Integer.parseInt(attrs.getNamedItem("enchantGroup6").getNodeValue()));
+        if (attrs.getNamedItem("enchantGroup7") != null)
+        	enchantLevels7 = EnchantGroupsTable.getInstance().addNewRouteForSkill(skillId, lastLvl, 7, Integer.parseInt(attrs.getNamedItem("enchantGroup7").getNodeValue()));
+        if (attrs.getNamedItem("enchantGroup8") != null)
+        	enchantLevels8 = EnchantGroupsTable.getInstance().addNewRouteForSkill(skillId, lastLvl, 8, Integer.parseInt(attrs.getNamedItem("enchantGroup8").getNodeValue()));
 
         _currentSkill.id     = skillId;
         _currentSkill.name   = skillName;