Util.java 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. /*
  2. * Copyright (C) 2004-2015 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.util;
  20. import java.io.File;
  21. import java.text.DateFormat;
  22. import java.text.DecimalFormat;
  23. import java.text.DecimalFormatSymbols;
  24. import java.text.NumberFormat;
  25. import java.text.SimpleDateFormat;
  26. import java.util.Arrays;
  27. import java.util.Collection;
  28. import java.util.Date;
  29. import java.util.Locale;
  30. import java.util.StringJoiner;
  31. import java.util.logging.Logger;
  32. import com.l2jserver.Config;
  33. import com.l2jserver.gameserver.GeoData;
  34. import com.l2jserver.gameserver.ThreadPoolManager;
  35. import com.l2jserver.gameserver.enums.HtmlActionScope;
  36. import com.l2jserver.gameserver.enums.IllegalActionPunishmentType;
  37. import com.l2jserver.gameserver.model.L2Object;
  38. import com.l2jserver.gameserver.model.actor.L2Character;
  39. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  40. import com.l2jserver.gameserver.model.actor.tasks.player.IllegalPlayerActionTask;
  41. import com.l2jserver.gameserver.model.interfaces.ILocational;
  42. import com.l2jserver.gameserver.network.serverpackets.AbstractHtmlPacket;
  43. import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
  44. import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
  45. import com.l2jserver.util.file.filter.ExtFilter;
  46. /**
  47. * General Utility functions related to game server.
  48. */
  49. public final class Util
  50. {
  51. private static final Logger LOGGER = Logger.getLogger(Util.class.getName());
  52. private static final NumberFormat ADENA_FORMATTER = NumberFormat.getIntegerInstance(Locale.ENGLISH);
  53. public static void handleIllegalPlayerAction(L2PcInstance actor, String message, IllegalActionPunishmentType punishment)
  54. {
  55. ThreadPoolManager.getInstance().scheduleGeneral(new IllegalPlayerActionTask(actor, message, punishment), 5000);
  56. }
  57. public static String getRelativePath(File base, File file)
  58. {
  59. return file.toURI().getPath().substring(base.toURI().getPath().length());
  60. }
  61. /**
  62. * @param from
  63. * @param to
  64. * @return degree value of object 2 to the horizontal line with object 1 being the origin.
  65. */
  66. public static double calculateAngleFrom(ILocational from, ILocational to)
  67. {
  68. return calculateAngleFrom(from.getX(), from.getY(), to.getX(), to.getY());
  69. }
  70. /**
  71. * @param fromX
  72. * @param fromY
  73. * @param toX
  74. * @param toY
  75. * @return degree value of object 2 to the horizontal line with object 1 being the origin
  76. */
  77. public static final double calculateAngleFrom(int fromX, int fromY, int toX, int toY)
  78. {
  79. double angleTarget = Math.toDegrees(Math.atan2(toY - fromY, toX - fromX));
  80. if (angleTarget < 0)
  81. {
  82. angleTarget = 360 + angleTarget;
  83. }
  84. return angleTarget;
  85. }
  86. public static final double convertHeadingToDegree(int clientHeading)
  87. {
  88. double degree = clientHeading / 182.044444444;
  89. return degree;
  90. }
  91. public static final int convertDegreeToClientHeading(double degree)
  92. {
  93. if (degree < 0)
  94. {
  95. degree = 360 + degree;
  96. }
  97. return (int) (degree * 182.044444444);
  98. }
  99. public static final int calculateHeadingFrom(ILocational from, ILocational to)
  100. {
  101. return calculateHeadingFrom(from.getX(), from.getY(), to.getX(), to.getY());
  102. }
  103. public static final int calculateHeadingFrom(int fromX, int fromY, int toX, int toY)
  104. {
  105. double angleTarget = Math.toDegrees(Math.atan2(toY - fromY, toX - fromX));
  106. if (angleTarget < 0)
  107. {
  108. angleTarget = 360 + angleTarget;
  109. }
  110. return (int) (angleTarget * 182.044444444);
  111. }
  112. public static final int calculateHeadingFrom(double dx, double dy)
  113. {
  114. double angleTarget = Math.toDegrees(Math.atan2(dy, dx));
  115. if (angleTarget < 0)
  116. {
  117. angleTarget = 360 + angleTarget;
  118. }
  119. return (int) (angleTarget * 182.044444444);
  120. }
  121. /**
  122. * Calculates distance between one set of x, y, z and another set of x, y, z.
  123. * @param x1 - X coordinate of first point.
  124. * @param y1 - Y coordinate of first point.
  125. * @param z1 - Z coordinate of first point.
  126. * @param x2 - X coordinate of second point.
  127. * @param y2 - Y coordinate of second point.
  128. * @param z2 - Z coordinate of second point.
  129. * @param includeZAxis - If set to true, Z coordinates will be included.
  130. * @param squared - If set to true, distance returned will be squared.
  131. * @return {@code double} - Distance between object and given x, y , z.
  132. */
  133. public static double calculateDistance(double x1, double y1, double z1, double x2, double y2, double z2, boolean includeZAxis, boolean squared)
  134. {
  135. final double distance = Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) + (includeZAxis ? Math.pow(z1 - z2, 2) : 0);
  136. return (squared) ? distance : Math.sqrt(distance);
  137. }
  138. /**
  139. * Calculates distance between 2 locations.
  140. * @param loc1 - First location.
  141. * @param loc2 - Second location.
  142. * @param includeZAxis - If set to true, Z coordinates will be included.
  143. * @param squared - If set to true, distance returned will be squared.
  144. * @return {@code double} - Distance between object and given location.
  145. */
  146. public static double calculateDistance(ILocational loc1, ILocational loc2, boolean includeZAxis, boolean squared)
  147. {
  148. return calculateDistance(loc1.getX(), loc1.getY(), loc1.getZ(), loc2.getX(), loc2.getY(), loc2.getZ(), includeZAxis, squared);
  149. }
  150. /**
  151. * @param str - the string whose first letter to capitalize
  152. * @return a string with the first letter of the {@code str} capitalized
  153. */
  154. public static String capitalizeFirst(String str)
  155. {
  156. if ((str == null) || str.isEmpty())
  157. {
  158. return str;
  159. }
  160. final char[] arr = str.toCharArray();
  161. final char c = arr[0];
  162. if (Character.isLetter(c))
  163. {
  164. arr[0] = Character.toUpperCase(c);
  165. }
  166. return new String(arr);
  167. }
  168. /**
  169. * (Based on ucwords() function of PHP)<br>
  170. * DrHouse: still functional but must be rewritten to avoid += to concat strings
  171. * @param str - the string to capitalize
  172. * @return a string with the first letter of every word in {@code str} capitalized
  173. */
  174. @Deprecated
  175. public static String capitalizeWords(String str)
  176. {
  177. if ((str == null) || str.isEmpty())
  178. {
  179. return str;
  180. }
  181. char[] charArray = str.toCharArray();
  182. StringBuilder result = new StringBuilder();
  183. // Capitalize the first letter in the given string!
  184. charArray[0] = Character.toUpperCase(charArray[0]);
  185. for (int i = 0; i < charArray.length; i++)
  186. {
  187. if (Character.isWhitespace(charArray[i]))
  188. {
  189. charArray[i + 1] = Character.toUpperCase(charArray[i + 1]);
  190. }
  191. result.append(charArray[i]);
  192. }
  193. return result.toString();
  194. }
  195. /**
  196. * @param range
  197. * @param obj1
  198. * @param obj2
  199. * @param includeZAxis
  200. * @return {@code true} if the two objects are within specified range between each other, {@code false} otherwise
  201. */
  202. public static boolean checkIfInRange(int range, L2Object obj1, L2Object obj2, boolean includeZAxis)
  203. {
  204. if ((obj1 == null) || (obj2 == null))
  205. {
  206. return false;
  207. }
  208. if (obj1.getInstanceId() != obj2.getInstanceId())
  209. {
  210. return false;
  211. }
  212. if (range == -1)
  213. {
  214. return true; // not limited
  215. }
  216. int rad = 0;
  217. if (obj1 instanceof L2Character)
  218. {
  219. rad += ((L2Character) obj1).getTemplate().getCollisionRadius();
  220. }
  221. if (obj2 instanceof L2Character)
  222. {
  223. rad += ((L2Character) obj2).getTemplate().getCollisionRadius();
  224. }
  225. double dx = obj1.getX() - obj2.getX();
  226. double dy = obj1.getY() - obj2.getY();
  227. double d = (dx * dx) + (dy * dy);
  228. if (includeZAxis)
  229. {
  230. double dz = obj1.getZ() - obj2.getZ();
  231. d += (dz * dz);
  232. }
  233. return d <= ((range * range) + (2 * range * rad) + (rad * rad));
  234. }
  235. /**
  236. * Checks if object is within short (sqrt(int.max_value)) radius, not using collisionRadius. Faster calculation than checkIfInRange if distance is short and collisionRadius isn't needed. Not for long distance checks (potential teleports, far away castles etc).
  237. * @param radius
  238. * @param obj1
  239. * @param obj2
  240. * @param includeZAxis if true, check also Z axis (3-dimensional check), otherwise only 2D
  241. * @return {@code true} if objects are within specified range between each other, {@code false} otherwise
  242. */
  243. public static boolean checkIfInShortRadius(int radius, L2Object obj1, L2Object obj2, boolean includeZAxis)
  244. {
  245. if ((obj1 == null) || (obj2 == null))
  246. {
  247. return false;
  248. }
  249. if (radius == -1)
  250. {
  251. return true; // not limited
  252. }
  253. int dx = obj1.getX() - obj2.getX();
  254. int dy = obj1.getY() - obj2.getY();
  255. if (includeZAxis)
  256. {
  257. int dz = obj1.getZ() - obj2.getZ();
  258. return ((dx * dx) + (dy * dy) + (dz * dz)) <= (radius * radius);
  259. }
  260. return ((dx * dx) + (dy * dy)) <= (radius * radius);
  261. }
  262. /**
  263. * @param str - the String to count
  264. * @return the number of "words" in a given string.
  265. */
  266. public static int countWords(String str)
  267. {
  268. return str.trim().split("\\s+").length;
  269. }
  270. /**
  271. * (Based on implode() in PHP)
  272. * @param strings an array of strings to concatenate
  273. * @param delimiter the delimiter to put between the strings
  274. * @return a delimited string for a given array of string elements.
  275. */
  276. public static String implodeString(Iterable<String> strings, String delimiter)
  277. {
  278. final StringJoiner sj = new StringJoiner(delimiter);
  279. strings.forEach(sj::add);
  280. return sj.toString();
  281. }
  282. /**
  283. * Based on implode() in PHP
  284. * @param <T>
  285. * @param array
  286. * @param delim
  287. * @return a delimited string for a given array of string elements.
  288. */
  289. public static <T> String implode(T[] array, String delim)
  290. {
  291. String result = "";
  292. for (T val : array)
  293. {
  294. result += val.toString() + delim;
  295. }
  296. if (!result.isEmpty())
  297. {
  298. result = result.substring(0, result.length() - 1);
  299. }
  300. return result;
  301. }
  302. /**
  303. * (Based on round() in PHP)
  304. * @param number - the number to round
  305. * @param numPlaces - how many digits after decimal point to leave intact
  306. * @return the value of {@code number} rounded to specified number of digits after the decimal point.
  307. */
  308. public static float roundTo(float number, int numPlaces)
  309. {
  310. if (numPlaces <= 1)
  311. {
  312. return Math.round(number);
  313. }
  314. float exponent = (float) Math.pow(10, numPlaces);
  315. return Math.round(number * exponent) / exponent;
  316. }
  317. /**
  318. * @param text - the text to check
  319. * @return {@code true} if {@code text} contains only numbers, {@code false} otherwise
  320. */
  321. public static boolean isDigit(String text)
  322. {
  323. if ((text == null) || text.isEmpty())
  324. {
  325. return false;
  326. }
  327. for (char c : text.toCharArray())
  328. {
  329. if (!Character.isDigit(c))
  330. {
  331. return false;
  332. }
  333. }
  334. return true;
  335. }
  336. /**
  337. * @param text - the text to check
  338. * @return {@code true} if {@code text} contains only letters and/or numbers, {@code false} otherwise
  339. */
  340. public static boolean isAlphaNumeric(String text)
  341. {
  342. if ((text == null) || text.isEmpty())
  343. {
  344. return false;
  345. }
  346. for (char c : text.toCharArray())
  347. {
  348. if (!Character.isLetterOrDigit(c))
  349. {
  350. return false;
  351. }
  352. }
  353. return true;
  354. }
  355. /**
  356. * Format the specified digit using the digit grouping symbol "," (comma).<br>
  357. * For example, 123456789 becomes 123,456,789.
  358. * @param amount - the amount of adena
  359. * @return the formatted adena amount
  360. */
  361. public static String formatAdena(long amount)
  362. {
  363. synchronized (ADENA_FORMATTER)
  364. {
  365. return ADENA_FORMATTER.format(amount);
  366. }
  367. }
  368. /**
  369. * @param val
  370. * @param format
  371. * @return formatted double value by specified format.
  372. */
  373. public static String formatDouble(double val, String format)
  374. {
  375. final DecimalFormat formatter = new DecimalFormat(format, new DecimalFormatSymbols(Locale.ENGLISH));
  376. return formatter.format(val);
  377. }
  378. /**
  379. * Format the given date on the given format
  380. * @param date : the date to format.
  381. * @param format : the format to correct by.
  382. * @return a string representation of the formatted date.
  383. */
  384. public static String formatDate(Date date, String format)
  385. {
  386. if (date == null)
  387. {
  388. return null;
  389. }
  390. final DateFormat dateFormat = new SimpleDateFormat(format);
  391. return dateFormat.format(date);
  392. }
  393. /**
  394. * @param <T>
  395. * @param array - the array to look into
  396. * @param obj - the object to search for
  397. * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise.
  398. */
  399. public static <T> boolean contains(T[] array, T obj)
  400. {
  401. for (T element : array)
  402. {
  403. if (element == obj)
  404. {
  405. return true;
  406. }
  407. }
  408. return false;
  409. }
  410. /**
  411. * @param array - the array to look into
  412. * @param obj - the integer to search for
  413. * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise
  414. */
  415. public static boolean contains(int[] array, int obj)
  416. {
  417. for (int element : array)
  418. {
  419. if (element == obj)
  420. {
  421. return true;
  422. }
  423. }
  424. return false;
  425. }
  426. public static File[] getDatapackFiles(String dirname, String extention)
  427. {
  428. File dir = new File(Config.DATAPACK_ROOT, "data/" + dirname);
  429. if (!dir.exists())
  430. {
  431. return null;
  432. }
  433. return dir.listFiles(new ExtFilter(extention));
  434. }
  435. public static String getDateString(Date date)
  436. {
  437. SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  438. return dateFormat.format(date.getTime());
  439. }
  440. private static final void buildHtmlBypassCache(L2PcInstance player, HtmlActionScope scope, String html)
  441. {
  442. String htmlLower = html.toLowerCase(Locale.ENGLISH);
  443. int bypassEnd = 0;
  444. int bypassStart = htmlLower.indexOf("=\"bypass ", bypassEnd);
  445. int bypassStartEnd;
  446. while (bypassStart != -1)
  447. {
  448. bypassStartEnd = bypassStart + 9;
  449. bypassEnd = htmlLower.indexOf("\"", bypassStartEnd);
  450. if (bypassEnd == -1)
  451. {
  452. break;
  453. }
  454. int hParamPos = htmlLower.indexOf("-h ", bypassStartEnd);
  455. String bypass;
  456. if ((hParamPos != -1) && (hParamPos < bypassEnd))
  457. {
  458. bypass = html.substring(hParamPos + 3, bypassEnd).trim();
  459. }
  460. else
  461. {
  462. bypass = html.substring(bypassStartEnd, bypassEnd).trim();
  463. }
  464. int firstParameterStart = bypass.indexOf(AbstractHtmlPacket.VAR_PARAM_START_CHAR);
  465. if (firstParameterStart != -1)
  466. {
  467. bypass = bypass.substring(0, firstParameterStart + 1);
  468. }
  469. if (Config.HTML_ACTION_CACHE_DEBUG)
  470. {
  471. LOGGER.info("Cached html bypass(" + scope.toString() + "): '" + bypass + "'");
  472. }
  473. player.addHtmlAction(scope, bypass);
  474. bypassStart = htmlLower.indexOf("=\"bypass ", bypassEnd);
  475. }
  476. }
  477. private static final void buildHtmlLinkCache(L2PcInstance player, HtmlActionScope scope, String html)
  478. {
  479. String htmlLower = html.toLowerCase(Locale.ENGLISH);
  480. int linkEnd = 0;
  481. int linkStart = htmlLower.indexOf("=\"link ", linkEnd);
  482. int linkStartEnd;
  483. while (linkStart != -1)
  484. {
  485. linkStartEnd = linkStart + 7;
  486. linkEnd = htmlLower.indexOf("\"", linkStartEnd);
  487. if (linkEnd == -1)
  488. {
  489. break;
  490. }
  491. String htmlLink = html.substring(linkStartEnd, linkEnd).trim();
  492. if (htmlLink.isEmpty())
  493. {
  494. LOGGER.warning("Html link path is empty!");
  495. continue;
  496. }
  497. if (htmlLink.contains(".."))
  498. {
  499. LOGGER.warning("Html link path is invalid: " + htmlLink);
  500. continue;
  501. }
  502. if (Config.HTML_ACTION_CACHE_DEBUG)
  503. {
  504. LOGGER.info("Cached html link(" + scope.toString() + "): '" + htmlLink + "'");
  505. }
  506. // let's keep an action cache with "link " lowercase literal kept
  507. player.addHtmlAction(scope, "link " + htmlLink);
  508. linkStart = htmlLower.indexOf("=\"link ", linkEnd);
  509. }
  510. }
  511. /**
  512. * Builds the html action cache for the specified scope.<br>
  513. * An {@code npcObjId} of 0 means, the cached actions can be clicked<br>
  514. * without beeing near an npc which is spawned in the world.
  515. * @param player the player to build the html action cache for
  516. * @param scope the scope to build the html action cache for
  517. * @param npcObjId the npc object id the html actions are cached for
  518. * @param html the html code to parse
  519. */
  520. public static void buildHtmlActionCache(L2PcInstance player, HtmlActionScope scope, int npcObjId, String html)
  521. {
  522. if ((player == null) || (scope == null) || (npcObjId < 0) || (html == null))
  523. {
  524. throw new IllegalArgumentException();
  525. }
  526. if (Config.HTML_ACTION_CACHE_DEBUG)
  527. {
  528. LOGGER.info("Set html action npc(" + scope.toString() + "): " + npcObjId);
  529. }
  530. player.setHtmlActionOriginObjectId(scope, npcObjId);
  531. buildHtmlBypassCache(player, scope, html);
  532. buildHtmlLinkCache(player, scope, html);
  533. }
  534. /**
  535. * Helper method to send a NpcHtmlMessage to the specified player.
  536. * @param activeChar the player to send the html content to
  537. * @param html the html content
  538. */
  539. public static void sendHtml(L2PcInstance activeChar, String html)
  540. {
  541. final NpcHtmlMessage npcHtml = new NpcHtmlMessage();
  542. npcHtml.setHtml(html);
  543. activeChar.sendPacket(npcHtml);
  544. }
  545. /**
  546. * Helper method to send a community board html to the specified player.<br>
  547. * HtmlActionCache will be build with npc origin 0 which means the<br>
  548. * links on the html are not bound to a specific npc.
  549. * @param activeChar the player
  550. * @param html the html content
  551. */
  552. public static void sendCBHtml(L2PcInstance activeChar, String html)
  553. {
  554. sendCBHtml(activeChar, html, 0);
  555. }
  556. /**
  557. * Helper method to send a community board html to the specified player.<br>
  558. * When {@code npcObjId} is greater -1 the HtmlActionCache will be build<br>
  559. * with the npcObjId as origin. An origin of 0 means the cached bypasses<br>
  560. * are not bound to a specific npc.
  561. * @param activeChar the player to send the html content to
  562. * @param html the html content
  563. * @param npcObjId bypass origin to use
  564. */
  565. public static void sendCBHtml(L2PcInstance activeChar, String html, int npcObjId)
  566. {
  567. sendCBHtml(activeChar, html, null, npcObjId);
  568. }
  569. /**
  570. * Helper method to send a community board html to the specified player.<br>
  571. * HtmlActionCache will be build with npc origin 0 which means the<br>
  572. * links on the html are not bound to a specific npc. It also fills a<br>
  573. * multiedit field in the send html if fillMultiEdit is not null.
  574. * @param activeChar the player
  575. * @param html the html content
  576. * @param fillMultiEdit text to fill the multiedit field with(may be null)
  577. */
  578. public static void sendCBHtml(L2PcInstance activeChar, String html, String fillMultiEdit)
  579. {
  580. sendCBHtml(activeChar, html, fillMultiEdit, 0);
  581. }
  582. /**
  583. * Helper method to send a community board html to the specified player.<br>
  584. * It fills a multiedit field in the send html if {@code fillMultiEdit}<br>
  585. * is not null. When {@code npcObjId} is greater -1 the HtmlActionCache will be build<br>
  586. * with the npcObjId as origin. An origin of 0 means the cached bypasses<br>
  587. * are not bound to a specific npc.
  588. * @param activeChar the player
  589. * @param html the html content
  590. * @param fillMultiEdit text to fill the multiedit field with(may be null)
  591. * @param npcObjId bypass origin to use
  592. */
  593. public static void sendCBHtml(L2PcInstance activeChar, String html, String fillMultiEdit, int npcObjId)
  594. {
  595. if ((activeChar == null) || (html == null))
  596. {
  597. return;
  598. }
  599. activeChar.clearHtmlActions(HtmlActionScope.COMM_BOARD_HTML);
  600. if (npcObjId > -1)
  601. {
  602. buildHtmlActionCache(activeChar, HtmlActionScope.COMM_BOARD_HTML, npcObjId, html);
  603. }
  604. if (fillMultiEdit != null)
  605. {
  606. activeChar.sendPacket(new ShowBoard(html, "1001"));
  607. fillMultiEditContent(activeChar, fillMultiEdit);
  608. }
  609. else
  610. {
  611. if (html.length() < 16250)
  612. {
  613. activeChar.sendPacket(new ShowBoard(html, "101"));
  614. activeChar.sendPacket(new ShowBoard(null, "102"));
  615. activeChar.sendPacket(new ShowBoard(null, "103"));
  616. }
  617. else if (html.length() < (16250 * 2))
  618. {
  619. activeChar.sendPacket(new ShowBoard(html.substring(0, 16250), "101"));
  620. activeChar.sendPacket(new ShowBoard(html.substring(16250), "102"));
  621. activeChar.sendPacket(new ShowBoard(null, "103"));
  622. }
  623. else if (html.length() < (16250 * 3))
  624. {
  625. activeChar.sendPacket(new ShowBoard(html.substring(0, 16250), "101"));
  626. activeChar.sendPacket(new ShowBoard(html.substring(16250, 16250 * 2), "102"));
  627. activeChar.sendPacket(new ShowBoard(html.substring(16250 * 2), "103"));
  628. }
  629. else
  630. {
  631. activeChar.sendPacket(new ShowBoard("<html><body><br><center>Error: HTML was too long!</center></body></html>", "101"));
  632. activeChar.sendPacket(new ShowBoard(null, "102"));
  633. activeChar.sendPacket(new ShowBoard(null, "103"));
  634. }
  635. }
  636. }
  637. /**
  638. * Fills the community board's multiedit window with text. Must send after sendCBHtml
  639. * @param activeChar
  640. * @param text
  641. */
  642. public static void fillMultiEditContent(L2PcInstance activeChar, String text)
  643. {
  644. activeChar.sendPacket(new ShowBoard(Arrays.asList("0", "0", "0", "0", "0", "0", activeChar.getName(), Integer.toString(activeChar.getObjectId()), activeChar.getAccountName(), "9", " ", " ", text.replaceAll("<br>", Config.EOL), "0", "0", "0", "0")));
  645. }
  646. /**
  647. * Return the number of playable characters in a defined radius around the specified object.
  648. * @param range : the radius in which to look for players
  649. * @param npc : the object whose knownlist to check
  650. * @param playable : if {@code true}, count summons and pets aswell
  651. * @param invisible : if {@code true}, count invisible characters aswell
  652. * @return the number of targets found
  653. */
  654. public static int getPlayersCountInRadius(int range, L2Object npc, boolean playable, boolean invisible)
  655. {
  656. int count = 0;
  657. final Collection<L2Object> objs = npc.getKnownList().getKnownObjects().values();
  658. for (L2Object obj : objs)
  659. {
  660. if ((obj != null) && (playable && (obj.isPlayable() || obj.isPet())))
  661. {
  662. if (!invisible && obj.isInvisible())
  663. {
  664. continue;
  665. }
  666. final L2Character cha = (L2Character) obj;
  667. if (((cha.getZ() < (npc.getZ() - 100)) && (cha.getZ() > (npc.getZ() + 100))) || !(GeoData.getInstance().canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), npc.getX(), npc.getY(), npc.getZ())))
  668. {
  669. continue;
  670. }
  671. if (Util.checkIfInRange(range, npc, obj, true) && !cha.isDead())
  672. {
  673. count++;
  674. }
  675. }
  676. }
  677. return count;
  678. }
  679. public static boolean isInsideRangeOfObjectId(L2Object obj, int targetObjId, int radius)
  680. {
  681. L2Object target = obj.getKnownList().getKnownObjects().get(targetObjId);
  682. if (target == null)
  683. {
  684. return false;
  685. }
  686. if (obj.calculateDistance(target, false, false) > radius)
  687. {
  688. return false;
  689. }
  690. return true;
  691. }
  692. public static int min(int value1, int value2, int... values)
  693. {
  694. int min = Math.min(value1, value2);
  695. for (int value : values)
  696. {
  697. if (min > value)
  698. {
  699. min = value;
  700. }
  701. }
  702. return min;
  703. }
  704. public static int max(int value1, int value2, int... values)
  705. {
  706. int max = Math.max(value1, value2);
  707. for (int value : values)
  708. {
  709. if (max < value)
  710. {
  711. max = value;
  712. }
  713. }
  714. return max;
  715. }
  716. public static long min(long value1, long value2, long... values)
  717. {
  718. long min = Math.min(value1, value2);
  719. for (long value : values)
  720. {
  721. if (min > value)
  722. {
  723. min = value;
  724. }
  725. }
  726. return min;
  727. }
  728. public static long max(long value1, long value2, long... values)
  729. {
  730. long max = Math.max(value1, value2);
  731. for (long value : values)
  732. {
  733. if (max < value)
  734. {
  735. max = value;
  736. }
  737. }
  738. return max;
  739. }
  740. public static float min(float value1, float value2, float... values)
  741. {
  742. float min = Math.min(value1, value2);
  743. for (float value : values)
  744. {
  745. if (min > value)
  746. {
  747. min = value;
  748. }
  749. }
  750. return min;
  751. }
  752. public static float max(float value1, float value2, float... values)
  753. {
  754. float max = Math.max(value1, value2);
  755. for (float value : values)
  756. {
  757. if (max < value)
  758. {
  759. max = value;
  760. }
  761. }
  762. return max;
  763. }
  764. public static double min(double value1, double value2, double... values)
  765. {
  766. double min = Math.min(value1, value2);
  767. for (double value : values)
  768. {
  769. if (min > value)
  770. {
  771. min = value;
  772. }
  773. }
  774. return min;
  775. }
  776. public static double max(double value1, double value2, double... values)
  777. {
  778. double max = Math.max(value1, value2);
  779. for (double value : values)
  780. {
  781. if (max < value)
  782. {
  783. max = value;
  784. }
  785. }
  786. return max;
  787. }
  788. public static int getIndexOfMaxValue(int... array)
  789. {
  790. int index = 0;
  791. for (int i = 1; i < array.length; i++)
  792. {
  793. if (array[i] > array[index])
  794. {
  795. index = i;
  796. }
  797. }
  798. return index;
  799. }
  800. public static int getIndexOfMinValue(int... array)
  801. {
  802. int index = 0;
  803. for (int i = 1; i < array.length; i++)
  804. {
  805. if (array[i] < array[index])
  806. {
  807. index = i;
  808. }
  809. }
  810. return index;
  811. }
  812. /**
  813. * Re-Maps a value from one range to another.
  814. * @param input
  815. * @param inputMin
  816. * @param inputMax
  817. * @param outputMin
  818. * @param outputMax
  819. * @return The mapped value
  820. */
  821. public static int map(int input, int inputMin, int inputMax, int outputMin, int outputMax)
  822. {
  823. input = constrain(input, inputMin, inputMax);
  824. return (((input - inputMin) * (outputMax - outputMin)) / (inputMax - inputMin)) + outputMin;
  825. }
  826. /**
  827. * Re-Maps a value from one range to another.
  828. * @param input
  829. * @param inputMin
  830. * @param inputMax
  831. * @param outputMin
  832. * @param outputMax
  833. * @return The mapped value
  834. */
  835. public static long map(long input, long inputMin, long inputMax, long outputMin, long outputMax)
  836. {
  837. input = constrain(input, inputMin, inputMax);
  838. return (((input - inputMin) * (outputMax - outputMin)) / (inputMax - inputMin)) + outputMin;
  839. }
  840. /**
  841. * Re-Maps a value from one range to another.
  842. * @param input
  843. * @param inputMin
  844. * @param inputMax
  845. * @param outputMin
  846. * @param outputMax
  847. * @return The mapped value
  848. */
  849. public static double map(double input, double inputMin, double inputMax, double outputMin, double outputMax)
  850. {
  851. input = constrain(input, inputMin, inputMax);
  852. return (((input - inputMin) * (outputMax - outputMin)) / (inputMax - inputMin)) + outputMin;
  853. }
  854. /**
  855. * Constrains a number to be within a range.
  856. * @param input the number to constrain, all data types
  857. * @param min the lower end of the range, all data types
  858. * @param max the upper end of the range, all data types
  859. * @return input: if input is between min and max, min: if input is less than min, max: if input is greater than max
  860. */
  861. public static int constrain(int input, int min, int max)
  862. {
  863. return (input < min) ? min : (input > max) ? max : input;
  864. }
  865. /**
  866. * Constrains a number to be within a range.
  867. * @param input the number to constrain, all data types
  868. * @param min the lower end of the range, all data types
  869. * @param max the upper end of the range, all data types
  870. * @return input: if input is between min and max, min: if input is less than min, max: if input is greater than max
  871. */
  872. public static long constrain(long input, long min, long max)
  873. {
  874. return (input < min) ? min : (input > max) ? max : input;
  875. }
  876. /**
  877. * Constrains a number to be within a range.
  878. * @param input the number to constrain, all data types
  879. * @param min the lower end of the range, all data types
  880. * @param max the upper end of the range, all data types
  881. * @return input: if input is between min and max, min: if input is less than min, max: if input is greater than max
  882. */
  883. public static double constrain(double input, double min, double max)
  884. {
  885. return (input < min) ? min : (input > max) ? max : input;
  886. }
  887. /**
  888. * @param array - the array to look into
  889. * @param obj - the object to search for
  890. * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise.
  891. */
  892. public static boolean startsWith(String[] array, String obj)
  893. {
  894. for (String element : array)
  895. {
  896. if (element.startsWith(obj))
  897. {
  898. return true;
  899. }
  900. }
  901. return false;
  902. }
  903. /**
  904. * @param array - the array to look into
  905. * @param obj - the object to search for
  906. * @param ignoreCase
  907. * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise.
  908. */
  909. public static boolean contains(String[] array, String obj, boolean ignoreCase)
  910. {
  911. for (String element : array)
  912. {
  913. if (element.equals(obj) || (ignoreCase && element.equalsIgnoreCase(obj)))
  914. {
  915. return true;
  916. }
  917. }
  918. return false;
  919. }
  920. }