Selaa lähdekoodia

BETA: NpcTable rework now's a bit more organized and also is possible to (re) load any npcId on the fly thanks qwerty13 for testing

Rumen Nikiforov 13 vuotta sitten
vanhempi
sitoutus
ee7f6b4c8e

+ 801 - 714
L2J_Server_BETA/java/com/l2jserver/gameserver/datatables/NpcTable.java

@@ -25,6 +25,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import javolution.util.FastList;
+import javolution.util.FastMap;
 
 import com.l2jserver.Config;
 import com.l2jserver.L2DatabaseFactory;
@@ -35,15 +36,12 @@ import com.l2jserver.gameserver.model.L2MinionData;
 import com.l2jserver.gameserver.model.L2NpcAIData;
 import com.l2jserver.gameserver.model.L2Skill;
 import com.l2jserver.gameserver.model.base.ClassId;
+import com.l2jserver.gameserver.model.quest.Quest;
+import com.l2jserver.gameserver.model.quest.Quest.QuestEventType;
 import com.l2jserver.gameserver.skills.BaseStats;
 import com.l2jserver.gameserver.templates.StatsSet;
 import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
 
-/**
- * This class ...
- *
- * @version $Revision: 1.8.2.6.2.9 $ $Date: 2005/04/06 16:13:25 $
- */
 public class NpcTable
 {
 	private static Logger _log = Logger.getLogger(NpcTable.class.getName());
@@ -64,697 +62,157 @@ public class NpcTable
 	
 	private void restoreNpcData()
 	{
-		Connection con = null;
+		loadNpcs(0);
+		loadNpcsSkills(0);
+		loadNpcsDrop(0);
+		loadNpcsSkillLearn(0);
+		loadMinions(0);
+		loadNpcsAI(0);
+		loadNpcsElement(0);	
+	}
+
+	private void fillNpcTable(ResultSet NpcData) throws Exception
+	{
+		StatsSet npcDat = new StatsSet();
+		int id = NpcData.getInt("id");
+		int idTemp = NpcData.getInt("idTemplate");
+		
+		assert idTemp < 1000000;
+		
+		npcDat.set("npcId", id);
+		npcDat.set("idTemplate", idTemp);
+		int level = NpcData.getInt("level");
+		npcDat.set("level", level);
+		npcDat.set("jClass", NpcData.getString("class"));
+		
+		npcDat.set("baseShldDef", 0);
+		npcDat.set("baseShldRate", 0);
+		npcDat.set("baseCritRate", NpcData.getInt("critical"));
 		
+		npcDat.set("name", NpcData.getString("name"));
+		npcDat.set("serverSideName", NpcData.getBoolean("serverSideName"));
+		//npcDat.set("name", "");
+		npcDat.set("title", NpcData.getString("title"));
+		npcDat.set("serverSideTitle", NpcData.getBoolean("serverSideTitle"));
+		npcDat.set("collision_radius", NpcData.getDouble("collision_radius"));
+		npcDat.set("collision_height", NpcData.getDouble("collision_height"));
+		npcDat.set("sex", NpcData.getString("sex"));
+		npcDat.set("type", NpcData.getString("type"));
+		npcDat.set("baseAtkRange", NpcData.getInt("attackrange"));
+		npcDat.set("rewardExp", NpcData.getInt("exp"));
+		npcDat.set("rewardSp", NpcData.getInt("sp"));
+		npcDat.set("basePAtkSpd", NpcData.getInt("atkspd"));
+		npcDat.set("baseMAtkSpd", NpcData.getInt("matkspd"));
+		npcDat.set("aggroRange", NpcData.getInt("aggro"));
+		npcDat.set("rhand", NpcData.getInt("rhand"));
+		npcDat.set("lhand", NpcData.getInt("lhand"));
+		npcDat.set("enchant", NpcData.getInt("enchant"));
+		npcDat.set("baseWalkSpd", NpcData.getInt("walkspd"));
+		npcDat.set("baseRunSpd", NpcData.getInt("runspd"));
+		npcDat.set("targetable", NpcData.getBoolean("targetable"));
+		npcDat.set("show_name", NpcData.getBoolean("show_name"));
+		
+		// constants, until we have stats in DB
+		npcDat.safeSet("baseSTR", NpcData.getInt("str"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
+		npcDat.safeSet("baseCON", NpcData.getInt("con"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
+		npcDat.safeSet("baseDEX", NpcData.getInt("dex"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
+		npcDat.safeSet("baseINT", NpcData.getInt("int"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
+		npcDat.safeSet("baseWIT", NpcData.getInt("wit"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
+		npcDat.safeSet("baseMEN", NpcData.getInt("men"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
+		
+		npcDat.set("baseHpMax", NpcData.getDouble("hp"));
+		npcDat.set("baseCpMax", 0);
+		npcDat.set("baseMpMax", NpcData.getDouble("mp"));
+		npcDat.set("baseHpReg", NpcData.getFloat("hpreg") > 0 ? NpcData.getFloat("hpreg") : 1.5 + ((level - 1) / 10.0));
+		npcDat.set("baseMpReg", NpcData.getFloat("mpreg") > 0 ? NpcData.getFloat("mpreg") : 0.9 + 0.3 * ((level - 1) / 10.0));
+		npcDat.set("basePAtk", NpcData.getInt("patk"));
+		npcDat.set("basePDef", NpcData.getInt("pdef"));
+		npcDat.set("baseMAtk", NpcData.getInt("matk"));
+		npcDat.set("baseMDef", NpcData.getInt("mdef"));
+		
+		npcDat.set("dropHerbGroup", NpcData.getInt("dropHerbGroup"));
+		
+		// Default element resists
+		npcDat.set("baseFireRes", 20);
+		npcDat.set("baseWindRes", 20);
+		npcDat.set("baseWaterRes", 20);
+		npcDat.set("baseEarthRes", 20);
+		npcDat.set("baseHolyRes", 20);
+		npcDat.set("baseDarkRes", 20);
+		
+		_npcs.put(id, new L2NpcTemplate(npcDat));
+	}
+	
+	public void reloadNpc(int id)
+	{
 		try
 		{
-			con = L2DatabaseFactory.getInstance().getConnection();
-			PreparedStatement statement;
-			try
-			{
-				statement = con.prepareStatement("SELECT "
-						+ L2DatabaseFactory.getInstance().safetyString(new String[] { "id", "idTemplate", "name", "serverSideName",
-								"title", "serverSideTitle", "class", "collision_radius", "collision_height", "level", "sex", "type",
-								"attackrange", "hp", "mp", "hpreg", "mpreg", "str", "con", "dex", "int", "wit", "men", "exp", "sp", "patk",
-								"pdef", "matk", "mdef", "atkspd", "critical", "aggro", "matkspd", "rhand", "lhand", "enchant", "walkspd", "runspd",
-								"dropHerbGroup" }) + " FROM npc");
-				ResultSet npcdata = statement.executeQuery();
-				
-				fillNpcTable(npcdata, false);
-				npcdata.close();
-				statement.close();
-			}
-			catch (Exception e)
-			{
-				_log.log(Level.SEVERE, "NPCTable: Error creating NPC table.", e);
-			}
-			if (Config.CUSTOM_NPC_TABLE) // reload certain NPCs
-			{
-				try
-				{
-					statement = con.prepareStatement("SELECT "
-							+ L2DatabaseFactory.getInstance().safetyString(new String[] { "id", "idTemplate", "name", "serverSideName",
-									"title", "serverSideTitle", "class", "collision_radius", "collision_height", "level", "sex", "type",
-									"attackrange", "hp", "mp", "hpreg", "mpreg", "str", "con", "dex", "int", "wit", "men", "exp", "sp",
-									"patk", "pdef", "matk", "mdef", "atkspd", "critical", "aggro", "matkspd", "rhand", "lhand", "enchant", "walkspd",
-									"runspd", "dropHerbGroup" }) + " FROM custom_npc");
-					ResultSet npcdata = statement.executeQuery();
-					
-					fillNpcTable(npcdata, true);
-					npcdata.close();
-					statement.close();
-				}
-				catch (Exception e)
-				{
-					_log.log(Level.SEVERE, "NPCTable: Error creating custom NPC table.", e);
-				}
-			}
-			
-			try
-			{
-				statement = con.prepareStatement("SELECT npcid, skillid, level FROM npcskills");
-				ResultSet npcskills = statement.executeQuery();
-				L2NpcTemplate npcDat = null;
-				L2Skill npcSkill = null;
-				
-				while (npcskills.next())
-				{
-					int mobId = npcskills.getInt("npcid");
-					npcDat = _npcs.get(mobId);
-					
-					if (npcDat == null)
-					{
-						_log.warning("NPCTable: Skill data for undefined NPC. npcId: " + mobId);
-						continue;
-					}
-					
-					int skillId = npcskills.getInt("skillid");
-					int level = npcskills.getInt("level");
-					
-					if (npcDat.race == null && skillId == 4416)
-					{
-						npcDat.setRace(level);
-						continue;
-					}
-					
-					npcSkill = SkillTable.getInstance().getInfo(skillId, level);
-					
-					if (npcSkill == null)
-						continue;
-					
-					npcDat.addSkill(npcSkill);
-				}
-				
-				npcskills.close();
-				statement.close();
-			}
-			catch (Exception e)
-			{
-				_log.log(Level.SEVERE, "NPCTable: Error reading NPC skills table.", e);
-			}
-			
-			if (Config.CUSTOM_NPC_SKILLS_TABLE)
-			{
-				try
-				{
-					statement = con.prepareStatement("SELECT npcid, skillid, level FROM custom_npcskills");
-					ResultSet npcskills = statement.executeQuery();
-					L2NpcTemplate npcDat = null;
-					L2Skill npcSkill = null;
-					
-					while (npcskills.next())
-					{
-						int mobId = npcskills.getInt("npcid");
-						npcDat = _npcs.get(mobId);
-						
-						if (npcDat == null)
-						{
-							_log.warning("Custom NPCTable: Skill data for undefined NPC. npcId: " + mobId);
-							continue;
-						}
-						
-						int skillId = npcskills.getInt("skillid");
-						int level = npcskills.getInt("level");
-						
-						if (npcDat.race == null && skillId == 4416)
-						{
-							npcDat.setRace(level);
-							continue;
-						}
-						
-						npcSkill = SkillTable.getInstance().getInfo(skillId, level);
-						
-						if (npcSkill == null)
-							continue;
-						
-						npcDat.addSkill(npcSkill);
-					}
-					
-					npcskills.close();
-					statement.close();
-				}
-				catch (Exception e)
-				{
-					_log.log(Level.SEVERE, "Custom NPCTable: Error reading NPC skills table.", e);
-				}
-			}
-			
-			try
-			{
-				statement = con.prepareStatement("SELECT "
-						+ L2DatabaseFactory.getInstance().safetyString(new String[] { "mobId", "itemId", "min", "max", "category", "chance" })
-						+ " FROM droplist ORDER BY mobId, chance DESC");
-				ResultSet dropData = statement.executeQuery();
-				L2DropData dropDat = null;
-				L2NpcTemplate npcDat = null;
-				
-				while (dropData.next())
-				{
-					int mobId = dropData.getInt("mobId");
-					npcDat = _npcs.get(mobId);
-					if (npcDat == null)
-					{
-						_log.warning("NPCTable: Drop data for undefined NPC. npcId: " + mobId);
-						continue;
-					}
-					dropDat = new L2DropData();
-					
-					dropDat.setItemId(dropData.getInt("itemId"));
-					dropDat.setMinDrop(dropData.getInt("min"));
-					dropDat.setMaxDrop(dropData.getInt("max"));
-					dropDat.setChance(dropData.getDouble("chance"));
-					
-					int category = dropData.getInt("category");
-					
-					if (ItemTable.getInstance().getTemplate(dropDat.getItemId()) == null)
-					{
-						_log.warning("Drop data for undefined item template! NpcId: " + mobId+" itemId: "+dropDat.getItemId());
-						continue;
-					}
-					
-					npcDat.addDropData(dropDat, category);
-				}
-				
-				dropData.close();
-				statement.close();
-			}
-			catch (Exception e)
-			{
-				_log.log(Level.SEVERE, "NPCTable: Error reading NPC dropdata. ", e);
-			}
+			// save a copy of the old data
+			L2NpcTemplate old = getTemplate(id);
 			
-			if (Config.CUSTOM_DROPLIST_TABLE)
-			{
-				try
-				{
-					statement = con.prepareStatement("SELECT "
-							+ L2DatabaseFactory.getInstance().safetyString(new String[] { "mobId", "itemId", "min", "max", "category",
-							"chance" }) + " FROM custom_droplist ORDER BY mobId, chance DESC");
-					ResultSet dropData = statement.executeQuery();
-					L2DropData dropDat = null;
-					L2NpcTemplate npcDat = null;
-					int cCount = 0;
-					while (dropData.next())
-					{
-						int mobId = dropData.getInt("mobId");
-						npcDat = _npcs.get(mobId);
-						if (npcDat == null)
-						{
-							_log.warning("NPCTable: CUSTOM DROPLIST: Drop data for undefined NPC. npcId: " + mobId);
-							continue;
-						}
-						dropDat = new L2DropData();
-						dropDat.setItemId(dropData.getInt("itemId"));
-						dropDat.setMinDrop(dropData.getInt("min"));
-						dropDat.setMaxDrop(dropData.getInt("max"));
-						dropDat.setChance(dropData.getInt("chance"));
-						int category = dropData.getInt("category");
-						
-						if (ItemTable.getInstance().getTemplate(dropDat.getItemId()) == null)
-						{
-							_log.warning("Custom drop data for undefined item template! NpcId: " + mobId+" itemId: "+dropDat.getItemId());
-							continue;
-						}
-						
-						npcDat.addDropData(dropDat, category);
-						cCount++;
-					}
-					dropData.close();
-					statement.close();
-					_log.info("CustomDropList: Added " + cCount + " custom droplist.");
-				}
-				catch (Exception e)
-				{
-					_log.log(Level.SEVERE, "NPCTable: Error reading NPC custom dropdata.", e);
-				}
-			}
+			TIntObjectHashMap<L2Skill> skills = new TIntObjectHashMap<L2Skill>();
+			List<L2MinionData> minions = new FastList<L2MinionData>();
+			Map<QuestEventType, Quest[]> quests = new FastMap<QuestEventType, Quest[]>();
+			ClassId[] classIds = null;
+			FastList<L2DropCategory> categories = new FastList<L2DropCategory>();
 			
-			try
+			if (old != null)
 			{
-				statement = con.prepareStatement("SELECT "
-						+ L2DatabaseFactory.getInstance().safetyString(new String[] { "npc_id", "class_id" }) + " FROM skill_learn");
-				ResultSet learndata = statement.executeQuery();
+				if (old.getSkills() != null)
+					skills.putAll(old.getSkills());
 				
-				while (learndata.next())
-				{
-					int npcId = learndata.getInt("npc_id");
-					int classId = learndata.getInt("class_id");
-					L2NpcTemplate npc = getTemplate(npcId);
-					
-					if (npc == null)
-					{
-						_log.warning("NPCTable: Error getting NPC template ID " + npcId + " while trying to load skill trainer data.");
-						continue;
-					}
-					
-					npc.addTeachInfo(ClassId.values()[classId]);
-				}
+				if (old.getDropData() != null)
+					categories.addAll(old.getDropData());
 				
-				learndata.close();
-				statement.close();
-			}
-			catch (Exception e)
-			{
-				_log.log(Level.SEVERE, "NPCTable: Error reading NPC trainer data.", e);
-			}
-			
-			try
-			{
-				statement = con.prepareStatement("SELECT "
-						+ L2DatabaseFactory.getInstance().safetyString(new String[] { "boss_id", "minion_id", "amount_min", "amount_max" })
-						+ " FROM minions");
-				ResultSet minionData = statement.executeQuery();
-				L2MinionData minionDat = null;
-				L2NpcTemplate npcDat = null;
-				int cnt = 0;
+				if (old.getTeachInfo() != null)
+					classIds = old.getTeachInfo().clone();
 				
-				while (minionData.next())
-				{
-					int raidId = minionData.getInt("boss_id");
-					npcDat = _npcs.get(raidId);
-					if (npcDat == null)
-					{
-						_log.warning("Minion references undefined boss NPC. Boss NpcId: " + raidId);
-						continue;
-					}
-					minionDat = new L2MinionData();
-					minionDat.setMinionId(minionData.getInt("minion_id"));
-					minionDat.setAmountMin(minionData.getInt("amount_min"));
-					minionDat.setAmountMax(minionData.getInt("amount_max"));
-					npcDat.addRaidData(minionDat);
-					cnt++;
-				}
+				if (old.getMinionData() != null)
+					minions.addAll(old.getMinionData());
 				
-				minionData.close();
-				statement.close();
-				_log.info("NpcTable: Loaded " + cnt + " Minions.");
-			}
-			catch (Exception e)
-			{
-				_log.log(Level.SEVERE, "NPCTable: Error loading minion data.", e);
+				if (!old.getEventQuests().isEmpty())
+					quests.putAll(old.getEventQuests());
 			}
 			
-			//-------------------------------------------------------------------
-			//NPC AI Attributes & Data ...
+			loadNpcs(id);
+			loadNpcsSkills(id);
+			loadNpcsDrop(id);
+			loadNpcsSkillLearn(id);
+			loadMinions(id);
+			loadNpcsAI(id);
+			loadNpcsElement(id);
 			
-			try
-			{
-				statement = con.prepareStatement("SELECT * FROM npcaidata ORDER BY npcId");
-				ResultSet NpcAIDataTable = statement.executeQuery();
-				L2NpcAIData npcAIDat = null;
-				L2NpcTemplate npcDat = null;
-				int cont=0;
-				while (NpcAIDataTable.next())
-				{
-					int npc_id = NpcAIDataTable.getInt("npcId");
-					npcDat = _npcs.get(npc_id);
-					if (npcDat == null)
-					{
-						_log.severe("NPCTable: AI Data Error with id : " + npc_id);
-						continue;
-					}
-					npcAIDat = new L2NpcAIData();
-					
-					npcAIDat.setMinSkillChance(NpcAIDataTable.getInt("minSkillChance"));
-					npcAIDat.setMaxSkillChance(NpcAIDataTable.getInt("maxSkillChance"));
-					npcAIDat.setPrimarySkillId(NpcAIDataTable.getInt("primarySkillId"));
-					npcAIDat.setCanMove(NpcAIDataTable.getInt("canMove"));
-					npcAIDat.setShortRangeSkill(NpcAIDataTable.getInt("minRangeSkill"));
-					npcAIDat.setShortRangeChance(NpcAIDataTable.getInt("minRangeChance"));
-					npcAIDat.setLongRangeSkill(NpcAIDataTable.getInt("maxRangeSkill"));
-					npcAIDat.setLongRangeChance(NpcAIDataTable.getInt("maxRangeChance"));
-					npcAIDat.setSoulShot(NpcAIDataTable.getInt("soulshot"));
-					npcAIDat.setSpiritShot(NpcAIDataTable.getInt("spiritshot"));
-					npcAIDat.setSpiritShotChance(NpcAIDataTable.getInt("spsChance"));
-					npcAIDat.setSoulShotChance(NpcAIDataTable.getInt("ssChance"));
-					npcAIDat.setIsChaos(NpcAIDataTable.getInt("isChaos"));
-					npcAIDat.setClan(NpcAIDataTable.getString("clan"));
-					npcAIDat.setClanRange(NpcAIDataTable.getInt("clanRange"));
-					npcAIDat.setEnemyClan(NpcAIDataTable.getString("enemyClan"));
-					npcAIDat.setEnemyRange(NpcAIDataTable.getInt("enemyRange"));
-					npcAIDat.setDodge(NpcAIDataTable.getInt("dodge"));
-					npcAIDat.setAi(NpcAIDataTable.getString("aiType"));
-					//npcAIDat.setSwitchRangeChance(NpcAIDataTable.getInt("rangeswitchchance"));
-					//npcAIDat.setBaseShldRate(NpcAIDataTable.getInt("baseShldRate"));
-					//npcAIDat.setBaseShldDef(NpcAIDataTable.getInt("baseShldDef"));
-					
-					npcDat.setAIData(npcAIDat);
-					cont++;
-				}
-				
-				NpcAIDataTable.close();
-				statement.close();
-				_log.info("NPC AI Data Table: Loaded " + cont + " AI Data.");
-			}
-			catch (Exception e)
-			{
-				_log.log(Level.SEVERE, "NPCTable: Error reading NPC AI Data: " + e.getMessage(), e);
-			}
+			// restore additional data from saved copy
+			L2NpcTemplate created = getTemplate(id);
 			
-			if (Config.CUSTOM_NPC_TABLE)
+			if (old != null && created != null)
 			{
-				try
-				{
-					statement = con.prepareStatement("SELECT * FROM custom_npcaidata ORDER BY npcId");
-					ResultSet NpcAIDataTable = statement.executeQuery();
-					L2NpcAIData npcAIDat = null;
-					L2NpcTemplate npcDat = null;
-					int cont = 0;
-					while (NpcAIDataTable.next())
-					{
-						int npc_id = NpcAIDataTable.getInt("npcId");
-						npcDat = _npcs.get(npc_id);
-						if (npcDat == null)
-						{
-							_log.severe("NPCTable: Custom AI Data Error with id : " + npc_id);
-							continue;
-						}
-						npcAIDat = new L2NpcAIData();
-						
-						npcAIDat.setPrimarySkillId(NpcAIDataTable.getInt("primarySkillId"));
-						npcAIDat.setMinSkillChance(NpcAIDataTable.getInt("minSkillChance"));
-						npcAIDat.setMaxSkillChance(NpcAIDataTable.getInt("maxSkillChance"));
-						npcAIDat.setCanMove(NpcAIDataTable.getInt("canMove"));
-						npcAIDat.setSoulShot(NpcAIDataTable.getInt("soulshot"));
-						npcAIDat.setSpiritShot(NpcAIDataTable.getInt("spiritshot"));
-						npcAIDat.setSoulShotChance(NpcAIDataTable.getInt("ssChance"));
-						npcAIDat.setSpiritShotChance(NpcAIDataTable.getInt("spsChance"));
-						npcAIDat.setIsChaos(NpcAIDataTable.getInt("isChaos"));
-						npcAIDat.setShortRangeSkill(NpcAIDataTable.getInt("minRangeSkill"));
-						npcAIDat.setShortRangeChance(NpcAIDataTable.getInt("minRangeChance"));
-						npcAIDat.setLongRangeSkill(NpcAIDataTable.getInt("maxRangeSkill"));
-						npcAIDat.setLongRangeChance(NpcAIDataTable.getInt("maxRangeChance"));
-						npcAIDat.setClan(NpcAIDataTable.getString("clan"));
-						npcAIDat.setClanRange(NpcAIDataTable.getInt("clanRange"));
-						npcAIDat.setEnemyClan(NpcAIDataTable.getString("enemyClan"));
-						npcAIDat.setEnemyRange(NpcAIDataTable.getInt("enemyRange"));
-						npcAIDat.setDodge(NpcAIDataTable.getInt("dodge"));
-						npcAIDat.setAi(NpcAIDataTable.getString("aiType"));
-						//npcAIDat.setSwitchRangeChance(NpcAIDataTable.getInt("rangeswitchchance"));
-						//npcAIDat.setBaseShldRate(NpcAIDataTable.getInt("baseShldRate"));
-						//npcAIDat.setBaseShldDef(NpcAIDataTable.getInt("baseShldDef"));
-						
-						npcDat.setAIData(npcAIDat);
-						cont++;
-					}
-					
-					NpcAIDataTable.close();
-					statement.close();
-					_log.info("NPC AI Data Table: Loaded " + cont + " Custom AI Data.");
-				}
-				catch (Exception e)
+				if (!skills.isEmpty())
 				{
-					_log.log(Level.SEVERE, "NPCTable: Error reading NPC Custom AI Data: " + e.getMessage(), e);
+					for (L2Skill skill : skills.values(new L2Skill[skills.size()]))
+						created.addSkill(skill);
 				}
-			}
-			
-			try
-			{
-				statement = con.prepareStatement("SELECT " + L2DatabaseFactory.getInstance().safetyString(new String[] {"npc_id", "elemAtkType","elemAtkValue","fireDefValue","waterDefValue","earthDefValue","windDefValue","holyDefValue","darkDefValue"}) + " FROM npc_elementals ORDER BY npc_id");
-				ResultSet NpcElementals = statement.executeQuery();
-				L2NpcTemplate npcDat = null;
-				int cont=0;
-				while (NpcElementals.next())
+				if (classIds != null)
 				{
-					int npc_id = NpcElementals.getInt("npc_id");
-					npcDat = _npcs.get(npc_id);
-					if (npcDat == null)
-					{
-						_log.severe("NPCElementals: Elementals Error with id : " + npc_id);
-						continue;
-					}
-					switch(NpcElementals.getByte("elemAtkType"))
-					{
-						case Elementals.FIRE:
-							npcDat.baseFire = NpcElementals.getInt("elemAtkValue");
-							break;
-						case Elementals.WATER:
-							npcDat.baseWater = NpcElementals.getInt("elemAtkValue");
-							break;
-						case Elementals.EARTH:
-							npcDat.baseEarth = NpcElementals.getInt("elemAtkValue");
-							break;
-						case Elementals.WIND:
-							npcDat.baseWind = NpcElementals.getInt("elemAtkValue");
-							break;
-						case Elementals.HOLY:
-							npcDat.baseHoly = NpcElementals.getInt("elemAtkValue");
-							break;
-						case Elementals.DARK:
-							npcDat.baseDark = NpcElementals.getInt("elemAtkValue");
-							break;
-						default:
-							_log.severe("NPCElementals: Elementals Error with id : " + npc_id + "; unknown elementType: " + NpcElementals.getByte("elemAtkType"));
-							continue;
-					}
-					npcDat.baseFireRes = NpcElementals.getInt("fireDefValue");
-					npcDat.baseWaterRes = NpcElementals.getInt("waterDefValue");
-					npcDat.baseEarthRes = NpcElementals.getInt("earthDefValue");
-					npcDat.baseWindRes = NpcElementals.getInt("windDefValue");
-					npcDat.baseHolyRes = NpcElementals.getInt("holyDefValue");
-					npcDat.baseDarkRes = NpcElementals.getInt("darkDefValue");
-					cont++;
+					for (ClassId classId : classIds)
+						created.addTeachInfo(classId);
 				}
-				NpcElementals.close();
-				statement.close();
-				_log.info("NPC Elementals Data Table: Loaded " + cont + " elementals Data.");
-			}
-			catch (Exception e)
-			{
-				_log.log(Level.SEVERE, "NPCTable: Error reading NPC Elementals Data: " + e.getMessage(), e);
-			}
-			
-			if (Config.CUSTOM_NPC_TABLE)
-			{
-				try
+				if (!minions.isEmpty())
 				{
-					statement = con.prepareStatement("SELECT " + L2DatabaseFactory.getInstance().safetyString(new String[] {"npc_id", "elemAtkType","elemAtkValue","fireDefValue","waterDefValue","earthDefValue","windDefValue","holyDefValue","darkDefValue"}) + " FROM custom_npc_elementals ORDER BY npc_id");
-					ResultSet NpcElementals = statement.executeQuery();
-					L2NpcTemplate npcDat = null;
-					int cont=0;
-					while (NpcElementals.next())
-					{
-						int npc_id = NpcElementals.getInt("npc_id");
-						npcDat = _npcs.get(npc_id);
-						if (npcDat == null)
-						{
-							_log.severe("NPCElementals: custom Elementals Error with id : " + npc_id);
-							continue;
-						}
-						switch(NpcElementals.getByte("elemAtkType"))
-						{
-							case Elementals.FIRE:
-								npcDat.baseFire = NpcElementals.getInt("elemAtkValue");
-								break;
-							case Elementals.WATER:
-								npcDat.baseWater = NpcElementals.getInt("elemAtkValue");
-								break;
-							case Elementals.EARTH:
-								npcDat.baseEarth = NpcElementals.getInt("elemAtkValue");
-								break;
-							case Elementals.WIND:
-								npcDat.baseWind = NpcElementals.getInt("elemAtkValue");
-								break;
-							case Elementals.HOLY:
-								npcDat.baseHoly = NpcElementals.getInt("elemAtkValue");
-								break;
-							case Elementals.DARK:
-								npcDat.baseDark = NpcElementals.getInt("elemAtkValue");
-								break;
-							default:
-								_log.severe("NPCElementals: custom Elementals Error with id : " + npc_id + "; unknown elementType: " + NpcElementals.getByte("elemAtkType"));
-								continue;
-						}
-						npcDat.baseFireRes = NpcElementals.getInt("fireDefValue");
-						npcDat.baseWaterRes = NpcElementals.getInt("waterDefValue");
-						npcDat.baseEarthRes = NpcElementals.getInt("earthDefValue");
-						npcDat.baseWindRes = NpcElementals.getInt("windDefValue");
-						npcDat.baseHolyRes = NpcElementals.getInt("holyDefValue");
-						npcDat.baseDarkRes = NpcElementals.getInt("darkDefValue");
-						cont++;
-					}
-					NpcElementals.close();
-					statement.close();
-					_log.info("NPC Elementals Data Table: Loaded " + cont + " custom elementals Data.");
+					for (L2MinionData minion : minions)
+						created.addRaidData(minion);
 				}
-				catch (Exception e)
+				
+				if (!quests.isEmpty())
 				{
-					_log.log(Level.SEVERE, "NPCTable: Error reading NPC Custom Elementals Data: " + e.getMessage(), e);
+					created.getEventQuests().putAll(quests);
 				}
 			}
 		}
 		catch (Exception e)
-		{
-			_log.log(Level.SEVERE, "NPCTable: Failed loading database connection: " + e.getMessage(), e);
-		}
-		finally
-		{
-			L2DatabaseFactory.close(con);
-		}
-	}
-	
-	private void fillNpcTable(ResultSet NpcData, boolean customData) throws Exception
-	{
-		int count = 0;
-		while (NpcData.next())
-		{
-			StatsSet npcDat = new StatsSet();
-			int id = NpcData.getInt("id");
-			int idTemp = NpcData.getInt("idTemplate");
-			
-			assert idTemp < 1000000;
-			
-			npcDat.set("npcId", id);
-			npcDat.set("idTemplate", idTemp);
-			int level = NpcData.getInt("level");
-			npcDat.set("level", level);
-			npcDat.set("jClass", NpcData.getString("class"));
-			
-			npcDat.set("baseShldDef", 0);
-			npcDat.set("baseShldRate", 0);
-			npcDat.set("baseCritRate", NpcData.getInt("critical"));
-			
-			npcDat.set("name", NpcData.getString("name"));
-			npcDat.set("serverSideName", NpcData.getBoolean("serverSideName"));
-			//npcDat.set("name", "");
-			npcDat.set("title", NpcData.getString("title"));
-			npcDat.set("serverSideTitle", NpcData.getBoolean("serverSideTitle"));
-			npcDat.set("collision_radius", NpcData.getDouble("collision_radius"));
-			npcDat.set("collision_height", NpcData.getDouble("collision_height"));
-			npcDat.set("sex", NpcData.getString("sex"));
-			npcDat.set("type", NpcData.getString("type"));
-			npcDat.set("baseAtkRange", NpcData.getInt("attackrange"));
-			npcDat.set("rewardExp", NpcData.getInt("exp"));
-			npcDat.set("rewardSp", NpcData.getInt("sp"));
-			npcDat.set("basePAtkSpd", NpcData.getInt("atkspd"));
-			npcDat.set("baseMAtkSpd", NpcData.getInt("matkspd"));
-			npcDat.set("aggroRange", NpcData.getInt("aggro"));
-			npcDat.set("rhand", NpcData.getInt("rhand"));
-			npcDat.set("lhand", NpcData.getInt("lhand"));
-			npcDat.set("enchant", NpcData.getInt("enchant"));
-			npcDat.set("baseWalkSpd", NpcData.getInt("walkspd"));
-			npcDat.set("baseRunSpd", NpcData.getInt("runspd"));
-			
-			// constants, until we have stats in DB
-			npcDat.safeSet("baseSTR", NpcData.getInt("str"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
-			npcDat.safeSet("baseCON", NpcData.getInt("con"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
-			npcDat.safeSet("baseDEX", NpcData.getInt("dex"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
-			npcDat.safeSet("baseINT", NpcData.getInt("int"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
-			npcDat.safeSet("baseWIT", NpcData.getInt("wit"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
-			npcDat.safeSet("baseMEN", NpcData.getInt("men"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: "+NpcData.getInt("idTemplate"));
-			
-			npcDat.set("baseHpMax", NpcData.getDouble("hp"));
-			npcDat.set("baseCpMax", 0);
-			npcDat.set("baseMpMax", NpcData.getDouble("mp"));
-			npcDat.set("baseHpReg", NpcData.getFloat("hpreg") > 0 ? NpcData.getFloat("hpreg") : 1.5 + ((level - 1) / 10.0));
-			npcDat.set("baseMpReg", NpcData.getFloat("mpreg") > 0 ? NpcData.getFloat("mpreg") : 0.9 + 0.3 * ((level - 1) / 10.0));
-			npcDat.set("basePAtk", NpcData.getInt("patk"));
-			npcDat.set("basePDef", NpcData.getInt("pdef"));
-			npcDat.set("baseMAtk", NpcData.getInt("matk"));
-			npcDat.set("baseMDef", NpcData.getInt("mdef"));
-			
-			npcDat.set("dropHerbGroup", NpcData.getInt("dropHerbGroup"));
-			
-			// Default element resists
-			npcDat.set("baseFireRes", 20);
-			npcDat.set("baseWindRes", 20);
-			npcDat.set("baseWaterRes", 20);
-			npcDat.set("baseEarthRes", 20);
-			npcDat.set("baseHolyRes", 20);
-			npcDat.set("baseDarkRes", 20);
-			
-			L2NpcTemplate template = new L2NpcTemplate(npcDat);
-			/*template.addVulnerability(Stats.BOW_WPN_VULN, 1);
-			template.addVulnerability(Stats.CROSSBOW_WPN_VULN, 1);
-			template.addVulnerability(Stats.BLUNT_WPN_VULN, 1);
-			template.addVulnerability(Stats.DAGGER_WPN_VULN, 1);*/
-			
-			_npcs.put(id, template);
-			count++;
-		}
-		
-		if (!customData)
-			_log.info("NpcTable: (Re)Loaded " + count + " NPC template(s).");
-		else
-			_log.info("NpcTable: (Re)Loaded " + count + " custom NPC template(s).");
-	}
-	
-	public void reloadNpc(int id)
-	{
-		Connection con = null;
-		
-		try
-		{
-			// save a copy of the old data
-			L2NpcTemplate old = getTemplate(id);
-			TIntObjectHashMap<L2Skill> skills = new TIntObjectHashMap<L2Skill>();
-			
-			if (old.getSkills() != null)
-				skills.putAll(old.getSkills());
-			
-			FastList<L2DropCategory> categories = new FastList<L2DropCategory>();
-			
-			if (old.getDropData() != null)
-				categories.addAll(old.getDropData());
-			
-			ClassId[] classIds = null;
-			
-			if (old.getTeachInfo() != null)
-				classIds = old.getTeachInfo().clone();
-			
-			List<L2MinionData> minions = new FastList<L2MinionData>();
-			
-			if (old.getMinionData() != null)
-				minions.addAll(old.getMinionData());
-			
-			// reload the NPC base data
-			con = L2DatabaseFactory.getInstance().getConnection();
-			PreparedStatement st = con.prepareStatement("SELECT "
-					+ L2DatabaseFactory.getInstance().safetyString(new String[] { "id", "idTemplate", "name", "serverSideName", "title",
-							"serverSideTitle", "class", "collision_radius", "collision_height", "level", "sex", "type", "attackrange",
-							"hp", "mp", "hpreg", "mpreg", "str", "con", "dex", "int", "wit", "men", "exp", "sp", "patk", "pdef", "matk",
-							"mdef", "atkspd", "critical", "aggro", "matkspd", "rhand", "lhand", "enchant", "walkspd", "runspd",
-							"dropHerbGroup" })
-							+ " FROM npc WHERE id=?");
-			st.setInt(1, id);
-			ResultSet rs = st.executeQuery();
-			fillNpcTable(rs, false);
-			if (Config.CUSTOM_NPC_TABLE) // reload certain NPCs
-			{
-				st = con.prepareStatement("SELECT "
-						+ L2DatabaseFactory.getInstance().safetyString(new String[] { "id", "idTemplate", "name", "serverSideName",
-								"title", "serverSideTitle", "class", "collision_radius", "collision_height", "level", "sex", "type",
-								"attackrange", "hp", "mp", "hpreg", "mpreg", "str", "con", "dex", "int", "wit", "men", "exp", "sp", "patk",
-								"pdef", "matk", "mdef", "atkspd", "critical", "aggro", "matkspd", "rhand", "lhand", "enchant", "walkspd", "runspd",
-								"dropHerbGroup" }) + " FROM custom_npc WHERE id=?");
-				st.setInt(1, id);
-				rs = st.executeQuery();
-				fillNpcTable(rs, true);
-			}
-			rs.close();
-			st.close();
-			
-			// restore additional data from saved copy
-			L2NpcTemplate created = getTemplate(id);
-			
-			for (L2Skill skill : skills.values(new L2Skill[skills.size()]))
-				created.addSkill(skill);
-			
-			if (classIds != null)
-				for (ClassId classId : classIds)
-					created.addTeachInfo(classId);
-			
-			for (L2MinionData minion : minions)
-				created.addRaidData(minion);
-		}
-		catch (Exception e)
 		{
 			_log.log(Level.WARNING, "NPCTable: Could not reload data for NPC " + id + ": " + e.getMessage(), e);
 		}
-		finally
-		{
-			L2DatabaseFactory.close(con);
-		}
 	}
 	
 	// just wrapper
@@ -846,44 +304,43 @@ public class NpcTable
 	
 	public L2NpcTemplate getTemplateByName(String name)
 	{
-		for (L2NpcTemplate npcTemplate : _npcs.valueCollection())
-		{
+		for (L2NpcTemplate npcTemplate : _npcs.values(new L2NpcTemplate[_npcs.size()]))
 			if (npcTemplate.name.equalsIgnoreCase(name))
 				return npcTemplate;
-		}
+		
 		return null;
 	}
 	
 	public L2NpcTemplate[] getAllOfLevel(int lvl)
 	{
-		final List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
-		for (L2NpcTemplate npcTemplate : _npcs.valueCollection())
-		{
-			if (npcTemplate.level == lvl)
-				list.add(npcTemplate);
-		}
+		List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
+		
+		for (L2NpcTemplate t : _npcs.values(new L2NpcTemplate[_npcs.size()]))
+			if (t.level == lvl)
+				list.add(t);
+		
 		return list.toArray(new L2NpcTemplate[list.size()]);
 	}
 	
 	public L2NpcTemplate[] getAllMonstersOfLevel(int lvl)
 	{
-		final List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
-		for (L2NpcTemplate npcTemplate : _npcs.valueCollection())
-		{
-			if (npcTemplate.level == lvl && "L2Monster".equals(npcTemplate.type))
-				list.add(npcTemplate);
-		}
+		List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
+		
+		for (L2NpcTemplate t : _npcs.values(new L2NpcTemplate[_npcs.size()]))
+			if (t.level == lvl && "L2Monster".equals(t.type))
+				list.add(t);
+		
 		return list.toArray(new L2NpcTemplate[list.size()]);
 	}
 	
 	public L2NpcTemplate[] getAllNpcStartingWith(String letter)
 	{
-		final List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
-		for (L2NpcTemplate npcTemplate : _npcs.valueCollection())
-		{
-			if (npcTemplate.name.startsWith(letter) && "L2Npc".equals(npcTemplate.type))
-				list.add(npcTemplate);
-		}
+		List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
+		
+		for (L2NpcTemplate t : _npcs.values(new L2NpcTemplate[_npcs.size()]))
+			if (t.name.startsWith(letter) && "L2Npc".equals((t).type))
+				list.add(t);
+		
 		return list.toArray(new L2NpcTemplate[list.size()]);
 	}
 	
@@ -893,47 +350,677 @@ public class NpcTable
 	 */
 	public L2NpcTemplate[] getAllNpcOfClassType(String classType)
 	{
-		final List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
-		for (L2NpcTemplate npcTemplate : _npcs.valueCollection())
+		List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
+		
+		for (L2NpcTemplate t : _npcs.values(new L2NpcTemplate[_npcs.size()]))
+			if (classType.equals(t.type))
+				list.add(t);
+		
+		return list.toArray(new L2NpcTemplate[list.size()]);
+	}
+	
+	public void loadNpcs(int id)
+	{
+		Connection con = null;
+		try
 		{
-			if (classType.equals(npcTemplate.type))
-				list.add(npcTemplate);
+			con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement statement = null;
+			if (id > 0)
+			{
+				statement = con.prepareStatement("SELECT * FROM npc WHERE id = ?");
+				statement.setInt(1, id);
+			}
+			else
+			{
+				statement = con.prepareStatement("SELECT * FROM npc ORDER BY id");
+			}
+			ResultSet rset = statement.executeQuery();
+			
+			int cont = 0;
+			int cCont = 0;
+			
+			while (rset.next())
+			{
+				fillNpcTable(rset);
+				cont++;
+			}
+			
+			rset.close();
+			statement.close();
+			
+			if (Config.CUSTOM_NPC_TABLE)
+			{
+				if (id > 0)
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_npc WHERE id = ?");
+					statement.setInt(1, id);
+				}
+				else
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_npc ORDER BY id");
+				}
+				rset = statement.executeQuery();
+				
+				while (rset.next())
+				{
+					fillNpcTable(rset);
+					cCont++;
+				}
+				
+				rset.close();
+				statement.close();
+			}
+			
+			_log.info("NpcTable: Loaded " + cont + " (Custom: " + cCont + ") NPC template(s).");
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "NPCTable: Error creating NPC table.", e);
+		}
+		finally
+		{
+			L2DatabaseFactory.close(con);
 		}
-		return list.toArray(new L2NpcTemplate[list.size()]);
 	}
-
-	/**
-	 * @param clazz the class type to search.
-	 * @return list of all NPC templates with class {@code clazz}.
-	 */
-	public List<L2NpcTemplate> getAllNpcOfClass(Class<?> clazz)
+	
+	public void loadNpcsSkills(int id)
 	{
-		final List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
-		for (L2NpcTemplate npcTemplate : _npcs.valueCollection())
+		Connection con = null;
+		
+		try
 		{
-			if (npcTemplate.type.equals(clazz.getSimpleName()))
+			con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement statement = null;
+			if (id > 0)
+			{
+				statement = con.prepareStatement("SELECT * FROM npcskills WHERE npcid = ?");
+				statement.setInt(1, id);
+			}
+			else
+			{
+				statement = con.prepareStatement("SELECT * FROM npcskills ORDER BY npcid");
+			}
+			
+			ResultSet rset = statement.executeQuery();
+			
+			int cont = 0;
+			int cCont = 0;
+			
+			L2NpcTemplate npcDat = null;
+			L2Skill npcSkill = null;
+			
+			while (rset.next())
+			{
+				int mobId = rset.getInt("npcid");
+				npcDat = _npcs.get(mobId);
+				
+				if (npcDat == null)
+				{
+					_log.warning("NPCTable: Skill data for undefined NPC. npcId: " + mobId);
+					continue;
+				}
+				
+				int skillId = rset.getInt("skillid");
+				int level = rset.getInt("level");
+				
+				if (npcDat.race == null && skillId == 4416)
+				{
+					npcDat.setRace(level);
+					continue;
+				}
+				
+				npcSkill = SkillTable.getInstance().getInfo(skillId, level);
+				
+				if (npcSkill == null)
+					continue;
+				cont++;
+				npcDat.addSkill(npcSkill);
+			}
+			
+			rset.close();
+			statement.close();
+			
+			if (Config.CUSTOM_NPC_SKILLS_TABLE)
 			{
-				list.add(npcTemplate);
+				if (id > 0)
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_npcskills WHERE npcid = ?");
+					statement.setInt(1, id);
+				}
+				else
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_npcskills ORDER BY npcid");
+				}
+				rset = statement.executeQuery();
+				
+				while (rset.next())
+				{
+					int mobId = rset.getInt("npcid");
+					npcDat = _npcs.get(mobId);
+					
+					if (npcDat == null)
+					{
+						_log.warning("Custom NPCTable: Skill data for undefined NPC. npcId: " + mobId);
+						continue;
+					}
+					
+					int skillId = rset.getInt("skillid");
+					int level = rset.getInt("level");
+					
+					if (npcDat.race == null && skillId == 4416)
+					{
+						npcDat.setRace(level);
+						continue;
+					}
+					
+					npcSkill = SkillTable.getInstance().getInfo(skillId, level);
+					
+					if (npcSkill == null)
+						continue;
+					
+					cCont++;
+					npcDat.addSkill(npcSkill);
+				}
+				
+				rset.close();
+				statement.close();
 			}
+			
+			_log.info("NpcTable: Loaded " + cont + " (Custom: " + cCont + ") npc skills.");
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "NPCTable: Error reading NPC skills table.", e);
+		}
+		finally
+		{
+			L2DatabaseFactory.close(con);
 		}
-		return list;
 	}
 	
-	/**
-	 * @param aiType the AI type to search.
-	 * @return list of all NPC templates with AI type {@code aiType}.
-	 */
-	public List<L2NpcTemplate> getAllNpcOfAiType(String aiType)
+	public void loadNpcsDrop(int id)
 	{
-		final List<L2NpcTemplate> list = new FastList<L2NpcTemplate>();
-		for (L2NpcTemplate npcTemplate : _npcs.valueCollection())
+		Connection con = null;
+		try
 		{
-			if ((npcTemplate.getAIDataStatic() != null) && npcTemplate.getAIDataStatic().getAiType().name().equals(aiType))
+			con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement statement = null;
+			
+			if (id > 0)
 			{
-				list.add(npcTemplate);
+				statement = con.prepareStatement("SELECT * FROM droplist WHERE mobId = ? ORDER BY mobId, chance DESC");
+				statement.setInt(1, id);
 			}
+			else
+			{
+				statement = con.prepareStatement("SELECT * FROM droplist ORDER BY mobId, chance DESC");
+			}
+			
+			ResultSet rset = statement.executeQuery();
+			L2DropData dropDat = null;
+			L2NpcTemplate npcDat = null;
+			
+			int cont = 0;
+			int cCont = 0;
+			
+			while (rset.next())
+			{
+				int mobId = rset.getInt("mobId");
+				npcDat = _npcs.get(mobId);
+				if (npcDat == null)
+				{
+					_log.warning("NPCTable: Drop data for undefined NPC. npcId: " + mobId);
+					continue;
+				}
+				dropDat = new L2DropData();
+				
+				dropDat.setItemId(rset.getInt("itemId"));
+				dropDat.setMinDrop(rset.getInt("min"));
+				dropDat.setMaxDrop(rset.getInt("max"));
+				dropDat.setChance(rset.getInt("chance"));
+				
+				int category = rset.getInt("category");
+				
+				if (ItemTable.getInstance().getTemplate(dropDat.getItemId()) == null)
+				{
+					_log.warning("Drop data for undefined item template! NpcId: " + mobId+" itemId: "+dropDat.getItemId());
+					continue;
+				}
+				cont++;
+				npcDat.addDropData(dropDat, category);
+			}
+			
+			rset.close();
+			statement.close();
+			
+			if (Config.CUSTOM_DROPLIST_TABLE)
+			{
+				if (id > 0)
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_droplist WHERE mobId = ? ORDER BY mobId, chance DESC");
+					statement.setInt(1, id);
+				}
+				else
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_droplist ORDER BY mobId, chance DESC");
+				}
+				
+				rset = statement.executeQuery();
+			
+				while (rset.next())
+				{
+					int mobId = rset.getInt("mobId");
+					npcDat = _npcs.get(mobId);
+					if (npcDat == null)
+					{
+						_log.warning("NPCTable: CUSTOM DROPLIST: Drop data for undefined NPC. npcId: " + mobId);
+						continue;
+					}
+					dropDat = new L2DropData();
+					dropDat.setItemId(rset.getInt("itemId"));
+					dropDat.setMinDrop(rset.getInt("min"));
+					dropDat.setMaxDrop(rset.getInt("max"));
+					dropDat.setChance(rset.getInt("chance"));
+					int category = rset.getInt("category");
+					
+					if (ItemTable.getInstance().getTemplate(dropDat.getItemId()) == null)
+					{
+						_log.warning("Custom drop data for undefined item template! NpcId: " + mobId+" itemId: "+dropDat.getItemId());
+						continue;
+					}
+					
+					npcDat.addDropData(dropDat, category);
+					cCont++;
+				}
+				rset.close();
+				statement.close();
+			}
+			_log.info("NpcTable: Loaded " + cont + " (Custom: " + cCont + ") drops.");
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "NPCTable: Error reading NPC dropdata. ", e);
+		}
+		finally
+		{
+			L2DatabaseFactory.close(con);
+		}
+	}
+	
+	private void loadNpcsSkillLearn(int id)
+	{
+		Connection con = null;
+		try
+		{
+			con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement statement = null;
+			
+			if (id > 0)
+			{
+				statement = con.prepareStatement("SELECT * FROM skill_learn WHERE npc_id = ?");
+				statement.setInt(1, id);
+			}
+			else
+			{
+				statement = con.prepareStatement("SELECT * FROM skill_learn");
+			}
+			
+			ResultSet rset = statement.executeQuery();
+			
+			int cont = 0;
+			
+			while (rset.next())
+			{
+				int npcId = rset.getInt("npc_id");
+				int classId = rset.getInt("class_id");
+				L2NpcTemplate npc = getTemplate(npcId);
+				
+				if (npc == null)
+				{
+					_log.warning("NPCTable: Error getting NPC template ID " + npcId + " while trying to load skill trainer data.");
+					continue;
+				}
+				cont++;
+				npc.addTeachInfo(ClassId.values()[classId]);
+			}
+			
+			rset.close();
+			statement.close();
+			
+			_log.info("NpcTable: Loaded " + cont + " Skill Learn.");
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "NPCTable: Error reading NPC trainer data.", e);
+		}
+		finally
+		{
+			L2DatabaseFactory.close(con);
+		}
+	}
+	
+	public void loadMinions(int id)
+	{
+		Connection con = null;
+		try
+		{
+			con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement statement = null;
+			
+			if (id > 0)
+			{
+				statement = con.prepareStatement("SELECT * FROM minions WHERE boss_id = ?");
+				statement.setInt(1, id);
+			}
+			else
+			{
+				statement = con.prepareStatement("SELECT * FROM minions ORDER BY boss_id");
+			}
+			
+			ResultSet rset = statement.executeQuery();
+			
+			L2MinionData minionDat = null;
+			L2NpcTemplate npcDat = null;
+			int cnt = 0;
+			
+			while (rset.next())
+			{
+				int raidId = rset.getInt("boss_id");
+				npcDat = _npcs.get(raidId);
+				if (npcDat == null)
+				{
+					_log.warning("Minion references undefined boss NPC. Boss NpcId: " + raidId);
+					continue;
+				}
+				minionDat = new L2MinionData();
+				minionDat.setMinionId(rset.getInt("minion_id"));
+				minionDat.setAmountMin(rset.getInt("amount_min"));
+				minionDat.setAmountMax(rset.getInt("amount_max"));
+				npcDat.addRaidData(minionDat);
+				cnt++;
+			}
+			
+			rset.close();
+			statement.close();
+			_log.info("NpcTable: Loaded " + cnt + " Minions.");
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "NPCTable: Error loading minion data.", e);
+		}
+		finally
+		{
+			L2DatabaseFactory.close(con);
+		}
+	}
+	
+	public void loadNpcsAI(int id)
+	{
+		Connection con = null;
+		try
+		{
+			con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement statement = null;
+			
+			if (id > 0)
+			{
+				statement = con.prepareStatement("SELECT * FROM npcaidata WHERE npcId = ?");
+				statement.setInt(1, id);
+			}
+			else
+			{
+				statement = con.prepareStatement("SELECT * FROM npcaidata ORDER BY npcId");
+			}
+			
+			ResultSet rset = statement.executeQuery();
+			
+			L2NpcAIData npcAIDat = null;
+			L2NpcTemplate npcDat = null;
+		
+			int cont = 0;
+			int cCont = 0;
+			
+			while (rset.next())
+			{
+				int npc_id = rset.getInt("npcId");
+				npcDat = _npcs.get(npc_id);
+				if (npcDat == null)
+				{
+					_log.severe("NPCTable: AI Data Error with id : " + npc_id);
+					continue;
+				}
+				npcAIDat = new L2NpcAIData();
+				
+				npcAIDat.setPrimarySkillId(rset.getInt("primarySkillId"));
+				npcAIDat.setMinSkillChance(rset.getInt("minSkillChance"));
+				npcAIDat.setMaxSkillChance(rset.getInt("maxSkillChance"));
+				npcAIDat.setCanMove(rset.getInt("canMove"));
+				npcAIDat.setSoulShot(rset.getInt("soulshot"));
+				npcAIDat.setSpiritShot(rset.getInt("spiritshot"));
+				npcAIDat.setSoulShotChance(rset.getInt("ssChance"));
+				npcAIDat.setSpiritShotChance(rset.getInt("spsChance"));
+				npcAIDat.setIsChaos(rset.getInt("isChaos"));
+				npcAIDat.setShortRangeSkill(rset.getInt("minRangeSkill"));
+				npcAIDat.setShortRangeChance(rset.getInt("minRangeChance"));
+				npcAIDat.setLongRangeSkill(rset.getInt("maxRangeSkill"));
+				npcAIDat.setLongRangeChance(rset.getInt("maxRangeChance"));
+				npcAIDat.setClan(rset.getString("clan"));
+				npcAIDat.setClanRange(rset.getInt("clanRange"));
+				npcAIDat.setEnemyClan(rset.getString("enemyClan"));
+				npcAIDat.setEnemyRange(rset.getInt("enemyRange"));
+				npcAIDat.setDodge(rset.getInt("dodge"));
+				npcAIDat.setAi(rset.getString("aiType"));
+				
+				npcDat.setAIData(npcAIDat);
+				cont++;
+			}
+			
+			rset.close();
+			statement.close();
+			
+			if (Config.CUSTOM_NPC_TABLE)
+			{
+				if (id > 0)
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_npcaidata WHERE npcId = ?");
+					statement.setInt(1, id);
+				}
+				else
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_npcaidata ORDER BY npcId");
+				}
+				
+				rset = statement.executeQuery();
+				
+				while (rset.next())
+				{
+					int npc_id = rset.getInt("npcId");
+					npcDat = _npcs.get(npc_id);
+					if (npcDat == null)
+					{
+						_log.severe("NPCTable: Custom AI Data Error with id : " + npc_id);
+						continue;
+					}
+					npcAIDat = new L2NpcAIData();
+					
+					npcAIDat.setPrimarySkillId(rset.getInt("primarySkillId"));
+					npcAIDat.setMinSkillChance(rset.getInt("minSkillChance"));
+					npcAIDat.setMaxSkillChance(rset.getInt("maxSkillChance"));
+					npcAIDat.setCanMove(rset.getInt("canMove"));
+					npcAIDat.setSoulShot(rset.getInt("soulshot"));
+					npcAIDat.setSpiritShot(rset.getInt("spiritshot"));
+					npcAIDat.setSoulShotChance(rset.getInt("ssChance"));
+					npcAIDat.setSpiritShotChance(rset.getInt("spsChance"));
+					npcAIDat.setIsChaos(rset.getInt("isChaos"));
+					npcAIDat.setShortRangeSkill(rset.getInt("minRangeSkill"));
+					npcAIDat.setShortRangeChance(rset.getInt("minRangeChance"));
+					npcAIDat.setLongRangeSkill(rset.getInt("maxRangeSkill"));
+					npcAIDat.setLongRangeChance(rset.getInt("maxRangeChance"));
+					npcAIDat.setClan(rset.getString("clan"));
+					npcAIDat.setClanRange(rset.getInt("clanRange"));
+					npcAIDat.setEnemyClan(rset.getString("enemyClan"));
+					npcAIDat.setEnemyRange(rset.getInt("enemyRange"));
+					npcAIDat.setDodge(rset.getInt("dodge"));
+					npcAIDat.setAi(rset.getString("aiType"));
+					
+					npcDat.setAIData(npcAIDat);
+					cCont++;
+				}
+				
+				rset.close();
+				statement.close();
+			}
+			
+			_log.info("NpcTable: Loaded " + cont + " (Custom: " + cCont + ") AI Data.");
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "NPCTable: Error reading NPC AI Data: " + e.getMessage(), e);
+		}
+		finally
+		{
+			L2DatabaseFactory.close(con);
+		}
+	}
+	
+	public void loadNpcsElement(int id)
+	{
+		Connection con = null;
+		try
+		{
+			con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement statement = null;
+			if (id > 0)
+			{
+				statement = con.prepareStatement("SELECT * FROM npc_elementals WHERE npc_id = ?");
+				statement.setInt(1, id);
+			}
+			else
+			{
+				statement = con.prepareStatement("SELECT * FROM npc_elementals ORDER BY npc_id");
+			}
+			
+			ResultSet rset = statement.executeQuery();
+			L2NpcTemplate npcDat = null;
+			
+			int cont = 0;
+			int cCount = 0;
+			
+			while (rset.next())
+			{
+				int npc_id = rset.getInt("npc_id");
+				npcDat = _npcs.get(npc_id);
+				if (npcDat == null)
+				{
+					_log.severe("NPCElementals: Elementals Error with id : " + npc_id);
+					continue;
+				}
+				switch(rset.getByte("elemAtkType"))
+				{
+					case Elementals.FIRE:
+						npcDat.baseFire = rset.getInt("elemAtkValue");
+						break;
+					case Elementals.WATER:
+						npcDat.baseWater = rset.getInt("elemAtkValue");
+						break;
+					case Elementals.EARTH:
+						npcDat.baseEarth = rset.getInt("elemAtkValue");
+						break;
+					case Elementals.WIND:
+						npcDat.baseWind = rset.getInt("elemAtkValue");
+						break;
+					case Elementals.HOLY:
+						npcDat.baseHoly = rset.getInt("elemAtkValue");
+						break;
+					case Elementals.DARK:
+						npcDat.baseDark = rset.getInt("elemAtkValue");
+						break;
+					default:
+						_log.severe("NPCElementals: Elementals Error with id : " + npc_id + "; unknown elementType: " + rset.getByte("elemAtkType"));
+						continue;
+				}
+				npcDat.baseFireRes = rset.getInt("fireDefValue");
+				npcDat.baseWaterRes = rset.getInt("waterDefValue");
+				npcDat.baseEarthRes = rset.getInt("earthDefValue");
+				npcDat.baseWindRes = rset.getInt("windDefValue");
+				npcDat.baseHolyRes = rset.getInt("holyDefValue");
+				npcDat.baseDarkRes = rset.getInt("darkDefValue");
+				cont++;
+			}
+			
+			rset.close();
+			statement.close();
+			
+			if (Config.CUSTOM_NPC_TABLE)
+			{
+				if (id > 0)
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_npc_elementals WHERE npc_id = ?");
+					statement.setInt(1, id);
+				}
+				else
+				{
+					statement = con.prepareStatement("SELECT * FROM custom_npc_elementals ORDER BY npc_id");
+				}
+				
+				rset = statement.executeQuery();
+		
+				while (rset.next())
+				{
+					int npc_id = rset.getInt("npc_id");
+					npcDat = _npcs.get(npc_id);
+					if (npcDat == null)
+					{
+						_log.severe("NPCElementals: Custom Elementals Error with id : " + npc_id);
+						continue;
+					}
+					switch(rset.getByte("elemAtkType"))
+					{
+						case Elementals.FIRE:
+							npcDat.baseFire = rset.getInt("elemAtkValue");
+							break;
+						case Elementals.WATER:
+							npcDat.baseWater = rset.getInt("elemAtkValue");
+							break;
+						case Elementals.EARTH:
+							npcDat.baseEarth = rset.getInt("elemAtkValue");
+							break;
+						case Elementals.WIND:
+							npcDat.baseWind = rset.getInt("elemAtkValue");
+							break;
+						case Elementals.HOLY:
+							npcDat.baseHoly = rset.getInt("elemAtkValue");
+							break;
+						case Elementals.DARK:
+							npcDat.baseDark = rset.getInt("elemAtkValue");
+							break;
+						default:
+							_log.severe("NPCElementals: Custom Elementals Error with id : " + npc_id + "; unknown elementType: " + rset.getByte("elemAtkType"));
+							continue;
+					}
+					npcDat.baseFireRes = rset.getInt("fireDefValue");
+					npcDat.baseWaterRes = rset.getInt("waterDefValue");
+					npcDat.baseEarthRes = rset.getInt("earthDefValue");
+					npcDat.baseWindRes = rset.getInt("windDefValue");
+					npcDat.baseHolyRes = rset.getInt("holyDefValue");
+					npcDat.baseDarkRes = rset.getInt("darkDefValue");
+					cont++;
+				}
+				rset.close();
+				statement.close();
+			}
+			
+			_log.info("NpcTable: Loaded " + cont + " (Custom: " + cCount + ") elementals Data.");
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "NPCTable: Error reading NPC Elementals Data: " + e.getMessage(), e);
+		}
+		finally
+		{
+			L2DatabaseFactory.close(con);
 		}
-		return list;
 	}
 	
 	@SuppressWarnings("synthetic-access")

+ 8 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/templates/chars/L2NpcTemplate.java

@@ -32,6 +32,7 @@ import com.l2jserver.gameserver.model.L2Skill;
 import com.l2jserver.gameserver.model.actor.instance.L2XmassTreeInstance;
 import com.l2jserver.gameserver.model.base.ClassId;
 import com.l2jserver.gameserver.model.quest.Quest;
+import com.l2jserver.gameserver.model.quest.Quest.QuestEventType;
 import com.l2jserver.gameserver.templates.StatsSet;
 
 /**
@@ -995,4 +996,11 @@ public final class L2NpcTemplate extends L2CharTemplate
 	{
 		return _hasSuicideSkills;
 	}
+	
+	public Map<QuestEventType, Quest[]> getEventQuests()
+	{
+		if (_questEvents == null)
+			_questEvents = new FastMap<Quest.QuestEventType, Quest[]>();
+		return _questEvents;
+	}
 }