NpcTable.java 31 KB

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