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

外挂编程

开发平台:

Windows_Unix

  1. $message .= shift(@tmp) . "n";
  2. foreach (@tmp) {
  3. $length = length($_->[0]) if length($_->[0]) > $length;
  4. }
  5. my $pattern = "$cmd %-${length}s    %sn";
  6. my $padsize = length($cmd) + $length + 5;
  7. my $pad = sprintf("%-${padsize}s", '');
  8. foreach (@tmp) {
  9. if ($padsize + length($_->[1]) > 79) {
  10. @words = split(/ /, $_->[1]);
  11. $message .= sprintf("$cmd %-${length}s    ", $_->[0]);
  12. $messageTmp = '';
  13. foreach my $word (@words) {
  14. if ($padsize + length($messageTmp) + length($word) + 1 > 79) {
  15. $message .= $messageTmp . "n$pad";
  16. $messageTmp = '';
  17. } else {
  18. $messageTmp .= "$word ";
  19. }
  20. }
  21. $message .= $messageTmp."n";
  22. }
  23. else {
  24. $message .= sprintf($pattern, $_->[0], $_->[1]);
  25. }
  26. }
  27. $message .= "--------------------------------------------------n";
  28. message $message, "list";
  29. }
  30. sub cmdIdentify {
  31. if (!$net || $net->getState() != Network::IN_GAME) {
  32. error TF("You must be logged in the game to use this command (%s)n", shift);
  33. return;
  34. }
  35. my (undef, $arg1) = @_;
  36. if ($arg1 eq "" && defined @identifyID) {
  37. message T("---------Identify List--------n"), "list";
  38. for (my $i = 0; $i < @identifyID; $i++) {
  39. next if ($identifyID[$i] eq "");
  40. message(swrite(
  41. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
  42. [$i, $char->inventory->get($identifyID[$i])->{name}]),
  43. "list");
  44. }
  45. message("------------------------------n", "list");
  46. } elsif (!defined @identifyID) {
  47. error TF("The identify list is empty, please use the identify skill or a magnifier first.n");
  48. } elsif ($arg1 =~ /^d+$/) {
  49. if ($identifyID[$arg1] eq "") {
  50. error TF("Error in function 'identify' (Identify Item)n" .
  51. "Identify Item %s does not existn", $arg1);
  52. } else {
  53. $messageSender->sendIdentify($char->inventory->get($identifyID[$arg1])->{index});
  54. }
  55. } else {
  56. error TF("Syntax Error in function 'identify' (Identify Item)n" .
  57. "Usage: identify [<identify #>]n");
  58. }
  59. }
  60. sub cmdIgnore {
  61. if (!$net || $net->getState() != Network::IN_GAME) {
  62. error TF("You must be logged in the game to use this command (%s)n", shift);
  63. return;
  64. }
  65. my (undef, $args) = @_;
  66. my ($arg1, $arg2) = $args =~ /^(d+) ([sS]*)/;
  67. if ($arg1 eq "" || $arg2 eq "" || ($arg1 ne "0" && $arg1 ne "1")) {
  68. error T("Syntax Error in function 'ignore' (Ignore Player/Everyone)n" .
  69. "Usage: ignore <flag> <name | all>n");
  70. } else {
  71. if ($arg2 eq "all") {
  72. $messageSender->sendIgnoreAll(!$arg1);
  73. } else {
  74. $messageSender->sendIgnore($arg2, !$arg1);
  75. }
  76. }
  77. }
  78. sub cmdIhist {
  79. # Display item history
  80. my (undef, $args) = @_;
  81. $args = 5 if ($args eq "");
  82. if (!($args =~ /^d+$/)) {
  83. error T("Syntax Error in function 'ihist' (Show Item History)n" .
  84. "Usage: ihist [<number of entries #>]n");
  85. } elsif (open(ITEM, "<", $Settings::item_log_file)) {
  86. my @item = <ITEM>;
  87. close(ITEM);
  88. message T("------ Item History --------------------n"), "list";
  89. my $i = @item - $args;
  90. $i = 0 if ($i < 0);
  91. for (; $i < @item; $i++) {
  92. message($item[$i], "list");
  93. }
  94. message("----------------------------------------n", "list");
  95. } else {
  96. error TF("Unable to open %sn", $Settings::item_log_file);
  97. }
  98. }
  99. sub cmdInventory {
  100. # Display inventory items
  101. my (undef, $args) = @_;
  102. my ($arg1) = $args =~ /^(w+)/;
  103. my ($arg2) = $args =~ /^w+ (.+)/;
  104. if (!$char || $char->inventory->size() == 0) {
  105. error T("Inventory is emptyn");
  106. return;
  107. }
  108. if ($arg1 eq "" || $arg1 eq "eq" || $arg1 eq "neq" || $arg1 eq "u" || $arg1 eq "nu") {
  109. my @useable;
  110. my @equipment;
  111. my @uequipment;
  112. my @non_useable;
  113. my ($i, $display, $index, $sell);
  114. foreach my $item (@{$char->inventory->getItems()}) {
  115. if (($item->{type} == 3 ||
  116.      $item->{type} == 6 ||
  117.      $item->{type} == 10 ||
  118.      $item->{type} == 16 ||
  119.      $item->{type} == 17) && !$item->{equipped}) {
  120. push @non_useable, $item->{invIndex};
  121. } elsif ($item->{type} <= 2) {
  122. push @useable, $item->{invIndex};
  123. } else {
  124. my %eqp;
  125. $eqp{index} = $item->{index};
  126. $eqp{binID} = $item->{invIndex};
  127. $eqp{name} = $item->{name};
  128. $eqp{type} = $itemTypes_lut{$item->{type}};
  129. $eqp{equipped} = ($item->{type} == 10 || $item->{type} == 16 || $item->{type} == 17) ? $item->{amount} . " left" : $equipTypes_lut{$item->{equipped}};
  130. $eqp{equipped} .= " ($item->{equipped})";
  131. # Translation Comment: Mark to tell item not identified
  132. $eqp{identified} = " -- " . T("Not Identified") if !$item->{identified};
  133. if ($item->{equipped}) {
  134. push @equipment, %eqp;
  135. } else {
  136. push @uequipment, %eqp;
  137. }
  138. }
  139. }
  140. my $msg = T("-----------Inventory-----------n");
  141. if ($arg1 eq "" || $arg1 eq "eq") {
  142. # Translation Comment: List of usable equipments
  143. $msg .= T("-- Equipment (Equipped) --n");
  144. foreach my $item (@equipment) {
  145. $sell = defined(findIndex(@sellList, "invIndex", $item->{binID})) ? T("Will be sold") : "";
  146. $display = sprintf("%-3d  %s -- %s", $item->{binID}, $item->{name}, $item->{equipped});
  147. $msg .= sprintf("%-57s %sn", $display, $sell);
  148. }
  149. }
  150. if ($arg1 eq "" || $arg1 eq "neq") {
  151. # Translation Comment: List of equipments
  152. $msg .= T("-- Equipment (Not Equipped) --n");
  153. foreach my $item (@uequipment) {
  154. $sell = defined(findIndex(@sellList, "invIndex", $item->{binID})) ? T("Will be sold") : "";
  155. $display = sprintf("%-3d  %s (%s) %s", $item->{binID}, $item->{name}, $item->{type}, $item->{identified});
  156. $msg .= sprintf("%-57s %sn", $display, $sell);
  157. }
  158. }
  159. if ($arg1 eq "" || $arg1 eq "nu") {
  160. # Translation Comment: List of non-usable items
  161. $msg .= T("-- Non-Usable --n");
  162. for ($i = 0; $i < @non_useable; $i++) {
  163. $index = $non_useable[$i];
  164. my $item = $char->inventory->get($index);
  165. $display = $item->{name};
  166. $display .= " x $item->{amount}";
  167. # Translation Comment: Tell if the item is marked to be sold 
  168. $sell = defined(findIndex(@sellList, "invIndex", $index)) ? T("Will be sold") : "";
  169. $msg .= swrite(
  170. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<",
  171. [$index, $display, $sell]);
  172. }
  173. }
  174. if ($arg1 eq "" || $arg1 eq "u") {
  175. # Translation Comment: List of usable items
  176. $msg .= T("-- Usable --n");
  177. for ($i = 0; $i < @useable; $i++) {
  178. $index = $useable[$i];
  179. my $item = $char->inventory->get($index);
  180. $display = $item->{name};
  181. $display .= " x $item->{amount}";
  182. $sell = defined(findIndex(@sellList, "invIndex", $index)) ? T("Will be sold") : "";
  183. $msg .= swrite(
  184. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<",
  185. [$index, $display, $sell]);
  186. }
  187. }
  188. $msg .= "-------------------------------n";
  189. message($msg, "list");
  190. } elsif ($arg1 eq "desc" && $arg2 ne "") {
  191. cmdInventory_desc($arg2);
  192. } else {
  193. error T("Syntax Error in function 'i' (Inventory List)n" .
  194. "Usage: i [<u|eq|neq|nu|desc>] [<inventory item>]n");
  195. }
  196. }
  197. sub cmdInventory_desc {
  198. my ($name) = @_;
  199. my $item = Match::inventoryItem($name);
  200. if (!$item) {
  201. error TF("Error in function 'i' (Inventory Item Description)n" .
  202. "Inventory Item %s does not existn", $name);
  203. return;
  204. }
  205. printItemDesc($item->{nameID});
  206. }
  207. sub cmdItemList {
  208. message T("-----------Item List-----------n" .
  209. "   # Name                           Coordn"), "list";
  210. for (my $i = 0; $i < @itemsID; $i++) {
  211. next if ($itemsID[$i] eq "");
  212. my $item = $items{$itemsID[$i]};
  213. my $display = "$item->{name} x $item->{amount}";
  214. message(sprintf("%4d %-30s (%3d, %3d)n",
  215. $i, $display, $item->{pos}{x}, $item->{pos}{y}),
  216. "list");
  217. }
  218. message("-------------------------------n", "list");
  219. }
  220. sub cmdItemLogClear {
  221. itemLog_clear();
  222. message T("Item log cleared.n"), "success";
  223. }
  224. #sub cmdJudge {
  225. # my (undef, $args) = @_;
  226. # my ($arg1) = $args =~ /^(d+)/;
  227. # my ($arg2) = $args =~ /^d+ (d+)/;
  228. # if ($arg1 eq "" || $arg2 eq "") {
  229. # error "Syntax Error in function 'judge' (Give an alignment point to Player)n" .
  230. # "Usage: judge <player #> <0 (good) | 1 (bad)>n";
  231. # } elsif ($playersID[$arg1] eq "") {
  232. # error "Error in function 'judge' (Give an alignment point to Player)n" .
  233. # "Player $arg1 does not exist.n";
  234. # } else {
  235. # $arg2 = ($arg2 >= 1);
  236. # $messageSender->sendAlignment($playersID[$arg1], $arg2);
  237. # }
  238. #}
  239. sub cmdKill {
  240. my (undef, $ID) = @_;
  241. my $target = $playersID[$ID];
  242. unless ($target) {
  243. error TF("Player %s does not exist.n", $ID);
  244. return;
  245. }
  246. attack($target);
  247. }
  248. sub cmdLook {
  249. my (undef, $args) = @_;
  250. my ($arg1) = $args =~ /^(d+)/;
  251. my ($arg2) = $args =~ /^d+ (d+)$/;
  252. if ($arg1 eq "") {
  253. error T("Syntax Error in function 'look' (Look a Direction)n" .
  254. "Usage: look <body dir> [<head dir>]n");
  255. } else {
  256. look($arg1, $arg2);
  257. }
  258. }
  259. sub cmdLookPlayer {
  260. my (undef, $arg1) = @_;
  261. if ($arg1 eq "") {
  262. error T("Syntax Error in function 'lookp' (Look at Player)n" .
  263. "Usage: lookp <player #>n");
  264. } elsif (!$playersID[$arg1]) {
  265. error TF("Error in function 'lookp' (Look at Player)n" .
  266. "'%s' is not a valid player number.n", $arg1);
  267. } else {
  268. lookAtPosition($players{$playersID[$arg1]}{pos_to});
  269. }
  270. }
  271. sub cmdManualMove {
  272. if (!$net || $net->getState() != Network::IN_GAME) {
  273. error TF("You must be logged in the game to use this command (%s)n", shift);
  274. return;
  275. }
  276. my ($switch, $steps) = @_;
  277. if (!$steps) {
  278. $steps = 5; 
  279. } elsif ($steps !~ /^d+$/) {
  280. error TF("Error in function '%s' (Manual Move)n" .
  281. "Usage: %s [distance]n", $switch, $switch);
  282. return;
  283. }
  284. if ($switch eq "east") {
  285. manualMove($steps, 0);
  286. } elsif ($switch eq "west") {
  287. manualMove(-$steps, 0);
  288. } elsif ($switch eq "north") {
  289. manualMove(0, $steps);
  290. } elsif ($switch eq "south") {
  291. manualMove(0, -$steps);
  292. } elsif ($switch eq "northeast") {
  293. manualMove($steps, $steps);
  294. } elsif ($switch eq "southwest") {
  295. manualMove(-$steps, -$steps);
  296. } elsif ($switch eq "northwest") {
  297. manualMove(-$steps, $steps);
  298. } elsif ($switch eq "southeast") {
  299. manualMove($steps, -$steps);
  300. }
  301. }
  302. sub cmdMemo {
  303. if (!$net || $net->getState() != Network::IN_GAME) {
  304. error TF("You must be logged in the game to use this command (%s)n", shift);
  305. return;
  306. }
  307. $messageSender->sendMemo();
  308. }
  309. sub cmdMonsterList {
  310. my ($dmgTo, $dmgFrom, $dist, $pos, $name, $monsters);
  311. message TF("-----------Monster List-----------n" .
  312. "#   Name                        ID      DmgTo DmgFrom  Distance    Coordinatesn"), "list";
  313. $monsters = $monstersList->getItems() if ($monstersList);
  314. foreach my $monster (@{$monsters}) {
  315. $dmgTo = ($monster->{dmgTo} ne "")
  316. ? $monster->{dmgTo}
  317. : 0;
  318. $dmgFrom = ($monster->{dmgFrom} ne "")
  319. ? $monster->{dmgFrom}
  320. : 0;
  321. $dist = distance($char->{pos_to}, $monster->{pos_to});
  322. $dist = sprintf("%.1f", $dist) if (index($dist, '.') > -1);
  323. $pos = '(' . $monster->{pos_to}{x} . ', ' . $monster->{pos_to}{y} . ')';
  324. $name = $monster->name;
  325. if ($name ne $monster->{name_given}) {
  326. $name .= '[' . $monster->{name_given} . ']';
  327. }
  328. message(swrite(
  329. "@<< @<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<< @<<<< @<<<<    @<<<<<      @<<<<<<<<<<",
  330. [$monster->{binID}, $name, $monster->{binType}, $dmgTo, $dmgFrom, $dist, $pos]),
  331. "list");
  332. }
  333. message("----------------------------------n", "list");
  334. }
  335. sub cmdMove {
  336. if (!$net || $net->getState() != Network::IN_GAME) {
  337. error TF("You must be logged in the game to use this command (%s)n", shift);
  338. return;
  339. }
  340. my (undef, $args) = @_;
  341. my ($arg1, $arg2, $arg3) = $args =~ /^(.+?) (.+?)(?: (.*))?$/;
  342. my ($map, $x, $y);
  343. if ($arg1 eq "") {
  344. # map name or portal number
  345. $map = $args;
  346. } elsif ($arg3 eq "") {
  347. # coordinates
  348. $x = $arg1;
  349. $y = $arg2;
  350. $map = $field{name};
  351. } elsif ($arg1 =~ /^d+$/) {
  352. # coordinates and map
  353. $x = $arg1;
  354. $y = $arg2;
  355. $map = $arg3;
  356. } else {
  357. # map and coordinates
  358. $x = $arg2;
  359. $y = $arg3;
  360. $map = $arg1;
  361. }
  362. if ((($x !~ /^d+$/ || $y !~ /^d+$/) && $arg1 ne "") || ($args eq "")) {
  363. error T("Syntax Error in function 'move' (Move Player)n" .
  364. "Usage: move <x> <y> [<map>]n" .
  365. "       move <map> [<x> <y>]n" .
  366. "       move <portal#>n");
  367. } elsif ($map eq "stop") {
  368. AI::clear(qw/move route mapRoute/);
  369. message T("Stopped all movementn"), "success";
  370. } else {
  371. AI::clear(qw/move route mapRoute/);
  372. if ($maps_lut{"${map}.rsw"}) {
  373. if ($x ne "") {
  374. message TF("Calculating route to: %s(%s): %s, %sn", 
  375. $maps_lut{$map.'.rsw'}, $map, $x, $y), "route";
  376. } else {
  377. message TF("Calculating route to: %s(%s)n", 
  378. $maps_lut{$map.'.rsw'}, $map), "route";
  379. }
  380. main::ai_route($map, $x, $y,
  381. attackOnRoute => 1,
  382. noSitAuto => 1,
  383. notifyUponArrival => 1);
  384. } elsif ($map =~ /^d+$/) {
  385. if ($portalsID[$map]) {
  386. message TF("Move into portal number %s (%s,%s)n", 
  387. $map, $portals{$portalsID[$map]}{'pos'}{'x'}, $portals{$portalsID[$map]}{'pos'}{'y'});
  388. main::ai_route($field{name}, $portals{$portalsID[$map]}{'pos'}{'x'}, $portals{$portalsID[$map]}{'pos'}{'y'}, attackOnRoute => 1, noSitAuto => 1);
  389. } else {
  390. error T("No portals exist.n");
  391. }
  392. } else {
  393. error TF("Map %s does not existn", $map);
  394. }
  395. }
  396. }
  397. sub cmdNPCList {
  398. my (undef, $args) = @_;
  399. my @arg = parseArgs($args);
  400. my $msg = T("-----------NPC List-----------n" .
  401. "#    Name                         Coordinates   IDn");
  402. if ($npcsList) {
  403. if ($arg[0] =~ /^d+$/) {
  404. my $i = $arg[0];
  405. if (my $npc = $npcsList->get($i)) {
  406. my $pos = "($npc->{pos_to}{x}, $npc->{pos_to}{y})";
  407. $msg .= swrite(
  408. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<   @<<<<<<<<",
  409. [$i, $npc->name, $pos, $npc->{nameID}]);
  410. $msg .= "---------------------------------n";
  411. message $msg, "info";
  412. } else {
  413. error T("Syntax Error in function 'nl' (List NPCs)n" .
  414. "Usage: nl [<npc #>]n");
  415. }
  416. return;
  417. }
  418. my $npcs = $npcsList->getItems();
  419. foreach my $npc (@{$npcs}) {
  420. my $pos = "($npc->{pos}{x}, $npc->{pos}{y})";
  421. $msg .= swrite(
  422. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<   @<<<<<<<<",
  423. [$npc->{binID}, $npc->name, $pos, $npc->{nameID}]);
  424. }
  425. }
  426. $msg .= "---------------------------------n";
  427. message $msg, "list";
  428. }
  429. sub cmdOpenShop {
  430. if (!$net || $net->getState() != Network::IN_GAME) {
  431. error TF("You must be logged in the game to use this command (%s)n", shift);
  432. return;
  433. }
  434. main::openShop();
  435. }
  436. sub cmdParty {
  437. my (undef, $args) = @_;
  438. my ($arg1) = $args =~ /^(w*)/;
  439. my ($arg2) = $args =~ /^w* (d+)b/;
  440. if ($arg1 eq "" && (!$char || !$char->{'party'} || !%{$char->{'party'}} )) {
  441. error T("Error in function 'party' (Party Functions)n" .
  442. "Can't list party - you're not in a party.n");
  443. } elsif ($arg1 eq "") {
  444. message TF("----------Party-----------n" .
  445. "%sn" .
  446. "#      Name                  Map                    Online    HPn", 
  447. $char->{'party'}{'name'}), "list";
  448. for (my $i = 0; $i < @partyUsersID; $i++) {
  449. next if ($partyUsersID[$i] eq "");
  450. my $coord_string = "";
  451. my $hp_string = "";
  452. my $name_string = $char->{'party'}{'users'}{$partyUsersID[$i]}{'name'};
  453. my $admin_string = ($char->{'party'}{'users'}{$partyUsersID[$i]}{'admin'}) ? "(A)" : "";
  454. my $online_string;
  455. my $map_string;
  456. if ($partyUsersID[$i] eq $accountID) {
  457. # Translation Comment: Is the party user on list online?
  458. $online_string = T("Yes");
  459. ($map_string) = $field{name};
  460. $coord_string = $char->{'pos'}{'x'}. ", ".$char->{'pos'}{'y'};
  461. $hp_string = $char->{'hp'}."/".$char->{'hp_max'}
  462. ." (".int($char->{'hp'}/$char->{'hp_max'} * 100)
  463. ."%)";
  464. } else {
  465. $online_string = ($char->{'party'}{'users'}{$partyUsersID[$i]}{'online'}) ? T("Yes") : T("No");
  466. ($map_string) = $char->{'party'}{'users'}{$partyUsersID[$i]}{'map'} =~ /([sS]*).gat/;
  467. $coord_string = $char->{'party'}{'users'}{$partyUsersID[$i]}{'pos'}{'x'}
  468. . ", ".$char->{'party'}{'users'}{$partyUsersID[$i]}{'pos'}{'y'}
  469. if ($char->{'party'}{'users'}{$partyUsersID[$i]}{'pos'}{'x'} ne ""
  470. && $char->{'party'}{'users'}{$partyUsersID[$i]}{'online'});
  471. $hp_string = $char->{'party'}{'users'}{$partyUsersID[$i]}{'hp'}."/".$char->{'party'}{'users'}{$partyUsersID[$i]}{'hp_max'}
  472. ." (".int($char->{'party'}{'users'}{$partyUsersID[$i]}{'hp'}/$char->{'party'}{'users'}{$partyUsersID[$i]}{'hp_max'} * 100)
  473. ."%)" if ($char->{'party'}{'users'}{$partyUsersID[$i]}{'hp_max'} && $char->{'party'}{'users'}{$partyUsersID[$i]}{'online'});
  474. }
  475. message(swrite(
  476. "@< @<< @<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<< @<<       @<<<<<<<<<<<<<<<<<<",
  477. [$i, $admin_string, $name_string, $map_string, $coord_string, $online_string, $hp_string]),
  478. "list");
  479. }
  480. message("--------------------------n", "list");
  481. } elsif (!$net || $net->getState() != Network::IN_GAME) {
  482. error TF("You must be logged in the game to use this command (%s)n", 'party ' . $arg1);
  483. return;
  484. } elsif ($arg1 eq "create") {
  485. my ($arg2) = $args =~ /^w* ([sS]*)/;
  486. if ($arg2 eq "") {
  487. error T("Syntax Error in function 'party create' (Organize Party)n" .
  488. "Usage: party create <party name>n");
  489. } else {
  490. $messageSender->sendPartyOrganize($arg2);
  491. }
  492. } elsif ($arg1 eq "join" && $arg2 ne "1" && $arg2 ne "0") {
  493. error T("Syntax Error in function 'party join' (Accept/Deny Party Join Request)n" .
  494. "Usage: party join <flag>n");
  495. } elsif ($arg1 eq "join" && $incomingParty{'ID'} eq "") {
  496. error T("Error in function 'party join' (Join/Request to Join Party)n" .
  497. "Can't accept/deny party request - no incoming request.n");
  498. } elsif ($arg1 eq "join") {
  499. $messageSender->sendPartyJoin($incomingParty{'ID'}, $arg2);
  500. undef %incomingParty;
  501. } elsif ($arg1 eq "request" && ( !$char->{'party'} || !%{$char->{'party'}} )) {
  502. error T("Error in function 'party request' (Request to Join Party)n" .
  503. "Can't request a join - you're not in a party.n");
  504. } elsif ($arg1 eq "request" && $playersID[$arg2] eq "") {
  505. error TF("Error in function 'party request' (Request to Join Party)n" .
  506. "Can't request to join party - player %s does not exist.n", $arg2);
  507. } elsif ($arg1 eq "request") {
  508. $messageSender->sendPartyJoinRequest($playersID[$arg2]);
  509. } elsif ($arg1 eq "leave" && (!$char->{'party'} || !%{$char->{'party'}} ) ) {
  510. error T("Error in function 'party leave' (Leave Party)n" .
  511. "Can't leave party - you're not in a party.n");
  512. } elsif ($arg1 eq "leave") {
  513. $messageSender->sendPartyLeave();
  514. } elsif ($arg1 eq "share" && ( !$char->{'party'} || !%{$char->{'party'}} )) {
  515. error T("Error in function 'party share' (Set Party Share EXP)n" .
  516. "Can't set share - you're not in a party.n");
  517. } elsif ($arg1 eq "share" && $arg2 ne "1" && $arg2 ne "0") {
  518. error T("Syntax Error in function 'party share' (Set Party Share EXP)n" .
  519. "Usage: party share <flag>n");
  520. } elsif ($arg1 eq "share") {
  521. $messageSender->sendPartyShareEXP($arg2);
  522. } elsif ($arg1 eq "kick" && ( !$char->{'party'} || !%{$char->{'party'}} )) {
  523. error T("Error in function 'party kick' (Kick Party Member)n" .
  524. "Can't kick member - you're not in a party.n");
  525. } elsif ($arg1 eq "kick" && $arg2 eq "") {
  526. error T("Syntax Error in function 'party kick' (Kick Party Member)n" . 
  527. "Usage: party kick <party member #>n");
  528. } elsif ($arg1 eq "kick" && $partyUsersID[$arg2] eq "") {
  529. error TF("Error in function 'party kick' (Kick Party Member)n" .
  530. "Can't kick member - member %s doesn't exist.n", $arg2);
  531. } elsif ($arg1 eq "kick") {
  532. $messageSender->sendPartyKick($partyUsersID[$arg2]
  533. ,$char->{'party'}{'users'}{$partyUsersID[$arg2]}{'name'});
  534. } else {
  535. error T("Syntax Error in function 'party' (Party Management)n" .
  536. "Usage: party [<create|join|request|leave|share|kick>]n");
  537. }
  538. }
  539. sub cmdPartyChat {
  540. if (!$net || $net->getState() != Network::IN_GAME) {
  541. error TF("You must be logged in the game to use this command (%s)n", shift);
  542. return;
  543. }
  544. my (undef, $arg1) = @_;
  545. if ($arg1 eq "") {
  546. error T("Syntax Error in function 'p' (Party Chat)n" .
  547. "Usage: p <message>n");
  548. } else {
  549. sendMessage($messageSender, "p", $arg1);
  550. }
  551. }
  552. sub cmdPecopeco {
  553. my (undef, $arg1) = @_;
  554. my $hasPecopeco;
  555. if ($char) {
  556. foreach my $ID (keys %{$char->{statuses}}) {
  557. if ($ID eq "Pecopeco") {
  558. $hasPecopeco = 1;
  559. last;
  560. }
  561. }
  562. }
  563. if ($arg1 eq "") {
  564. if ($hasPecopeco) {
  565. message T("Your Pecopeco is activen");
  566. } else {
  567. message T("Your Pecopeco is inactiven");
  568. }
  569. } elsif ($arg1 eq "release") {
  570. if (!$net || $net->getState() != Network::IN_GAME) {
  571. error TF("You must be logged in the game to use this command (%s)n", 'pecopeco release');
  572. return;
  573. }
  574. if (!$hasPecopeco) {
  575. error T("Error in function 'pecopeco release' (Remove Pecopeco Status)n" .
  576. "You don't possess a Pecopeco.n");
  577. } else {
  578. $messageSender->sendCompanionRelease();
  579. }
  580. }
  581. }
  582. sub cmdPet {
  583. my (undef, $subcmd) = @_;
  584. if (!%pet) {
  585. error T("Error in function 'pet' (Pet Management)n" .
  586. "You don't have a pet.n");
  587. } elsif ($subcmd eq "s" || $subcmd eq "status") {
  588. message TF("-----------Pet Status-----------nName: %-23s Accessory: %s", $pet{name}, itemNameSimple($pet{accessory})), "list";
  589. } elsif (!$net || $net->getState() != Network::IN_GAME) {
  590. error TF("You must be logged in the game to use this command (%s)n", 'pet ' . $subcmd);
  591. return;
  592. } elsif ($subcmd eq "p" || $subcmd eq "performance") {
  593. $messageSender->sendPetPerformance();
  594. } elsif ($subcmd eq "r" || $subcmd eq "return") {
  595. $messageSender->sendPetReturnToEgg();
  596. } elsif ($subcmd eq "u" || $subcmd eq "unequip") {
  597. $messageSender->sendPetUnequipItem();
  598. }
  599. }
  600. sub cmdPetList {
  601. message T("-----------Pet List-----------n" .
  602. "#    Type                     Namen"), "list";
  603. for (my $i = 0; $i < @petsID; $i++) {
  604. next if ($petsID[$i] eq "");
  605. message(swrite(
  606. "@<<< @<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<",
  607. [$i, $pets{$petsID[$i]}{'name'}, $pets{$petsID[$i]}{'name_given'}]),
  608. "list");
  609. }
  610. message("----------------------------------n", "list");
  611. }
  612. sub cmdPlayerList {
  613. my (undef, $args) = @_;
  614. my $msg;
  615. if ($args eq "g") {
  616. my $maxpl;
  617. my $maxplg=0;
  618. $msg =  T("-----------Player List-----------n" .
  619. "#    Name                                Sex   Lv  Job         Dist  Coordn");
  620. if ($playersList) {
  621. foreach my $player (@{$playersList->getItems()}) {
  622. my ($name, $dist, $pos);
  623. $name = $player->name;
  624. if ($char->{guild}{name} eq ($player->{guild}{name})) {
  625. if ($player->{guild} && %{$player->{guild}}) {
  626. $name .= " [$player->{guild}{name}]";
  627. }
  628. $dist = distance($char->{pos_to}, $player->{pos_to});
  629. $dist = sprintf("%.1f", $dist) if (index ($dist, '.') > -1);
  630. $pos = '(' . $player->{pos_to}{x} . ', ' . $player->{pos_to}{y} . ')';
  631. $maxplg = $maxplg+1;
  632. $msg .= swrite(
  633. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<< @<< @<<<<<<<<<< @<<<< @<<<<<<<<<<",
  634. [$player->{binID}, $name, $sex_lut{$player->{sex}}, $player->{lv}, $player->job, $dist, $pos]);
  635. }
  636. $maxpl = @{$playersList->getItems()};
  637. }
  638. }
  639. $msg .= "Total guild players: $maxplg n";
  640. if ($maxpl ne "") {
  641. $msg .= "Total players: $maxpl n";
  642. } else {
  643. $msg .= "There are no players near you.n";
  644. }
  645. $msg .= "---------------------------------n";
  646. message($msg, "list");
  647. return;
  648. }
  649. if ($args eq "p") {
  650. my $maxpl;
  651. my $maxplp=0;
  652. $msg =  T("-----------Player List-----------n" .
  653. "#    Name                                Sex   Lv  Job         Dist  Coordn");
  654. if ($playersList) {
  655. foreach my $player (@{$playersList->getItems()}) {
  656. my ($name, $dist, $pos);
  657. $name = $player->name;
  658. if ($char->{party}{name} eq ($player->{party}{name})) {
  659. if ($player->{guild} && %{$player->{guild}}) {
  660. $name .= " [$player->{guild}{name}]";
  661. }
  662. $dist = distance($char->{pos_to}, $player->{pos_to});
  663. $dist = sprintf("%.1f", $dist) if (index ($dist, '.') > -1);
  664. $pos = '(' . $player->{pos_to}{x} . ', ' . $player->{pos_to}{y} . ')';
  665. $maxplp = $maxplp+1;
  666. $msg .= swrite(
  667. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<< @<< @<<<<<<<<<< @<<<< @<<<<<<<<<<",
  668. [$player->{binID}, $name, $sex_lut{$player->{sex}}, $player->{lv}, $player->job, $dist, $pos]);
  669. }
  670. $maxpl = @{$playersList->getItems()};
  671. }
  672. }
  673. $msg .= "Total party players: $maxplp n";
  674. if ($maxpl ne "") {
  675. $msg .= "Total players: $maxpl n";
  676. } else {
  677. $msg .= "There are no players near you.n";
  678. }
  679. $msg .= "---------------------------------n";
  680. message($msg, "list");
  681. return;
  682. }
  683. if ($args ne "") {
  684. my Actor::Player $player = Match::player($args) if ($playersList);
  685. if (!$player) {
  686. error TF("Player "%s" does not exist.n", $args);
  687. return;
  688. }
  689. my $ID = $player->{ID};
  690. my $body = $player->{look}{body} % 8;
  691. my $head = $player->{look}{head};
  692. if ($head == 0) {
  693. $head = $body;
  694. } elsif ($head == 1) {
  695. $head = $body - 1;
  696. } else {
  697. $head = $body + 1;
  698. }
  699. my $pos = calcPosition($player);
  700. my $mypos = calcPosition($char);
  701. my $dist = sprintf("%.1f", distance($pos, $mypos));
  702. $dist =~ s/.0$//;
  703. my %vecPlayerToYou;
  704. my %vecYouToPlayer;
  705. getVector(%vecPlayerToYou, $mypos, $pos);
  706. getVector(%vecYouToPlayer, $pos, $mypos);
  707. my $degPlayerToYou = vectorToDegree(%vecPlayerToYou);
  708. my $degYouToPlayer = vectorToDegree(%vecYouToPlayer);
  709. my $hex = getHex($ID);
  710. my $playerToYou = int(sprintf("%.0f", (360 - $degPlayerToYou) / 45)) % 8;
  711. my $youToPlayer = int(sprintf("%.0f", (360 - $degYouToPlayer) / 45)) % 8;
  712. my $headTop = headgearName($player->{headgear}{top});
  713. my $headMid = headgearName($player->{headgear}{mid});
  714. my $headLow = headgearName($player->{headgear}{low});
  715. $msg = TF("------------------Player Info ------------------n" .
  716. "%s (%d)n" .
  717. "Account ID: %s (Hex: %s)n" .
  718. "Party: %sn" .
  719. "Guild: %sn" .
  720. "Guild title: %sn" .
  721. "Position: %s, %s (%s of you: %s degrees)n" .
  722. "Level: %-7d Distance: %-17sn" .
  723. "Sex: %-6s    Class: %sn" .
  724. "-------------------------------------------------n" .
  725. "Body direction: %-19s Head direction:  %-19sn" .
  726. "Weapon: %sn" .
  727. "Shield: %sn" .
  728. "Shoes : %sn" .
  729. "Upper headgear: %-19s Middle headgear: %-19sn" .
  730. "Lower headgear: %-19s Hair color:      %-19sn" .
  731. "Walk speed: %s secs per blockn", 
  732. $player->name, $player->{binID}, $player->{nameID}, $hex, 
  733. ($player->{party} && $player->{party}{name} ne '') ? $player->{party}{name} : '',
  734. ($player->{guild}) ? $player->{guild}{name} : '',
  735. ($player->{guild}) ? $player->{guild}{title} : '',
  736. $pos->{x}, $pos->{y}, $directions_lut{$youToPlayer}, int($degYouToPlayer),
  737. $player->{lv}, $dist, $sex_lut{$player->{sex}}, $jobs_lut{$player->{jobID}},
  738. "$directions_lut{$body} ($body)", "$directions_lut{$head} ($head)",
  739. itemName({nameID => $player->{weapon}}),
  740. itemName({nameID => $player->{shield}}),
  741. itemName({nameID => $player->{shoes}}), $headTop, $headMid, 
  742.   $headLow, "$haircolors{$player->{hair_color}} ($player->{hair_color})",
  743.   $player->{walk_speed});
  744. if ($player->{dead}) {
  745. $msg .= T("Player is dead.n");
  746. } elsif ($player->{sitting}) {
  747. $msg .= T("Player is sitting.n");
  748. }
  749. if ($degPlayerToYou >= $head * 45 - 29 && $degPlayerToYou <= $head * 45 + 29) {
  750. $msg .= T("Player is facing towards you.n");
  751. }
  752. $msg .= "------------------- Statuses -------------------n";
  753. #############################################################
  754. #Statuses
  755. #############################################################
  756. my $statuses = 'none';
  757. if (defined $player->{statuses} && %{$player->{statuses}}) {
  758. $statuses = join(", ", keys %{$player->{statuses}});
  759. }
  760. $msg .= TF("Statuses: %s n", $statuses);
  761. $msg .= "-------------------------------------------------n";
  762. message $msg, "info";
  763. return;
  764. }
  765. {
  766. my $maxpl;
  767. $msg =  T("-----------Player List-----------n" .
  768. "#    Name                                Sex   Lv  Job         Dist  Coordn");
  769. if ($playersList) {
  770. foreach my $player (@{$playersList->getItems()}) {
  771. my ($name, $dist, $pos);
  772. $name = $player->name;
  773. if ($player->{guild} && %{$player->{guild}}) {
  774. $name .= " [$player->{guild}{name}]";
  775. }
  776. $dist = distance($char->{pos_to}, $player->{pos_to});
  777. $dist = sprintf("%.1f", $dist) if (index ($dist, '.') > -1);
  778. $pos = '(' . $player->{pos_to}{x} . ', ' . $player->{pos_to}{y} . ')';
  779. $maxpl = @{$playersList->getItems()};
  780. $msg .= swrite(
  781. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<< @<< @<<<<<<<<<< @<<<< @<<<<<<<<<<",
  782. [$player->{binID}, $name, $sex_lut{$player->{sex}}, $player->{lv}, $player->job, $dist, $pos]);
  783. }
  784. }
  785. if ($maxpl ne "") {
  786. $msg .= "Total players: $maxpl n";
  787. } else {$msg .= "There are no players near you.n";}
  788. $msg .= "---------------------------------n";
  789. message($msg, "list");
  790. }
  791. }
  792. sub cmdPlugin {
  793. return if ($Settings::lockdown);
  794. my (undef, $input) = @_;
  795. my @args = split(/ +/, $input, 2);
  796. if (@args == 0) {
  797. message T("--------- Currently loaded plugins ---------n" .
  798. "#   Name              Descriptionn"), "list";
  799. my $i = 0;
  800. foreach my $plugin (@Plugins::plugins) {
  801. next unless $plugin;
  802. message(swrite(
  803. "@<< @<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
  804. [$i, $plugin->{name}, $plugin->{description}]
  805. ), "list");
  806. $i++;
  807. }
  808. message("--------------------------------------------n", "list");
  809. } elsif ($args[0] eq 'reload') {
  810. my @names;
  811. if ($args[1] =~ /^d+$/) {
  812. push @names, $Plugins::plugins[$args[1]]{name};
  813. } elsif ($args[1] eq '') {
  814. error T("Syntax Error in function 'plugin reload' (Reload Plugin)n" .
  815. "Usage: plugin reload <plugin name|plugin number#|"all">n");
  816. return;
  817. } elsif ($args[1] eq 'all') {
  818. foreach my $plugin (@Plugins::plugins) {
  819. push @names, $plugin->{name};
  820. }
  821. } else {
  822. foreach my $plugin (@Plugins::plugins) {
  823. if ($plugin->{name} =~ /$args[1]/i) {
  824. push @names, $plugin->{name};
  825. }
  826. }
  827. if (!@names) {
  828. error T("Error in function 'plugin reload' (Reload Plugin)n" .
  829. "The specified plugin names do not exist.n");
  830. return;
  831. }
  832. }
  833. foreach (my $i = 0; $i < @names; $i++) {
  834. Plugins::reload($names[$i]);
  835. }
  836. } elsif ($args[0] eq 'load') {
  837. if ($args[1] eq '') {
  838. error T("Syntax Error in function 'plugin load' (Load Plugin)n" .
  839. "Usage: plugin load <filename|"all">n");
  840. return;
  841. } elsif ($args[1] eq 'all') {
  842. Plugins::loadAll();
  843. } else {
  844. Plugins::load($args[1]);
  845. }
  846. } elsif ($args[0] eq 'unload') {
  847. if ($args[1] =~ /^d+$/) {
  848. if ($Plugins::plugins[$args[1]]) {
  849. my $name = $Plugins::plugins[$args[1]]{name};
  850. Plugins::unload($name);
  851. message TF("Plugin %s unloaded.n", $name), "system";
  852. } else {
  853. error TF("'%s' is not a valid plugin number.n", $args[1]);
  854. }
  855. } elsif ($args[1] eq '') {
  856. error T("Syntax Error in function 'plugin unload' (Unload Plugin)n" .
  857. "Usage: plugin unload <plugin name|plugin number#|"all">n");
  858. return;
  859. } elsif ($args[1] eq 'all') {
  860. Plugins::unloadAll();
  861. } else {
  862. foreach my $plugin (@Plugins::plugins) {
  863. if ($plugin->{name} =~ /$args[1]/i) {
  864. my $name = $plugin->{name};
  865. Plugins::unload($name);
  866. message TF("Plugin %s unloaded.n", $name), "system";
  867. }
  868. }
  869. }
  870. } else {
  871. my $msg;
  872. $msg = T("--------------- Plugin command syntax ---------------n" .
  873. "Command:                                              Description:n" .
  874. " plugin                                                List loaded pluginsn" .
  875. " plugin load <filename>                                Load a pluginn" .
  876. " plugin unload <plugin name|plugin number#|"all">      Unload a loaded pluginn" .
  877. " plugin reload <plugin name|plugin number#|"all">      Reload a loaded pluginn" .
  878. "-----------------------------------------------------n");
  879. if ($args[0] eq 'help') {
  880. message($msg, "info");
  881. } else {
  882. error T("Syntax Error in function 'plugin' (Control Plugins)n");
  883. error($msg);
  884. }
  885. }
  886. }
  887. sub cmdPMList {
  888. message T("-----------PM List-----------n"), "list";
  889. for (my $i = 1; $i <= @privMsgUsers; $i++) {
  890. message(swrite(
  891. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<",
  892. [$i, $privMsgUsers[$i - 1]]),
  893. "list");
  894. }
  895. message("-----------------------------n", "list");
  896. }
  897. sub cmdPortalList {
  898. my (undef, $args) = @_;
  899. my ($arg) = parseArgs($args,1);
  900. if ($arg eq '') {
  901. message T("-----------Portal List-----------n" .
  902. "#    Name                                Coordinatesn"), "list";
  903. for (my $i = 0; $i < @portalsID; $i++) {
  904. next if $portalsID[$i] eq "";
  905. my $portal = $portals{$portalsID[$i]};
  906. my $coords = "($portal->{pos}{x}, $portal->{pos}{y})";
  907. message(swrite(
  908. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<",
  909. [$i, $portal->{name}, $coords]),
  910. "list");
  911. }
  912. message("---------------------------------n", "list");
  913. } elsif ($arg eq 'recompile') {
  914. Settings::loadByRegexp(qr/portals/);
  915. Misc::compilePortals() if Misc::compilePortals_check();
  916. }
  917. }
  918. sub cmdPrivateMessage {
  919. if (!$net || $net->getState() != Network::IN_GAME) {
  920. error TF("You must be logged in the game to use this command (%s)n", shift);
  921. return;
  922. }
  923. my ($switch, $args) = @_;
  924. my ($user, $msg) = parseArgs($args, 2);
  925. if ($user eq "" || $msg eq "") {
  926. error T("Syntax Error in function 'pm' (Private Message)n" .
  927. "Usage: pm (username) (message)n       pm (<#>) (message)n");
  928. return;
  929. } elsif ($user =~ /^d+$/) {
  930. if ($user - 1 >= @privMsgUsers) {
  931. error TF("Error in function 'pm' (Private Message)n" .
  932. "Quick look-up %s does not existn", $user);
  933. } elsif (!@privMsgUsers) {
  934. error T("Error in function 'pm' (Private Message)n" .
  935. "You have not pm-ed anyone beforen");
  936. } else {
  937. sendMessage($messageSender, "pm", $msg, $privMsgUsers[$user - 1]);
  938. $lastpm{msg} = $msg;
  939. $lastpm{user} = $privMsgUsers[$user - 1];
  940. }
  941. } else {
  942. if (!defined binFind(@privMsgUsers, $user)) {
  943. push @privMsgUsers, $user;
  944. }
  945. sendMessage($messageSender, "pm", $msg, $user);
  946. $lastpm{msg} = $msg;
  947. $lastpm{user} = $user;
  948. }
  949. }
  950. sub cmdQuit {
  951. quit();
  952. }
  953. sub cmdReload {
  954. my (undef, $args) = @_;
  955. if ($args eq '') {
  956. error T("Syntax Error in function 'reload' (Reload Configuration Files)n" .
  957. "Usage: reload <name|"all">n");
  958. } else {
  959. parseReload($args);
  960. }
  961. }
  962. sub cmdReloadCode {
  963. my (undef, $args) = @_;
  964. if ($args ne "") {
  965. Modules::addToReloadQueue(parseArgs($args));
  966. } else {
  967. Modules::reloadFile("$FindBin::RealBin/src/functions.pl");
  968. }
  969. }
  970. sub cmdRelog {
  971. my (undef, $arg) = @_;
  972. if (!$arg || $arg =~ /^d+$/) {
  973. @cmdQueueList = ();
  974. $cmdQueue = 0;
  975. relog($arg);
  976. } else {
  977. error T("Syntax Error in function 'relog' (Log out then log in.)n" .
  978. "Usage: relog [delay]n");
  979. }
  980. }
  981. sub cmdRepair {
  982. if (!$net || $net->getState() != Network::IN_GAME) {
  983. error TF("You must be logged in the game to use this command (%s)n", shift);
  984. return;
  985. my (undef, $listID) = @_;
  986. if ($listID =~ /^d+$/) {
  987. if ($repairList{$listID}) {
  988. $messageSender->sendRepairItem($repairList{$listID});
  989. my $name = itemNameSimple($repairList{$listID}{nameID});
  990. message TF("Sending repair item: %sn", $name);
  991. } elsif (!defined $repairList{$listID}) {
  992. error TF("Item with index: %s does either not exist in the repair list or the list is empty.n", $listID);
  993. }
  994. } else {
  995. error T("Syntax Error in function 'repair' (Repair player's items.)n" .
  996. "Usage: repair [item index]n");
  997. }
  998. }
  999. sub cmdRespawn {
  1000. if (!$net || $net->getState() != Network::IN_GAME) {
  1001. error TF("You must be logged in the game to use this command (%s)n", shift);
  1002. return;
  1003. }
  1004. if ($char->{dead}) {
  1005. $messageSender->sendRespawn();
  1006. } else {
  1007. main::useTeleport(2);
  1008. }
  1009. }
  1010. sub cmdSell {
  1011. if (!$net || $net->getState() != Network::IN_GAME) {
  1012. error TF("You must be logged in the game to use this command (%s)n", shift);
  1013. return;
  1014. }
  1015. my @args = parseArgs($_[1]);
  1016. if ($args[0] eq "" && $talk{buyOrSell}) {
  1017. $messageSender->sendGetSellList($talk{ID});
  1018. } elsif ($args[0] eq "list") {
  1019. if (@sellList == 0) {
  1020. message T("Your sell list is empty.n"), "info";
  1021. } else {
  1022. my $text = '';
  1023. $text .= T("------------- Sell list -------------n" .
  1024. "#   Item                           Amountn");
  1025. foreach my $item (@sellList) {
  1026. $text .= sprintf("%-3d %-30s %dn", $item->{invIndex}, $item->{name}, $item->{amount});
  1027. }
  1028. $text .= "-------------------------------------n";
  1029. message($text, "list");
  1030. }
  1031. } elsif ($args[0] eq "done") {
  1032. $messageSender->sendSellBulk(@sellList);
  1033. message TF("Sold %s items.n", @sellList.""), "success";
  1034. @sellList = ();
  1035. } elsif ($args[0] eq "cancel") {
  1036. @sellList = ();
  1037. message T("Sell list has been cleared.n"), "info";
  1038. } elsif ($args[0] eq "" || ($args[0] !~ /^d+$/ && $args[0] !~ /[,-]/)) {
  1039. error T("Syntax Error in function 'sell' (Sell Inventory Item)n" .
  1040. "Usage: sell <inventory item index #> [<amount>]n" .
  1041. "       sell listn" .
  1042. "       sell donen" .
  1043. "       sell canceln");
  1044. } else {
  1045. my @items = Actor::Item::getMultiple($args[0]);
  1046. if (@items > 0) {
  1047. foreach my $item (@items) {
  1048. my %obj;
  1049. if (defined(findIndex(@sellList, "invIndex", $item->{invIndex}))) {
  1050. error TF("%s (%s) is already in the sell list.n", $item->nameString, $item->{invIndex});
  1051. next;
  1052. }
  1053. $obj{name} = $item->nameString();
  1054. $obj{index} = $item->{index};
  1055. $obj{invIndex} = $item->{invIndex};
  1056. if (!$args[1] || $args[1] > $item->{amount}) {
  1057. $obj{amount} = $item->{amount};
  1058. } else {
  1059. $obj{amount} = $args[1];
  1060. }
  1061. push @sellList, %obj;
  1062. message TF("Added to sell list: %s (%s) x %sn", $obj{name}, $obj{invIndex}, $obj{amount}), "info";
  1063. }
  1064. message T("Type 'sell done' to sell everything in your sell list.n"), "info";
  1065. } else {
  1066. error TF("Error in function 'sell' (Sell Inventory Item)n" .
  1067. "'%s' is not a valid item index #; no item has been added to the sell list.n", 
  1068. $args[0]);
  1069. }
  1070. }
  1071. }
  1072. sub cmdSendRaw {
  1073. if (!$net || $net->getState() == Network::NOT_CONNECTED) {
  1074. error TF("You must be connected to the server to use this command (%s)n", shift);
  1075. return;
  1076. }
  1077. my (undef, $args) = @_;
  1078. $messageSender->sendRaw($args);
  1079. }
  1080. sub cmdShopInfoSelf {
  1081. if (!$shopstarted) {
  1082. error T("You do not have a shop open.n");
  1083. return;
  1084. }
  1085. # FIXME: Read the packet the server sends us to determine
  1086. # the shop title instead of using $shop{title}.
  1087. message TF("%sn" .
  1088. "#  Name                                     Type         Qty       Price   Soldn",
  1089. center(" $shop{title} ", 79, '-')), "list";
  1090. my $priceAfterSale=0;
  1091. my $i = 1;
  1092. for my $item (@articles) {
  1093. next unless $item;
  1094. message(swrite(
  1095. "@< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<< @>>> @>>>>>>>>>z @>>>>>",
  1096. [$i++, $item->{name}, $itemTypes_lut{$item->{type}}, $item->{quantity}, formatNumber($item->{price}), $item->{sold}]),
  1097. "list");
  1098. $priceAfterSale += ($item->{quantity} * $item->{price});
  1099. }
  1100. message TF("%sn" .
  1101. "You have earned: %sz.n" .
  1102. "Current zeny:    %sz.n" .
  1103. "Maximum earned:  %sz.n" .
  1104. "Maximum zeny:    %sz.n",
  1105. ('-'x79), formatNumber($shopEarned), formatNumber($char->{zenny}), 
  1106. formatNumber($priceAfterSale), formatNumber($priceAfterSale + $char->{zenny})), "list";
  1107. }
  1108. sub cmdSit {
  1109. if (!$net || $net->getState() != Network::IN_GAME) {
  1110. error TF("You must be logged in the game to use this command (%s)n", shift);
  1111. return;
  1112. }
  1113. $ai_v{sitAuto_forcedBySitCommand} = 1;
  1114. AI::clear("move", "route", "mapRoute");
  1115. AI::clear("attack") unless ai_getAggressives();
  1116. require Task::SitStand;
  1117. my $task = new Task::ErrorReport(
  1118. task => new Task::SitStand(
  1119. mode => 'sit',
  1120. priority => Task::USER_PRIORITY
  1121. )
  1122. );
  1123. $taskManager->add($task);
  1124. $ai_v{sitAuto_forceStop} = 0;
  1125. }
  1126. sub cmdSkills {
  1127. my (undef, $args) = @_;
  1128. my ($arg1) = $args =~ /^(w+)/;
  1129. my ($arg2) = $args =~ /^w+ (d+)/;
  1130. if ($arg1 eq "") {
  1131. my $msg = T("----------Skill List-----------n" .
  1132. "   # Skill Name                     Lv      SPn");
  1133. for my $handle (@skillsID) {
  1134. my $skill = new Skill(handle => $handle);
  1135. my $sp = $char->{skills}{$handle}{sp} || '';
  1136. $msg .= swrite(
  1137. "@>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>    @>>>",
  1138. [$skill->getIDN(), $skill->getName(), $char->getSkillLevel($skill), $sp]);
  1139. }
  1140. $msg .= TF("nSkill Points: %dn", $char->{points_skill});
  1141. $msg .= "-------------------------------n";
  1142. message($msg, "list");
  1143. } elsif ($arg1 eq "add" && $arg2 =~ /d+/) {
  1144. if (!$net || $net->getState() != Network::IN_GAME) {
  1145. error TF("You must be logged in the game to use this command (%s)n", 'skills add');
  1146. return;
  1147. }
  1148. my $skill = new Skill(idn => $arg2);
  1149. if (!$skill->getIDN() || !$char->{skills}{$skill->getHandle()}) {
  1150. error TF("Error in function 'skills add' (Add Skill Point)n" .
  1151. "Skill %s does not exist.n", $arg2);
  1152. } elsif ($char->{points_skill} < 1) {
  1153. error TF("Error in function 'skills add' (Add Skill Point)n" .
  1154. "Not enough skill points to increase %sn", $skill->getName());
  1155. } else {
  1156. $messageSender->sendAddSkillPoint($skill->getIDN());
  1157. }
  1158. } elsif ($arg1 eq "desc" && $arg2 =~ /d+/) {
  1159. my $skill = new Skill(idn => $arg2);
  1160. if (!$skill->getIDN()) {
  1161. error TF("Error in function 'skills desc' (Skill Description)n" .
  1162. "Skill %s does not exist.n", $arg2);
  1163. } else {
  1164. my $description = $skillsDesc_lut{$skill->getHandle()} || T("Error: No description available.n");
  1165. message TF("===============Skill Description===============n" .
  1166. "Skill: %snn", $skill->getName()), "info";
  1167. message $description, "info";
  1168. message "==============================================n", "info";
  1169. }
  1170. } else {
  1171. error T("Syntax Error in function 'skills' (Skills Functions)n" .
  1172. "Usage: skills [<add | desc>] [<skill #>]n");
  1173. }
  1174. }
  1175. sub cmdSlaveList {
  1176. my ($dist, $pos, $name, $slaves);
  1177. message TF("-----------Slave List-----------n" .
  1178. "#   Name                        Type                   Distance    Coordinatesn"), "list";
  1179. $slaves = $slavesList->getItems() if ($slavesList);
  1180. foreach my $slave (@{$slaves}) {
  1181. $dist = distance($char->{pos_to}, $slave->{pos_to});
  1182. $dist = sprintf("%.1f", $dist) if (index($dist, '.') > -1);
  1183. $pos = '(' . $slave->{pos_to}{x} . ', ' . $slave->{pos_to}{y} . ')';
  1184. $name = $slave->name;
  1185. if ($name ne $slave->{name_given}) {
  1186. $name .= '[' . $slave->{name_given} . ']';
  1187. }
  1188. message(swrite(
  1189. "@<< @<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<    @<<<<<      @<<<<<<<<<<",
  1190. [$slave->{binID}, $name, $slave->{actorType}, $dist, $pos]),
  1191. "list");
  1192. }
  1193. message("----------------------------------n", "list");
  1194. }
  1195. sub cmdSpells {
  1196. message T("-----------Area Effects List-----------n" .
  1197. "  # Type                 Source                   X   Yn"), "list";
  1198. for my $ID (@spellsID) {
  1199. my $spell = $spells{$ID};
  1200. next unless $spell;
  1201. message sprintf("%3d %-20s %-20s   %3d %3dn", $spell->{binID}, getSpellName($spell->{type}), main::getActorName($spell->{sourceID}), $spell->{pos}{x}, $spell->{pos}{y}), "list";
  1202. }
  1203. message "---------------------------------------n", "list";
  1204. }
  1205. sub cmdStand {
  1206. if (!$net || $net->getState() != Network::IN_GAME) {
  1207. error TF("You must be logged in the game to use this command (%s)n", shift);
  1208. return;
  1209. }
  1210. delete $ai_v{sitAuto_forcedBySitCommand};
  1211. $ai_v{sitAuto_forceStop} = 1;
  1212. require Task::SitStand;
  1213. my $task = new Task::ErrorReport(
  1214. task => new Task::SitStand(
  1215. mode => 'stand',
  1216. priority => Task::USER_PRIORITY
  1217. )
  1218. );
  1219. $taskManager->add($task);
  1220. }
  1221. sub cmdStatAdd {
  1222. # Add status point
  1223. if (!$net || $net->getState() != Network::IN_GAME) {
  1224. error TF("You must be logged in the game to use this command (%s)n", shift);
  1225. return;
  1226. }
  1227. my (undef, $arg) = @_;
  1228. if ($arg ne "str" && $arg ne "agi" && $arg ne "vit" && $arg ne "int"
  1229.  && $arg ne "dex" && $arg ne "luk") {
  1230. error T("Syntax Error in function 'stat_add' (Add Status Point)n" .
  1231. "Usage: stat_add <str | agi | vit | int | dex | luk>n");
  1232. } elsif ($char->{'$arg'} >= 99 && !$config{statsAdd_over_99}) {
  1233. error T("Error in function 'stat_add' (Add Status Point)n" .
  1234. "You cannot add more stat points than 99n");
  1235. } elsif ($char->{"points_$arg"} > $char->{'points_free'}) {
  1236. error TF("Error in function 'stat_add' (Add Status Point)n" .
  1237. "Not enough status points to increase %sn", $arg);
  1238. } else {
  1239. my $ID;
  1240. if ($arg eq "str") {
  1241. $ID = 0x0D;
  1242. } elsif ($arg eq "agi") {
  1243. $ID = 0x0E;
  1244. } elsif ($arg eq "vit") {
  1245. $ID = 0x0F;
  1246. } elsif ($arg eq "int") {
  1247. $ID = 0x10;
  1248. } elsif ($arg eq "dex") {
  1249. $ID = 0x11;
  1250. } elsif ($arg eq "luk") {
  1251. $ID = 0x12;
  1252. }
  1253. $char->{$arg} += 1;
  1254. $messageSender->sendAddStatusPoint($ID);
  1255. }
  1256. }
  1257. sub cmdStats {
  1258. if (!$char) {
  1259. error T("Character stats information not yet available.n");
  1260. return;
  1261. }
  1262. my $guildName = $char->{guild} ? $char->{guild}{name} : T("None");
  1263. my $msg = swrite(TF(
  1264. "---------- Char Stats ----------n" .
  1265. "Str: @<<+@<< #@< Atk:  @<<+@<< Def:  @<<+@<<n" .
  1266. "Agi: @<<+@<< #@< Matk: @<<@@<< Mdef: @<<+@<<n" .
  1267. "Vit: @<<+@<< #@< Hit:  @<<     Flee: @<<+@<<n" .
  1268. "Int: @<<+@<< #@< Critical: @<< Aspd: @<<n" .
  1269. "Dex: @<<+@<< #@< Status Points: @<<<n" .
  1270. "Luk: @<<+@<< #@< Guild: @<<<<<<<<<<<<<<<<<<<<<n" .
  1271. "--------------------------------n" .
  1272. "Hair color: @<<<<<<<<<<<<<<<<<n" .
  1273. "Walk speed: %.2f secs per blockn" .
  1274. "--------------------------------", $char->{walk_speed}),
  1275. [$char->{'str'}, $char->{'str_bonus'}, $char->{'points_str'}, $char->{'attack'}, $char->{'attack_bonus'}, $char->{'def'}, $char->{'def_bonus'},
  1276. $char->{'agi'}, $char->{'agi_bonus'}, $char->{'points_agi'}, $char->{'attack_magic_min'}, '~', $char->{'attack_magic_max'}, $char->{'def_magic'}, $char->{'def_magic_bonus'},
  1277. $char->{'vit'}, $char->{'vit_bonus'}, $char->{'points_vit'}, $char->{'hit'}, $char->{'flee'}, $char->{'flee_bonus'},
  1278. $char->{'int'}, $char->{'int_bonus'}, $char->{'points_int'}, $char->{'critical'}, $char->{'attack_speed'},
  1279. $char->{'dex'}, $char->{'dex_bonus'}, $char->{'points_dex'}, $char->{'points_free'},
  1280. $char->{'luk'}, $char->{'luk_bonus'}, $char->{'points_luk'}, $guildName,
  1281. "$haircolors{$char->{hair_color}} ($char->{hair_color})"]);
  1282. $msg .= T("You are sitting.n") if ($char->{sitting});
  1283. message $msg, "info";
  1284. }
  1285. sub cmdStatus {
  1286. # Display character status
  1287. my $msg;
  1288. my ($baseEXPKill, $jobEXPKill);
  1289. if (!$char) {
  1290. error T("Character status information not yet available.n");
  1291. return;
  1292. }
  1293. if ($char->{'exp_last'} > $char->{'exp'}) {
  1294. $baseEXPKill = $char->{'exp_max_last'} - $char->{'exp_last'} + $char->{'exp'};
  1295. } elsif ($char->{'exp_last'} == 0 && $char->{'exp_max_last'} == 0) {
  1296. $baseEXPKill = 0;
  1297. } else {
  1298. $baseEXPKill = $char->{'exp'} - $char->{'exp_last'};
  1299. }
  1300. if ($char->{'exp_job_last'} > $char->{'exp_job'}) {
  1301. $jobEXPKill = $char->{'exp_job_max_last'} - $char->{'exp_job_last'} + $char->{'exp_job'};
  1302. } elsif ($char->{'exp_job_last'} == 0 && $char->{'exp_job_max_last'} == 0) {
  1303. $jobEXPKill = 0;
  1304. } else {
  1305. $jobEXPKill = $char->{'exp_job'} - $char->{'exp_job_last'};
  1306. }
  1307. my ($hp_string, $sp_string, $base_string, $job_string, $weight_string, $job_name_string, $zeny_string);
  1308. $hp_string = $char->{'hp'}."/".$char->{'hp_max'}." ("
  1309. .int($char->{'hp'}/$char->{'hp_max'} * 100)
  1310. ."%)" if $char->{'hp_max'};
  1311. $sp_string = $char->{'sp'}."/".$char->{'sp_max'}." ("
  1312. .int($char->{'sp'}/$char->{'sp_max'} * 100)
  1313. ."%)" if $char->{'sp_max'};
  1314. $base_string = formatNumber($char->{'exp'})."/".formatNumber($char->{'exp_max'})." /$baseEXPKill ("
  1315. .sprintf("%.2f",$char->{'exp'}/$char->{'exp_max'} * 100)
  1316. ."%)"
  1317. if $char->{'exp_max'};
  1318. $job_string = formatNumber($char->{'exp_job'})."/".formatNumber($char->{'exp_job_max'})." /$jobEXPKill ("
  1319. .sprintf("%.2f",$char->{'exp_job'}/$char->{'exp_job_max'} * 100)
  1320. ."%)"
  1321. if $char->{'exp_job_max'};
  1322. $weight_string = $char->{'weight'}."/".$char->{'weight_max'} .
  1323. " (" . sprintf("%.1f", $char->{'weight'}/$char->{'weight_max'} * 100)
  1324. . "%)"
  1325. if $char->{'weight_max'};
  1326. $job_name_string = "$jobs_lut{$char->{'jobID'}} $sex_lut{$char->{'sex'}}";
  1327. $zeny_string = formatNumber($char->{'zenny'}) if (defined($char->{'zenny'}));
  1328. # Translation Comment: No status effect on player
  1329. my $statuses = 'none';
  1330. if (defined $char->{statuses} && %{$char->{statuses}}) {
  1331. $statuses = join(", ", keys %{$char->{statuses}});
  1332. }
  1333. my $dmgpsec_string = sprintf("%.2f", $dmgpsec);
  1334. my $totalelasped_string = sprintf("%.2f", $totalelasped);
  1335. my $elasped_string = sprintf("%.2f", $elasped);
  1336. $msg = swrite(
  1337. TF("----------------------- Status -------------------------n" .
  1338. "@<<<<<<<<<<<<<<<<<<<<<<<         HP: @>>>>>>>>>>>>>>>>>>n" .
  1339. "@<<<<<<<<<<<<<<<<<<<<<<<         SP: @>>>>>>>>>>>>>>>>>>n" .
  1340. "Base: @<<    @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>n" .
  1341. "Job : @<<    @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>n" .
  1342. "Zeny: @<<<<<<<<<<<<<<<<<     Weight: @>>>>>>>>>>>>>>>>>>n" .
  1343. "Statuses: %sn" .
  1344. "Spirits/Coins: %sn" .
  1345. "--------------------------------------------------------n" .
  1346. "Total Damage: @>>>>>>>>>>>>> Dmg/sec: @<<<<<<<<<<<<<<n" .
  1347. "Total Time spent (sec): @>>>>>>>>n" .
  1348. "Last Monster took (sec): @>>>>>>>n" .
  1349. "--------------------------------------------------------",
  1350. $statuses, (exists $char->{spirits} ? $char->{spirits} : 0)),
  1351. [$char->{'name'}, $hp_string, $job_name_string, $sp_string,
  1352. $char->{'lv'}, $base_string, $char->{'lv_job'}, $job_string, $zeny_string, $weight_string,
  1353. $totaldmg, $dmgpsec_string, $totalelasped_string, $elasped_string]);
  1354. message($msg, "info");
  1355. }
  1356. sub cmdStorage {
  1357. if ($storage{opened} || $storage{openedThisSession}) {
  1358. my (undef, $args) = @_;
  1359. my ($switch, $items) = split(' ', $args, 2);
  1360. if (!$switch || $switch eq 'eq' || $switch eq 'u' || $switch eq 'nu') {
  1361. cmdStorage_list($switch);
  1362. } elsif ($switch eq 'add' && $storage{opened}) {
  1363. cmdStorage_add($items);
  1364. } elsif ($switch eq 'addfromcart'  && $storage{opened}) {
  1365. cmdStorage_addfromcart($items);
  1366. } elsif ($switch eq 'get'  && $storage{opened}) {
  1367. cmdStorage_get($items);
  1368. } elsif ($switch eq 'gettocart'  && $storage{opened}) {
  1369. cmdStorage_gettocart($items);
  1370. } elsif ($switch eq 'close'  && $storage{opened}) {
  1371. cmdStorage_close();
  1372. } elsif ($switch eq 'log') {
  1373. cmdStorage_log();
  1374. } elsif ($switch eq 'desc') {
  1375. cmdStorage_desc($items);
  1376. } else {
  1377. error T("Syntax Error in function 'storage' (Storage Functions)n" .
  1378. "Usage: storage [<eq|u|nu>]n" .
  1379. "       storage closen" .
  1380. "       storage add <inventory_item> [<amount>]n" .
  1381. "       storage addfromcart <cart_item> [<amount>]n" . 
  1382. "       storage get <storage_item> [<amount>]n" . 
  1383. "       storage gettocart <storage_item> [<amount>]n" .
  1384. "       storage desc <storage_item_#>n".
  1385. "       storage log");
  1386. }
  1387. } else {
  1388. error T("No information about storage; it has not been opened before in this sessionn");
  1389. }
  1390. }
  1391. sub cmdStorage_list {
  1392. my $type = shift;
  1393. message "$typen";
  1394. my @useable;
  1395. my @equipment;
  1396. my @non_useable;
  1397. for (my $i = 0; $i < @storageID; $i++) {
  1398. next if ($storageID[$i] eq "");
  1399. my $item = $storage{$storageID[$i]};
  1400. if ($item->{type} == 3 ||
  1401.     $item->{type} == 6 ||
  1402.     $item->{type} == 10 ||
  1403.     $item->{type} == 16 ||
  1404.             $item->{type} == 17) {
  1405. push @non_useable, $item;
  1406. } elsif ($item->{type} <= 2) {
  1407. push @useable, $item;
  1408. } else {
  1409. my %eqp;
  1410. $eqp{binID} = $i;
  1411. $eqp{name} = $item->{name};
  1412. $eqp{type} = $itemTypes_lut{$item->{type}};
  1413. $eqp{identified} = " -- " . T("Not Identified") if !$item->{identified};
  1414. push @equipment, %eqp;
  1415. }
  1416. }
  1417. my $msg = T("-----------Storage-------------n");
  1418. if (!$type || $type eq 'eq') {
  1419. $msg .= T("-- Equipment --n");
  1420. foreach my $item (@equipment) {
  1421. $msg .= sprintf("%-3d  %s (%s) %sn", $item->{binID}, $item->{name}, $item->{type}, $item->{identified});
  1422. }
  1423. }
  1424. if (!$type || $type eq 'nu') {
  1425. $msg .= T("-- Non-Usable --n");
  1426. for (my $i = 0; $i < @non_useable; $i++) {
  1427. my $item = $non_useable[$i];
  1428. my $binID = $item->{binID};
  1429. my $display = $item->{name};
  1430. $display .= " x $item->{amount}";
  1431. $msg .= swrite(
  1432. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
  1433. [$binID, $display]);
  1434. }
  1435. }
  1436. if (!$type || $type eq 'u') {
  1437. $msg .= T("-- Usable --n");
  1438. for (my $i = 0; $i < @useable; $i++) {
  1439. my $item = $useable[$i];
  1440. my $binID = $item->{binID};
  1441. my $display = $item->{name};
  1442. $display .= " x $item->{amount}";
  1443. $msg .= swrite(
  1444. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
  1445. [$binID, $display]);
  1446. }
  1447. }
  1448. $msg .= "-------------------------------n";
  1449. $msg .= TF("Capacity: %d/%dn", $storage{items}, $storage{items_max});
  1450. $msg .= "-------------------------------n";
  1451. message($msg, "list");
  1452. }
  1453. sub cmdStorage_add {
  1454. my $items = shift;
  1455. my ($name, $amount) = $items =~ /^(.*?)(?: (d+))?$/;
  1456. my $item = Match::inventoryItem($name);
  1457. if (!$item) {
  1458. error TF("Inventory Item '%s' does not exist.n", $name);
  1459. return;
  1460. }
  1461. if ($item->{equipped}) {
  1462. error TF("Inventory Item '%s' is equipped.n", $name);
  1463. return;
  1464. }
  1465. if (!defined($amount) || $amount > $item->{amount}) {
  1466. $amount = $item->{amount};
  1467. }
  1468. $messageSender->sendStorageAdd($item->{index}, $amount);
  1469. }
  1470. sub cmdStorage_addfromcart {
  1471. my $items = shift;
  1472. my ($name, $amount) = $items =~ /^(.*?)(?: (d+))?$/;
  1473. my $item = Match::cartItem($name);
  1474. if (!$item) {
  1475. error TF("Cart Item '%s' does not exist.n", $name);
  1476. return;
  1477. }
  1478. if (!defined($amount) || $amount > $item->{amount}) {
  1479. $amount = $item->{amount};
  1480. }
  1481. $messageSender->sendStorageAddFromCart($item->{index}, $amount);
  1482. }
  1483. sub cmdStorage_get {
  1484. my $items = shift;
  1485. my ($names, $amount) = $items =~ /^(.*?)(?: (d+))?$/;
  1486. my @names = split(',', $names);
  1487. my @items;
  1488. for my $name (@names) {
  1489. if ($name =~ /^(d+)-(d+)$/) {
  1490. for my $i ($1..$2) {
  1491. push @items, $storage{$storageID[$i]} if ($storage{$storageID[$i]});
  1492. }
  1493. } else {
  1494. my $item = Match::storageItem($name);
  1495. if (!$item) {
  1496. error TF("Storage Item '%s' does not exist.n", $name);
  1497. next;
  1498. }
  1499. push @items, $item;
  1500. }
  1501. }
  1502. storageGet(@items, $amount) if @items;
  1503. }
  1504. sub cmdStorage_gettocart { 
  1505. my $items = shift; 
  1506. my ($name, $amount) = $items =~ /^(.*?)(?: (d+))?$/; 
  1507. my $item = Match::storageItem($name); 
  1508. if (!$item) { 
  1509. error TF("Storage Item '%s' does not exist.n", $name); 
  1510. return; 
  1511. }
  1512. if (!defined($amount) || $amount > $item->{amount}) { 
  1513. $amount = $item->{amount}; 
  1514. }
  1515. $messageSender->sendStorageGetToCart($item->{index}, $amount); 
  1516. }
  1517. sub cmdStorage_close {
  1518. $messageSender->sendStorageClose();
  1519. }
  1520. sub cmdStorage_log {
  1521. writeStorageLog(1);
  1522. }
  1523. sub cmdStorage_desc {
  1524. my $items = shift;
  1525. my $item = Match::storageItem($items);
  1526. if (!$item) {
  1527. error TF("Error in function 'storage desc' (Show Storage Item Description)n" .
  1528. "Storage Item %s does not exist.n", $items);
  1529. } else {
  1530. printItemDesc($item->{nameID});
  1531. }
  1532. }
  1533. sub cmdStore {
  1534. my (undef, $args) = @_;
  1535. my ($arg1) = $args =~ /^(w+)/;
  1536. my ($arg2) = $args =~ /^w+ (d+)/;
  1537. if ($arg1 eq "" && !$talk{'buyOrSell'}) {
  1538. message T("----------Store List-----------n" .
  1539. "#  Name                    Type           Pricen"), "list";
  1540. my $display;
  1541. for (my $i = 0; $i < @storeList; $i++) {
  1542. $display = $storeList[$i]{'name'};
  1543. message(swrite(
  1544. "@< @<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<< @>>>>>>>z",
  1545. [$i, $display, $itemTypes_lut{$storeList[$i]{'type'}}, $storeList[$i]{'price'}]),
  1546. "list");
  1547. }
  1548. message("-------------------------------n", "list");
  1549. } elsif ($arg1 eq "" && $talk{'buyOrSell'}
  1550.  && ($net && $net->getState() == Network::IN_GAME)) {
  1551. $messageSender->sendGetStoreList($talk{'ID'});
  1552. } elsif ($arg1 eq "desc" && $arg2 =~ /d+/ && !$storeList[$arg2]) {
  1553. error TF("Error in function 'store desc' (Store Item Description)n" .
  1554. "Store item %s does not existn", $arg2);
  1555. } elsif ($arg1 eq "desc" && $arg2 =~ /d+/) {
  1556. printItemDesc($storeList[$arg2]{nameID});
  1557. } else {
  1558. error T("Syntax Error in function 'store' (Store Functions)n" .
  1559. "Usage: store [<desc>] [<store item #>]n");
  1560. }
  1561. }
  1562. sub cmdSwitchConf {
  1563. my (undef, $filename) = @_;
  1564. if (!defined $filename) {
  1565. error T("Syntax Error in function 'switchconf' (Switch Configuration File)n" .
  1566. "Usage: switchconf <filename>n");
  1567. } elsif (! -f $filename) {
  1568. error TF("Syntax Error in function 'switchconf' (Switch Configuration File)n" .
  1569. "File %s does not exist.n", $filename);
  1570. } else {
  1571. switchConfigFile($filename);
  1572. message TF("Switched config file to "%s".n", $filename), "system";
  1573. }
  1574. }
  1575. sub cmdTake {
  1576. my (undef, $arg1) = @_;
  1577. if ($arg1 eq "") {
  1578. error T("Syntax Error in function 'take' (Take Item)n" .
  1579. "Usage: take <item #>n");
  1580. } elsif ($arg1 eq "first" && scalar(keys(%items)) == 0) {
  1581. error T("Error in function 'take first' (Take Item)n" .
  1582. "There are no items near.n");
  1583. } elsif ($arg1 eq "first") {
  1584. my @keys = keys %items;
  1585. AI::take($keys[0]);
  1586. } elsif (!$itemsID[$arg1]) {
  1587. error TF("Error in function 'take' (Take Item)n" .
  1588. "Item %s does not exist.n", $arg1);
  1589. } else {
  1590. main::take($itemsID[$arg1]);
  1591. }
  1592. }
  1593. sub cmdTalk {
  1594. if (!$net || $net->getState() != Network::IN_GAME) {
  1595. error TF("You must be logged in the game to use this command (%s)n", shift);
  1596. return;
  1597. }
  1598. my (undef, $args) = @_;
  1599. my ($arg1) = $args =~ /^(w+)/;
  1600. my ($arg2) = $args =~ /^w+ (d+)/;
  1601. if ($arg1 =~ /^d+$/ && $npcsID[$arg1] eq "") {
  1602. error TF("Error in function 'talk' (Talk to NPC)n" .
  1603. "NPC %s does not existn", $arg1);
  1604. } elsif ($arg1 =~ /^d+$/) {
  1605. $messageSender->sendTalk($npcsID[$arg1]);
  1606. } elsif (($arg1 eq "resp" || $arg1 eq "num" || $arg1 eq "text") && !%talk) {
  1607. error TF("Error in function 'talk %s' (Respond to NPC)n" .
  1608. "You are not talking to any NPC.n", $arg1);
  1609. } elsif ($arg1 eq "resp" && $arg2 eq "") {
  1610. if (!$talk{'responses'}) {
  1611. error T("Error in function 'talk resp' (Respond to NPC)n" .
  1612. "No NPC response list available.n");
  1613. return;
  1614. }
  1615. my $display = $talk{name};
  1616. message TF("----------Responses-----------n" .
  1617. "NPC: %sn" .
  1618. "#  Responsen", $display),"list";
  1619. for (my $i = 0; $i < @{$talk{'responses'}}; $i++) {
  1620. message(sprintf(
  1621. "%2s %sn",
  1622. $i, $talk{'responses'}[$i]),
  1623. "list");
  1624. }
  1625. message("-------------------------------n", "list");
  1626. } elsif ($arg1 eq "resp" && $arg2 ne "" && $talk{'responses'}[$arg2] eq "") {
  1627. error TF("Error in function 'talk resp' (Respond to NPC)n" .
  1628. "Response %s does not exist.n", $arg2);
  1629. } elsif ($arg1 eq "resp" && $arg2 ne "") {
  1630. if ($talk{'responses'}[$arg2] eq "Cancel Chat") {
  1631. $arg2 = 255;
  1632. } else {
  1633. $arg2 += 1;
  1634. }
  1635. $messageSender->sendTalkResponse($talk{'ID'}, $arg2);
  1636. } elsif ($arg1 eq "num" && $arg2 eq "") {
  1637. error T("Error in function 'talk num' (Respond to NPC)n" .
  1638. "You must specify a number.n");
  1639. } elsif ($arg1 eq "num" && !($arg2 =~ /^d+$/)) {
  1640. error TF("Error in function 'talk num' (Respond to NPC)n" .
  1641. "%s is not a valid number.n", $arg2);
  1642. } elsif ($arg1 eq "num" && $arg2 =~ /^d+$/) {
  1643. $messageSender->sendTalkNumber($talk{'ID'}, $arg2);
  1644. } elsif ($arg1 eq "text") {
  1645. my ($arg2) = $args =~ /^w+ (.*)/;
  1646. if ($arg2 eq "") {
  1647. error T("Error in function 'talk text' (Respond to NPC)n" .
  1648. "You must specify a string.n");
  1649. } else {
  1650. $messageSender->sendTalkText($talk{'ID'}, $arg2);
  1651. }
  1652. } elsif ($arg1 eq "cont" && !%talk) {
  1653. error T("Error in function 'talk cont' (Continue Talking to NPC)n" .
  1654. "You are not talking to any NPC.n");
  1655. } elsif ($arg1 eq "cont") {
  1656. $messageSender->sendTalkContinue($talk{'ID'});
  1657. } elsif ($arg1 eq "no") {
  1658. if (!%talk) {
  1659. error T("You are not talking to any NPC.n");
  1660. } elsif ($ai_v{npc_talk}{talk} eq 'select') {
  1661. $messageSender->sendTalkResponse($talk{ID}, 255);
  1662. } elsif (!$talk{canceled}) {
  1663. $messageSender->sendTalkCancel($talk{ID});
  1664. $talk{canceled} = 1;
  1665. }
  1666. } else {
  1667. error T("Syntax Error in function 'talk' (Talk to NPC)n" .
  1668. "Usage: talk <NPC # | cont | resp | num> [<response #>|<number #>]n");
  1669. }
  1670. }
  1671. sub cmdTalkNPC {
  1672. my (undef, $args) = @_;
  1673. my ($x, $y, $sequence) = $args =~ /^(d+) (d+) (.+)$/;
  1674. unless (defined $x) {
  1675. error T("Syntax Error in function 'talknpc' (Talk to an NPC)n" .
  1676. "Usage: talknpc <x> <y> <sequence>n");
  1677. return;
  1678. }
  1679. message TF("Talking to NPC at (%d, %d) using sequence: %sn", $x, $y, $sequence);
  1680. main::ai_talkNPC($x, $y, $sequence);
  1681. }
  1682. sub cmdTank {
  1683. my (undef, $arg) = @_;
  1684. $arg =~ s/ .*//;
  1685. if ($arg eq "") {
  1686. error T("Syntax Error in function 'tank' (Tank for a Player)n" .
  1687. "Usage: tank <player #|player name>n");
  1688. } elsif ($arg eq "stop") {
  1689. configModify("tankMode", 0);
  1690. } elsif ($arg =~ /^d+$/) {
  1691. if (!$playersID[$arg]) {
  1692. error TF("Error in function 'tank' (Tank for a Player)n" .
  1693. "Player %s does not exist.n", $arg);
  1694. } else {
  1695. configModify("tankMode", 1);
  1696. configModify("tankModeTarget", $players{$playersID[$arg]}{name});
  1697. }
  1698. } else {
  1699. my $found;
  1700. foreach my $ID (@playersID) {
  1701. next if !$ID;
  1702. if (lc $players{$ID}{name} eq lc $arg) {
  1703. $found = $ID;
  1704. last;
  1705. }
  1706. }
  1707. if ($found) {
  1708. configModify("tankMode", 1);
  1709. configModify("tankModeTarget", $players{$found}{name});
  1710. } else {
  1711. error TF("Error in function 'tank' (Tank for a Player)n" .
  1712. "Player %s does not exist.n", $arg);
  1713. }
  1714. }
  1715. }
  1716. sub cmdTeleport {
  1717. if (!$net || $net->getState() != Network::IN_GAME) {
  1718. error TF("You must be logged in the game to use this command (%s)n", shift);
  1719. return;
  1720. }
  1721. my (undef, $args) = @_;
  1722. my ($arg1) = $args =~ /^(d)/;
  1723. $arg1 = 1 unless $arg1;
  1724. main::useTeleport($arg1);
  1725. }
  1726. sub cmdTestShop {
  1727. my @items = main::makeShop();
  1728. return unless @items;
  1729. message TF("%sn" .
  1730. "Name                                      Amount  Pricen", 
  1731. center(" $shop{title} ", 79, '-')), "list";
  1732. for my $item (@items) {
  1733. message(sprintf("%-40s %7d %10s zn", $item->{name}, 
  1734. $item->{amount}, main::formatNumber($item->{price})), "list");
  1735. }
  1736. message("-------------------------------------------------------------------------------n", "list");
  1737. message TF("Total of %d items to sell.n", binSize(@items)), "list";
  1738. }
  1739. sub cmdTimeout {
  1740. my (undef, $args) = @_;
  1741. my ($arg1) = $args =~ /^(w+)/;
  1742. my ($arg2) = $args =~ /^w+s+([sS]+)s*$/;
  1743. if ($arg1 eq "") {
  1744. error T("Syntax Error in function 'timeout' (set a timeout)n" .
  1745. "Usage: timeout <type> [<seconds>]n");
  1746. } elsif ($timeout{$arg1} eq "") {
  1747. error TF("Error in function 'timeout' (set a timeout)n" .
  1748. "Timeout %s doesn't existn", $arg1);
  1749. } elsif ($arg2 eq "") {
  1750. message TF("Timeout '%s' is %sn", 
  1751. $arg1, $timeout{$arg1}{timeout}), "info";
  1752. } else {
  1753. setTimeout($arg1, $arg2);
  1754. }
  1755. }
  1756. sub cmdTop10 {
  1757. if (!$net || $net->getState() != Network::IN_GAME) {
  1758. error TF("You must be logged in the game to use this command (%s)n", shift);
  1759. return;
  1760. }
  1761. my (undef, $args) = @_;
  1762. my ($arg1) = $args;
  1763. if ($arg1 eq "") {
  1764. message T("Function 'top10' (Show Top 10 Lists)n" .
  1765. "Usage: top10 <b|a|t|p> | <black|alche|tk|pk> | <blacksmith|alchemist|taekwon|pvp>n");
  1766. } elsif ($arg1 eq "a" || $arg1 eq "alche" || $arg1 eq "alchemist") {
  1767. $messageSender->sendTop10Alchemist();
  1768. } elsif ($arg1 eq "b" || $arg1 eq "black" || $arg1 eq "blacksmith") {
  1769. $messageSender->sendTop10Blacksmith();
  1770. } elsif ($arg1 eq "p" || $arg1 eq "pk" || $arg1 eq "pvp") {
  1771. $messageSender->sendTop10PK();
  1772. } elsif ($arg1 eq "t" || $arg1 eq "tk" || $arg1 eq "taekwon") {
  1773. $messageSender->sendTop10Taekwon();
  1774. } else {
  1775. error T("Syntax Error in function 'top10' (Show Top 10 Lists)n" .
  1776. "Usage: top10 <b|a|t|p> |n" .
  1777. "             <black|alche|tk|pk> |n".
  1778. "             <blacksmith|alchemist|taekwon|pvp>n");
  1779. }
  1780. }
  1781. sub cmdUnequip {
  1782. # unequip an item
  1783. my (undef, $args) = @_;
  1784. my ($arg1,$arg2) = $args =~ /^(S+)s*(.*)/;
  1785. my $slot;
  1786. my $item;
  1787. if ($arg1 eq "") {
  1788. cmdEquip_list();
  1789. return;
  1790. }
  1791. if ($arg1 eq "slots") {
  1792. # Translation Comment: List of equiped items on each slot
  1793. message T("Slots:n") . join("n", @Actor::Item::slots). "n", "list";
  1794. return;
  1795. }
  1796. if (!$net || $net->getState() != Network::IN_GAME) {
  1797. error TF("You must be logged in the game to use this command (%s)n", 'eq ' . $args);
  1798. return;
  1799. }
  1800. if ($equipSlot_rlut{$arg1}) {
  1801. $slot = $arg1;
  1802. } else {
  1803. $arg1 .= " $arg2" if $arg2;
  1804. }
  1805. $item = Actor::Item::get(defined $slot ? $arg2 : $arg1, undef, 0);
  1806. if (!$item) {
  1807. $args =~ s/^($slot)s//g if ($slot);
  1808. $slot = "undefined" unless ($slot);
  1809. error TF("No such equipped Inventory Item: %s in slot: %sn", $args, $slot);
  1810. return;
  1811. }
  1812. if (!$item->{type_equip} && $item->{type} != 10 && $item->{type} != 16 && $item->{type} != 17) {
  1813. error TF("Inventory Item %s (%s) can't be unequipped.n", 
  1814. $item->{name}, $item->{invIndex});
  1815. return;
  1816. }
  1817. if ($slot) {
  1818. $item->unequipFromSlot($slot);
  1819. } else {
  1820. $item->unequip();
  1821. }
  1822. }
  1823. sub cmdUseItemOnMonster {
  1824. if (!$net || $net->getState() != Network::IN_GAME) {
  1825. error TF("You must be logged in the game to use this command (%s)n", shift);
  1826. return;
  1827. }
  1828. my (undef, $args) = @_;
  1829. my ($arg1) = $args =~ /^(d+)/;
  1830. my ($arg2) = $args =~ /^d+ (d+)/;
  1831. if ($arg1 eq "" || $arg2 eq "") {
  1832. error T("Syntax Error in function 'im' (Use Item on Monster)n" .
  1833. "Usage: im <item #> <monster #>n");
  1834. } elsif (!$char->inventory->get($arg1)) {
  1835. error TF("Error in function 'im' (Use Item on Monster)n" .
  1836. "Inventory Item %s does not exist.n", $arg1);
  1837. } elsif ($char->inventory->get($arg1)->{type} > 2) {
  1838. error TF("Error in function 'im' (Use Item on Monster)n" .
  1839. "Inventory Item %s is not of type Usable.n", $arg1);
  1840. } elsif ($monstersID[$arg2] eq "") {
  1841. error TF("Error in function 'im' (Use Item on Monster)n" .
  1842. "Monster %s does not exist.n", $arg2);
  1843. } else {
  1844. $char->inventory->get($arg1)->use($monstersID[$arg2]);
  1845. }
  1846. }
  1847. sub cmdUseItemOnPlayer {
  1848. if (!$net || $net->getState() != Network::IN_GAME) {
  1849. error TF("You must be logged in the game to use this command (%s)n", shift);
  1850. return;
  1851. }
  1852. my (undef, $args) = @_;
  1853. my ($arg1) = $args =~ /^(d+)/;
  1854. my ($arg2) = $args =~ /^d+ (d+)/;
  1855. if ($arg1 eq "" || $arg2 eq "") {
  1856. error T("Syntax Error in function 'ip' (Use Item on Player)n" .
  1857. "Usage: ip <item #> <player #>n");
  1858. } elsif (!$char->inventory->get($arg1)) {
  1859. error TF("Error in function 'ip' (Use Item on Player)n" .
  1860. "Inventory Item %s does not exist.n", $arg1);
  1861. } elsif ($char->inventory->get($arg1)->{type} > 2) {
  1862. error TF("Error in function 'ip' (Use Item on Player)n" .
  1863. "Inventory Item %s is not of type Usable.n", $arg1);
  1864. } elsif ($playersID[$arg2] eq "") {
  1865. error TF("Error in function 'ip' (Use Item on Player)n" .
  1866. "Player %s does not exist.n", $arg2);
  1867. } else {
  1868. $char->inventory->get($arg1)->use($playersID[$arg2]);
  1869. }
  1870. }
  1871. sub cmdUseItemOnSelf {
  1872. if (!$net || $net->getState() != Network::IN_GAME) {
  1873. error TF("You must be logged in the game to use this command (%s)n", shift);
  1874. return;
  1875. }
  1876. my (undef, $args) = @_;
  1877. if ($args eq "") {
  1878. error T("Syntax Error in function 'is' (Use Item on Yourself)n" .
  1879. "Usage: is <item>n");
  1880. return;
  1881. }
  1882. my $item = Actor::Item::get($args);
  1883. if (!$item) {
  1884. error TF("Error in function 'is' (Use Item on Yourself)n" .
  1885. "Inventory Item %s does not exist.n", $args);
  1886. return;
  1887. }
  1888. if ($item->{type} > 2) {
  1889. error TF("Error in function 'is' (Use Item on Yourself)n" .
  1890. "Inventory Item %s is not of type Usable.n", $item);
  1891. return;
  1892. }
  1893. $item->use;
  1894. }
  1895. sub cmdUseSkill {
  1896. if (!$net || $net->getState() != Network::IN_GAME) {
  1897. error TF("You must be logged in the game to use this command (%s)n", shift);
  1898. return;
  1899. }
  1900. my ($cmd, $args_string) = @_;
  1901. my ($target, $actorList, $skill, $level) = @_;
  1902. my @args = parseArgs($args_string);
  1903. if ($cmd eq 'sl') {
  1904. my $x = $args[1];
  1905. my $y = $args[2];
  1906. if (@args < 3 || @args > 4) {
  1907. error T("Syntax error in function 'sl' (Use Skill on Location)n" .
  1908. "Usage: sl <skill #> <x> <y> [level]n");
  1909. return;
  1910. } elsif ($x !~ /^d+$/ || $y !~ /^d+/) {
  1911. error T("Error in function 'sl' (Use Skill on Location)n" .
  1912. "Invalid coordinates given.n");
  1913. return;
  1914. } else {
  1915. $target = { x => $x, y => $y };
  1916. $level = $args[3];
  1917. }
  1918. # This was the code for choosing a random location when x and y are not given:
  1919. # my $pos = calcPosition($char);
  1920. # my @positions = calcRectArea($pos->{x}, $pos->{y}, int(rand 2) + 2);
  1921. # $pos = $positions[rand(@positions)];
  1922. # ($x, $y) = ($pos->{x}, $pos->{y});
  1923. } elsif ($cmd eq 'ss') {
  1924. if (@args < 1 || @args > 2) {
  1925. error T("Syntax error in function 'ss' (Use Skill on Self)n" .
  1926. "Usage: ss <skill #> [level]n");
  1927. return;
  1928. } else {
  1929. $target = $char;
  1930. $level = $args[1];
  1931. }
  1932. } elsif ($cmd eq 'sp') {
  1933. if (@args < 2 || @args > 3) {
  1934. error T("Syntax error in function 'sp' (Use Skill on Player)n" .
  1935. "Usage: sp <skill #> <player #> [level]n");
  1936. return;
  1937. } else {
  1938. $target = Match::player($args[1], 1);
  1939. if (!$target) {
  1940. error TF("Error in function 'sp' (Use Skill on Player)n" .
  1941. "Player '%s' does not exist.n", $args[1]);
  1942. return;
  1943. }
  1944. $actorList = $playersList;
  1945. $level = $args[2];
  1946. }
  1947. } elsif ($cmd eq 'sm') {
  1948. if (@args < 2 || @args > 3) {
  1949. error T("Syntax error in function 'sm' (Use Skill on Monster)n" .
  1950. "Usage: sm <skill #> <monster #> [level]n");
  1951. return;
  1952. } else {
  1953. $target = $monstersList->get($args[1]);
  1954. if (!$target) {
  1955. error TF("Error in function 'sm' (Use Skill on Monster)n" .
  1956. "Monster %d does not exist.n", $args[1]);
  1957. return;
  1958. }
  1959. $actorList = $monstersList;
  1960. $level = $args[2];
  1961. }
  1962. } elsif ($cmd eq 'ssp') {
  1963. if (@args < 2 || @args > 3) {
  1964. error T("Syntax error in function 'ssp' (Use Skill on Area Spell Location)n" .
  1965. "Usage: ssp <skill #> <spell #> [level]n");
  1966. return;
  1967. }
  1968. my $targetID = $spellsID[$args[1]];
  1969. if (!$targetID) {
  1970. error TF("Spell %d does not exist.n", $args[1]);
  1971. return;
  1972. }
  1973. my $pos = $spells{$targetID}{pos_to};
  1974. $target = { %{$pos} };
  1975. }
  1976. $skill = new Skill(auto => $args[0], level => $level);
  1977. require Task::UseSkill;
  1978. my $skillTask = new Task::UseSkill(
  1979. target => $target,
  1980. actorList => $actorList,
  1981. skill => $skill,
  1982. priority => Task::USER_PRIORITY
  1983. );
  1984. my $task = new Task::ErrorReport(task => $skillTask);
  1985. $taskManager->add($task);
  1986. }
  1987. sub cmdVender {
  1988. if (!$net || $net->getState() != Network::IN_GAME) {
  1989. error TF("You must be logged in the game to use this command (%s)n", shift);
  1990. return;
  1991. }
  1992. my (undef, $args) = @_;
  1993. my ($arg1) = $args =~ /^([dw]+)/;
  1994. my ($arg2) = $args =~ /^[dw]+ (d+)/;
  1995. my ($arg3) = $args =~ /^[dw]+ d+ (d+)/;
  1996. if ($arg1 eq "") {
  1997. error T("Syntax error in function 'vender' (Vender Shop)n" .
  1998. "Usage: vender <vender # | end> [<item #> <amount>]n");
  1999. } elsif ($arg1 eq "end") {
  2000. undef @venderItemList;
  2001. undef $venderID;
  2002. } elsif ($venderListsID[$arg1] eq "") {
  2003. error TF("Error in function 'vender' (Vender Shop)n" .
  2004. "Vender %s does not exist.n", $arg1);
  2005. } elsif ($arg2 eq "") {
  2006. $messageSender->sendEnteringVender($venderListsID[$arg1]);
  2007. } elsif ($venderListsID[$arg1] ne $venderID) {
  2008. error T("Error in function 'vender' (Vender Shop)n" .
  2009. "Vender ID is wrong.n");
  2010. } else {
  2011. if ($arg3 <= 0) {
  2012. $arg3 = 1;
  2013. }
  2014. $messageSender->sendBuyVender($venderID, $arg2, $arg3);
  2015. }
  2016. }
  2017. sub cmdVenderList {
  2018. message T("-----------Vender List-----------n" .
  2019. "#   Title                                Coords     Ownern"), "list";
  2020. for (my $i = 0; $i < @venderListsID; $i++) {
  2021. next if ($venderListsID[$i] eq "");
  2022. my $player = Actor::get($venderListsID[$i]);
  2023. # autovivifies $obj->{pos_to} but it doesnt matter
  2024. message(sprintf(
  2025. "%3d %-36s (%3s, %3s) %-20sn",
  2026. $i, $venderLists{$venderListsID[$i]}{'title'},
  2027. $player->{pos_to}{x} || '?', $player->{pos_to}{y} || '?', $player->name),
  2028. "list");
  2029. }
  2030. message("----------------------------------n", "list");
  2031. }
  2032. sub cmdVerbose {
  2033. if ($config{'verbose'}) {
  2034. configModify("verbose", 0);
  2035. } else {
  2036. configModify("verbose", 1);
  2037. }
  2038. }
  2039. sub cmdVersion {
  2040. message "$Settings::versionText";
  2041. }
  2042. sub cmdWarp {
  2043. if (!$net || $net->getState() != Network::IN_GAME) {
  2044. error TF("You must be logged in the game to use this command (%s)n", shift);
  2045. return;
  2046. }
  2047. my (undef, $map) = @_;
  2048. if ($map eq '') {
  2049. error T("Error in function 'warp' (Open/List Warp Portal)n" .
  2050. "Usage: warp <map name | map number# | list>n");
  2051. } elsif ($map =~ /^d+$/) {
  2052. if (!$char->{warp}{memo} || !@{$char->{warp}{memo}}) {
  2053. error T("You didn't cast warp portal.n");
  2054. return;
  2055. }
  2056. if ($map < 0 || $map > @{$char->{warp}{memo}}) {
  2057. error TF("Invalid map number %s.n", $map);
  2058. } else {
  2059. my $name = $char->{warp}{memo}[$map];
  2060. my $rsw = "$name.rsw";
  2061. message TF("Attempting to open a warp portal to %s (%s)n", 
  2062. $maps_lut{$rsw}, $name), "info";
  2063. $messageSender->sendOpenWarp("$name.gat");
  2064. }
  2065. } elsif ($map eq 'list') {
  2066. if (!$char->{warp}{memo} || !@{$char->{warp}{memo}}) {
  2067. error T("You didn't cast warp portal.n");
  2068. return;
  2069. }
  2070. message T("----------------- Warp Portal --------------------n" .
  2071. "#  Place                           Mapn", "list");
  2072. for (my $i = 0; $i < @{$char->{warp}{memo}}; $i++) {
  2073. message(swrite(
  2074. "@< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<",
  2075. [$i, $maps_lut{$char->{warp}{memo}[$i].'.rsw'},
  2076. $char->{warp}{memo}[$i]]),
  2077. "list");
  2078. }
  2079. message("--------------------------------------------------n", "list");
  2080. } elsif (!defined $maps_lut{$map.'.rsw'}) {
  2081. error TF("Map '%s' does not exist.n", $map);
  2082. } else {
  2083. my $rsw = "$map.rsw";
  2084. message TF("Attempting to open a warp portal to %s (%s)n", 
  2085. $maps_lut{$rsw}, $map), "info";
  2086. $messageSender->sendOpenWarp("$map.gat");
  2087. }
  2088. }
  2089. sub cmdWeight {
  2090. if (!$char) {
  2091. error T("Character weight information not yet available.n");
  2092. return;
  2093. }
  2094. my (undef, $itemWeight) = @_;
  2095. $itemWeight ||= 1;
  2096. if ($itemWeight !~ /^d+(.d+)?$/) {
  2097. error T("Syntax error in function 'weight' (Inventory Weight Info)n" .
  2098. "Usage: weight [item weight]n");
  2099. return;
  2100. }
  2101. my $itemString = $itemWeight == 1 ? '' : "*$itemWeight";
  2102. message TF("Weight: %s/%s (%s%)n", $char->{weight}, $char->{weight_max}, sprintf("%.02f", $char->weight_percent)), "list";
  2103. if ($char->weight_percent < 90) {
  2104. if ($char->weight_percent < 50) {
  2105. my $weight_50 = int((int($char->{weight_max}*0.5) - $char->{weight}) / $itemWeight);
  2106. message TF("You can carry %s%s before %s overweight.n", 
  2107. $weight_50, $itemString, '50%'), "list";
  2108. } else {
  2109. message TF("You are %s overweight.n", '50%'), "list";
  2110. }
  2111. my $weight_90 = int((int($char->{weight_max}*0.9) - $char->{weight}) / $itemWeight);
  2112. message TF("You can carry %s%s before %s overweight.n", 
  2113. $weight_90, $itemString, '90%'), "list";
  2114. } else {
  2115. message TF("You are %s overweight.n", '90%');
  2116. }
  2117. }
  2118. sub cmdWhere {
  2119. if (!$char) {
  2120. error T("Location not yet available.n");
  2121. return;
  2122. }
  2123. my $pos = calcPosition($char);
  2124. message TF("Location %s (%s) : %d, %dn", $maps_lut{$field{name}.'.rsw'}, 
  2125. $field{name}, $pos->{x}, $pos->{y}), "info";
  2126. }
  2127. sub cmdWho {
  2128. if (!$net || $net->getState() != Network::IN_GAME) {
  2129. error TF("You must be logged in the game to use this command (%s)n", shift);
  2130. return;
  2131. }
  2132. $messageSender->sendWho();
  2133. }
  2134. sub cmdWhoAmI {
  2135. if (!$char) {
  2136. error T("Character information not yet available.n");
  2137. return;
  2138. }
  2139. my $GID = unpack("L1", $charID);
  2140. my $AID = unpack("L1", $accountID);
  2141. message TF("Name:    %s (Level %s %s %s)n" .
  2142. "Char ID: %sn" .
  2143. "Acct ID: %sn", 
  2144. $char->{name}, $char->{lv}, $sex_lut{$char->{sex}}, $jobs_lut{$char->{jobID}}, 
  2145. $GID, $AID), "list";
  2146. }
  2147. sub cmdMail {
  2148. if (!$net || $net->getState() != Network::IN_GAME) {
  2149. error TF("You must be logged in the game to use this command (%s)n", shift);
  2150. return;
  2151. }
  2152. my ($cmd, $args_string) = @_;
  2153. my @args = parseArgs($args_string, 4);
  2154. # mail send
  2155. if ($cmd eq 'ms') {
  2156. unless ($args[0] && $args[1] && $args[2]) {
  2157. message T("Usage: ms <receiver> <title> <message>n"), "info";
  2158. } else {
  2159. my ($receiver, $title, $msg) = ($args[0], $args[1], $args[2]);
  2160. $messageSender->sendMailSend((70+length($msg)), $receiver, $title, length($msg), $msg);
  2161. }
  2162. # mail open
  2163. } elsif ($cmd eq 'mo') {
  2164. unless ($args[0] =~ /^d+$/) {
  2165. message T("Usage: mo <mail #>n"), "info";
  2166. } elsif (!$mailList->[$args[0]]) {
  2167. if (@{$mailList}) {
  2168. message TF("No mail found with index: %s. (might need to re-open mailbox)n", $args[0]), "info";
  2169. } else {
  2170. message T("Mailbox has not been opened or is empty.n"), "info";
  2171. }
  2172. } else {
  2173. $messageSender->sendMailRead($mailList->[$args[0]]->{mailID});
  2174. }
  2175. # mail inbox => set on begin as standard?
  2176. } elsif ($cmd eq 'mi') {
  2177. # if mail not already opened needed?
  2178. $messageSender->sendMailboxOpen();
  2179. # mail window (almost useless?)
  2180. } elsif ($cmd eq 'mw') {
  2181. unless (defined $args[0]) {
  2182. message T("Usage: mw [0|1|2] (0:write, 1:take item back, 2:zenny input ok)n"), "info";
  2183. } elsif ($args[0] =~ /^[0-2]$/) {
  2184. $messageSender->sendMailOperateWindow($args[0]);
  2185. } else {
  2186. error T("Syntax error in function 'mw' (mailbox window)n" .
  2187. "Usage: mw [0|1|2] (0:write, 1:take item back, 2:zenny input ok)n");
  2188. }
  2189. # mail attachment control
  2190. } elsif ($cmd eq 'ma') {
  2191. if ($args[0] eq "get" && $args[1] =~ /^d+$/) {
  2192. unless ($mailList->[$args[1]]->{mailID}) {
  2193. if (@{$mailList}) {
  2194. message TF("No mail found with index: %s. (might need to re-open mailbox)n", $args[1]), "info";
  2195. } else {
  2196. message T("Mailbox has not been opened or is empty.n"), "info";
  2197. }
  2198. } else {
  2199. $messageSender->sendMailGetAttach($mailList->[$args[1]]->{mailID});
  2200. }
  2201. } elsif ($args[0] eq "add") {
  2202. unless ($args[2] =~ /^d+$/) {
  2203. message T("Usage: ma add [zeny <amount>]|[item <amount> (<item #>|<item name>)]n"), "info";
  2204. } elsif ($args[1] eq "zeny") {
  2205. $messageSender->sendMailSetAttach($args[2], undef);
  2206. } elsif ($args[1] eq "item" && defined $args[3]) {
  2207. my $item = Actor::Item::get($args[3]);
  2208. if ($item) {
  2209. my $serverIndex = $item->{index};
  2210. $messageSender->sendMailSetAttach($args[2], $serverIndex);
  2211. } else {
  2212. message TF("Item with index or name: %s does not exist in inventory.n", $args[3]), "info";
  2213. }
  2214. } else {
  2215. error T("Syntax error in function 'ma' (mail attachment control)n" .
  2216. "Usage: ma add [zeny <amount>]|[item <amount> (<item #>|<item name>)]n");
  2217. }
  2218. } else {
  2219. message T("Usage: ma (get <mail #>)|(add [zeny <amount>]|[item <amount> (<item #>|<item name>)])n"), "info";
  2220. }
  2221. # mail delete (can't delete mail without removing attachment/zeny first)
  2222. } elsif ($cmd eq 'md') {
  2223. unless ($args[0] =~ /^d+$/) {
  2224. message T("Usage: md <mail #>n"), "info";
  2225. } elsif (!$mailList->[$args[0]]) {
  2226. if (@{$mailList}) {
  2227. message TF("No mail found with index: %s. (might need to re-open mailbox)n", $args[0]), "info";
  2228. } else {
  2229. message T("Mailbox has not been opened or is empty.n"), "info";
  2230. }
  2231. } else {
  2232. $messageSender->sendMailDelete($mailList->[$args[0]]->{mailID});
  2233. }
  2234. # mail return
  2235. } elsif ($cmd eq 'mr') {
  2236. unless ($args[0] =~ /^d+$/) {
  2237. message T("Usage: mr <mail #>n"), "info";
  2238. } elsif (!$mailList->[$args[0]]) {
  2239. if (@{$mailList}) {
  2240. message TF("No mail found with index: %s. (might need to re-open mailbox)n", $args[1]), "info";
  2241. } else {
  2242. message T("Mailbox has not been opened or is empty.n"), "info";
  2243. }
  2244. } else {
  2245. $messageSender->sendMailReturn($mailList->[$args[0]]->{mailID}, $mailList->[$args[0]]->{sender});
  2246. }
  2247. # with command mail, list of possebilities: $cmd eq 'm'
  2248. } else {
  2249. message T("Mail commands: ms, mi, mo, md, mw, mr, man"), "info";
  2250. }
  2251. }
  2252. sub cmdAuction {
  2253. if (!$net || $net->getState() != Network::IN_GAME) {
  2254. error TF("You must be logged in the game to use this command (%s)n", shift);
  2255. return;
  2256. }
  2257. my ($cmd, $args_string) = @_;
  2258. my @args = parseArgs($args_string, 4);
  2259. # auction add item
  2260. # TODO: it doesn't seem possible to add more than 1 item?
  2261. if ($cmd eq 'aua') {
  2262. unless (defined $args[0] && $args[1] =~ /^d+$/) {
  2263. message T("Usage: aua (<item #>|<item name>) <amount>n"), "info";
  2264. } elsif (my $item = Actor::Item::get($args[0])) {
  2265. my $serverIndex = $item->{index};
  2266. $messageSender->sendAuctionAddItem($serverIndex, $args[1]);
  2267. }
  2268. # auction remove item
  2269. } elsif ($cmd eq 'aur') {
  2270. $messageSender->sendAuctionAddItemCancel();
  2271. # auction create (add item first)
  2272. } elsif ($cmd eq 'auc') {
  2273. unless ($args[0] && $args[1] && $args[2]) {
  2274. message T("Usage: auc <current price> <instant buy price> <hours>n"), "info";
  2275. } else {
  2276. my ($price, $buynow, $hours) = ($args[0], $args[1], $args[2]);
  2277. $messageSender->sendAuctionCreate($price, $buynow, $hours);
  2278. }
  2279. # auction create (add item first)
  2280. } elsif ($cmd eq 'aub') {
  2281. unless (defined $args[0] && $args[1] =~ /^d+$/) {
  2282. message T("Usage: aub <id> <price>n"), "info";
  2283. } else {
  2284. unless ($auctionList->[$args[0]]->{ID}) {
  2285. if (@{$auctionList}) {
  2286. message TF("No auction item found with index: %s. (might need to re-open auction window)n", $args[0]), "info";
  2287. } else {
  2288. message T("Auction window has not been opened or is empty.n"), "info";
  2289. }
  2290. } else {
  2291. $messageSender->sendAuctionBuy($auctionList->[$args[0]]->{ID}, $args[1]);
  2292. }
  2293. }
  2294. # auction info (my)
  2295. } elsif ($cmd eq 'aui') {
  2296. # funny thing is, we can access this info trough 'aus' aswell
  2297. unless ($args[0] eq "selling" || $args[0] eq "buying") {
  2298. message T("Usage: aui (selling|buying)n"), "info";
  2299. } else {
  2300. $args[0] = ($args[0] eq "selling") ? 0 : 1;
  2301. $messageSender->sendAuctionReqMyInfo($args[0]);
  2302. }
  2303. # auction delete
  2304. } elsif ($cmd eq 'aud') {
  2305. unless ($args[0] =~ /^d+$/) {
  2306. message T("Usage: aud <index>n"), "info";
  2307. } else {
  2308. unless ($auctionList->[$args[0]]->{ID}) {
  2309. if (@{$auctionList}) {
  2310. message TF("No auction item found with index: %s. (might need to re-open auction window)n", $args[0]), "info";
  2311. } else {
  2312. message T("Auction window has not been opened or is empty.n"), "info";
  2313. }
  2314. } else {
  2315. $messageSender->sendAuctionCancel($auctionList->[$args[0]]->{ID});
  2316. }
  2317. }
  2318. # auction end (item gets sold to highest bidder?)
  2319. } elsif ($cmd eq 'aue') {
  2320. unless ($args[0] =~ /^d+$/) {
  2321. message T("Usage: aue <index>n"), "info";
  2322. } else {
  2323. unless ($auctionList->[$args[0]]->{ID}) {
  2324. if (@{$auctionList}) {
  2325. message TF("No auction item found with index: %s. (might need to re-open auction window)n", $args[0]), "info";
  2326. } else {
  2327. message T("Auction window has not been opened or is empty.n"), "info";
  2328. }
  2329. } else {
  2330. $messageSender->sendAuctionMySellStop($auctionList->[$args[0]]->{ID});
  2331. }
  2332. }
  2333. # auction search
  2334. } elsif ($cmd eq 'aus') {
  2335. # TODO: can you in official servers do a query on both a category AND price/text? (eA doesn't allow you to)
  2336. unless (defined $args[0]) {
  2337. message T("Usage: aus <type> [<price>|<text>]n" .
  2338. "      types (0:Armor 1:Weapon 2:Card 3:Misc 4:By Text 5:By Price 6:Sell 7:Buy)n"), "info";
  2339. # armor, weapon, card, misc, sell, buy
  2340. } elsif ($args[0] =~ /^[0-3]$/ || $args[0] =~ /^[6-7]$/) {
  2341. $messageSender->sendAuctionItemSearch($args[0]);
  2342. # by text
  2343. } elsif ($args[0] == 5) {
  2344. unless (defined $args[1]) {
  2345. message T("Usage: aus 5 <text>n"), "info";
  2346. } else {
  2347. $messageSender->sendAuctionItemSearch($args[0], undef, $args[1]);
  2348. }
  2349. # by price
  2350. } elsif ($args[0] == 6) {
  2351. unless ($args[1] =~ /^d+$/) {
  2352. message T("Usage: aus 6 <price>n"), "info";
  2353. } else {
  2354. $messageSender->sendAuctionItemSearch($args[0], $args[1]);
  2355. }
  2356. } else {
  2357. error T("Possible value's for the <type> parameter are:n" .
  2358. "(0:Armor 1:Weapon 2:Card 3:Misc 4:By Text 5:By Price 6:Sell 7:Buy)n");
  2359. }
  2360. # with command auction, list of possebilities: $cmd eq 'au'
  2361. } else {
  2362. message T("Auction commands: aua, aur, auc, aub, aui, aud, aue, ausn"), "info";
  2363. }
  2364. }
  2365. return 1;