NpcTable.java 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.gameserver.datatables;
  16. import gnu.trove.map.hash.TIntObjectHashMap;
  17. import java.sql.Connection;
  18. import java.sql.PreparedStatement;
  19. import java.sql.ResultSet;
  20. import java.sql.SQLException;
  21. import java.util.ArrayList;
  22. import java.util.HashMap;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.Map.Entry;
  26. import java.util.logging.Level;
  27. import java.util.logging.Logger;
  28. import javolution.util.FastList;
  29. import com.l2jserver.Config;
  30. import com.l2jserver.L2DatabaseFactory;
  31. import com.l2jserver.gameserver.model.Elementals;
  32. import com.l2jserver.gameserver.model.L2DropCategory;
  33. import com.l2jserver.gameserver.model.L2DropData;
  34. import com.l2jserver.gameserver.model.L2MinionData;
  35. import com.l2jserver.gameserver.model.L2NpcAIData;
  36. import com.l2jserver.gameserver.model.StatsSet;
  37. import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
  38. import com.l2jserver.gameserver.model.base.ClassId;
  39. import com.l2jserver.gameserver.model.quest.Quest;
  40. import com.l2jserver.gameserver.model.quest.Quest.QuestEventType;
  41. import com.l2jserver.gameserver.model.skills.L2Skill;
  42. import com.l2jserver.gameserver.model.stats.BaseStats;
  43. public class NpcTable
  44. {
  45. private static final Logger _log = Logger.getLogger(NpcTable.class.getName());
  46. private final TIntObjectHashMap<L2NpcTemplate> _npcs = new TIntObjectHashMap<L2NpcTemplate>();
  47. private NpcTable()
  48. {
  49. _npcs.clear();
  50. restoreNpcData();
  51. }
  52. private void restoreNpcData()
  53. {
  54. loadNpcs(0);
  55. loadNpcsSkills(0);
  56. loadNpcsDrop(0);
  57. loadNpcsSkillLearn(0);
  58. loadMinions(0);
  59. loadNpcsAI(0);
  60. loadNpcsElement(0);
  61. }
  62. /**
  63. * @param NpcData
  64. * @throws Exception
  65. */
  66. private void fillNpcTable(ResultSet NpcData) throws Exception
  67. {
  68. StatsSet npcDat = new StatsSet();
  69. int id = NpcData.getInt("id");
  70. int idTemp = NpcData.getInt("idTemplate");
  71. assert idTemp < 1000000;
  72. npcDat.set("npcId", id);
  73. npcDat.set("idTemplate", idTemp);
  74. int level = NpcData.getInt("level");
  75. npcDat.set("level", level);
  76. npcDat.set("client_class", NpcData.getString("class"));
  77. npcDat.set("baseShldDef", 0);
  78. npcDat.set("baseShldRate", 0);
  79. npcDat.set("baseCritRate", NpcData.getInt("critical"));
  80. npcDat.set("name", NpcData.getString("name"));
  81. npcDat.set("serverSideName", NpcData.getBoolean("serverSideName"));
  82. npcDat.set("title", NpcData.getString("title"));
  83. npcDat.set("serverSideTitle", NpcData.getBoolean("serverSideTitle"));
  84. npcDat.set("collision_radius", NpcData.getDouble("collision_radius"));
  85. npcDat.set("collision_height", NpcData.getDouble("collision_height"));
  86. npcDat.set("sex", NpcData.getString("sex"));
  87. npcDat.set("type", NpcData.getString("type"));
  88. npcDat.set("baseAtkRange", NpcData.getInt("attackrange"));
  89. npcDat.set("rewardExp", NpcData.getInt("exp"));
  90. npcDat.set("rewardSp", NpcData.getInt("sp"));
  91. npcDat.set("basePAtkSpd", NpcData.getInt("atkspd"));
  92. npcDat.set("baseMAtkSpd", NpcData.getInt("matkspd"));
  93. npcDat.set("rhand", NpcData.getInt("rhand"));
  94. npcDat.set("lhand", NpcData.getInt("lhand"));
  95. npcDat.set("enchant", NpcData.getInt("enchant"));
  96. npcDat.set("baseWalkSpd", NpcData.getInt("walkspd"));
  97. npcDat.set("baseRunSpd", NpcData.getInt("runspd"));
  98. // constants, until we have stats in DB
  99. npcDat.safeSet("baseSTR", NpcData.getInt("str"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
  100. npcDat.safeSet("baseCON", NpcData.getInt("con"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
  101. npcDat.safeSet("baseDEX", NpcData.getInt("dex"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
  102. npcDat.safeSet("baseINT", NpcData.getInt("int"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
  103. npcDat.safeSet("baseWIT", NpcData.getInt("wit"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
  104. npcDat.safeSet("baseMEN", NpcData.getInt("men"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
  105. npcDat.set("baseHpMax", NpcData.getDouble("hp"));
  106. npcDat.set("baseCpMax", 0);
  107. npcDat.set("baseMpMax", NpcData.getDouble("mp"));
  108. npcDat.set("baseHpReg", NpcData.getFloat("hpreg") > 0 ? NpcData.getFloat("hpreg") : 1.5 + ((level - 1) / 10.0));
  109. npcDat.set("baseMpReg", NpcData.getFloat("mpreg") > 0 ? NpcData.getFloat("mpreg") : 0.9 + (0.3 * ((level - 1) / 10.0)));
  110. npcDat.set("basePAtk", NpcData.getInt("patk"));
  111. npcDat.set("basePDef", NpcData.getInt("pdef"));
  112. npcDat.set("baseMAtk", NpcData.getInt("matk"));
  113. npcDat.set("baseMDef", NpcData.getInt("mdef"));
  114. npcDat.set("dropHerbGroup", NpcData.getInt("dropHerbGroup"));
  115. // Default element resists
  116. npcDat.set("baseFireRes", 20);
  117. npcDat.set("baseWindRes", 20);
  118. npcDat.set("baseWaterRes", 20);
  119. npcDat.set("baseEarthRes", 20);
  120. npcDat.set("baseHolyRes", 20);
  121. npcDat.set("baseDarkRes", 20);
  122. _npcs.put(id, new L2NpcTemplate(npcDat));
  123. }
  124. /**
  125. * @param id of the NPC to reload.
  126. */
  127. public void reloadNpc(int id)
  128. {
  129. try
  130. {
  131. // save a copy of the old data
  132. L2NpcTemplate old = getTemplate(id);
  133. Map<QuestEventType, List<Quest>> quests = new HashMap<>();
  134. TIntObjectHashMap<L2Skill> skills = new TIntObjectHashMap<>();
  135. List<L2MinionData> minions = new ArrayList<>();
  136. List<ClassId> classIds = new ArrayList<>();
  137. List<L2DropCategory> categories = new ArrayList<>();
  138. if (old != null)
  139. {
  140. skills.putAll(old.getSkills());
  141. categories.addAll(old.getDropData());
  142. classIds.addAll(old.getTeachInfo());
  143. minions.addAll(old.getMinionData());
  144. if (!old.getEventQuests().isEmpty())
  145. {
  146. quests.putAll(old.getEventQuests());
  147. }
  148. }
  149. loadNpcs(id);
  150. loadNpcsSkills(id);
  151. loadNpcsDrop(id);
  152. loadNpcsSkillLearn(id);
  153. loadMinions(id);
  154. loadNpcsAI(id);
  155. loadNpcsElement(id);
  156. // restore additional data from saved copy
  157. L2NpcTemplate created = getTemplate(id);
  158. if ((old != null) && (created != null))
  159. {
  160. if (!skills.isEmpty())
  161. {
  162. for (L2Skill skill : skills.values(new L2Skill[0]))
  163. {
  164. created.addSkill(skill);
  165. }
  166. }
  167. for (ClassId classId : classIds)
  168. {
  169. created.addTeachInfo(classId);
  170. }
  171. if (!minions.isEmpty())
  172. {
  173. for (L2MinionData minion : minions)
  174. {
  175. created.addRaidData(minion);
  176. }
  177. }
  178. if (!quests.isEmpty())
  179. {
  180. created.getEventQuests().putAll(quests);
  181. }
  182. }
  183. }
  184. catch (Exception e)
  185. {
  186. _log.log(Level.WARNING, getClass().getSimpleName() + ": Could not reload data for NPC " + id + ": " + e.getMessage(), e);
  187. }
  188. }
  189. /**
  190. * Just wrapper.
  191. */
  192. public void reloadAllNpc()
  193. {
  194. restoreNpcData();
  195. }
  196. /**
  197. * @param npc
  198. */
  199. public void saveNpc(StatsSet npc)
  200. {
  201. final Map<String, Object> set = npc.getSet();
  202. int length = 0;
  203. for (Object obj : set.keySet())
  204. {
  205. // 15 is just guessed npc name length
  206. length += ((String) obj).length() + 7 + 15;
  207. }
  208. final StringBuilder npcSb = new StringBuilder(length);
  209. final StringBuilder npcAiSb = new StringBuilder(30);
  210. String attribute;
  211. String value;
  212. for (Entry<String, Object> entry : set.entrySet())
  213. {
  214. attribute = entry.getKey();
  215. value = String.valueOf(entry.getValue());
  216. switch (attribute)
  217. {
  218. case "npcId":
  219. break;
  220. case "aggro":
  221. case "showName":
  222. case "targetable":
  223. {
  224. appendEntry(npcAiSb, attribute, value);
  225. break;
  226. }
  227. default:
  228. {
  229. appendEntry(npcSb, attribute, value);
  230. }
  231. }
  232. }
  233. Connection con = null;
  234. try
  235. {
  236. con = L2DatabaseFactory.getInstance().getConnection();
  237. int updated = 0;
  238. final int npcId = npc.getInteger("npcId");
  239. if (Config.CUSTOM_NPC_TABLE)
  240. {
  241. updated = performUpdate(npcSb, "custom_npc", "id", npcId, con);
  242. performUpdate(npcAiSb, "custom_npcaidata", "npcId", npcId, con);
  243. }
  244. if (updated == 0)
  245. {
  246. performUpdate(npcSb, "npc", "id", npcId, con);
  247. performUpdate(npcAiSb, "npcaidata", "npcId", npcId, con);
  248. }
  249. }
  250. catch (Exception e)
  251. {
  252. _log.log(Level.WARNING, getClass().getSimpleName() + ": Could not store new NPC data in database: " + e.getMessage(), e);
  253. }
  254. finally
  255. {
  256. L2DatabaseFactory.close(con);
  257. }
  258. }
  259. /**
  260. * @param sb the string builder to append the attribute and value.
  261. * @param attribute the attribute to append.
  262. * @param value the value to append.
  263. */
  264. private final void appendEntry(StringBuilder sb, String attribute, String value)
  265. {
  266. if (sb.length() > 0)
  267. {
  268. sb.append(", ");
  269. }
  270. sb.append(attribute);
  271. sb.append(" = '");
  272. sb.append(value);
  273. sb.append("'");
  274. }
  275. /**
  276. * @param sb the string builder with the parameters
  277. * @param table the table to update.
  278. * @param key the key of the table.
  279. * @param npcId the Npc Id.
  280. * @param con the current database connection.
  281. * @return the count of updated NPCs.
  282. * @throws SQLException the SQL exception.
  283. */
  284. private final int performUpdate(StringBuilder sb, String table, String key, int npcId, Connection con) throws SQLException
  285. {
  286. int updated = 0;
  287. if ((sb != null) && !sb.toString().isEmpty())
  288. {
  289. final StringBuilder sbQuery = new StringBuilder(sb.length() + 28);
  290. sbQuery.append("UPDATE ");
  291. sbQuery.append(table);
  292. sbQuery.append(" SET ");
  293. sbQuery.append(sb.toString());
  294. sbQuery.append(" WHERE ");
  295. sbQuery.append(key);
  296. sbQuery.append(" = ?");
  297. final PreparedStatement statement = con.prepareStatement(sbQuery.toString());
  298. statement.setInt(1, npcId);
  299. updated = statement.executeUpdate();
  300. statement.close();
  301. }
  302. return updated;
  303. }
  304. /**
  305. * @param id the template Id to get.
  306. * @return the template for the given id.
  307. */
  308. public L2NpcTemplate getTemplate(int id)
  309. {
  310. return _npcs.get(id);
  311. }
  312. /**
  313. * @param name of the template to get.
  314. * @return the template for the given name.
  315. */
  316. public L2NpcTemplate getTemplateByName(String name)
  317. {
  318. for (L2NpcTemplate npcTemplate : _npcs.values(new L2NpcTemplate[0]))
  319. {
  320. if (npcTemplate.getName().equalsIgnoreCase(name))
  321. {
  322. return npcTemplate;
  323. }
  324. }
  325. return null;
  326. }
  327. /**
  328. * @param lvls of all the templates to get.
  329. * @return the template list for the given level.
  330. */
  331. public List<L2NpcTemplate> getAllOfLevel(int ...lvls)
  332. {
  333. final List<L2NpcTemplate> list = new FastList<>();
  334. for (int lvl : lvls)
  335. {
  336. for (L2NpcTemplate t : _npcs.values(new L2NpcTemplate[0]))
  337. {
  338. if (t.getLevel() == lvl)
  339. {
  340. list.add(t);
  341. }
  342. }
  343. }
  344. return list;
  345. }
  346. /**
  347. * @param lvls of all the monster templates to get.
  348. * @return the template list for the given level.
  349. */
  350. public List<L2NpcTemplate> getAllMonstersOfLevel(int ...lvls)
  351. {
  352. final List<L2NpcTemplate> list = new FastList<>();
  353. for (int lvl : lvls)
  354. {
  355. for (L2NpcTemplate t : _npcs.values(new L2NpcTemplate[0]))
  356. {
  357. if ((t.getLevel() == lvl) && t.isType("L2Monster"))
  358. {
  359. list.add(t);
  360. }
  361. }
  362. }
  363. return list;
  364. }
  365. /**
  366. * @param letters of all the NPC templates which its name start with.
  367. * @return the template list for the given letter.
  368. */
  369. public List<L2NpcTemplate> getAllNpcStartingWith(String ...letters)
  370. {
  371. final List<L2NpcTemplate> list = new FastList<>();
  372. for (String letter : letters)
  373. {
  374. for (L2NpcTemplate t : _npcs.values(new L2NpcTemplate[0]))
  375. {
  376. if (t.getName().startsWith(letter) && t.isType("L2Npc"))
  377. {
  378. list.add(t);
  379. }
  380. }
  381. }
  382. return list;
  383. }
  384. /**
  385. * @param classTypes of all the templates to get.
  386. * @return the template list for the given class type.
  387. */
  388. public List<L2NpcTemplate> getAllNpcOfClassType(String ...classTypes)
  389. {
  390. final List<L2NpcTemplate> list = new FastList<>();
  391. for (String classType : classTypes)
  392. {
  393. for (L2NpcTemplate t : _npcs.values(new L2NpcTemplate[0]))
  394. {
  395. if (t.isType(classType))
  396. {
  397. list.add(t);
  398. }
  399. }
  400. }
  401. return list;
  402. }
  403. /**
  404. * Id equals to zero or lesser means all.
  405. * @param id of the NPC to load.
  406. */
  407. public void loadNpcs(int id)
  408. {
  409. Connection con = null;
  410. try
  411. {
  412. con = L2DatabaseFactory.getInstance().getConnection();
  413. PreparedStatement statement;
  414. if (id > 0)
  415. {
  416. statement = con.prepareStatement("SELECT * FROM npc WHERE id = ?");
  417. statement.setInt(1, id);
  418. }
  419. else
  420. {
  421. statement = con.prepareStatement("SELECT * FROM npc ORDER BY id");
  422. }
  423. ResultSet rset = statement.executeQuery();
  424. int cont = 0;
  425. int cCont = 0;
  426. while (rset.next())
  427. {
  428. fillNpcTable(rset);
  429. cont++;
  430. }
  431. rset.close();
  432. statement.close();
  433. if (Config.CUSTOM_NPC_TABLE)
  434. {
  435. if (id > 0)
  436. {
  437. statement = con.prepareStatement("SELECT * FROM custom_npc WHERE id = ?");
  438. statement.setInt(1, id);
  439. }
  440. else
  441. {
  442. statement = con.prepareStatement("SELECT * FROM custom_npc ORDER BY id");
  443. }
  444. rset = statement.executeQuery();
  445. while (rset.next())
  446. {
  447. fillNpcTable(rset);
  448. cCont++;
  449. }
  450. rset.close();
  451. statement.close();
  452. }
  453. _log.info(getClass().getSimpleName() + ": Loaded " + cont + " (Custom: " + cCont + ") NPC template(s).");
  454. }
  455. catch (Exception e)
  456. {
  457. _log.log(Level.SEVERE, getClass().getSimpleName() + ": Error creating NPC table.", e);
  458. }
  459. finally
  460. {
  461. L2DatabaseFactory.close(con);
  462. }
  463. }
  464. /**
  465. * Id equals to zero or lesser means all.
  466. * @param id of the NPC to load it's skills.
  467. */
  468. public void loadNpcsSkills(int id)
  469. {
  470. Connection con = null;
  471. try
  472. {
  473. con = L2DatabaseFactory.getInstance().getConnection();
  474. PreparedStatement statement;
  475. if (id > 0)
  476. {
  477. statement = con.prepareStatement("SELECT * FROM npcskills WHERE npcid = ?");
  478. statement.setInt(1, id);
  479. }
  480. else
  481. {
  482. statement = con.prepareStatement("SELECT * FROM npcskills ORDER BY npcid");
  483. }
  484. ResultSet rset = statement.executeQuery();
  485. int cont = 0;
  486. int cCont = 0;
  487. L2NpcTemplate npcDat = null;
  488. L2Skill npcSkill = null;
  489. while (rset.next())
  490. {
  491. int mobId = rset.getInt("npcid");
  492. npcDat = _npcs.get(mobId);
  493. if (npcDat == null)
  494. {
  495. _log.warning(getClass().getSimpleName() + ": Skill data for undefined NPC. npcId: " + mobId);
  496. continue;
  497. }
  498. int skillId = rset.getInt("skillid");
  499. int level = rset.getInt("level");
  500. if (skillId == L2Skill.SKILL_NPC_RACE)
  501. {
  502. npcDat.setRace(level);
  503. continue;
  504. }
  505. npcSkill = SkillTable.getInstance().getInfo(skillId, level);
  506. if (npcSkill == null)
  507. {
  508. continue;
  509. }
  510. cont++;
  511. npcDat.addSkill(npcSkill);
  512. }
  513. rset.close();
  514. statement.close();
  515. if (Config.CUSTOM_NPC_SKILLS_TABLE)
  516. {
  517. if (id > 0)
  518. {
  519. statement = con.prepareStatement("SELECT * FROM custom_npcskills WHERE npcid = ?");
  520. statement.setInt(1, id);
  521. }
  522. else
  523. {
  524. statement = con.prepareStatement("SELECT * FROM custom_npcskills ORDER BY npcid");
  525. }
  526. rset = statement.executeQuery();
  527. while (rset.next())
  528. {
  529. int mobId = rset.getInt("npcid");
  530. npcDat = _npcs.get(mobId);
  531. if (npcDat == null)
  532. {
  533. _log.warning("Custom " + getClass().getSimpleName() + ": Skill data for undefined NPC. npcId: " + mobId);
  534. continue;
  535. }
  536. int skillId = rset.getInt("skillid");
  537. int level = rset.getInt("level");
  538. if ((npcDat.getRace() == null) && (skillId == L2Skill.SKILL_NPC_RACE))
  539. {
  540. npcDat.setRace(level);
  541. continue;
  542. }
  543. npcSkill = SkillTable.getInstance().getInfo(skillId, level);
  544. if (npcSkill == null)
  545. {
  546. continue;
  547. }
  548. cCont++;
  549. npcDat.addSkill(npcSkill);
  550. }
  551. rset.close();
  552. statement.close();
  553. }
  554. _log.info(getClass().getSimpleName() + ": Loaded " + cont + " (Custom: " + cCont + ") npc skills.");
  555. }
  556. catch (Exception e)
  557. {
  558. _log.log(Level.SEVERE, getClass().getSimpleName() + ": Error reading NPC skills table.", e);
  559. }
  560. finally
  561. {
  562. L2DatabaseFactory.close(con);
  563. }
  564. }
  565. /**
  566. * Id equals to zero or lesser means all.
  567. * @param id of the NPC to load it's drops.
  568. */
  569. public void loadNpcsDrop(int id)
  570. {
  571. Connection con = null;
  572. try
  573. {
  574. con = L2DatabaseFactory.getInstance().getConnection();
  575. PreparedStatement statement = null;
  576. if (id > 0)
  577. {
  578. statement = con.prepareStatement("SELECT * FROM droplist WHERE mobId = ? ORDER BY mobId, chance DESC");
  579. statement.setInt(1, id);
  580. }
  581. else
  582. {
  583. statement = con.prepareStatement("SELECT * FROM droplist ORDER BY mobId, chance DESC");
  584. }
  585. ResultSet rset = statement.executeQuery();
  586. L2DropData dropDat = null;
  587. L2NpcTemplate npcDat = null;
  588. int cont = 0;
  589. int cCont = 0;
  590. while (rset.next())
  591. {
  592. int mobId = rset.getInt("mobId");
  593. npcDat = _npcs.get(mobId);
  594. if (npcDat == null)
  595. {
  596. _log.warning(getClass().getSimpleName() + ": Drop data for undefined NPC. npcId: " + mobId);
  597. continue;
  598. }
  599. dropDat = new L2DropData();
  600. dropDat.setItemId(rset.getInt("itemId"));
  601. dropDat.setMinDrop(rset.getInt("min"));
  602. dropDat.setMaxDrop(rset.getInt("max"));
  603. dropDat.setChance(rset.getInt("chance"));
  604. int category = rset.getInt("category");
  605. if (ItemTable.getInstance().getTemplate(dropDat.getItemId()) == null)
  606. {
  607. _log.warning(getClass().getSimpleName() + ": Drop data for undefined item template! NpcId: " + mobId + " itemId: " + dropDat.getItemId());
  608. continue;
  609. }
  610. cont++;
  611. npcDat.addDropData(dropDat, category);
  612. }
  613. rset.close();
  614. statement.close();
  615. if (Config.CUSTOM_DROPLIST_TABLE)
  616. {
  617. if (id > 0)
  618. {
  619. statement = con.prepareStatement("SELECT * FROM custom_droplist WHERE mobId = ? ORDER BY mobId, chance DESC");
  620. statement.setInt(1, id);
  621. }
  622. else
  623. {
  624. statement = con.prepareStatement("SELECT * FROM custom_droplist ORDER BY mobId, chance DESC");
  625. }
  626. rset = statement.executeQuery();
  627. int mobId;
  628. int category;
  629. while (rset.next())
  630. {
  631. mobId = rset.getInt("mobId");
  632. npcDat = _npcs.get(mobId);
  633. if (npcDat == null)
  634. {
  635. _log.warning(getClass().getSimpleName() + ": CUSTOM DROPLIST: Drop data for undefined NPC. npcId: " + mobId);
  636. continue;
  637. }
  638. dropDat = new L2DropData();
  639. dropDat.setItemId(rset.getInt("itemId"));
  640. dropDat.setMinDrop(rset.getInt("min"));
  641. dropDat.setMaxDrop(rset.getInt("max"));
  642. dropDat.setChance(rset.getInt("chance"));
  643. category = rset.getInt("category");
  644. if (ItemTable.getInstance().getTemplate(dropDat.getItemId()) == null)
  645. {
  646. _log.warning(getClass().getSimpleName() + ": Custom drop data for undefined item template! NpcId: " + mobId + " itemId: " + dropDat.getItemId());
  647. continue;
  648. }
  649. npcDat.addDropData(dropDat, category);
  650. cCont++;
  651. }
  652. rset.close();
  653. statement.close();
  654. }
  655. _log.info(getClass().getSimpleName() + ": Loaded " + cont + " (Custom: " + cCont + ") drops.");
  656. }
  657. catch (Exception e)
  658. {
  659. _log.log(Level.SEVERE, getClass().getSimpleName() + ": Error reading NPC dropdata. ", e);
  660. }
  661. finally
  662. {
  663. L2DatabaseFactory.close(con);
  664. }
  665. }
  666. /**
  667. * Id equals to zero or lesser means all.
  668. * @param id of the NPC to load it's skill learn list.
  669. */
  670. private void loadNpcsSkillLearn(int id)
  671. {
  672. Connection con = null;
  673. try
  674. {
  675. con = L2DatabaseFactory.getInstance().getConnection();
  676. PreparedStatement statement;
  677. if (id > 0)
  678. {
  679. statement = con.prepareStatement("SELECT * FROM skill_learn WHERE npc_id = ?");
  680. statement.setInt(1, id);
  681. }
  682. else
  683. {
  684. statement = con.prepareStatement("SELECT * FROM skill_learn");
  685. }
  686. ResultSet rset = statement.executeQuery();
  687. int cont = 0;
  688. int npcId;
  689. int classId;
  690. L2NpcTemplate npc;
  691. while (rset.next())
  692. {
  693. npcId = rset.getInt("npc_id");
  694. classId = rset.getInt("class_id");
  695. npc = getTemplate(npcId);
  696. if (npc == null)
  697. {
  698. _log.warning(getClass().getSimpleName() + ": Error getting NPC template ID " + npcId + " while trying to load skill trainer data.");
  699. continue;
  700. }
  701. cont++;
  702. npc.addTeachInfo(ClassId.getClassId(classId));
  703. }
  704. rset.close();
  705. statement.close();
  706. _log.info(getClass().getSimpleName() + ": Loaded " + cont + " Skill Learn.");
  707. }
  708. catch (Exception e)
  709. {
  710. _log.log(Level.SEVERE, getClass().getSimpleName() + ": Error reading NPC trainer data.", e);
  711. }
  712. finally
  713. {
  714. L2DatabaseFactory.close(con);
  715. }
  716. }
  717. /**
  718. * Id equals to zero or lesser means all.
  719. * @param id of the NPC to load it's minions.
  720. */
  721. public void loadMinions(int id)
  722. {
  723. Connection con = null;
  724. try
  725. {
  726. con = L2DatabaseFactory.getInstance().getConnection();
  727. PreparedStatement statement = null;
  728. if (id > 0)
  729. {
  730. statement = con.prepareStatement("SELECT * FROM minions WHERE boss_id = ?");
  731. statement.setInt(1, id);
  732. }
  733. else
  734. {
  735. statement = con.prepareStatement("SELECT * FROM minions ORDER BY boss_id");
  736. }
  737. ResultSet rset = statement.executeQuery();
  738. L2MinionData minionDat = null;
  739. L2NpcTemplate npcDat = null;
  740. int cnt = 0;
  741. int raidId;
  742. while (rset.next())
  743. {
  744. raidId = rset.getInt("boss_id");
  745. npcDat = _npcs.get(raidId);
  746. if (npcDat == null)
  747. {
  748. _log.warning(getClass().getSimpleName() + ": Minion references undefined boss NPC. Boss NpcId: " + raidId);
  749. continue;
  750. }
  751. minionDat = new L2MinionData();
  752. minionDat.setMinionId(rset.getInt("minion_id"));
  753. minionDat.setAmountMin(rset.getInt("amount_min"));
  754. minionDat.setAmountMax(rset.getInt("amount_max"));
  755. npcDat.addRaidData(minionDat);
  756. cnt++;
  757. }
  758. rset.close();
  759. statement.close();
  760. _log.info(getClass().getSimpleName() + ": Loaded " + cnt + " Minions.");
  761. }
  762. catch (Exception e)
  763. {
  764. _log.log(Level.SEVERE, getClass().getSimpleName() + ": Error loading minion data.", e);
  765. }
  766. finally
  767. {
  768. L2DatabaseFactory.close(con);
  769. }
  770. }
  771. /**
  772. * Id equals to zero or lesser means all.
  773. * @param id of the NPC to load it's AI data.
  774. */
  775. public void loadNpcsAI(int id)
  776. {
  777. Connection con = null;
  778. try
  779. {
  780. con = L2DatabaseFactory.getInstance().getConnection();
  781. PreparedStatement statement = null;
  782. if (id > 0)
  783. {
  784. statement = con.prepareStatement("SELECT * FROM npcaidata WHERE npcId = ?");
  785. statement.setInt(1, id);
  786. }
  787. else
  788. {
  789. statement = con.prepareStatement("SELECT * FROM npcaidata ORDER BY npcId");
  790. }
  791. ResultSet rset = statement.executeQuery();
  792. L2NpcAIData npcAIDat = null;
  793. L2NpcTemplate npcDat = null;
  794. int cont = 0;
  795. int cCont = 0;
  796. int npcId;
  797. while (rset.next())
  798. {
  799. npcId = rset.getInt("npcId");
  800. npcDat = _npcs.get(npcId);
  801. if (npcDat == null)
  802. {
  803. _log.severe(getClass().getSimpleName() + ": AI Data Error with id : " + npcId);
  804. continue;
  805. }
  806. npcAIDat = new L2NpcAIData();
  807. npcAIDat.setPrimarySkillId(rset.getInt("primarySkillId"));
  808. npcAIDat.setMinSkillChance(rset.getInt("minSkillChance"));
  809. npcAIDat.setMaxSkillChance(rset.getInt("maxSkillChance"));
  810. npcAIDat.setAggro(rset.getInt("aggro"));
  811. npcAIDat.setCanMove(rset.getInt("canMove"));
  812. npcAIDat.setShowName(rset.getBoolean("showName"));
  813. npcAIDat.setTargetable(rset.getBoolean("targetable"));
  814. npcAIDat.setSoulShot(rset.getInt("soulshot"));
  815. npcAIDat.setSpiritShot(rset.getInt("spiritshot"));
  816. npcAIDat.setSoulShotChance(rset.getInt("ssChance"));
  817. npcAIDat.setSpiritShotChance(rset.getInt("spsChance"));
  818. npcAIDat.setIsChaos(rset.getInt("isChaos"));
  819. npcAIDat.setShortRangeSkill(rset.getInt("minRangeSkill"));
  820. npcAIDat.setShortRangeChance(rset.getInt("minRangeChance"));
  821. npcAIDat.setLongRangeSkill(rset.getInt("maxRangeSkill"));
  822. npcAIDat.setLongRangeChance(rset.getInt("maxRangeChance"));
  823. npcAIDat.setClan(rset.getString("clan"));
  824. npcAIDat.setClanRange(rset.getInt("clanRange"));
  825. npcAIDat.setEnemyClan(rset.getString("enemyClan"));
  826. npcAIDat.setEnemyRange(rset.getInt("enemyRange"));
  827. npcAIDat.setDodge(rset.getInt("dodge"));
  828. npcAIDat.setAi(rset.getString("aiType"));
  829. npcDat.setAIData(npcAIDat);
  830. cont++;
  831. }
  832. rset.close();
  833. statement.close();
  834. if (Config.CUSTOM_NPC_TABLE)
  835. {
  836. if (id > 0)
  837. {
  838. statement = con.prepareStatement("SELECT * FROM custom_npcaidata WHERE npcId = ?");
  839. statement.setInt(1, id);
  840. }
  841. else
  842. {
  843. statement = con.prepareStatement("SELECT * FROM custom_npcaidata ORDER BY npcId");
  844. }
  845. rset = statement.executeQuery();
  846. while (rset.next())
  847. {
  848. npcId = rset.getInt("npcId");
  849. npcDat = _npcs.get(npcId);
  850. if (npcDat == null)
  851. {
  852. _log.severe(getClass().getSimpleName() + ": Custom AI Data Error with id : " + npcId);
  853. continue;
  854. }
  855. npcAIDat = new L2NpcAIData();
  856. npcAIDat.setPrimarySkillId(rset.getInt("primarySkillId"));
  857. npcAIDat.setMinSkillChance(rset.getInt("minSkillChance"));
  858. npcAIDat.setMaxSkillChance(rset.getInt("maxSkillChance"));
  859. npcAIDat.setAggro(rset.getInt("aggro"));
  860. npcAIDat.setCanMove(rset.getInt("canMove"));
  861. npcAIDat.setShowName(rset.getBoolean("showName"));
  862. npcAIDat.setTargetable(rset.getBoolean("targetable"));
  863. npcAIDat.setSoulShot(rset.getInt("soulshot"));
  864. npcAIDat.setSpiritShot(rset.getInt("spiritshot"));
  865. npcAIDat.setSoulShotChance(rset.getInt("ssChance"));
  866. npcAIDat.setSpiritShotChance(rset.getInt("spsChance"));
  867. npcAIDat.setIsChaos(rset.getInt("isChaos"));
  868. npcAIDat.setShortRangeSkill(rset.getInt("minRangeSkill"));
  869. npcAIDat.setShortRangeChance(rset.getInt("minRangeChance"));
  870. npcAIDat.setLongRangeSkill(rset.getInt("maxRangeSkill"));
  871. npcAIDat.setLongRangeChance(rset.getInt("maxRangeChance"));
  872. npcAIDat.setClan(rset.getString("clan"));
  873. npcAIDat.setClanRange(rset.getInt("clanRange"));
  874. npcAIDat.setEnemyClan(rset.getString("enemyClan"));
  875. npcAIDat.setEnemyRange(rset.getInt("enemyRange"));
  876. npcAIDat.setDodge(rset.getInt("dodge"));
  877. npcAIDat.setAi(rset.getString("aiType"));
  878. npcDat.setAIData(npcAIDat);
  879. cCont++;
  880. }
  881. rset.close();
  882. statement.close();
  883. }
  884. _log.info(getClass().getSimpleName() + ": Loaded " + cont + " (Custom: " + cCont + ") AI Data.");
  885. }
  886. catch (Exception e)
  887. {
  888. _log.log(Level.SEVERE, getClass().getSimpleName() + ": Error reading NPC AI Data: " + e.getMessage(), e);
  889. }
  890. finally
  891. {
  892. L2DatabaseFactory.close(con);
  893. }
  894. }
  895. /**
  896. * Id equals to zero or lesser means all.
  897. * @param id of the NPC to load it's element data.
  898. */
  899. public void loadNpcsElement(int id)
  900. {
  901. Connection con = null;
  902. try
  903. {
  904. con = L2DatabaseFactory.getInstance().getConnection();
  905. PreparedStatement statement = null;
  906. if (id > 0)
  907. {
  908. statement = con.prepareStatement("SELECT * FROM npc_elementals WHERE npc_id = ?");
  909. statement.setInt(1, id);
  910. }
  911. else
  912. {
  913. statement = con.prepareStatement("SELECT * FROM npc_elementals ORDER BY npc_id");
  914. }
  915. ResultSet rset = statement.executeQuery();
  916. L2NpcTemplate npcDat = null;
  917. int cont = 0;
  918. int cCount = 0;
  919. int npcId;
  920. while (rset.next())
  921. {
  922. npcId = rset.getInt("npc_id");
  923. npcDat = _npcs.get(npcId);
  924. if (npcDat == null)
  925. {
  926. _log.severe("NPCElementals: Elementals Error with id : " + npcId);
  927. continue;
  928. }
  929. switch (rset.getByte("elemAtkType"))
  930. {
  931. case Elementals.FIRE:
  932. npcDat.setBaseFire(rset.getInt("elemAtkValue"));
  933. break;
  934. case Elementals.WATER:
  935. npcDat.setBaseWater(rset.getInt("elemAtkValue"));
  936. break;
  937. case Elementals.EARTH:
  938. npcDat.setBaseEarth(rset.getInt("elemAtkValue"));
  939. break;
  940. case Elementals.WIND:
  941. npcDat.setBaseWind(rset.getInt("elemAtkValue"));
  942. break;
  943. case Elementals.HOLY:
  944. npcDat.setBaseHoly(rset.getInt("elemAtkValue"));
  945. break;
  946. case Elementals.DARK:
  947. npcDat.setBaseDark(rset.getInt("elemAtkValue"));
  948. break;
  949. default:
  950. _log.severe("NPCElementals: Elementals Error with id : " + npcId + "; unknown elementType: " + rset.getByte("elemAtkType"));
  951. continue;
  952. }
  953. npcDat.setBaseFireRes(rset.getInt("fireDefValue"));
  954. npcDat.setBaseWaterRes(rset.getInt("waterDefValue"));
  955. npcDat.setBaseEarthRes(rset.getInt("earthDefValue"));
  956. npcDat.setBaseWindRes(rset.getInt("windDefValue"));
  957. npcDat.setBaseHolyRes(rset.getInt("holyDefValue"));
  958. npcDat.setBaseDarkRes(rset.getInt("darkDefValue"));
  959. cont++;
  960. }
  961. rset.close();
  962. statement.close();
  963. if (Config.CUSTOM_NPC_TABLE)
  964. {
  965. if (id > 0)
  966. {
  967. statement = con.prepareStatement("SELECT * FROM custom_npc_elementals WHERE npc_id = ?");
  968. statement.setInt(1, id);
  969. }
  970. else
  971. {
  972. statement = con.prepareStatement("SELECT * FROM custom_npc_elementals ORDER BY npc_id");
  973. }
  974. rset = statement.executeQuery();
  975. while (rset.next())
  976. {
  977. npcId = rset.getInt("npc_id");
  978. npcDat = _npcs.get(npcId);
  979. if (npcDat == null)
  980. {
  981. _log.severe("NPCElementals: Custom Elementals Error with id : " + npcId);
  982. continue;
  983. }
  984. switch (rset.getByte("elemAtkType"))
  985. {
  986. case Elementals.FIRE:
  987. npcDat.setBaseFire(rset.getInt("elemAtkValue"));
  988. break;
  989. case Elementals.WATER:
  990. npcDat.setBaseWater(rset.getInt("elemAtkValue"));
  991. break;
  992. case Elementals.EARTH:
  993. npcDat.setBaseEarth(rset.getInt("elemAtkValue"));
  994. break;
  995. case Elementals.WIND:
  996. npcDat.setBaseWind(rset.getInt("elemAtkValue"));
  997. break;
  998. case Elementals.HOLY:
  999. npcDat.setBaseHoly(rset.getInt("elemAtkValue"));
  1000. break;
  1001. case Elementals.DARK:
  1002. npcDat.setBaseDark(rset.getInt("elemAtkValue"));
  1003. break;
  1004. default:
  1005. _log.severe("NPCElementals: Custom Elementals Error with id : " + npcId + "; unknown elementType: " + rset.getByte("elemAtkType"));
  1006. continue;
  1007. }
  1008. npcDat.setBaseFireRes(rset.getInt("fireDefValue"));
  1009. npcDat.setBaseWaterRes(rset.getInt("waterDefValue"));
  1010. npcDat.setBaseEarthRes(rset.getInt("earthDefValue"));
  1011. npcDat.setBaseWindRes(rset.getInt("windDefValue"));
  1012. npcDat.setBaseHolyRes(rset.getInt("holyDefValue"));
  1013. npcDat.setBaseDarkRes(rset.getInt("darkDefValue"));
  1014. cont++;
  1015. }
  1016. rset.close();
  1017. statement.close();
  1018. }
  1019. _log.info(getClass().getSimpleName() + ": Loaded " + cont + " (Custom: " + cCount + ") elementals Data.");
  1020. }
  1021. catch (Exception e)
  1022. {
  1023. _log.log(Level.SEVERE, getClass().getSimpleName() + ": Error reading NPC Elementals Data: " + e.getMessage(), e);
  1024. }
  1025. finally
  1026. {
  1027. L2DatabaseFactory.close(con);
  1028. }
  1029. }
  1030. public static NpcTable getInstance()
  1031. {
  1032. return SingletonHolder._instance;
  1033. }
  1034. @SuppressWarnings("synthetic-access")
  1035. private static class SingletonHolder
  1036. {
  1037. protected static final NpcTable _instance = new NpcTable();
  1038. }
  1039. }