NpcTable.java 31 KB

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