AdminEditNpc.java 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  1. /*
  2. * Copyright (C) 2004-2013 L2J DataPack
  3. *
  4. * This file is part of L2J DataPack.
  5. *
  6. * L2J DataPack 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 DataPack 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 handlers.admincommandhandlers;
  20. import java.sql.Connection;
  21. import java.sql.PreparedStatement;
  22. import java.sql.SQLException;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.StringTokenizer;
  26. import java.util.logging.Level;
  27. import java.util.logging.Logger;
  28. import com.l2jserver.L2DatabaseFactory;
  29. import com.l2jserver.gameserver.datatables.ItemTable;
  30. import com.l2jserver.gameserver.datatables.NpcTable;
  31. import com.l2jserver.gameserver.datatables.SkillTable;
  32. import com.l2jserver.gameserver.handler.IAdminCommandHandler;
  33. import com.l2jserver.gameserver.model.Elementals;
  34. import com.l2jserver.gameserver.model.L2DropCategory;
  35. import com.l2jserver.gameserver.model.L2DropData;
  36. import com.l2jserver.gameserver.model.L2Object;
  37. import com.l2jserver.gameserver.model.StatsSet;
  38. import com.l2jserver.gameserver.model.actor.L2Npc;
  39. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  40. import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
  41. import com.l2jserver.gameserver.model.items.L2Item;
  42. import com.l2jserver.gameserver.model.skills.L2Skill;
  43. import com.l2jserver.gameserver.model.stats.MoveType;
  44. import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
  45. /**
  46. * @author Nos
  47. */
  48. public class AdminEditNpc implements IAdminCommandHandler
  49. {
  50. private static Logger _log = Logger.getLogger(AdminEditNpc.class.getName());
  51. private static final String[] ADMIN_COMMANDS =
  52. {
  53. "admin_edit_npc",
  54. "admin_save_npc",
  55. "admin_show_skill_list_npc",
  56. "admin_add_skill_npc",
  57. "admin_del_skill_npc",
  58. "admin_show_drop_list",
  59. "admin_add_drop",
  60. "admin_del_drop",
  61. "admin_log_npc_spawn"
  62. };
  63. @Override
  64. public boolean useAdminCommand(String command, L2PcInstance activeChar)
  65. {
  66. final StringTokenizer st = new StringTokenizer(command, " ");
  67. final String actualCommand = st.nextToken();
  68. switch (actualCommand.toLowerCase())
  69. {
  70. case "admin_edit_npc":
  71. {
  72. if (st.countTokens() < 2)
  73. {
  74. activeChar.sendMessage("Usage: //edit_npc <stats|ai|elementals|visuals> <npc_id>");
  75. return false;
  76. }
  77. String category = st.nextToken();
  78. try
  79. {
  80. int npcId = Integer.parseInt(st.nextToken());
  81. final L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcId);
  82. if (npc != null)
  83. {
  84. showNpcProperty(activeChar, npc, category);
  85. }
  86. else
  87. {
  88. activeChar.sendMessage("NPC does not exist or not loaded. npc_id:" + npcId);
  89. }
  90. }
  91. catch (NumberFormatException e)
  92. {
  93. activeChar.sendMessage("npc_id must be a number.");
  94. }
  95. break;
  96. }
  97. case "admin_save_npc":
  98. {
  99. if (st.countTokens() < 3)
  100. {
  101. activeChar.sendMessage("Usage: //save_npc <stats|ai|elementals|visuals> <npc_id> <statToSet> <value>");
  102. return false;
  103. }
  104. String category = st.nextToken();
  105. try
  106. {
  107. int npcId = Integer.parseInt(st.nextToken());
  108. String statToSet = st.nextToken();
  109. String value = st.hasMoreTokens() ? st.nextToken() : "";
  110. while (st.hasMoreTokens())
  111. {
  112. value += " " + st.nextToken();
  113. }
  114. final L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcId);
  115. if (npc != null)
  116. {
  117. saveNpcProperty(activeChar, npc, category, statToSet, value);
  118. }
  119. else
  120. {
  121. activeChar.sendMessage("NPC does not exist or not loaded. npc_id:" + npcId);
  122. }
  123. }
  124. catch (NumberFormatException e)
  125. {
  126. activeChar.sendMessage("npc_id must be a number.");
  127. }
  128. break;
  129. }
  130. case "admin_show_skill_list_npc":
  131. {
  132. if (st.countTokens() < 1)
  133. {
  134. activeChar.sendMessage("Usage: //show_skill_list_npc <npc_id> <page>");
  135. return false;
  136. }
  137. try
  138. {
  139. int npcId = Integer.parseInt(st.nextToken());
  140. int page = st.hasMoreTokens() ? Integer.parseInt(st.nextToken()) : 0;
  141. final L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcId);
  142. if (npc != null)
  143. {
  144. showNpcSkillList(activeChar, npc, page);
  145. }
  146. else
  147. {
  148. activeChar.sendMessage("NPC does not exist or not loaded. npc_id:" + npcId);
  149. }
  150. }
  151. catch (NumberFormatException e)
  152. {
  153. activeChar.sendMessage("npc_id must be a number.");
  154. }
  155. break;
  156. }
  157. case "admin_add_skill_npc":
  158. {
  159. if (st.countTokens() < 3)
  160. {
  161. activeChar.sendMessage("Usage: //add_skill_npc <npc_id> <skill_id> <skill_lvl>");
  162. return false;
  163. }
  164. try
  165. {
  166. int npcId = Integer.parseInt(st.nextToken());
  167. int skillId = Integer.parseInt(st.nextToken());
  168. int skillLvl = Integer.parseInt(st.nextToken());
  169. final L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcId);
  170. if (npc != null)
  171. {
  172. L2Skill skill = SkillTable.getInstance().getInfo(skillId, skillLvl);
  173. if (skill != null)
  174. {
  175. addNpcSkill(activeChar, npc, skill);
  176. }
  177. else
  178. {
  179. activeChar.sendMessage("Skill does not exist or not loaded. skill_id:" + skillId + " skill_lvl:" + skillLvl);
  180. }
  181. }
  182. else
  183. {
  184. activeChar.sendMessage("NPC does not exist or not loaded. npc_id:" + npcId);
  185. }
  186. }
  187. catch (NumberFormatException e)
  188. {
  189. activeChar.sendMessage("npc_id, skill_id and skill_lvl must all be numbers.");
  190. }
  191. break;
  192. }
  193. case "admin_del_skill_npc":
  194. {
  195. if (st.countTokens() < 2)
  196. {
  197. activeChar.sendMessage("Usage: //del_skill_npc <npc_id> <skill_id> <page>");
  198. return false;
  199. }
  200. try
  201. {
  202. int npcId = Integer.parseInt(st.nextToken());
  203. int skillId = Integer.parseInt(st.nextToken());
  204. int page = st.hasMoreTokens() ? Integer.parseInt(st.nextToken()) : 0;
  205. final L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcId);
  206. if (npc != null)
  207. {
  208. delNpcSkill(activeChar, npc, skillId, page);
  209. }
  210. else
  211. {
  212. activeChar.sendMessage("NPC does not exist or not loaded. ID:" + npcId);
  213. }
  214. }
  215. catch (NumberFormatException e)
  216. {
  217. activeChar.sendMessage("npc_id, skill_id and skill_lvl must all be numbers.");
  218. }
  219. break;
  220. }
  221. case "admin_show_drop_list":
  222. {
  223. if (st.countTokens() < 1)
  224. {
  225. activeChar.sendMessage("Usage: //show_drop_list <npc_id> <page>");
  226. return false;
  227. }
  228. try
  229. {
  230. int npcId = Integer.parseInt(st.nextToken());
  231. int page = st.hasMoreTokens() ? Integer.parseInt(st.nextToken()) : 0;
  232. final L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcId);
  233. if (npc != null)
  234. {
  235. showNpcDropList(activeChar, npc, page);
  236. }
  237. else
  238. {
  239. activeChar.sendMessage("NPC does not exist or not loaded. npc_id:" + npcId);
  240. }
  241. }
  242. catch (NumberFormatException e)
  243. {
  244. activeChar.sendMessage("npc_id must be a number.");
  245. }
  246. break;
  247. }
  248. case "admin_add_drop":
  249. {
  250. if (st.countTokens() < 6)
  251. {
  252. activeChar.sendMessage("Usage: //add_drop <npc_id> <item_id> <category> <min> <max> <chance>");
  253. return false;
  254. }
  255. try
  256. {
  257. int npcId = Integer.parseInt(st.nextToken());
  258. int itemId = Integer.parseInt(st.nextToken());
  259. int category = Integer.parseInt(st.nextToken());
  260. int min = Integer.parseInt(st.nextToken());
  261. int max = Integer.parseInt(st.nextToken());
  262. int chance = Integer.parseInt(st.nextToken());
  263. final L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcId);
  264. if (npc != null)
  265. {
  266. addNpcDrop(activeChar, npc, itemId, category, min, max, chance);
  267. }
  268. else
  269. {
  270. activeChar.sendMessage("NPC does not exist or not loaded. npc_id:" + npcId);
  271. }
  272. }
  273. catch (NumberFormatException e)
  274. {
  275. activeChar.sendMessage("npc_id must be a number.");
  276. }
  277. break;
  278. }
  279. case "admin_del_drop":
  280. {
  281. if (st.countTokens() < 3)
  282. {
  283. activeChar.sendMessage("Usage: //add_drop <npc_id> <item_id> <category> <min> <max> <chance>");
  284. return false;
  285. }
  286. try
  287. {
  288. int npcId = Integer.parseInt(st.nextToken());
  289. int category = Integer.parseInt(st.nextToken());
  290. int itemId = Integer.parseInt(st.nextToken());
  291. int page = st.hasMoreTokens() ? Integer.parseInt(st.nextToken()) : 0;
  292. final L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcId);
  293. if (npc != null)
  294. {
  295. delNpcDrop(activeChar, npc, category, itemId, page);
  296. }
  297. else
  298. {
  299. activeChar.sendMessage("NPC does not exist or not loaded. npc_id:" + npcId);
  300. }
  301. }
  302. catch (NumberFormatException e)
  303. {
  304. activeChar.sendMessage("npc_id must be a number.");
  305. }
  306. break;
  307. }
  308. case "admin_log_npc_spawn":
  309. {
  310. L2Object target = activeChar.getTarget();
  311. if (target instanceof L2Npc)
  312. {
  313. L2Npc npc = (L2Npc) target;
  314. _log.info("('', 1, " + npc.getId() + ", " + npc.getX() + ", " + npc.getY() + ", " + npc.getZ() + ", 0, 0, " + npc.getHeading() + ", 60, 0, 0),");
  315. }
  316. break;
  317. }
  318. }
  319. return true;
  320. }
  321. private void showNpcProperty(L2PcInstance activeChar, L2NpcTemplate npc, String category)
  322. {
  323. if (category.equalsIgnoreCase("stats") || category.equalsIgnoreCase("ai") || category.equalsIgnoreCase("elementals") || category.equalsIgnoreCase("visuals"))
  324. {
  325. NpcHtmlMessage html = new NpcHtmlMessage(5, 1);
  326. html.setFile(activeChar.getHtmlPrefix(), "data/html/admin/editnpc-" + category.toLowerCase() + ".htm");
  327. html.replace("%npcId%", String.valueOf(npc.getId()));
  328. html.replace("%title_npc_id%", String.valueOf(npc.getId()));
  329. html.replace("%title_npc_name%", String.valueOf(npc.getName()));
  330. switch (category.toLowerCase())
  331. {
  332. case "stats":
  333. {
  334. html.replace("%level%", String.valueOf(npc.getLevel()));
  335. html.replace("%exp%", String.valueOf(npc.getRewardExp()));
  336. html.replace("%sp%", String.valueOf(npc.getRewardSp()));
  337. html.replace("%hp%", String.valueOf(npc.getBaseHpMax()));
  338. html.replace("%mp%", String.valueOf(npc.getBaseMpMax()));
  339. html.replace("%hpreg%", String.valueOf(npc.getBaseHpReg()));
  340. html.replace("%mpreg%", String.valueOf(npc.getBaseMpReg()));
  341. html.replace("%patk%", String.valueOf(npc.getBasePAtk()));
  342. html.replace("%pdef%", String.valueOf(npc.getBasePDef()));
  343. html.replace("%matk%", String.valueOf(npc.getBaseMAtk()));
  344. html.replace("%mdef%", String.valueOf(npc.getBaseMDef()));
  345. html.replace("%atkspd%", String.valueOf(npc.getBasePAtkSpd()));
  346. html.replace("%matkspd%", String.valueOf(npc.getBaseMAtkSpd()));
  347. html.replace("%str%", String.valueOf(npc.getBaseSTR()));
  348. html.replace("%con%", String.valueOf(npc.getBaseCON()));
  349. html.replace("%dex%", String.valueOf(npc.getBaseDEX()));
  350. html.replace("%int%", String.valueOf(npc.getBaseINT()));
  351. html.replace("%wit%", String.valueOf(npc.getBaseWIT()));
  352. html.replace("%men%", String.valueOf(npc.getBaseMEN()));
  353. html.replace("%critical%", String.valueOf(npc.getBaseCritRate()));
  354. html.replace("%attackrange%", String.valueOf(npc.getBaseAttackRange()));
  355. html.replace("%walkspd%", String.valueOf(npc.getBaseMoveSpeed(MoveType.WALK)));
  356. html.replace("%runspd%", String.valueOf(npc.getBaseMoveSpeed(MoveType.RUN)));
  357. break;
  358. }
  359. case "ai":
  360. {
  361. html.replace("%aggro%", String.valueOf(npc.getAIDataStatic().getAggroRange()));
  362. html.replace("%clan%", String.valueOf(npc.getAIDataStatic().getClan()));
  363. html.replace("%clanRange%", String.valueOf(npc.getAIDataStatic().getClanRange()));
  364. html.replace("%enemyClan%", String.valueOf(npc.getAIDataStatic().getEnemyClan()));
  365. html.replace("%enemyRange%", String.valueOf(npc.getAIDataStatic().getEnemyRange()));
  366. html.replace("%dodge%", String.valueOf(npc.getAIDataStatic().getDodge()));
  367. html.replace("%canMove%", String.valueOf(npc.getAIDataStatic().getCanMove()));
  368. html.replace("%primarySkillId%", String.valueOf(npc.getAIDataStatic().getPrimarySkillId()));
  369. html.replace("%minSkillChance%", String.valueOf(npc.getAIDataStatic().getMinSkillChance()));
  370. html.replace("%maxSkillChance%", String.valueOf(npc.getAIDataStatic().getMaxSkillChance()));
  371. html.replace("%minRangeSkill%", String.valueOf(npc.getAIDataStatic().getShortRangeSkill()));
  372. html.replace("%minRangeChance%", String.valueOf(npc.getAIDataStatic().getShortRangeChance()));
  373. html.replace("%maxRangeSkill%", String.valueOf(npc.getAIDataStatic().getLongRangeSkill()));
  374. html.replace("%maxRangeChance%", String.valueOf(npc.getAIDataStatic().getLongRangeChance()));
  375. html.replace("%soulShot%", String.valueOf(npc.getAIDataStatic().getSoulShot()));
  376. html.replace("%ssChance%", String.valueOf(npc.getAIDataStatic().getSoulShotChance()));
  377. html.replace("%spiritShot%", String.valueOf(npc.getAIDataStatic().getSpiritShot()));
  378. html.replace("%spsChance%", String.valueOf(npc.getAIDataStatic().getSpiritShotChance()));
  379. html.replace("%isChaos%", String.valueOf(npc.getAIDataStatic().getIsChaos()));
  380. html.replace("%aiType%", String.valueOf(npc.getAIDataStatic().getAiType()));
  381. break;
  382. }
  383. case "elementals":
  384. {
  385. int elements[] =
  386. {
  387. npc.getBaseFire(),
  388. npc.getBaseWater(),
  389. npc.getBaseWind(),
  390. npc.getBaseEarth(),
  391. npc.getBaseHoly(),
  392. npc.getBaseDark()
  393. };
  394. byte attackAttribute = -1;
  395. int max_element = 0;
  396. for (byte i = 0; i < 6; i++)
  397. {
  398. if (elements[i] > max_element)
  399. {
  400. attackAttribute = i;
  401. max_element = elements[i];
  402. }
  403. }
  404. html.replace("%elemAtkType%", Elementals.getElementName(attackAttribute));
  405. html.replace("%elemAtkValue%", String.valueOf(attackAttribute != -1 ? elements[attackAttribute] : 0));
  406. html.replace("%fireDefValue%", String.valueOf(npc.getBaseFireRes()));
  407. html.replace("%waterDefValue%", String.valueOf(npc.getBaseWaterRes()));
  408. html.replace("%windDefValue%", String.valueOf(npc.getBaseWindRes()));
  409. html.replace("%earthDefValue%", String.valueOf(npc.getBaseEarthRes()));
  410. html.replace("%holyDefValue%", String.valueOf(npc.getBaseHolyRes()));
  411. html.replace("%darkDefValue%", String.valueOf(npc.getBaseDarkRes()));
  412. break;
  413. }
  414. case "visuals":
  415. {
  416. html.replace("%idTemplate%", String.valueOf(npc.getIdTemplate()));
  417. html.replace("%type%", String.valueOf(npc.getType()));
  418. html.replace("%showName%", String.valueOf(npc.getAIDataStatic().showName() ? 1 : 0));
  419. html.replace("%name%", npc.getName());
  420. html.replace("%serverSideName%", String.valueOf(npc.isServerSideName() ? 1 : 0));
  421. html.replace("%title%", npc.getTitle());
  422. html.replace("%serverSideTitle%", String.valueOf(npc.isServerSideTitle() ? 1 : 0));
  423. html.replace("%targetable%", String.valueOf(npc.getAIDataStatic().isTargetable() ? 1 : 0));
  424. html.replace("%rhand%", String.valueOf(npc.getRightHand()));
  425. html.replace("%lhand%", String.valueOf(npc.getLeftHand()));
  426. html.replace("%enchant%", String.valueOf(npc.getEnchantEffect()));
  427. html.replace("%collision_radius%", String.valueOf(npc.getCollisionRadius()));
  428. html.replace("%collision_height%", String.valueOf(npc.getCollisionHeight()));
  429. html.replace("%sex%", String.valueOf(npc.getSex()));
  430. html.replace("%dropHerbGroup%", String.valueOf(npc.getDropHerbGroup()));
  431. break;
  432. }
  433. }
  434. activeChar.sendPacket(html);
  435. }
  436. else
  437. {
  438. activeChar.sendMessage("category can only be stats, ai, elementals or visuals.");
  439. }
  440. }
  441. private void saveNpcProperty(L2PcInstance activeChar, L2NpcTemplate npc, String category, String statToSet, String value)
  442. {
  443. StatsSet newNpcData = new StatsSet();
  444. try
  445. {
  446. newNpcData.set("npcId", npc.getId());
  447. switch (statToSet)
  448. {
  449. case "serverSideName":
  450. case "serverSideTitle":
  451. {
  452. int intValue = Integer.parseInt(value);
  453. if ((intValue == 0) || (intValue == 1))
  454. {
  455. newNpcData.set(statToSet, intValue);
  456. }
  457. else
  458. {
  459. activeChar.sendMessage("Value of " + statToSet + " must be 0 or 1.");
  460. return;
  461. }
  462. break;
  463. }
  464. case "sex":
  465. {
  466. if (value.equalsIgnoreCase("male") || value.equalsIgnoreCase("female") || value.equalsIgnoreCase("etc"))
  467. {
  468. newNpcData.set(statToSet, value.toLowerCase());
  469. }
  470. else
  471. {
  472. activeChar.sendMessage("Value of " + statToSet + " must be male, female or etc.");
  473. return;
  474. }
  475. break;
  476. }
  477. case "enchant":
  478. {
  479. int intValue = Integer.parseInt(value);
  480. if ((intValue >= 0) && (intValue <= 50))
  481. {
  482. newNpcData.set(statToSet, intValue);
  483. }
  484. else
  485. {
  486. activeChar.sendMessage("Value of " + statToSet + " must be 0-50.");
  487. return;
  488. }
  489. break;
  490. }
  491. case "level":
  492. {
  493. int intValue = Integer.parseInt(value);
  494. if ((intValue >= 1) && (intValue <= 87))
  495. {
  496. newNpcData.set(statToSet, intValue);
  497. }
  498. else
  499. {
  500. activeChar.sendMessage("Value of " + statToSet + " must be 1-87.");
  501. return;
  502. }
  503. break;
  504. }
  505. case "str":
  506. case "con":
  507. case "dex":
  508. case "int":
  509. case "wit":
  510. case "men":
  511. {
  512. int intValue = Integer.parseInt(value);
  513. if ((intValue >= 1) && (intValue <= 99))
  514. {
  515. newNpcData.set(statToSet, intValue);
  516. }
  517. else
  518. {
  519. activeChar.sendMessage("Value of " + statToSet + " must be 1-99.");
  520. return;
  521. }
  522. break;
  523. }
  524. case "critical":
  525. {
  526. int intValue = Integer.parseInt(value);
  527. if ((intValue >= 1) && (intValue <= 127))
  528. {
  529. newNpcData.set(statToSet, intValue);
  530. }
  531. else
  532. {
  533. activeChar.sendMessage("Value of " + statToSet + " must be 1-127.");
  534. return;
  535. }
  536. break;
  537. }
  538. case "dropHerbGroup":
  539. {
  540. int intValue = Integer.parseInt(value);
  541. if ((intValue >= 0) && (intValue <= 127))
  542. {
  543. newNpcData.set(statToSet, intValue);
  544. }
  545. else
  546. {
  547. activeChar.sendMessage("Value of " + statToSet + " must be 0-127.");
  548. return;
  549. }
  550. break;
  551. }
  552. case "atkspd":
  553. case "matkspd":
  554. {
  555. int intValue = Integer.parseInt(value);
  556. if ((intValue >= 1) && (intValue <= 1000))
  557. {
  558. newNpcData.set(statToSet, intValue);
  559. }
  560. else
  561. {
  562. activeChar.sendMessage("Value of " + statToSet + " must be 1-1000.");
  563. return;
  564. }
  565. break;
  566. }
  567. case "attackrange":
  568. {
  569. int intValue = Integer.parseInt(value);
  570. if ((intValue >= 1) && (intValue <= 2000))
  571. {
  572. newNpcData.set(statToSet, intValue);
  573. }
  574. else
  575. {
  576. activeChar.sendMessage("Value of " + statToSet + " must be 1-2000.");
  577. return;
  578. }
  579. break;
  580. }
  581. case "rhand":
  582. case "lhand":
  583. {
  584. int intValue = Integer.parseInt(value);
  585. if ((intValue >= 0) && (intValue <= 65535))
  586. {
  587. newNpcData.set(statToSet, intValue);
  588. }
  589. else
  590. {
  591. activeChar.sendMessage("Value of " + statToSet + " must be 0-65535.");
  592. return;
  593. }
  594. break;
  595. }
  596. case "idTemplate":
  597. {
  598. int intValue = Integer.parseInt(value);
  599. if ((intValue >= 1) && (intValue <= 65535))
  600. {
  601. newNpcData.set(statToSet, intValue);
  602. }
  603. else
  604. {
  605. activeChar.sendMessage("Value of " + statToSet + " must be 1-65535.");
  606. return;
  607. }
  608. break;
  609. }
  610. case "exp":
  611. case "sp":
  612. {
  613. int intValue = Integer.parseInt(value);
  614. if ((intValue >= 0) && (intValue <= 2147483647))
  615. {
  616. newNpcData.set(statToSet, intValue);
  617. }
  618. else
  619. {
  620. activeChar.sendMessage("Value of " + statToSet + " must be 0-2147483647.");
  621. return;
  622. }
  623. break;
  624. }
  625. case "collision_radius":
  626. case "collision_height":
  627. {
  628. double doubleValue = Double.parseDouble(value);
  629. if ((doubleValue >= -9999.99) && (doubleValue <= 9999.99))
  630. {
  631. newNpcData.set(statToSet, doubleValue);
  632. }
  633. else
  634. {
  635. activeChar.sendMessage("Value of " + statToSet + " must be -9999.99-9999.99.");
  636. return;
  637. }
  638. break;
  639. }
  640. case "walkspd":
  641. case "runspd":
  642. {
  643. double doubleValue = Double.parseDouble(value);
  644. if ((doubleValue >= 0) && (doubleValue <= 99999.99999))
  645. {
  646. newNpcData.set(statToSet, doubleValue);
  647. }
  648. else
  649. {
  650. activeChar.sendMessage("Value of " + statToSet + " must be 0-99999.99999.");
  651. return;
  652. }
  653. break;
  654. }
  655. case "patk":
  656. case "pdef":
  657. case "matk":
  658. case "mdef":
  659. {
  660. double doubleValue = Double.parseDouble(value);
  661. if ((doubleValue >= 0) && (doubleValue <= 9999999.99999))
  662. {
  663. newNpcData.set(statToSet, doubleValue);
  664. }
  665. else
  666. {
  667. activeChar.sendMessage("Value of " + statToSet + " must be 0-9999999.99999.");
  668. return;
  669. }
  670. break;
  671. }
  672. case "hp":
  673. case "mp":
  674. case "hpreg":
  675. case "mpreg":
  676. {
  677. double doubleValue = Double.parseDouble(value);
  678. if ((doubleValue >= 0) && (doubleValue <= 999999999999999.999999999999999))
  679. {
  680. newNpcData.set(statToSet, doubleValue);
  681. }
  682. else
  683. {
  684. activeChar.sendMessage("Value of " + statToSet + " must be 0-999999999999999.999999999999999.");
  685. return;
  686. }
  687. break;
  688. }
  689. case "type":
  690. {
  691. if ((value.length() >= 1) && (value.length() <= 22))
  692. {
  693. Class.forName("com.l2jserver.gameserver.model.actor.instance." + value + "Instance");
  694. newNpcData.set(statToSet, value);
  695. }
  696. else
  697. {
  698. activeChar.sendMessage("Length of " + statToSet + " must be 1-22.");
  699. return;
  700. }
  701. break;
  702. }
  703. case "title":
  704. {
  705. if ((value.length() >= 0) && (value.length() <= 45))
  706. {
  707. newNpcData.set(statToSet, value);
  708. }
  709. else
  710. {
  711. activeChar.sendMessage("Length of " + statToSet + " must be 1-45.");
  712. return;
  713. }
  714. break;
  715. }
  716. case "name":
  717. {
  718. if ((value.length() >= 0) && (value.length() <= 200))
  719. {
  720. newNpcData.set(statToSet, value);
  721. }
  722. else
  723. {
  724. activeChar.sendMessage("Length of " + statToSet + " must be 1-200.");
  725. return;
  726. }
  727. break;
  728. }
  729. case "canMove":
  730. case "targetable":
  731. case "showName":
  732. case "isChaos":
  733. {
  734. int intValue = Integer.parseInt(value);
  735. if ((intValue == 0) || (intValue == 1))
  736. {
  737. newNpcData.set(statToSet, intValue);
  738. }
  739. else
  740. {
  741. activeChar.sendMessage("Value of " + statToSet + " must be 0 or 1.");
  742. return;
  743. }
  744. break;
  745. }
  746. case "dodge":
  747. case "minSkillChance":
  748. case "maxSkillChance":
  749. case "minRangeChance":
  750. case "maxRangeChance":
  751. case "ssChance":
  752. case "spsChance":
  753. {
  754. int intValue = Integer.parseInt(value);
  755. if ((intValue >= 0) && (intValue <= 100))
  756. {
  757. newNpcData.set(statToSet, intValue);
  758. }
  759. else
  760. {
  761. activeChar.sendMessage("Value of " + statToSet + " must be 0-100.");
  762. return;
  763. }
  764. break;
  765. }
  766. case "aggro":
  767. case "clanRange":
  768. case "enemyRange":
  769. {
  770. int intValue = Integer.parseInt(value);
  771. if ((intValue >= 0) && (intValue <= 3000))
  772. {
  773. newNpcData.set(statToSet, intValue);
  774. }
  775. else
  776. {
  777. activeChar.sendMessage("Value of " + statToSet + " must be 0-3000.");
  778. return;
  779. }
  780. break;
  781. }
  782. case "primarySkillId":
  783. case "minRangeSkill":
  784. case "maxRangeSkill":
  785. case "soulShot":
  786. case "spiritShot":
  787. {
  788. int intValue = Integer.parseInt(value);
  789. if ((intValue >= 0) && (intValue <= 65535))
  790. {
  791. newNpcData.set(statToSet, intValue);
  792. }
  793. else
  794. {
  795. activeChar.sendMessage("Value of " + statToSet + " must be 0-65535.");
  796. return;
  797. }
  798. break;
  799. }
  800. case "clan":
  801. case "enemyClan":
  802. {
  803. if (value.isEmpty())
  804. {
  805. newNpcData.set(statToSet, "null");
  806. }
  807. else if ((value.length() >= 1) && (value.length() <= 40))
  808. {
  809. newNpcData.set(statToSet, value);
  810. }
  811. else
  812. {
  813. activeChar.sendMessage("Length of " + statToSet + " must be 1-40 or empty for null.");
  814. return;
  815. }
  816. break;
  817. }
  818. case "aiType":
  819. {
  820. switch (value)
  821. {
  822. case "fighter":
  823. case "archer":
  824. case "mage":
  825. case "healer":
  826. case "balanced":
  827. case "corpse":
  828. {
  829. newNpcData.set(statToSet, value);
  830. break;
  831. }
  832. default:
  833. {
  834. activeChar.sendMessage("Value of " + statToSet + " must be fighter, archer, mage, healer, balanced, or corpse.");
  835. return;
  836. }
  837. }
  838. break;
  839. }
  840. case "elemAtkType":
  841. {
  842. switch (value)
  843. {
  844. case "fire":
  845. {
  846. newNpcData.set(statToSet, Elementals.FIRE);
  847. break;
  848. }
  849. case "water":
  850. {
  851. newNpcData.set(statToSet, Elementals.WATER);
  852. break;
  853. }
  854. case "earth":
  855. {
  856. newNpcData.set(statToSet, Elementals.EARTH);
  857. break;
  858. }
  859. case "wind":
  860. {
  861. newNpcData.set(statToSet, Elementals.WIND);
  862. break;
  863. }
  864. case "holy":
  865. {
  866. newNpcData.set(statToSet, Elementals.HOLY);
  867. break;
  868. }
  869. case "dark":
  870. {
  871. newNpcData.set(statToSet, Elementals.DARK);
  872. break;
  873. }
  874. default:
  875. {
  876. activeChar.sendMessage("Value of " + statToSet + " must be fire, water, earth, wind, holy or dark.");
  877. return;
  878. }
  879. }
  880. break;
  881. }
  882. case "elemAtkValue":
  883. case "fireDefValue":
  884. case "waterDefValue":
  885. case "windDefValue":
  886. case "earthDefValue":
  887. case "holyDefValue":
  888. case "darkDefValue":
  889. {
  890. int intValue = Integer.parseInt(value);
  891. if ((intValue >= 0) && (intValue <= 3000))
  892. {
  893. newNpcData.set(statToSet, intValue);
  894. }
  895. else
  896. {
  897. activeChar.sendMessage("Value of " + statToSet + " must be 0-3000.");
  898. return;
  899. }
  900. break;
  901. }
  902. default:
  903. {
  904. activeChar.sendMessage("Unknown stat " + statToSet + " can't set.");
  905. return;
  906. }
  907. }
  908. NpcTable.getInstance().saveNpc(newNpcData);
  909. showNpcProperty(activeChar, npc, category);
  910. }
  911. catch (Exception e)
  912. {
  913. activeChar.sendMessage("Could not set npc property. npc_id:" + npc.getId() + " stat:" + statToSet + " value:" + value);
  914. }
  915. }
  916. private void showNpcSkillList(L2PcInstance activeChar, L2NpcTemplate npc, int page)
  917. {
  918. final int PAGE_SIZE = 20;
  919. NpcHtmlMessage html = new NpcHtmlMessage(5, 1);
  920. html.setFile(activeChar.getHtmlPrefix(), "data/html/admin/editnpc-skills.htm");
  921. html.replace("%npcId%", String.valueOf(npc.getId()));
  922. html.replace("%title_npc_name%", String.valueOf(npc.getName()));
  923. html.replace("%page%", String.valueOf(page + 1));
  924. final Map<Integer, L2Skill> skills = npc.getSkills();
  925. int pages = skills.size() / PAGE_SIZE;
  926. if ((PAGE_SIZE * pages) < skills.size())
  927. {
  928. pages++;
  929. }
  930. if (pages > 1)
  931. {
  932. StringBuilder sb = new StringBuilder();
  933. sb.append("<table width=280 cellspacing=0><tr>");
  934. for (int i = 0; i < pages; i++)
  935. {
  936. sb.append("<td align=center><button action=\"bypass admin_show_skill_list_npc " + npc.getId() + " " + i + "\" value=\"" + (i + 1) + "\" width=30 height=22 back=\"L2UI_CT1.Button_DF_Down\" fore=\"L2UI_CT1.Button_DF\"></td>");
  937. }
  938. sb.append("</tr></table>");
  939. html.replace("%pages%", sb.toString());
  940. }
  941. else
  942. {
  943. html.replace("%pages%", "");
  944. }
  945. if (page >= pages)
  946. {
  947. page = pages - 1;
  948. }
  949. int start = 0;
  950. if (page > 0)
  951. {
  952. start = PAGE_SIZE * page;
  953. }
  954. int i = 0;
  955. StringBuilder sb = new StringBuilder(Math.min(PAGE_SIZE, skills.size()) * 550);
  956. for (L2Skill skill : skills.values())
  957. {
  958. if (i < start)
  959. {
  960. i++;
  961. continue;
  962. }
  963. sb.append("<table width=277 height=32 cellspacing=0 background=\"L2UI_CT1.Windows.Windows_DF_TooltipBG\">");
  964. sb.append("<tr><td fixwidth=32 background=\"" + skill.getIcon() + "\"></td>");
  965. sb.append("<td fixwidth=110>");
  966. sb.append(skill.getName());
  967. sb.append("</td>");
  968. sb.append("<td fixwidth=45 align=center>");
  969. sb.append(skill.getId());
  970. sb.append("</td>");
  971. sb.append("<td fixwidth=35 align=center>");
  972. sb.append(skill.getLevel());
  973. sb.append("</td>");
  974. sb.append("<td fixwidth=45>");
  975. sb.append("<button action=\"bypass admin_del_skill_npc " + npc.getId() + " " + skill.getId() + " " + page + "\" value=\"Delete\" width=45 height=30 back=\"L2UI_CT1.Button_DF_Calculator_Down\" fore=\"L2UI_CT1.Button_DF_Calculator\">");
  976. sb.append("</td></tr></table>");
  977. i++;
  978. if (i >= (PAGE_SIZE + start))
  979. {
  980. break;
  981. }
  982. }
  983. html.replace("%skills%", sb.toString());
  984. activeChar.sendPacket(html);
  985. }
  986. private void addNpcSkill(L2PcInstance activeChar, L2NpcTemplate npc, L2Skill skill)
  987. {
  988. try (Connection con = L2DatabaseFactory.getInstance().getConnection())
  989. {
  990. String table_name = npc.isCustom() ? "custom_npcskills" : "npcskills";
  991. try (PreparedStatement ps = con.prepareStatement("INSERT INTO `" + table_name + "`(`npcid`, `skillid`, `level`) VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE `level` = ?"))
  992. {
  993. ps.setInt(1, npc.getId());
  994. ps.setInt(2, skill.getId());
  995. ps.setInt(3, skill.getLevel());
  996. ps.setInt(4, skill.getLevel());
  997. ps.executeUpdate();
  998. }
  999. NpcTable.getInstance().reloadNpc(npc.getId(), false, false, false, true, false, false);
  1000. showNpcSkillList(activeChar, npc, 0);
  1001. }
  1002. catch (SQLException e)
  1003. {
  1004. String message = "Could not store new skill to database. npc_id: " + npc.getId() + " skill_id: " + skill.getId() + " skill_lvl:" + skill.getLevel();
  1005. activeChar.sendMessage(message);
  1006. _log.log(Level.WARNING, message, e);
  1007. }
  1008. }
  1009. private void delNpcSkill(L2PcInstance activeChar, L2NpcTemplate npc, int skillId, int page)
  1010. {
  1011. try (Connection con = L2DatabaseFactory.getInstance().getConnection())
  1012. {
  1013. String table_name = npc.isCustom() ? "custom_npcskills" : "npcskills";
  1014. try (PreparedStatement ps = con.prepareStatement("DELETE FROM `" + table_name + "` WHERE `npcid` = ? AND `skillid` = ?"))
  1015. {
  1016. ps.setInt(1, npc.getId());
  1017. ps.setInt(2, skillId);
  1018. ps.executeUpdate();
  1019. }
  1020. NpcTable.getInstance().reloadNpc(npc.getId(), false, false, false, true, false, false);
  1021. showNpcSkillList(activeChar, npc, page);
  1022. }
  1023. catch (SQLException e)
  1024. {
  1025. String message = "Could not delete skill from database. npc_id: " + npc.getId() + " skill_id: " + skillId;
  1026. activeChar.sendMessage(message);
  1027. _log.log(Level.WARNING, message, e);
  1028. }
  1029. }
  1030. private void showNpcDropList(L2PcInstance activeChar, L2NpcTemplate npc, int page)
  1031. {
  1032. final int PAGE_SIZE = 20;
  1033. NpcHtmlMessage html = new NpcHtmlMessage(5, 1);
  1034. html.setFile(activeChar.getHtmlPrefix(), "data/html/admin/editnpc-drops.htm");
  1035. html.replace("%npcId%", String.valueOf(npc.getId()));
  1036. html.replace("%title_npc_name%", String.valueOf(npc.getName()));
  1037. html.replace("%page%", String.valueOf(page + 1));
  1038. int itemCount = 0;
  1039. final List<L2DropCategory> dropCategories = npc.getDropData();
  1040. for (L2DropCategory dropCategory : dropCategories)
  1041. {
  1042. itemCount += dropCategory.getAllDrops().size();
  1043. }
  1044. int pages = itemCount / PAGE_SIZE;
  1045. if ((PAGE_SIZE * pages) < itemCount)
  1046. {
  1047. pages++;
  1048. }
  1049. if (pages > 1)
  1050. {
  1051. StringBuilder sb = new StringBuilder();
  1052. sb.append("<table width=280 cellspacing=0><tr>");
  1053. for (int i = 0; i < pages; i++)
  1054. {
  1055. sb.append("<td align=center><button action=\"bypass admin_show_drop_list " + npc.getId() + " " + i + "\" value=\"" + (i + 1) + "\" width=30 height=22 back=\"L2UI_CT1.Button_DF_Down\" fore=\"L2UI_CT1.Button_DF\"></td>");
  1056. }
  1057. sb.append("</tr></table>");
  1058. html.replace("%pages%", sb.toString());
  1059. }
  1060. else
  1061. {
  1062. html.replace("%pages%", "");
  1063. }
  1064. if (page >= pages)
  1065. {
  1066. page = pages - 1;
  1067. }
  1068. int start = 0;
  1069. if (page > 0)
  1070. {
  1071. start = PAGE_SIZE * page;
  1072. }
  1073. int i = 0;
  1074. StringBuilder sb = new StringBuilder(Math.min(PAGE_SIZE, itemCount) * 650);
  1075. for (L2DropCategory dropCategory : dropCategories)
  1076. {
  1077. for (L2DropData dropData : dropCategory.getAllDrops())
  1078. {
  1079. if (i < start)
  1080. {
  1081. i++;
  1082. continue;
  1083. }
  1084. final L2Item item = ItemTable.getInstance().getTemplate(dropData.getItemId());
  1085. if (item == null)
  1086. {
  1087. continue;
  1088. }
  1089. sb.append("Name: <font color=\"LEVEL\">[" + item.getName() + "]</font> ID: <font color=\"LEVEL\">[" + item.getItemId() + "]</font> Category: <font color=\"LEVEL\">[" + dropCategory.getCategoryType() + "]</font>");
  1090. sb.append("<table width=277 height=32 cellspacing=0 background=\"L2UI_CT1.Windows.Windows_DF_TooltipBG\">");
  1091. sb.append("<tr><td fixwidth=32 background=\"" + item.getIcon() + "\"></td>");
  1092. sb.append("<td fixwidth=64 align=center>");
  1093. sb.append(dropData.getMinDrop());
  1094. sb.append("</td>");
  1095. sb.append("<td fixwidth=64 align=center>");
  1096. sb.append(dropData.getMaxDrop());
  1097. sb.append("</td>");
  1098. sb.append("<td fixwidth=60 align=center>");
  1099. sb.append(dropData.getChance());
  1100. sb.append("</td>");
  1101. sb.append("<td fixwidth=45>");
  1102. sb.append("<button action=\"bypass admin_del_drop " + npc.getId() + " " + dropCategory.getCategoryType() + " " + item.getItemId() + " " + page + "\" value=\"Delete\" width=45 height=30 back=\"L2UI_CT1.Button_DF_Calculator_Down\" fore=\"L2UI_CT1.Button_DF_Calculator\">");
  1103. sb.append("</td></tr></table>");
  1104. i++;
  1105. if (i >= (PAGE_SIZE + start))
  1106. {
  1107. break;
  1108. }
  1109. }
  1110. if (i >= (PAGE_SIZE + start))
  1111. {
  1112. break;
  1113. }
  1114. }
  1115. html.replace("%drops%", sb.toString());
  1116. activeChar.sendPacket(html);
  1117. }
  1118. private void addNpcDrop(L2PcInstance activeChar, L2NpcTemplate npc, int itemId, int category, int min, int max, int chance)
  1119. {
  1120. try (Connection con = L2DatabaseFactory.getInstance().getConnection())
  1121. {
  1122. String table_name = npc.isCustom() ? "custom_droplist" : "droplist";
  1123. try (PreparedStatement ps = con.prepareStatement("INSERT INTO `" + table_name + "`(`mobId`, `itemId`, `min`, `max`, `category`, `chance`) VALUES(?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE `min` = ?, `max` = ?, `chance` = ?"))
  1124. {
  1125. ps.setInt(1, npc.getId());
  1126. ps.setInt(2, itemId);
  1127. ps.setInt(3, min);
  1128. ps.setInt(4, max);
  1129. ps.setInt(5, category);
  1130. ps.setInt(6, chance);
  1131. ps.setInt(7, min);
  1132. ps.setInt(8, max);
  1133. ps.setInt(9, chance);
  1134. ps.executeUpdate();
  1135. }
  1136. NpcTable.getInstance().reloadNpc(npc.getId(), false, false, false, false, true, false);
  1137. showNpcDropList(activeChar, npc, 0);
  1138. }
  1139. catch (SQLException e)
  1140. {
  1141. String message = "Could not store new drop to database. npc_id: " + npc.getId() + " item_id: " + itemId;
  1142. activeChar.sendMessage(message);
  1143. _log.log(Level.WARNING, message, e);
  1144. }
  1145. }
  1146. private void delNpcDrop(L2PcInstance activeChar, L2NpcTemplate npc, int category, int itemId, int page)
  1147. {
  1148. try (Connection con = L2DatabaseFactory.getInstance().getConnection())
  1149. {
  1150. String table_name = npc.isCustom() ? "custom_droplist" : "droplist";
  1151. try (PreparedStatement ps = con.prepareStatement("DELETE FROM `" + table_name + "` WHERE `mobId` = ? AND `category` = ? AND `itemId` = ?"))
  1152. {
  1153. ps.setInt(1, npc.getId());
  1154. ps.setInt(2, category);
  1155. ps.setInt(3, itemId);
  1156. ps.executeUpdate();
  1157. }
  1158. NpcTable.getInstance().reloadNpc(npc.getId(), false, false, false, false, true, false);
  1159. showNpcDropList(activeChar, npc, page);
  1160. }
  1161. catch (SQLException e)
  1162. {
  1163. String message = "Could not delete drop from database. npc_id: " + npc.getId() + " category: " + category + " item_id:" + itemId;
  1164. activeChar.sendMessage(message);
  1165. _log.log(Level.WARNING, message, e);
  1166. }
  1167. }
  1168. @Override
  1169. public String[] getAdminCommandList()
  1170. {
  1171. return ADMIN_COMMANDS;
  1172. }
  1173. }