NpcData.java 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. /*
  2. * Copyright (C) 2004-2014 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.util.ArrayList;
  21. import java.util.Collections;
  22. import java.util.EnumMap;
  23. import java.util.HashMap;
  24. import java.util.HashSet;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import java.util.concurrent.ConcurrentHashMap;
  29. import java.util.function.Predicate;
  30. import java.util.stream.Collectors;
  31. import org.w3c.dom.NamedNodeMap;
  32. import org.w3c.dom.Node;
  33. import com.l2jserver.Config;
  34. import com.l2jserver.gameserver.engines.DocumentParser;
  35. import com.l2jserver.gameserver.enums.AISkillScope;
  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.drops.DropListScope;
  40. import com.l2jserver.gameserver.model.drops.GeneralDropItem;
  41. import com.l2jserver.gameserver.model.drops.GroupedGeneralDropItem;
  42. import com.l2jserver.gameserver.model.drops.IDropItem;
  43. import com.l2jserver.gameserver.model.effects.L2EffectType;
  44. import com.l2jserver.gameserver.model.holders.MinionHolder;
  45. import com.l2jserver.gameserver.model.holders.SkillHolder;
  46. import com.l2jserver.gameserver.model.skills.Skill;
  47. import com.l2jserver.gameserver.util.Util;
  48. /**
  49. * NPC data parser.
  50. * @author Nos
  51. */
  52. public class NpcData extends DocumentParser
  53. {
  54. private final Map<Integer, L2NpcTemplate> _npcs = new ConcurrentHashMap<>();
  55. private final Map<String, Integer> _clans = new ConcurrentHashMap<>();
  56. private MinionData _minionData;
  57. protected NpcData()
  58. {
  59. load();
  60. }
  61. @Override
  62. public synchronized void load()
  63. {
  64. _minionData = new MinionData();
  65. parseDatapackDirectory("data/stats/npcs", false);
  66. _log.info(getClass().getSimpleName() + ": Loaded " + _npcs.size() + " NPCs.");
  67. if (Config.CUSTOM_NPC_DATA)
  68. {
  69. final int npcCount = _npcs.size();
  70. parseDatapackDirectory("data/stats/npcs/custom", true);
  71. _log.info(getClass().getSimpleName() + ": Loaded " + (_npcs.size() - npcCount) + " Custom NPCs.");
  72. }
  73. _minionData = null;
  74. loadNpcsSkillLearn();
  75. }
  76. @Override
  77. protected void parseDocument()
  78. {
  79. for (Node node = getCurrentDocument().getFirstChild(); node != null; node = node.getNextSibling())
  80. {
  81. if ("list".equalsIgnoreCase(node.getNodeName()))
  82. {
  83. for (Node list_node = node.getFirstChild(); list_node != null; list_node = list_node.getNextSibling())
  84. {
  85. if ("npc".equalsIgnoreCase(list_node.getNodeName()))
  86. {
  87. NamedNodeMap attrs = list_node.getAttributes();
  88. final StatsSet set = new StatsSet();
  89. final int npcId = parseInteger(attrs, "id");
  90. Map<String, Object> parameters = null;
  91. Map<Integer, Skill> skills = null;
  92. Set<Integer> clans = null;
  93. Set<Integer> ignoreClanNpcIds = null;
  94. Map<DropListScope, List<IDropItem>> dropLists = null;
  95. set.set("id", npcId);
  96. set.set("displayId", parseInteger(attrs, "displayId"));
  97. set.set("level", parseByte(attrs, "level"));
  98. set.set("type", parseString(attrs, "type"));
  99. set.set("name", parseString(attrs, "name"));
  100. set.set("usingServerSideName", parseBoolean(attrs, "usingServerSideName"));
  101. set.set("title", parseString(attrs, "title"));
  102. set.set("usingServerSideTitle", parseBoolean(attrs, "usingServerSideTitle"));
  103. for (Node npc_node = list_node.getFirstChild(); npc_node != null; npc_node = npc_node.getNextSibling())
  104. {
  105. attrs = npc_node.getAttributes();
  106. switch (npc_node.getNodeName().toLowerCase())
  107. {
  108. case "parameters":
  109. {
  110. if (parameters == null)
  111. {
  112. parameters = new HashMap<>();
  113. }
  114. for (Node parameters_node = npc_node.getFirstChild(); parameters_node != null; parameters_node = parameters_node.getNextSibling())
  115. {
  116. attrs = parameters_node.getAttributes();
  117. switch (parameters_node.getNodeName().toLowerCase())
  118. {
  119. case "param":
  120. {
  121. parameters.put(parseString(attrs, "name"), parseString(attrs, "value"));
  122. break;
  123. }
  124. case "skill":
  125. {
  126. parameters.put(parseString(attrs, "name"), new SkillHolder(parseInteger(attrs, "id"), parseInteger(attrs, "level")));
  127. break;
  128. }
  129. case "minions":
  130. {
  131. final List<MinionHolder> minions = new ArrayList<>(1);
  132. for (Node minions_node = parameters_node.getFirstChild(); minions_node != null; minions_node = minions_node.getNextSibling())
  133. {
  134. if (minions_node.getNodeName().equalsIgnoreCase("npc"))
  135. {
  136. attrs = minions_node.getAttributes();
  137. minions.add(new MinionHolder(parseInteger(attrs, "id"), parseInteger(attrs, "count"), parseInteger(attrs, "respawnTime"), parseInteger(attrs, "weightPoint")));
  138. }
  139. }
  140. if (!minions.isEmpty())
  141. {
  142. parameters.put(parseString(parameters_node.getAttributes(), "name"), minions);
  143. }
  144. break;
  145. }
  146. }
  147. }
  148. break;
  149. }
  150. case "race":
  151. case "sex":
  152. set.set(npc_node.getNodeName(), npc_node.getTextContent().toUpperCase());
  153. break;
  154. case "equipment":
  155. {
  156. set.set("chestId", parseInteger(attrs, "chest"));
  157. set.set("rhandId", parseInteger(attrs, "rhand"));
  158. set.set("lhandId", parseInteger(attrs, "lhand"));
  159. set.set("weaponEnchant", parseInteger(attrs, "weaponEnchant"));
  160. break;
  161. }
  162. case "acquire":
  163. {
  164. set.set("expRate", parseDouble(attrs, "expRate"));
  165. set.set("sp", parseDouble(attrs, "sp"));
  166. set.set("raidPoints", parseDouble(attrs, "raidPoints"));
  167. break;
  168. }
  169. case "stats":
  170. {
  171. set.set("baseSTR", parseInteger(attrs, "str"));
  172. set.set("baseINT", parseInteger(attrs, "int"));
  173. set.set("baseDEX", parseInteger(attrs, "dex"));
  174. set.set("baseWIT", parseInteger(attrs, "wit"));
  175. set.set("baseCON", parseInteger(attrs, "con"));
  176. set.set("baseMEN", parseInteger(attrs, "men"));
  177. for (Node stats_node = npc_node.getFirstChild(); stats_node != null; stats_node = stats_node.getNextSibling())
  178. {
  179. attrs = stats_node.getAttributes();
  180. switch (stats_node.getNodeName().toLowerCase())
  181. {
  182. case "vitals":
  183. {
  184. set.set("baseHpMax", parseDouble(attrs, "hp"));
  185. set.set("baseHpReg", parseDouble(attrs, "hpRegen"));
  186. set.set("baseMpMax", parseDouble(attrs, "mp"));
  187. set.set("baseMpReg", parseDouble(attrs, "mpRegen"));
  188. break;
  189. }
  190. case "attack":
  191. {
  192. set.set("basePAtk", parseDouble(attrs, "physical"));
  193. set.set("baseMAtk", parseDouble(attrs, "magical"));
  194. set.set("baseRndDam", parseInteger(attrs, "random"));
  195. set.set("baseCritRate", parseInteger(attrs, "critical"));
  196. set.set("accuracy", parseDouble(attrs, "accuracy"));// TODO: Implement me
  197. set.set("basePAtkSpd", parseInteger(attrs, "attackSpeed"));
  198. set.set("reuseDelay", parseInteger(attrs, "reuseDelay"));// TODO: Implement me
  199. set.set("baseAtkType", parseString(attrs, "type"));
  200. set.set("baseAtkRange", parseInteger(attrs, "range"));
  201. set.set("distance", parseInteger(attrs, "distance"));// TODO: Implement me
  202. set.set("width", parseInteger(attrs, "width"));// TODO: Implement me
  203. break;
  204. }
  205. case "defence":
  206. {
  207. set.set("basePDef", parseDouble(attrs, "physical"));
  208. set.set("baseMDef", parseDouble(attrs, "magical"));
  209. set.set("evasion", parseInteger(attrs, "evasion"));// TODO: Implement me
  210. set.set("baseShldDef", parseInteger(attrs, "shield"));
  211. set.set("baseShldRate", parseInteger(attrs, "shieldRate"));
  212. break;
  213. }
  214. case "attribute":
  215. {
  216. for (Node attribute_node = stats_node.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
  217. {
  218. attrs = attribute_node.getAttributes();
  219. switch (attribute_node.getNodeName().toLowerCase())
  220. {
  221. case "attack":
  222. {
  223. String attackAttributeType = parseString(attrs, "type");
  224. switch (attackAttributeType.toUpperCase())
  225. {
  226. case "FIRE":
  227. set.set("baseFire", parseInteger(attrs, "value"));
  228. break;
  229. case "WATER":
  230. set.set("baseWater", parseInteger(attrs, "value"));
  231. break;
  232. case "WIND":
  233. set.set("baseWind", parseInteger(attrs, "value"));
  234. break;
  235. case "EARTH":
  236. set.set("baseEarth", parseInteger(attrs, "value"));
  237. break;
  238. case "DARK":
  239. set.set("baseDark", parseInteger(attrs, "value"));
  240. break;
  241. case "HOLY":
  242. set.set("baseHoly", parseInteger(attrs, "value"));
  243. break;
  244. }
  245. break;
  246. }
  247. case "defence":
  248. {
  249. set.set("baseFireRes", parseInteger(attrs, "fire"));
  250. set.set("baseWaterRes", parseInteger(attrs, "water"));
  251. set.set("baseWindRes", parseInteger(attrs, "wind"));
  252. set.set("baseEarthRes", parseInteger(attrs, "earth"));
  253. set.set("baseHolyRes", parseInteger(attrs, "holy"));
  254. set.set("baseDarkRes", parseInteger(attrs, "dark"));
  255. set.set("baseElementRes", parseInteger(attrs, "default"));
  256. break;
  257. }
  258. }
  259. }
  260. break;
  261. }
  262. case "speed":
  263. {
  264. for (Node speed_node = stats_node.getFirstChild(); speed_node != null; speed_node = speed_node.getNextSibling())
  265. {
  266. attrs = speed_node.getAttributes();
  267. switch (speed_node.getNodeName().toLowerCase())
  268. {
  269. case "walk":
  270. {
  271. set.set("baseWalkSpd", parseDouble(attrs, "ground"));
  272. set.set("baseSwimWalkSpd", parseDouble(attrs, "swim"));
  273. set.set("baseFlyWalkSpd", parseDouble(attrs, "fly"));
  274. break;
  275. }
  276. case "run":
  277. {
  278. set.set("baseRunSpd", parseDouble(attrs, "ground"));
  279. set.set("baseSwimRunSpd", parseDouble(attrs, "swim"));
  280. set.set("baseFlyRunSpd", parseDouble(attrs, "fly"));
  281. break;
  282. }
  283. }
  284. }
  285. break;
  286. }
  287. case "hit_time":
  288. set.set("hit_time", npc_node.getTextContent());// TODO: Implement me default 600 (value in ms)
  289. break;
  290. }
  291. }
  292. break;
  293. }
  294. case "status":
  295. {
  296. set.set("unique", parseBoolean(attrs, "unique"));
  297. set.set("attackable", parseBoolean(attrs, "attackable"));
  298. set.set("targetable", parseBoolean(attrs, "targetable"));
  299. set.set("undying", parseBoolean(attrs, "undying"));
  300. set.set("showName", parseBoolean(attrs, "showName"));
  301. set.set("flying", parseBoolean(attrs, "flying"));
  302. set.set("canMove", parseBoolean(attrs, "canMove"));
  303. set.set("noSleepMode", parseBoolean(attrs, "noSleepMode"));
  304. set.set("passableDoor", parseBoolean(attrs, "passableDoor"));
  305. set.set("hasSummoner", parseBoolean(attrs, "hasSummoner"));
  306. set.set("canBeSown", parseBoolean(attrs, "canBeSown"));
  307. break;
  308. }
  309. case "skill_list":
  310. {
  311. skills = new HashMap<>();
  312. for (Node skill_list_node = npc_node.getFirstChild(); skill_list_node != null; skill_list_node = skill_list_node.getNextSibling())
  313. {
  314. if ("skill".equalsIgnoreCase(skill_list_node.getNodeName()))
  315. {
  316. attrs = skill_list_node.getAttributes();
  317. final int skillId = parseInteger(attrs, "id");
  318. final int skillLevel = parseInteger(attrs, "level");
  319. final Skill skill = SkillData.getInstance().getSkill(skillId, skillLevel);
  320. if (skill != null)
  321. {
  322. skills.put(skill.getId(), skill);
  323. }
  324. else
  325. {
  326. _log.warning("[" + getCurrentFile().getName() + "] skill not found. NPC ID: " + npcId + " Skill ID:" + skillId + " Skill Level: " + skillLevel);
  327. }
  328. }
  329. }
  330. break;
  331. }
  332. case "shots":
  333. {
  334. set.set("soulShot", parseInteger(attrs, "soul"));
  335. set.set("spiritShot", parseInteger(attrs, "spirit"));
  336. set.set("shotShotChance", parseInteger(attrs, "shotChance"));
  337. set.set("spiritShotChance", parseInteger(attrs, "spiritChance"));
  338. break;
  339. }
  340. case "corpse_time":
  341. set.set("corpseTime", npc_node.getTextContent());
  342. break;
  343. case "ex_crt_effect":
  344. set.set("ex_crt_effect", npc_node.getTextContent()); // TODO: Implement me default ? type boolean
  345. break;
  346. case "s_npc_prop_hp_rate":
  347. set.set("s_npc_prop_hp_rate", npc_node.getTextContent()); // TODO: Implement me default 1 type double
  348. break;
  349. case "ai":
  350. {
  351. set.set("aiType", parseString(attrs, "type"));
  352. set.set("aggroRange", parseInteger(attrs, "aggroRange"));
  353. set.set("clanHelpRange", parseInteger(attrs, "clanHelpRange"));
  354. set.set("dodge", parseInteger(attrs, "dodge"));
  355. set.set("isChaos", parseBoolean(attrs, "isChaos"));
  356. set.set("isAggressive", parseBoolean(attrs, "isAggressive"));
  357. for (Node ai_node = npc_node.getFirstChild(); ai_node != null; ai_node = ai_node.getNextSibling())
  358. {
  359. attrs = ai_node.getAttributes();
  360. switch (ai_node.getNodeName().toLowerCase())
  361. {
  362. case "skill":
  363. {
  364. set.set("minSkillChance", parseInteger(attrs, "minChance"));
  365. set.set("maxSkillChance", parseInteger(attrs, "maxChance"));
  366. set.set("primarySkillId", parseInteger(attrs, "primaryId"));
  367. set.set("shortRangeSkillId", parseInteger(attrs, "shortRangeId"));
  368. set.set("shortRangeSkillChance", parseInteger(attrs, "shortRangeChance"));
  369. set.set("longRangeSkillId", parseInteger(attrs, "longRangeId"));
  370. set.set("longRangeSkillChance", parseInteger(attrs, "longRangeChance"));
  371. break;
  372. }
  373. case "clan_list":
  374. {
  375. for (Node clan_list_node = ai_node.getFirstChild(); clan_list_node != null; clan_list_node = clan_list_node.getNextSibling())
  376. {
  377. attrs = clan_list_node.getAttributes();
  378. switch (clan_list_node.getNodeName().toLowerCase())
  379. {
  380. case "clan":
  381. {
  382. if (clans == null)
  383. {
  384. clans = new HashSet<>(1);
  385. }
  386. clans.add(getOrCreateClanId(clan_list_node.getTextContent()));
  387. break;
  388. }
  389. case "ignore_npc_id":
  390. {
  391. if (ignoreClanNpcIds == null)
  392. {
  393. ignoreClanNpcIds = new HashSet<>(1);
  394. }
  395. ignoreClanNpcIds.add(Integer.parseInt(clan_list_node.getTextContent()));
  396. break;
  397. }
  398. }
  399. }
  400. break;
  401. }
  402. }
  403. }
  404. break;
  405. }
  406. case "drop_lists":
  407. {
  408. for (Node drop_lists_node = npc_node.getFirstChild(); drop_lists_node != null; drop_lists_node = drop_lists_node.getNextSibling())
  409. {
  410. DropListScope dropListScope = null;
  411. try
  412. {
  413. dropListScope = Enum.valueOf(DropListScope.class, drop_lists_node.getNodeName().toUpperCase());
  414. }
  415. catch (Exception e)
  416. {
  417. }
  418. if (dropListScope != null)
  419. {
  420. if (dropLists == null)
  421. {
  422. dropLists = new EnumMap<>(DropListScope.class);
  423. }
  424. List<IDropItem> dropList = new ArrayList<>();
  425. parseDropList(drop_lists_node, dropListScope, dropList);
  426. dropLists.put(dropListScope, Collections.unmodifiableList(dropList));
  427. }
  428. }
  429. break;
  430. }
  431. case "collision":
  432. {
  433. for (Node collision_node = npc_node.getFirstChild(); collision_node != null; collision_node = collision_node.getNextSibling())
  434. {
  435. attrs = collision_node.getAttributes();
  436. switch (collision_node.getNodeName().toLowerCase())
  437. {
  438. case "radius":
  439. {
  440. set.set("collision_radius", parseDouble(attrs, "normal"));
  441. set.set("collisionRadiusGrown", parseDouble(attrs, "grown"));
  442. break;
  443. }
  444. case "height":
  445. {
  446. set.set("collision_height", parseDouble(attrs, "normal"));
  447. set.set("collisionHeightGrown", parseDouble(attrs, "grown"));
  448. break;
  449. }
  450. }
  451. }
  452. break;
  453. }
  454. }
  455. }
  456. L2NpcTemplate template = _npcs.get(npcId);
  457. if (template == null)
  458. {
  459. template = new L2NpcTemplate(set);
  460. _npcs.put(template.getId(), template);
  461. }
  462. else
  463. {
  464. template.set(set);
  465. }
  466. if (_minionData._tempMinions.containsKey(npcId))
  467. {
  468. if (parameters == null)
  469. {
  470. parameters = new HashMap<>();
  471. }
  472. parameters.putIfAbsent("Privates", _minionData._tempMinions.get(npcId));
  473. }
  474. if (parameters != null)
  475. {
  476. // Using unmodifiable map parameters of template are not meant to be changed at runtime.
  477. template.setParameters(new StatsSet(Collections.unmodifiableMap(parameters)));
  478. }
  479. else
  480. {
  481. template.setParameters(StatsSet.EMPTY_STATSET);
  482. }
  483. if (skills != null)
  484. {
  485. Map<AISkillScope, List<Skill>> aiSkillLists = null;
  486. for (Skill skill : skills.values())
  487. {
  488. if (!skill.isPassive())
  489. {
  490. if (aiSkillLists == null)
  491. {
  492. aiSkillLists = new EnumMap<>(AISkillScope.class);
  493. }
  494. List<AISkillScope> aiSkillScopes = new ArrayList<>();
  495. final AISkillScope shortOrLongRangeScope = skill.getCastRange() <= 150 ? AISkillScope.SHORT_RANGE : AISkillScope.SHORT_RANGE;
  496. if (skill.isSuicideAttack())
  497. {
  498. aiSkillScopes.add(AISkillScope.SUICIDE);
  499. }
  500. else
  501. {
  502. aiSkillScopes.add(AISkillScope.GENERAL);
  503. if (skill.isContinuous())
  504. {
  505. if (!skill.isDebuff())
  506. {
  507. aiSkillScopes.add(AISkillScope.BUFF);
  508. }
  509. else
  510. {
  511. aiSkillScopes.add(AISkillScope.DEBUFF);
  512. aiSkillScopes.add(AISkillScope.COT);
  513. aiSkillScopes.add(shortOrLongRangeScope);
  514. }
  515. }
  516. else
  517. {
  518. if (skill.hasEffectType(L2EffectType.DISPEL, L2EffectType.DISPEL_BY_SLOT))
  519. {
  520. aiSkillScopes.add(AISkillScope.NEGATIVE);
  521. aiSkillScopes.add(shortOrLongRangeScope);
  522. }
  523. else if (skill.hasEffectType(L2EffectType.HEAL))
  524. {
  525. aiSkillScopes.add(AISkillScope.HEAL);
  526. }
  527. else if (skill.hasEffectType(L2EffectType.PHYSICAL_ATTACK, L2EffectType.PHYSICAL_ATTACK_HP_LINK, L2EffectType.MAGICAL_ATTACK, L2EffectType.DEATH_LINK, L2EffectType.HP_DRAIN))
  528. {
  529. aiSkillScopes.add(AISkillScope.ATTACK);
  530. aiSkillScopes.add(AISkillScope.UNIVERSAL);
  531. aiSkillScopes.add(shortOrLongRangeScope);
  532. }
  533. else if (skill.hasEffectType(L2EffectType.SLEEP))
  534. {
  535. aiSkillScopes.add(AISkillScope.IMMOBILIZE);
  536. }
  537. else if (skill.hasEffectType(L2EffectType.STUN, L2EffectType.ROOT))
  538. {
  539. aiSkillScopes.add(AISkillScope.IMMOBILIZE);
  540. aiSkillScopes.add(shortOrLongRangeScope);
  541. }
  542. else if (skill.hasEffectType(L2EffectType.MUTE, L2EffectType.FEAR))
  543. {
  544. aiSkillScopes.add(AISkillScope.COT);
  545. aiSkillScopes.add(shortOrLongRangeScope);
  546. }
  547. else if (skill.hasEffectType(L2EffectType.PARALYZE))
  548. {
  549. aiSkillScopes.add(AISkillScope.IMMOBILIZE);
  550. aiSkillScopes.add(shortOrLongRangeScope);
  551. }
  552. else if (skill.hasEffectType(L2EffectType.DMG_OVER_TIME, L2EffectType.DMG_OVER_TIME_PERCENT))
  553. {
  554. aiSkillScopes.add(shortOrLongRangeScope);
  555. }
  556. else if (skill.hasEffectType(L2EffectType.RESURRECTION))
  557. {
  558. aiSkillScopes.add(AISkillScope.RES);
  559. }
  560. else
  561. {
  562. aiSkillScopes.add(AISkillScope.UNIVERSAL);
  563. }
  564. }
  565. }
  566. for (AISkillScope aiSkillScope : aiSkillScopes)
  567. {
  568. List<Skill> aiSkills = aiSkillLists.get(aiSkillScope);
  569. if (aiSkills == null)
  570. {
  571. aiSkills = new ArrayList<>();
  572. aiSkillLists.put(aiSkillScope, aiSkills);
  573. }
  574. aiSkills.add(skill);
  575. }
  576. }
  577. }
  578. template.setSkills(skills);
  579. template.setAISkillLists(aiSkillLists);
  580. }
  581. else
  582. {
  583. template.setSkills(null);
  584. template.setAISkillLists(null);
  585. }
  586. template.setClans(clans);
  587. template.setIgnoreClanNpcIds(ignoreClanNpcIds);
  588. template.setDropLists(dropLists);
  589. }
  590. }
  591. }
  592. }
  593. }
  594. private void parseDropList(Node drop_list_node, DropListScope dropListScope, List<IDropItem> drops)
  595. {
  596. for (Node drop_node = drop_list_node.getFirstChild(); drop_node != null; drop_node = drop_node.getNextSibling())
  597. {
  598. NamedNodeMap attrs = drop_node.getAttributes();
  599. switch (drop_node.getNodeName().toLowerCase())
  600. {
  601. case "group":
  602. {
  603. GroupedGeneralDropItem dropItem = dropListScope.newGroupedDropItem(parseDouble(attrs, "chance"));
  604. List<IDropItem> groupedDropList = new ArrayList<>(2);
  605. for (Node group_node = drop_node.getFirstChild(); group_node != null; group_node = group_node.getNextSibling())
  606. {
  607. parseDropListItem(group_node, dropListScope, groupedDropList);
  608. }
  609. List<GeneralDropItem> items = new ArrayList<>(groupedDropList.size());
  610. for (IDropItem item : groupedDropList)
  611. {
  612. if (item instanceof GeneralDropItem)
  613. {
  614. items.add((GeneralDropItem) item);
  615. }
  616. else
  617. {
  618. _log.warning("[" + getCurrentFile() + "] grouped general drop item supports only general drop item.");
  619. }
  620. }
  621. dropItem.setItems(items);
  622. drops.add(dropItem);
  623. break;
  624. }
  625. default:
  626. {
  627. parseDropListItem(drop_node, dropListScope, drops);
  628. break;
  629. }
  630. }
  631. }
  632. }
  633. private void parseDropListItem(Node drop_list_item, DropListScope dropListScope, List<IDropItem> drops)
  634. {
  635. NamedNodeMap attrs = drop_list_item.getAttributes();
  636. switch (drop_list_item.getNodeName().toLowerCase())
  637. {
  638. case "item":
  639. {
  640. final IDropItem dropItem = dropListScope.newDropItem(parseInteger(attrs, "id"), parseLong(attrs, "min"), parseLong(attrs, "max"), parseDouble(attrs, "chance"));
  641. if (dropItem != null)
  642. {
  643. drops.add(dropItem);
  644. }
  645. break;
  646. }
  647. }
  648. }
  649. /**
  650. * Gets or creates a clan id if it doesnt exists.
  651. * @param clanName the clan name to get or create its id
  652. * @return the clan id for the given clan name
  653. */
  654. private int getOrCreateClanId(String clanName)
  655. {
  656. Integer id = _clans.get(clanName.toUpperCase());
  657. if (id == null)
  658. {
  659. id = _clans.size();
  660. _clans.put(clanName.toUpperCase(), id);
  661. }
  662. return id;
  663. }
  664. /**
  665. * Gets the clan id
  666. * @param clanName the clan name to get its id
  667. * @return the clan id for the given clan name if it exists, -1 otherwise
  668. */
  669. public int getClanId(String clanName)
  670. {
  671. Integer id = _clans.get(clanName.toUpperCase());
  672. return id != null ? id : -1;
  673. }
  674. /**
  675. * Gets the template.
  676. * @param id the template Id to get.
  677. * @return the template for the given id.
  678. */
  679. public L2NpcTemplate getTemplate(int id)
  680. {
  681. return _npcs.get(id);
  682. }
  683. /**
  684. * Gets the template by name.
  685. * @param name of the template to get.
  686. * @return the template for the given name.
  687. */
  688. public L2NpcTemplate getTemplateByName(String name)
  689. {
  690. for (L2NpcTemplate npcTemplate : _npcs.values())
  691. {
  692. if (npcTemplate.getName().equalsIgnoreCase(name))
  693. {
  694. return npcTemplate;
  695. }
  696. }
  697. return null;
  698. }
  699. /**
  700. * Gets all templates matching the filter.
  701. * @param filter
  702. * @return the template list for the given filter
  703. */
  704. public List<L2NpcTemplate> getTemplates(Predicate<L2NpcTemplate> filter)
  705. {
  706. //@formatter:off
  707. return _npcs.values().stream()
  708. .filter(filter)
  709. .collect(Collectors.toList());
  710. //@formatter:on
  711. }
  712. /**
  713. * Gets the all of level.
  714. * @param lvls of all the templates to get.
  715. * @return the template list for the given level.
  716. */
  717. public List<L2NpcTemplate> getAllOfLevel(int... lvls)
  718. {
  719. return getTemplates(template -> Util.contains(lvls, template.getLevel()));
  720. }
  721. /**
  722. * Gets the all monsters of level.
  723. * @param lvls of all the monster templates to get.
  724. * @return the template list for the given level.
  725. */
  726. public List<L2NpcTemplate> getAllMonstersOfLevel(int... lvls)
  727. {
  728. return getTemplates(template -> Util.contains(lvls, template.getLevel()) && template.isType("L2Monster"));
  729. }
  730. /**
  731. * Gets the all npc starting with.
  732. * @param text of all the NPC templates which its name start with.
  733. * @return the template list for the given letter.
  734. */
  735. public List<L2NpcTemplate> getAllNpcStartingWith(String text)
  736. {
  737. return getTemplates(template -> template.isType("L2Npc") && template.getName().startsWith(text));
  738. }
  739. /**
  740. * Gets the all npc of class type.
  741. * @param classTypes of all the templates to get.
  742. * @return the template list for the given class type.
  743. */
  744. public List<L2NpcTemplate> getAllNpcOfClassType(String... classTypes)
  745. {
  746. return getTemplates(template -> Util.contains(classTypes, template.getType(), true));
  747. }
  748. public void loadNpcsSkillLearn()
  749. {
  750. _npcs.values().forEach(template ->
  751. {
  752. final List<ClassId> teachInfo = SkillLearnData.getInstance().getSkillLearnData(template.getId());
  753. if (teachInfo != null)
  754. {
  755. template.addTeachInfo(teachInfo);
  756. }
  757. });
  758. }
  759. /**
  760. * This class handles minions from Spawn System<br>
  761. * Once Spawn System gets reworked delete this class<br>
  762. * @author Zealar
  763. */
  764. private final class MinionData extends DocumentParser
  765. {
  766. public final Map<Integer, List<MinionHolder>> _tempMinions = new HashMap<>();
  767. protected MinionData()
  768. {
  769. load();
  770. }
  771. @Override
  772. public void load()
  773. {
  774. _tempMinions.clear();
  775. parseDatapackFile("data/minionData.xml");
  776. _log.info(getClass().getSimpleName() + ": Loaded " + _tempMinions.size() + " minions data.");
  777. }
  778. @Override
  779. protected void parseDocument()
  780. {
  781. for (Node node = getCurrentDocument().getFirstChild(); node != null; node = node.getNextSibling())
  782. {
  783. if ("list".equals(node.getNodeName()))
  784. {
  785. for (Node list_node = node.getFirstChild(); list_node != null; list_node = list_node.getNextSibling())
  786. {
  787. if ("npc".equals(list_node.getNodeName()))
  788. {
  789. final List<MinionHolder> minions = new ArrayList<>(1);
  790. NamedNodeMap attrs = list_node.getAttributes();
  791. int id = parseInteger(attrs, "id");
  792. for (Node npc_node = list_node.getFirstChild(); npc_node != null; npc_node = npc_node.getNextSibling())
  793. {
  794. if ("minion".equals(npc_node.getNodeName()))
  795. {
  796. attrs = npc_node.getAttributes();
  797. minions.add(new MinionHolder(parseInteger(attrs, "id"), parseInteger(attrs, "count"), parseInteger(attrs, "respawnTime"), 0));
  798. }
  799. }
  800. _tempMinions.put(id, minions);
  801. }
  802. }
  803. }
  804. }
  805. }
  806. }
  807. /**
  808. * Gets the single instance of NpcData.
  809. * @return single instance of NpcData
  810. */
  811. public static NpcData getInstance()
  812. {
  813. return SingletonHolder._instance;
  814. }
  815. private static class SingletonHolder
  816. {
  817. protected static final NpcData _instance = new NpcData();
  818. }
  819. }