Utils.pm.svn-base
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:35k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Utility Functions
  3. #
  4. #  Copyright (c) 2004,2005,2006,2007 OpenKore Development Team
  5. #
  6. #  This software is open source, licensed under the GNU General Public
  7. #  License, version 2.
  8. #  Basically, this means that you're allowed to modify and distribute
  9. #  this software. However, if you distribute modified versions, you MUST
  10. #  also distribute the source code.
  11. #  See http://www.gnu.org/licenses/gpl.html for the full license.
  12. #########################################################################
  13. ##
  14. # MODULE DESCRIPTION: Utility functions
  15. #
  16. # This module contains various general-purpose and independant utility
  17. # functions. Functions in this module should have <b>no</b> dependancies
  18. # on other Kore modules.
  19. package Utils;
  20. use strict;
  21. use Time::HiRes qw(time usleep);
  22. use IO::Socket::INET;
  23. use Math::Trig;
  24. use Text::Wrap;
  25. use Scalar::Util;
  26. use Exporter;
  27. use base qw(Exporter);
  28. use Config;
  29. use FastUtils;
  30. use Globals qw(%config);
  31. use Utils::DataStructures (':all', '!/^binFind$/');
  32. our @EXPORT = (
  33. @{$Utils::DataStructures::EXPORT_TAGS{all}},
  34. # Math
  35. qw(calcPosFromTime calcPosition calcTime checkMovementDirection countSteps distance
  36. intToSignedInt intToSignedShort
  37. blockDistance getVector moveAlong moveAlongVector
  38. normalize vectorToDegree max min round ceil),
  39. # OS-specific
  40. qw(checkLaunchedApp launchApp launchScript),
  41. # Other stuff
  42. qw(dataWaiting dumpHash formatNumber getCoordString getCoordString2
  43. getFormattedDate getHex giveHex getRange getTickCount
  44. inRange judgeSkillArea makeCoords makeCoords2 makeDistMap makeIP encodeIP parseArgs
  45. quarkToString stringToQuark shiftPack swrite timeConvert timeOut
  46. urldecode urlencode unShiftPack vocalString wrapText pin_encode)
  47. );
  48. our %strings;
  49. our %quarks;
  50. ################################
  51. ################################
  52. ### CATEGORY: Math
  53. ################################
  54. ################################
  55. ##
  56. # calcPosFromTime(pos, pos_to, speed, time)
  57. #
  58. # Returns: the position where an actor moving from $pos to $pos_to with
  59. # the speed $speed will be in $time amount of time.
  60. # Walls are not considered.
  61. sub calcPosFromTime {
  62. my ($pos, $pos_to, $speed, $time) = @_;
  63. my $posX = $$pos{x};
  64. my $posY = $$pos{y};
  65. my $pos_toX = $$pos_to{x};
  66. my $pos_toY = $$pos_to{y};
  67. my $stepType = 0; # 1 - vertical or horizontal; 2 - diagonal
  68. my $s = 0; # step
  69. my %result;
  70. $result{x} = $pos_toX;
  71. $result{y} = $pos_toY;
  72. if (!$speed) {
  73. return %result;
  74. }
  75. while (1) {
  76. $s++;
  77. $stepType = 0;
  78. if ($posX < $pos_toX) {
  79. $posX++;
  80. $stepType++;
  81. }
  82. if ($posX > $pos_toX) {
  83. $posX--;
  84. $stepType++;
  85. }
  86. if ($posY < $pos_toY) {
  87. $posY++;
  88. $stepType++;
  89. }
  90. if ($posY > $pos_toY) {
  91. $posY--;
  92. $stepType++;
  93. }
  94. if ($stepType == 2) {
  95. $time -= sqrt(2) / $speed;
  96. } elsif ($stepType == 1) {
  97. $time -= 1 / $speed;
  98. } else {
  99. $s--;
  100. last;
  101. }
  102. if ($time < 0) {
  103. $s--;
  104. last;
  105. }
  106. }
  107. %result = moveAlong($pos, $pos_to, $s);
  108. return %result;
  109. }
  110. ##
  111. # calcTime(pos, pos_to, speed)
  112. #
  113. # Returns: time to move from $pos to $pos_to with $speed speed.
  114. # Walls are not considered.
  115. sub calcTime {
  116. my ($pos, $pos_to, $speed) = @_;
  117. my $posX = $$pos{x};
  118. my $posY = $$pos{y};
  119. my $pos_toX = $$pos_to{x};
  120. my $pos_toY = $$pos_to{y};
  121. my $stepType = 0; # 1 - vertical or horizontal; 2 - diagonal
  122. my $time = 0;
  123. return if (!$speed); # Make sure $speed actually has a non-zero value...
  124. while ($posX ne $pos_toX || $posY ne $pos_toY) {
  125. $stepType = 0;
  126. if ($posX < $pos_toX) {
  127. $posX++;
  128. $stepType++;
  129. }
  130. if ($posX > $pos_toX) {
  131. $posX--;
  132. $stepType++;
  133. }
  134. if ($posY < $pos_toY) {
  135. $posY++;
  136. $stepType++;
  137. }
  138. if ($posY > $pos_toY) {
  139. $posY--;
  140. $stepType++;
  141. }
  142. if ($stepType == 2) {
  143. $time += sqrt(2) / $speed;
  144. } elsif ($stepType == 1) {
  145. $time += 1 / $speed;
  146. }
  147. }
  148. return $time;
  149. }
  150. ##
  151. # calcPosition(object, [extra_time, float])
  152. # object: $char (yourself), or a value in %monsters or %players.
  153. # float: If set to 1, return coordinates as floating point.
  154. # Returns: reference to a position hash.
  155. #
  156. # The position information server that the server sends indicates a motion:
  157. # it says that an object is walking from A to B, and that it will arrive at B shortly.
  158. # This function calculates the current position of $object based on the motion information.
  159. #
  160. # If $extra_time is given, this function will calculate where $object will be
  161. # after $extra_time seconds.
  162. #
  163. # Example:
  164. # my $pos;
  165. # $pos = calcPosition($char);
  166. # print "You are currently at: $pos->{x}, $pos->{y}n";
  167. #
  168. # $pos = calcPosition($monsters{$ID});
  169. # # Calculate where the player will be after 2 seconds
  170. # $pos = calcPosition($players{$ID}, 2);
  171. sub calcPosition {
  172. my ($object, $extra_time, $float) = @_;
  173. my $time_needed = $object->{time_move_calc};
  174. my $elasped = time - $object->{time_move} + $extra_time;
  175. if ($elasped >= $time_needed || !$time_needed) {
  176. return $object->{pos_to};
  177. } else {
  178. my (%vec, %result, $dist);
  179. my $pos = $object->{pos};
  180. my $pos_to = $object->{pos_to};
  181. getVector(%vec, $pos_to, $pos);
  182. $dist = (distance($pos, $pos_to) - 1) * ($elasped / $time_needed);
  183. moveAlongVector(%result, $pos, %vec, $dist);
  184. $result{x} = int sprintf("%.0f", $result{x}) if (!$float);
  185. $result{y} = int sprintf("%.0f", $result{y}) if (!$float);
  186. return %result;
  187. }
  188. }
  189. ##
  190. # checkMovementDirection(pos1, vec, pos2, fuzziness)
  191. #
  192. # Check whether an object - which is moving into the direction of vector $vec,
  193. # and is currently at position $pos1 - is moving towards $pos2.
  194. #
  195. # Example:
  196. # # Get monster movement direction
  197. # my %vec;
  198. # getVector(%vec, $monster->{pos_to}, $monster->{pos});
  199. # if (checkMovementDirection($monster->{pos}, %vec, $char->{pos}, 15)) {
  200. #  warning "Monster $monster->{name} is moving towards youn";
  201. #}
  202. sub checkMovementDirection {
  203. my ($pos1, $vec, $pos2, $fuzziness) = @_;
  204. my %objVec;
  205. getVector(%objVec, $pos2, $pos1);
  206. my $movementDegree = vectorToDegree($vec);
  207. my $obj1ToObj2Degree = vectorToDegree(%objVec);
  208. return abs($obj1ToObj2Degree - $movementDegree) <= $fuzziness ||
  209. (($obj1ToObj2Degree - $movementDegree) % 360) <= $fuzziness;
  210. }
  211. ##
  212. # countSteps(pos, pos_to)
  213. #
  214. # Returns: the number of steps from $pos to $pos_to.
  215. # Walls are not considered.
  216. sub countSteps {
  217. my ($pos, $pos_to) = @_;
  218. my $posX = $$pos{x};
  219. my $posY = $$pos{y};
  220. my $pos_toX = $$pos_to{x};
  221. my $pos_toY = $$pos_to{y};
  222. my $s = 0; # steps
  223. while ($posX ne $pos_toX || $posY ne $pos_toY) {
  224. $s++;
  225. if ($posX < $pos_toX) {
  226. $posX++;
  227. }
  228. if ($posX > $pos_toX) {
  229. $posX--;
  230. }
  231. if ($posY < $pos_toY) {
  232. $posY++;
  233. }
  234. if ($posY > $pos_toY) {
  235. $posY--;
  236. }
  237. }
  238. return $s;
  239. }
  240. ##
  241. # distance(r_hash1, r_hash2)
  242. # pos1, pos2: references to position hash tables.
  243. # Returns: the distance as a floating point number.
  244. #
  245. # Calculates the pythagorean distance between pos1 and pos2.
  246. #
  247. # FIXME: Some things in RO should use block distance instead.
  248. # Discussion at
  249. # http://openkore.sourceforge.net/forum/viewtopic.php?t=9176
  250. #
  251. # Example:
  252. # # Calculates the distance between you and a monster
  253. # my $dist = distance($char->{pos_to},
  254. #                     $monsters{$ID}{pos_to});
  255. sub distance {
  256.     my $pos1 = shift;
  257.     my $pos2 = shift;
  258.     return 0 if (!$pos1 && !$pos2);
  259.     
  260.     my %line;
  261.     if (defined $pos2) {
  262.         $line{x} = abs($pos1->{x} - $pos2->{x});
  263.         $line{y} = abs($pos1->{y} - $pos2->{y});
  264.     } else {
  265.         %line = %{$pos1};
  266.     }
  267.     return sqrt($line{x} ** 2 + $line{y} ** 2);
  268. }
  269. ##
  270. # int intToSignedInt(int i)
  271. #
  272. # Convert a 32-bit unsigned integer into a signed integer.
  273. sub intToSignedInt {
  274. my $result = $_[0];
  275. # Check most significant bit.
  276. if ($result & 2147483648) {
  277. return -0xFFFFFFFF + $result - 1;
  278. } else {
  279. return $result;
  280. }
  281. }
  282. ##
  283. # int intToSignedShort(int i)
  284. #
  285. # Convert a 16-bit unsigned integer into a signed integer.
  286. sub intToSignedShort {
  287. my $result = $_[0];
  288. # Check most significant bit.
  289. if ($result & 32768) {
  290. return -0xFFFF + $result - 1;
  291. } else {
  292. return $result;
  293. }
  294. }
  295. ##
  296. # blockDistance(pos1, pos2)
  297. # pos1, pos2: references to position hash tables.
  298. # Returns: the distance in number of blocks (integer).
  299. #
  300. # Calculates the distance in number of blocks between pos1 and pos2.
  301. # This is used for e.g. weapon range calculation.
  302. sub blockDistance {
  303. my ($pos1, $pos2) = @_;
  304. return max(abs($pos1->{x} - $pos2->{x}),
  305.            abs($pos1->{y} - $pos2->{y}));
  306. }
  307. ##
  308. # getVector(r_store, to, from)
  309. # r_store: reference to a hash. The result will be stored here.
  310. # to, from: reference to position hashes.
  311. #
  312. # Create a vector object. For those who don't know: a vector
  313. # is a mathematical term for describing a movement and its direction.
  314. # So this function creates a vector object, which describes the direction of the
  315. # movement %from to %to. You can use this vector object with other math functions.
  316. #
  317. # See also: moveAlongVector(), vectorToDegree()
  318. sub getVector {
  319. my $r_store = shift;
  320. my $to = shift;
  321. my $from = shift;
  322. $r_store->{x} = $to->{x} - $from->{x};
  323. $r_store->{y} = $to->{y} - $from->{y};
  324. }
  325. ##
  326. # moveAlong(pos, pos_to, step)
  327. #
  328. # Returns: the position where an actor will be after $step steps
  329. # while walking from $pos to $pos_to.
  330. # Walls are not considered.
  331. sub moveAlong {
  332. my ($pos, $pos_to, $step) = @_;
  333. my $posX = $$pos{x};
  334. my $posY = $$pos{y};
  335. my $pos_toX = $$pos_to{x};
  336. my $pos_toY = $$pos_to{y};
  337. my %result;
  338. $result{x} = $posX;
  339. $result{y} = $posY;
  340. if (!$step) {
  341. return %result;
  342. }
  343. for (my $s = 1; $s <= $step; $s++) {
  344. if ($posX < $pos_toX) {
  345. $posX++;
  346. }
  347. if ($posX > $pos_toX) {
  348. $posX--;
  349. }
  350. if ($posY < $pos_toY) {
  351. $posY++;
  352. }
  353. if ($posY > $pos_toY) {
  354. $posY--;
  355. }
  356. }
  357. $result{x} = $posX;
  358. $result{y} = $posY;
  359. return %result;
  360. }
  361. ##
  362. # moveAlongVector(result, r_pos, r_vec, dist)
  363. # result: reference to a hash, in which the destination position is stored.
  364. # r_pos: the source position.
  365. # r_vec: a vector object, as created by getVector()
  366. # dist: the distance to move from the source position.
  367. #
  368. # Calculate where you will end up to, if you walk $dist blocks from %r_pos
  369. # into the direction specified by %r_vec.
  370. #
  371. # See also: getVector()
  372. #
  373. # Example:
  374. # my %from = (x => 100, y => 100);
  375. # my %to = (x => 120, y => 120);
  376. # my %vec;
  377. # getVector(%vec, %to, %from);
  378. # my %result;
  379. # moveAlongVector(%result, %from, %vec, 10);
  380. # print "You are at $from{x},$from{y}.n";
  381. # print "If you walk $dist blocks into the direction of $to{x},$to{y}, you will end up at:n";
  382. # print "$result{x},$result{y}n";
  383. sub moveAlongVector {
  384. my $result = shift;
  385. my $r_pos = shift;
  386. my $r_vec = shift;
  387. my $dist = shift;
  388. if ($dist) {
  389. my %norm;
  390. normalize(%norm, $r_vec);
  391. $result->{x} = $$r_pos{'x'} + $norm{'x'} * $dist;
  392. $result->{y} = $$r_pos{'y'} + $norm{'y'} * $dist;
  393. } else {
  394. $result->{x} = $$r_pos{'x'} + $$r_vec{'x'};
  395. $result->{y} = $$r_pos{'y'} + $$r_vec{'y'};
  396. }
  397. }
  398. sub normalize {
  399. my $r_store = shift;
  400. my $r_vec = shift;
  401. my $dist;
  402. $dist = distance($r_vec);
  403. if ($dist > 0) {
  404. $$r_store{'x'} = $$r_vec{'x'} / $dist;
  405. $$r_store{'y'} = $$r_vec{'y'} / $dist;
  406. } else {
  407. $$r_store{'x'} = 0;
  408. $$r_store{'y'} = 0;
  409. }
  410. }
  411. ##
  412. # vectorToDegree(vector)
  413. # vector: a reference to a vector hash, as created by getVector().
  414. # Returns: the degree as a number.
  415. #
  416. # Converts a vector into a degree number.
  417. #
  418. # See also: getVector()
  419. #
  420. # Example:
  421. # my %from = (x => 100, y => 100);
  422. # my %to = (x => 120, y => 120);
  423. # my %vec;
  424. # getVector(%vec, %to, %from);
  425. # vectorToDegree(%vec); # => 45
  426. sub vectorToDegree {
  427. my $vec = shift;
  428. my $x = $vec->{x};
  429. my $y = $vec->{y};
  430. if ($y == 0) {
  431. if ($x < 0) {
  432. return 270;
  433. } elsif ($x > 0) {
  434. return 90;
  435. } else {
  436. return undef;
  437. }
  438. } else {
  439. my $ret = rad2deg(atan2($x, $y));
  440. if ($ret < 0) {
  441. return 360 + $ret;
  442. } else {
  443. return $ret;
  444. }
  445. }
  446. }
  447. ##
  448. # max($a, $b)
  449. #
  450. # Returns the greater of $a or $b.
  451. sub max {
  452. my ($a, $b) = @_;
  453. return $a > $b ? $a : $b;
  454. }
  455. ##
  456. # min($a, $b)
  457. #
  458. # Returns the lesser of $a or $b.
  459. sub min {
  460. my ($a, $b) = @_;
  461. return $a < $b ? $a : $b;
  462. }
  463. ##
  464. # round($number)
  465. #
  466. # Returns the rounded number
  467. sub round {
  468. my($number) = shift;
  469. return int($number + .5 * ($number <=> 0));
  470. }
  471. ##
  472. # ceil($number)
  473. #
  474. # Returns the rounded up number
  475. # Used for distances (only deciles taken into consideration)
  476. sub ceil {
  477. my($number) = shift;
  478. return int($number + .9 * ($number <=> 0));
  479. }
  480. #################################################
  481. #################################################
  482. ### CATEGORY: Operating system-specific stuff
  483. #################################################
  484. #################################################
  485. ##
  486. # checkLaunchApp(pid, [retval])
  487. # pid: the return value of launchApp() or launchScript()
  488. # retval: a reference to a scalar. If the app exited, the return value will be stored in here.
  489. # Returns: 1 if the app is still running, 0 if it has exited.
  490. #
  491. # If you ran a script or an app asynchronously, you can use this function to check
  492. # whether it's currently still running.
  493. #
  494. # See also: launchApp(), launchScript()
  495. sub checkLaunchedApp {
  496. my ($pid, $retval) = @_;
  497. if ($^O eq 'MSWin32') {
  498. my $result = ($pid->Wait(0) == 0);
  499. if ($result == 0 && $retval) {
  500. my $code;
  501. $pid->GetExitCode($code);
  502. $$retval = $code;
  503. }
  504. return $result;
  505. } else {
  506. import POSIX ':sys_wait_h';
  507. my $wnohang = eval "WNOHANG";
  508. return (waitpid($pid, $wnohang) <= 0);
  509. }
  510. }
  511. ##
  512. # launchApp(detach, args...)
  513. # detach: set to 1 if you don't care when this application exits.
  514. # args: the application's name and arguments.
  515. # Returns: a PID on Unix; a Win32::Process object on Windows.
  516. #
  517. # Asynchronously launch an application.
  518. #
  519. # See also: checkLaunchedApp()
  520. sub launchApp {
  521. my $detach = shift;
  522. if ($^O eq 'MSWin32') {
  523. my @args = @_;
  524. foreach (@args) {
  525. $_ = ""$_"";
  526. }
  527. my ($priority, $obj);
  528. undef $@;
  529. eval 'use Win32::Process; $priority = NORMAL_PRIORITY_CLASS;';
  530. die if ($@);
  531. Win32::Process::Create($obj, $_[0], "@args", 0, $priority, '.');
  532. return $obj;
  533. } else {
  534. require POSIX;
  535. import POSIX;
  536. my $pid = fork();
  537. if ($detach) {
  538. if ($pid == 0) {
  539. open(STDOUT, "> /dev/null");
  540. open(STDERR, "> /dev/null");
  541. POSIX::setsid();
  542. if (fork() == 0) {
  543. exec(@_);
  544. }
  545. POSIX::_exit(1);
  546. } elsif ($pid) {
  547. waitpid($pid, 0);
  548. }
  549. } else {
  550. if ($pid == 0) {
  551. #open(STDOUT, "> /dev/null");
  552. #open(STDERR, "> /dev/null");
  553. POSIX::setsid();
  554. exec(@_);
  555. POSIX::_exit(1);
  556. }
  557. }
  558. return $pid;
  559. }
  560. }
  561. ##
  562. # launchScript(async, module_paths, script, [args...])
  563. # async: 1 if you want to run the script in the background, or 0 if you want to wait until the script has exited.
  564. # module_paths: reference to an array which contains paths to look for modules, or undef.
  565. # script: filename of the Perl script.
  566. # args: parameters to pass to the script.
  567. # Returns: a PID on Unix, a Win32::Process object on Windows.
  568. #
  569. # Run a Perl script.
  570. #
  571. # See also: launchApp(), checkLaunchedApp()
  572. sub launchScript {
  573. my $async = shift;
  574. my $module_paths = shift;
  575. my $script = shift;
  576. my @interp;
  577. if (-f $Config{perlpath}) {
  578. @interp = ($Config{perlpath});
  579. delete $ENV{INTERPRETER};
  580. } else {
  581. @interp = ($ENV{INTERPRETER}, '!');
  582. }
  583. my @paths;
  584. if ($module_paths) {
  585. foreach (@{$module_paths}) {
  586. push @paths, "-I$_";
  587. }
  588. }
  589. if ($async) {
  590. return launchApp(0, @interp, @paths, $script, @_);
  591. } else {
  592. system(@interp, @paths, $script, @_);
  593. }
  594. }
  595. ########################################
  596. ########################################
  597. ### CATEGORY: Misc utility functions
  598. ########################################
  599. ########################################
  600. ##
  601. # dataWaiting(r_handle)
  602. # r_handle: A reference to a handle or a socket.
  603. # Returns: 1 if there's pending incoming data, 0 if not.
  604. #
  605. # Checks whether the socket $r_handle has pending incoming data.
  606. # If there is, then you can read from $r_handle without being blocked.
  607. sub dataWaiting {
  608. my $r_fh = shift;
  609. return 0 if (!defined $r_fh || !defined $$r_fh);
  610. my $bits = '';
  611. vec($bits, fileno($$r_fh), 1) = 1;
  612. # The timeout was 0.005
  613. return (select($bits, undef, undef, 0) > 0);
  614. #return select($bits, $bits, $bits, 0) > 1);
  615. }
  616. ##
  617. # dumpHash(r_hash)
  618. # r_hash: a reference to a hash/array.
  619. #
  620. # Return a formated output of the contents of a hash/array, for debugging purposes.
  621. sub dumpHash {
  622. my $out;
  623. my $buf = $_[0];
  624. if (ref($buf) eq "") {
  625. $buf =~ s/'/\'/gs;
  626. $buf =~ s/[00-37]/./gs;
  627. $out .= "'$buf'";
  628. } elsif (ref($buf) eq "HASH") {
  629. $out .= "{";
  630. foreach (keys %{$buf}) {
  631. s/'/\'/gs;
  632. $out .= "$_=>" . dumpHash($buf->{$_}) . ",";
  633. }
  634. chop $out;
  635. $out .= "}";
  636. } elsif (ref($buf) eq "ARRAY") {
  637. $out .= "[";
  638. for (my $i = 0; $i < @{$buf}; $i++) {
  639. s/'/\'/gs;
  640. $out .= "$i=>" . dumpHash($buf->[$i]) . ",";
  641. }
  642. chop $out;
  643. $out .= "]";
  644. }
  645. $out = '{empty}' if ($out eq '}');
  646. return $out;
  647. }
  648. ##
  649. # formatNumber(num)
  650. # num: An integer number.
  651. # Returns: A formatted number with commas.
  652. #
  653. # Add commas to $num so large numbers are more readable.
  654. # $num must be an integer, not a floating point number.
  655. #
  656. # Example:
  657. # formatNumber(1000000);   # -> 1,000,000
  658. sub formatNumber {
  659. my $num = reverse $_[0];
  660. if ($num == 0) {
  661. return 0;
  662. }else {
  663. $num =~ s/(ddd)(?=d)(?!d*.)/$1,/g;
  664. return scalar reverse $num;
  665. }
  666. }
  667. sub _find_x {
  668. my ($x, $y) = @_;
  669. my $a = _find_x_top($x, $y);
  670. my @ans = (
  671. [$a,$a+1,$a+2,$a+3,$a+4,$a+5,$a+6,$a+7],
  672. [$a+1,$a,$a+3,$a+2,$a+5,$a+4,$a+7,$a+6],
  673. [$a+2,$a+3,$a,$a+1,$a+6,$a+7,$a+4,$a+5],
  674. [$a+3,$a+2,$a+1,$a,$a+7,$a+6,$a+5,$a+4],
  675. [$a+4,$a+5,$a+6,$a+7,$a,$a+1,$a+2,$a+3],
  676. [$a+5,$a+4,$a+7,$a+6,$a+1,$a,$a+3,$a+2],
  677. [$a+6,$a+7,$a+4,$a+5,$a+2,$a+3,$a,$a+2],
  678. [$a+7,$a+6,$a+5,$a+4,$a+3,$a+2,$a+1,$a]
  679. );
  680. return $ans[int($x % 32) / 4][int($y % 32) / 4];
  681. }
  682. sub _find_x_top {
  683. my ($x, $y) = @_;
  684. my $b;
  685. if ($x < 256 && $y < 256) {
  686. $b = 0;
  687. } elsif ($x >= 256 && $y >= 256) {
  688. $b = 0;
  689. } else {
  690. $b = 64;
  691. }
  692. my @ans = (
  693. [$b,$b+1*8,$b+2*8,$b+3*8,$b+4*8,$b+5*8,$b+6*8,$b+7*8],
  694. [$b+1*8,$b,$b+3*8,$b+2*8,$b+5*8,$b+4*8,$b+7*8,$b+6*8],
  695. [$b+2*8,$b+3*8,$b,$b+1*8,$b+6*8,$b+7*8,$b+4*8,$b+5*8],
  696. [$b+3*8,$b+2*8,$b+1*8,$b,$b+7*8,$b+6*8,$b+5*8,$b+4*8],
  697. [$b+4*8,$b+5*8,$b+6*8,$b+7*8,$b,$b+1*8,$b+2*8,$b+3*8],
  698. [$b+5*8,$b+4*8,$b+7*8,$b+6*8,$b+1*8,$b,$b+3*8,$b+2*8],
  699. [$b+6*8,$b+7*8,$b+4*8,$b+5*8,$b+2*8,$b+3*8,$b,$b+2*8],
  700. [$b+7*8,$b+6*8,$b+5*8,$b+4*8,$b+3*8,$b+2*8,$b+1*8,$b]
  701. );
  702. return $ans[int($x % 256) / 32][int($y % 256) / 32];
  703. }
  704. sub getCoordString {
  705. my $x = int(shift);
  706. my $y = int(shift);
  707. my $nopadding = shift;
  708. my $coords = "";
  709. shiftPack($coords, 0x44, 8)
  710. unless (($config{serverType} == 0) || ($config{serverType} == 3) || ($config{serverType} == 5) || $nopadding);
  711. shiftPack($coords, $x, 10);
  712. shiftPack($coords, $y, 10);
  713. shiftPack($coords, 0, 4);
  714. return $coords;
  715. }
  716. sub getCoordString2 {
  717. my $x = int(shift);
  718. my $y = int(shift);
  719. my $nopadding = shift;
  720. my $coords = "";
  721. shiftPack($coords, 0x44, 8)
  722. unless (($config{serverType} == 0) || ($config{serverType} == 3) || ($config{serverType} == 5) || $nopadding);
  723. shiftPack($coords, $x, 10);
  724. shiftPack($coords, $y, 10);
  725. shiftPack($coords, 0, 28);
  726. return $coords;
  727. }
  728.  
  729. sub getFormattedDate {
  730.         my $thetime = shift;
  731.         my $r_date = shift;
  732.         my @localtime = localtime $thetime;
  733.         my $themonth = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)[$localtime[4]];
  734.         $localtime[2] = "0" . $localtime[2] if ($localtime[2] < 10);
  735.         $localtime[1] = "0" . $localtime[1] if ($localtime[1] < 10);
  736.         $localtime[0] = "0" . $localtime[0] if ($localtime[0] < 10);
  737.         $$r_date = "$themonth $localtime[3] $localtime[2]:$localtime[1]:$localtime[0] " . ($localtime[5] + 1900);
  738.         return $$r_date;
  739. }
  740. sub getHex {
  741. my $data = shift;
  742. my $i;
  743. my $return;
  744. for ($i = 0; $i < length($data); $i++) {
  745. $return .= uc(unpack("H2",substr($data, $i, 1)));
  746. if ($i + 1 < length($data)) {
  747. $return .= " ";
  748. }
  749. }
  750. return $return;
  751. }
  752. sub giveHex {
  753. return pack("H*",split(' ',shift));
  754. }
  755. sub getRange {
  756. my $param = shift;
  757. return if (!defined $param);
  758. # remove % from the first number here (i.e. hp 50%..60%) because it's easiest
  759. if ($param =~ /(-?d+(?:.d+)?)%?s*(?:-|..)s*(-?d+(?:.d+)?)/) {
  760. return ($1, $2, 1);
  761. } elsif ($param =~ />s*(-?d+(?:.d+)?)/) {
  762. return ($1, undef, 0);
  763. } elsif ($param =~ />=s*(-?d+(?:.d+)?)/) {
  764. return ($1, undef, 1);
  765. } elsif ($param =~ /<s*(-?d+(?:.d+)?)/) {
  766. return (undef, $1, 0);
  767. } elsif ($param =~ /<=s*(-?d+(?:.d+)?)/) {
  768. return (undef, $1, 1);
  769. } elsif ($param =~/^(-?d+(?:.d+)?)/) {
  770. return ($1, $1, 1);
  771. }
  772. }
  773. sub getTickCount {
  774. my $time = int(time()*1000);
  775. if (length($time) > 9) {
  776. return substr($time, length($time) - 8, length($time));
  777. } else {
  778. return $time;
  779. }
  780. }
  781. sub inRange {
  782. my $value = shift;
  783. my $param = shift;
  784. return 1 if (!defined $param);
  785. my ($min, $max, $inclusive) = getRange($param);
  786. if (defined $min && defined $max) {
  787. return 1 if ($value >= $min && $value <= $max);
  788. } elsif (defined $min) {
  789. return 1 if ($value > $min || ($inclusive && $value == $min));
  790. } elsif (defined $max) {
  791. return 1 if ($value < $max || ($inclusive && $value == $max));
  792. }
  793. return 0;
  794. }
  795. ##
  796. # judgeSkillArea(ID)
  797. # ID: a skill ID.
  798. # Returns: the size of the skill's area.
  799. #
  800. # Figure out how large the skill area is, in diameters.
  801. sub judgeSkillArea {
  802. my $id = shift;
  803. if ($id == 81 || $id == 85 || $id == 89 || $id == 83 || $id == 110 || $id == 91) {
  804.  return 5;
  805. } elsif ($id == 70 || $id == 79 ) {
  806.  return 4;
  807. } elsif ($id == 21 || $id == 17 ){
  808.  return 3;
  809. } elsif ($id == 88  || $id == 80
  810.       || $id == 11  || $id == 18
  811.       || $id == 140 || $id == 229 ) {
  812.  return 2;
  813. } else {
  814.  return 0;
  815. }
  816. }
  817. ##
  818. # makeCoords(r_hash, rawCoords)
  819. #
  820. # The maximum value for either coordinate (x or y) is 1023, 
  821. # thus making the number of bits for each coordinate 10. 
  822. # When both coordinates are packed together, 
  823. # the bit usage becomes double that, 20 -- or 2.5 bytes
  824. sub makeCoords {
  825. my ($r_hash, $rawCoords) = @_;
  826. unShiftPack($rawCoords, undef, 4);
  827. makeCoords2($r_hash, $rawCoords);
  828. }
  829.  
  830. sub makeCoords2 {
  831. my ($r_hash, $rawCoords) = @_;
  832. unShiftPack($rawCoords, $r_hash->{y}, 10);
  833. unShiftPack($rawCoords, $r_hash->{x}, 10);
  834. }
  835.  
  836. sub makeCoords3 {
  837. my ($r_hashFrom, $r_hashTo, $rawCoords) = @_;
  838.  
  839. unShiftPack($rawCoords, $$r_hashTo{'y'}, 10);
  840. unShiftPack($rawCoords, $$r_hashTo{'x'}, 10);
  841. unShiftPack($rawCoords, $$r_hashFrom{'y'}, 10);
  842. unShiftPack($rawCoords, $$r_hashFrom{'x'}, 10);
  843. }
  844.  
  845. ##
  846. # shiftPack(data, value, bits)
  847. # data: reference to existing data in which to pack onto
  848. # value: value to pack
  849. # bits: maximum number of bits used by value
  850. #
  851. # Packs a value onto a set of data using bitwise shifts
  852. sub shiftPack {
  853. my ($data, $value, $bits) = @_;
  854.   my ($newdata, $dw1, $dw2, $i, $mask, $done);
  855.  
  856. $mask = 2 ** (32 - $bits) - 1;
  857. $i = length($$data);
  858.  
  859. $newdata = "";
  860. $done = 0;
  861.  
  862. $dw1 = $value & (2 ** $bits - 1);
  863.   do {
  864. $i -= 4;
  865. $dw2 = ($i > 0) ?
  866. unpack('N', substr($$data, $i, 4)) :
  867. unpack('N', pack('x' . abs($i)) . substr($$data, 0, 4 + $i));
  868. $dw1 = $dw1 | (($dw2 & $mask) << $bits);
  869. $newdata = pack('N', $dw1) . $newdata;
  870. $dw1 = $dw2 >> (32 - $bits);
  871. } while ($i + 4 > 0);
  872.  
  873. $newdata = substr($newdata, 1) while (substr($newdata, 0, 1) eq pack('C', 0) && length($newdata));
  874. $$data = $newdata;
  875. }
  876. ##
  877. # urldecode(encoded_string)
  878. #
  879. # Decode an URL-encoded string.
  880. sub urldecode {
  881. my ($str) = @_;
  882. $str =~ tr/+?/  /;
  883. $str =~ s/%([0-9a-fA-F]{2})/pack('H2',$1)/ge;
  884. return $str;
  885. }
  886. ##
  887. # urlencode(str)
  888. #
  889. # URL-encodes a string.
  890. sub urlencode {
  891. my ($str) = @_;
  892. $str =~ s/([W])/"%" . uc(sprintf("%2.2x", ord($1)))/eg;
  893. return $str;
  894. }
  895. ##
  896. # unShiftPack(data, reference, bits)
  897. # data: data to unpack a value from
  898. # reference: reference to store the value in
  899. # bits: number of bits value requires
  900. #
  901. # This is the reverse operation of shiftPack.
  902. sub unShiftPack {
  903. my ($data, $reference, $bits) = @_;
  904. my ($newdata, $dw1, $dw2, $i, $mask, $done);
  905. $mask = 2 ** $bits - 1;
  906. $i = length($$data);
  907. $newdata = "";
  908. $done = 0;
  909. do {
  910. $i -= 4;
  911. $dw2 = ($i > 0) ?
  912. unpack('N', substr($$data, $i, 4)) :
  913. unpack('N', pack('x' . abs($i)) . substr($$data, 0, 4 + $i));
  914.  
  915. unless ($done) {
  916. $$reference = $dw2 & (2 ** $bits - 1) if (defined $reference);
  917. $done = 1;
  918. } else {
  919. $dw1 = $dw1 | (($dw2 & $mask) << (32 - $bits));
  920. $newdata = pack('N', $dw1) . $newdata;
  921. }
  922. $dw1 = $dw2 >> $bits;
  923. } while ($i + 4 > 0);
  924. $newdata = substr($newdata, 1) while (substr($newdata, 0, 1) eq pack('C', 0) && length($newdata));
  925. $$data = $newdata;
  926. }
  927. ##
  928. # makeDistMap(data, width, height)
  929. # data: the raw field data.
  930. # width: the field's width.
  931. # height: the field's height.
  932. # Returns: the raw data of the distance map.
  933. #
  934. # Create a distance map from raw field data. This distance map data is used by pathfinding
  935. # for wall avoidance support.
  936. # sub old_makeDistMap {
  937. #  # makeDistMap() is now written in C++ (src/auto/XSTools/misc/fastutils.xs)
  938. #  # The old Perl function is still here in case anyone wants to read it
  939. #  my $data = shift;
  940. #  my $width = shift;
  941. #  my $height = shift;
  942. #  # Simplify the raw map data. Each byte in the raw map data
  943. #  # represents a block on the field, but only some bytes are
  944. #  # interesting to pathfinding.
  945. #  for (my $i = 0; $i < length($data); $i++) {
  946. #  my $v = ord(substr($data, $i, 1));
  947. #  # 0 is open, 3 is walkable water
  948. #  if ($v == 0 || $v == 3) {
  949. #  $v = 255;
  950. #  } else {
  951. #  $v = 0;
  952. #  }
  953. #  substr($data, $i, 1, chr($v));
  954. #  }
  955. #  my $done = 0;
  956. #  until ($done) {
  957. #  $done = 1;
  958. #  #'push' wall distance right and up
  959. #  for (my $y = 0; $y < $height; $y++) {
  960. #  for (my $x = 0; $x < $width; $x++) {
  961. #  my $i = $y * $width + $x;
  962. #  my $dist = ord(substr($data, $i, 1));
  963. #  if ($x != $width - 1) {
  964. #  my $ir = $y * $width + $x + 1;
  965. #  my $distr = ord(substr($data, $ir, 1));
  966. #  my $comp = $dist - $distr;
  967. #  if ($comp > 1) {
  968. #  my $val = $distr + 1;
  969. #  $val = 255 if $val > 255;
  970. #  substr($data, $i, 1, chr($val));
  971. #  $done = 0;
  972. #  } elsif ($comp < -1) {
  973. #  my $val = $dist + 1;
  974. #  $val = 255 if $val > 255;
  975. #  substr($data, $ir, 1, chr($val));
  976. #  $done = 0;
  977. #  }
  978. #  }
  979. #  if ($y != $height - 1) {
  980. #  my $iu = ($y + 1) * $width + $x;
  981. #  my $distu = ord(substr($data, $iu, 1));
  982. #  my $comp = $dist - $distu;
  983. #  if ($comp > 1) {
  984. #  my $val = $distu + 1;
  985. #  $val = 255 if $val > 255;
  986. #  substr($data, $i, 1, chr($val));
  987. #  $done = 0;
  988. #  } elsif ($comp < -1) {
  989. #  my $val = $dist + 1;
  990. #  $val = 255 if $val > 255;
  991. #  substr($data, $iu, 1, chr($val));
  992. #  $done = 0;
  993. #  }
  994. #  }
  995. #  }
  996. #  }
  997. #  #'push' wall distance left and down
  998. #  for (my $y = $height - 1; $y >= 0; $y--) {
  999. #  for (my $x = $width - 1; $x >= 0 ; $x--) {
  1000. #  my $i = $y * $width + $x;
  1001. #  my $dist = ord(substr($data, $i, 1));
  1002. #  if ($x != 0) {
  1003. #  my $il = $y * $width + $x - 1;
  1004. #  my $distl = ord(substr($data, $il, 1));
  1005. #  my $comp = $dist - $distl;
  1006. #  if ($comp > 1) {
  1007. #  my $val = $distl + 1;
  1008. #  $val = 255 if $val > 255;
  1009. #  substr($data, $i, 1, chr($val));
  1010. #  $done = 0;
  1011. #  } elsif ($comp < -1) {
  1012. #  my $val = $dist + 1;
  1013. #  $val = 255 if $val > 255;
  1014. #  substr($data, $il, 1, chr($val));
  1015. #  $done = 0;
  1016. #  }
  1017. #  }
  1018. #  if ($y != 0) {
  1019. #  my $id = ($y - 1) * $width + $x;
  1020. #  my $distd = ord(substr($data, $id, 1));
  1021. #  my $comp = $dist - $distd;
  1022. #  if ($comp > 1) {
  1023. #  my $val = $distd + 1;
  1024. #  $val = 255 if $val > 255;
  1025. #  substr($data, $i, 1, chr($val));
  1026. #  $done = 0;
  1027. #  } elsif ($comp < -1) {
  1028. #  my $val = $dist + 1;
  1029. #  $val = 255 if $val > 255;
  1030. #  substr($data, $id, 1, chr($val));
  1031. #  $done = 0;
  1032. #  }
  1033. #  }
  1034. #  }
  1035. #  }
  1036. #  }
  1037. #  return $data;
  1038. # }
  1039. sub makeIP {
  1040. my $raw = shift;
  1041. my $ret;
  1042. for (my $i = 0; $i < 4; $i++) {
  1043. $ret .= hex(getHex(substr($raw, $i, 1)));
  1044. if ($i + 1 < 4) {
  1045. $ret .= ".";
  1046. }
  1047. }
  1048. return $ret;
  1049. }
  1050. sub encodeIP {
  1051. return pack("C*", split(/./, shift));
  1052. }
  1053. ##
  1054. # Array<String> parseArgs(String command, [int max], [String delimiters = ' '], [int* last_arg_pos])
  1055. # command: a command string.
  1056. # max: maximum number of arguments.
  1057. # delimiters: a character array of delimiters for arguments.
  1058. # last_arg_pos: reference to a scalar. The position of the start of the last argument is stored here.
  1059. # Returns: an array of arguments.
  1060. #
  1061. # Parse a command string and split it into an array of arguments.
  1062. # Quoted parts inside the command strings are considered one argument.
  1063. # Backslashes can be used to escape a special character (like quotes).
  1064. # Leadingand trailing whitespaces are ignored, unless quoted.
  1065. #
  1066. # Example:
  1067. # parseArgs("guild members"); # => ("guild", "members")
  1068. # parseArgs("c hello there", 2); # => ("c", "hello there")
  1069. # parseArgs("pm 'My Friend' hey there", 3); # ("pm", "My Friend", "hey there")
  1070. sub parseArgs {
  1071. my ($command, $max, $delimiters, $r_last_arg_pos) = @_;
  1072. my @args;
  1073. if (!defined $delimiters) {
  1074. $delimiters = qr/ /;
  1075. } else {
  1076. $delimiters = quotemeta $delimiters;
  1077. $delimiters = qr/[$delimiters]/;
  1078. }
  1079. my $last_arg_pos;
  1080. my $tmp;
  1081. ($tmp, $command) = $command =~ /^( *)(.*)/;
  1082. $last_arg_pos = length($tmp);
  1083. $command =~ s/ *$//;
  1084. my $len = length $command;
  1085. my $within_quote;
  1086. my $quote_char = '';
  1087. my $i;
  1088. for ($i = 0; $i < $len; $i++) {
  1089. my $char = substr($command, $i, 1);
  1090. if ($max && @args == $max) {
  1091. $args[0] = $command;
  1092. last;
  1093. } elsif ($char eq '\') {
  1094. $args[0] .= substr($command, $i + 1, 1);
  1095. $i++;
  1096. } elsif (($char eq '"' || $char eq "'") && ($quote_char eq '' || $quote_char eq $char)) {
  1097. $within_quote = !$within_quote;
  1098. $quote_char = ($within_quote) ? $char : '';
  1099. } elsif ($within_quote) {
  1100. $args[0] .= $char;
  1101. } elsif ($char =~ /$delimiters/) {
  1102. unshift @args, '';
  1103. $command = substr($command, $i + 1);
  1104. ($tmp, $command) =~ /^(${delimiters}*)(.*)/;
  1105. $len = length $command;
  1106. $last_arg_pos += $i + 1;
  1107. $i = -1;
  1108. } else {
  1109. $args[0] .= $char;
  1110. }
  1111. }
  1112. $$r_last_arg_pos = $last_arg_pos if ($r_last_arg_pos);
  1113. return reverse @args;
  1114. }
  1115. ##
  1116. # quarkToString(quark)
  1117. # quark: A quark as returned by stringToQuark()
  1118. #
  1119. # Convert a quark back into a string. See stringToQuark() for details.
  1120. sub quarkToString {
  1121. my $quark = $_[0];
  1122. return $strings{$quark};
  1123. }
  1124. ##
  1125. # stringToQuark(string)
  1126. #
  1127. # Convert a string into a so-called quark. Each string will be converted to a unique quark.
  1128. # This can be used to save memory, if your application uses many identical strings.
  1129. #
  1130. # For example, consider the following:
  1131. # <pre class="example">
  1132. # my @array;
  1133. # for (1..10000) {
  1134. #     push @array, "this is a string";
  1135. # }
  1136. # </pre>
  1137. # The above example will store 10000 different copies of the string "this is my string" into
  1138. # the array. Even though each string has the same content, each string uses its own memory.
  1139. #
  1140. # By using quarks, one can save a lot of memory:
  1141. # <pre class="example">
  1142. # my @array;
  1143. # for (1..10000) {
  1144. #     push @array, stringToQuark("this is a string");
  1145. # }
  1146. # </pre>
  1147. # The array will now contain 10000 instances of the same quark, so very little memory is wasted.
  1148. #
  1149. # To convert a quark back to a string, use quarkToString().
  1150. sub stringToQuark {
  1151. my $string = $_[0];
  1152. if (exists $quarks{$string}) {
  1153. return $quarks{$string};
  1154. } else {
  1155. my $ref = $string;
  1156. $quarks{$string} = $ref;
  1157. $strings{$ref} = $string;
  1158. return $ref;
  1159. }
  1160. }
  1161. sub swrite {
  1162. my $result = '';
  1163. for (my $i = 0; $i < @_; $i += 2) {
  1164. my $format = $_[$i];
  1165. my @args = @{$_[$i+1]};
  1166. if ($format =~ /@[<|>]/) {
  1167. $^A = '';
  1168. formline($format, @args);
  1169. $result .= "$^An";
  1170. } else {
  1171. $result .= "$formatn";
  1172. }
  1173. }
  1174. $^A = '';
  1175. return $result;
  1176. }
  1177. ##
  1178. # timeConvert(seconds)
  1179. # seconds: number of seconds.
  1180. # Returns: a human-readable version of $seconds.
  1181. #
  1182. # Converts $seconds into a string in the form of "x hours y minutes z seconds".
  1183. sub timeConvert {
  1184. my $time = shift;
  1185. my $hours = int($time / 3600);
  1186. my $time = $time % 3600;
  1187. my $minutes = int($time / 60);
  1188. my $time = $time % 60;
  1189. my $seconds = $time;
  1190. my $gathered = '';
  1191. $gathered = "$hours hours " if ($hours);
  1192. $gathered .= "$minutes minutes " if ($minutes);
  1193. $gathered .= "$seconds seconds" if ($seconds);
  1194. $gathered =~ s/ $//;
  1195. $gathered = '0 seconds' if ($gathered eq '');
  1196. return $gathered;
  1197. }
  1198. ##
  1199. # timeOut(r_time, [timeout])
  1200. # r_time: a time value, or a hash.
  1201. # timeout: the timeout value to use if $r_time is a time value.
  1202. # Returns: a boolean.
  1203. #
  1204. # If r_time is a time value:
  1205. # Check whether $timeout seconds have passed since $r_time.
  1206. #
  1207. # If r_time is a hash:
  1208. # Check whether $r_time->{timeout} seconds have passed since $r_time->{time}.
  1209. #
  1210. # This function is usually used to handle timeouts in a loop.
  1211. #
  1212. # Example:
  1213. # my %time;
  1214. # $time{time} = time;
  1215. # $time{timeout} = 10;
  1216. #
  1217. # while (1) {
  1218. #     if (timeOut(%time)) {
  1219. #         print "10 seconds have passed since this loop was started.n";
  1220. #         last;
  1221. #     }
  1222. # }
  1223. #
  1224. # my $startTime = time;
  1225. # while (1) {
  1226. #     if (timeOut($startTime, 6)) {
  1227. #         print "6 seconds have passed since this loop was started.n";
  1228. #         last;
  1229. #     }
  1230. # }
  1231. # timeOut() is implemented in tools/misc/fastutils.xs
  1232. ##
  1233. # vocalString(letter_length, [r_string])
  1234. # letter_length: the requested length of the result.
  1235. # r_string: a reference to a scalar. If given, the result will be stored here.
  1236. # Returns: the resulting string.
  1237. #
  1238. # Creates a random string of $letter_length long. The resulting string is pronouncable.
  1239. # This function can be used to generate a random password.
  1240. #
  1241. # Example:
  1242. # for (my $i = 0; $i < 5; $i++) {
  1243. #     printf("%sn", vocalString(10));
  1244. # }
  1245. sub vocalString {
  1246. my $letter_length = shift;
  1247. return if ($letter_length <= 0);
  1248. my $r_string = shift;
  1249. my $test;
  1250. my $i;
  1251. my $password;
  1252. my @cons = ("b", "c", "d", "g", "h", "j", "k", "l", "m", "n", "p", "r", "s", "t", "v", "w", "y", "z", "tr", "cl", "cr", "br", "fr", "th", "dr", "ch", "st", "sp", "sw", "pr", "sh", "gr", "tw", "wr", "ck");
  1253. my @vowels = ("a", "e", "i", "o", "u" , "a", "e" ,"i","o","u","a","e","i","o", "ea" , "ou" , "ie" , "ai" , "ee" ,"au", "oo");
  1254. my %badend = ( "tr" => 1, "cr" => 1, "br" => 1, "fr" => 1, "dr" => 1, "sp" => 1, "sw" => 1, "pr" =>1, "gr" => 1, "tw" => 1, "wr" => 1, "cl" => 1, "kr" => 1);
  1255. for (;;) {
  1256. $password = "";
  1257. for($i = 0; $i < $letter_length; $i++){
  1258. $password .= $cons[rand(@cons - 1)] . $vowels[rand(@vowels - 1)];
  1259. }
  1260. $password = substr($password, 0, $letter_length);
  1261. ($test) = ($password =~ /(..)z/);
  1262. last if ($badend{$test} != 1);
  1263. }
  1264. $$r_string = $password if ($r_string);
  1265. return $password;
  1266. }
  1267. ##
  1268. # String wrapText(String text, int maxLineLength)
  1269. # text: The text to wrap.
  1270. # maxLineLength: The maximum length of a line.
  1271. # Requires: defined($text) && $maxLineLength > 1
  1272. # Ensures: defined(result)
  1273. #
  1274. # Wrap the given text at the given length.
  1275. sub wrapText {
  1276. local($Text::Wrap::columns) = $_[1];
  1277. return wrap('', '', $_[0]);
  1278. }
  1279. ##
  1280. # int pin_encode(int pin, int key)
  1281. # pin: the PIN code
  1282. # key: the encryption key
  1283. #
  1284. # PIN Encode Function, used to hide the real PIN code, using KEY.
  1285. sub pin_encode {
  1286. my ($pin, $key) = @_;
  1287. $key &= 0xFFFFFFFF;
  1288. $key ^= 0xFFFFFFFF;
  1289. # Check PIN len
  1290. if ((length($pin) > 3) && (length($pin) < 9)) {
  1291. my $pincode;
  1292. # Convert String to number
  1293. $pincode = $pin;
  1294. # Encryption loop
  1295. for(my $loopin = 0; $loopin < length($pin); $loopin++) {
  1296. $pincode &= 0xFFFFFFFF;
  1297. $pincode += 0x05F5E100; # Static Encryption Key
  1298. $pincode &= 0xFFFFFFFF;
  1299. }
  1300. # Finalize Encryption
  1301. $pincode &= 0xFFFFFFFF;
  1302. $pincode ^= $key;
  1303. $pincode &= 0xFFFFFFFF;
  1304. return $pincode;
  1305. } elsif (length($pin) == 0) {
  1306. my $pincode;
  1307. # Convert String to number
  1308. $pincode = 0;
  1309. # Finalize Encryption
  1310. $pincode &= 0xFFFFFFFF;
  1311. $pincode ^= $key;
  1312. $pincode &= 0xFFFFFFFF;
  1313. return $pincode;
  1314. } else {
  1315. return 0;
  1316. }
  1317. }
  1318. 1;