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

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Commandline
  3. #
  4. #  This software is open source, licensed under the GNU General Public
  5. #  License, version 2.
  6. #  Basically, this means that you're allowed to modify and distribute
  7. #  this software. However, if you distribute modified versions, you MUST
  8. #  also distribute the source code.
  9. #  See http://www.gnu.org/licenses/gpl.html for the full license.
  10. #
  11. #  $Revision: 6780 $
  12. #  $Id: Commands.pm 6780 2009-07-23 21:32:55Z Technologyguild $
  13. #
  14. #########################################################################
  15. ##
  16. # MODULE DESCRIPTION: Commandline input processing
  17. #
  18. # This module processes commandline input.
  19. package Commands;
  20. use strict;
  21. use warnings;
  22. no warnings qw(redefine uninitialized);
  23. use Time::HiRes qw(time);
  24. use encoding 'utf8';
  25. use Modules 'register';
  26. use Globals;
  27. use Log qw(message debug error warning);
  28. use Network;
  29. use Network::Send ();
  30. use Settings;
  31. use Plugins;
  32. use Skill;
  33. use Utils;
  34. use Utils::Exceptions;
  35. use Misc;
  36. use AI;
  37. use Task;
  38. use Task::ErrorReport;
  39. use Match;
  40. use Translation;
  41. use I18N qw(stringToBytes);
  42. our %handlers;
  43. our %completions;
  44. undef %handlers;
  45. undef %completions;
  46. our %customCommands;
  47. sub initHandlers {
  48. %handlers = (
  49. a                  => &cmdAttack,
  50. ai                 => &cmdAI,
  51. aiv                => &cmdAIv,
  52. al                 => &cmdShopInfoSelf,
  53. arrowcraft         => &cmdArrowCraft,
  54. as                 => &cmdAttackStop,
  55. autobuy            => &cmdAutoBuy,
  56. autosell           => &cmdAutoSell,
  57. autostorage        => &cmdAutoStorage,
  58. auth               => &cmdAuthorize,
  59. bangbang           => &cmdBangBang,
  60. bingbing           => &cmdBingBing,
  61. buy                => &cmdBuy,
  62. c                  => &cmdChat,
  63. card               => &cmdCard,
  64. cart               => &cmdCart,
  65. chat               => &cmdChatRoom,
  66. chist              => &cmdChist,
  67. cil                => &cmdItemLogClear,
  68. cl                 => &cmdChatLogClear,
  69. closeshop          => &cmdCloseShop,
  70. conf               => &cmdConf,
  71. damage             => &cmdDamage,
  72. deal               => &cmdDeal,
  73. debug              => &cmdDebug,
  74. dl                 => &cmdDealList,
  75. doridori           => &cmdDoriDori,
  76. drop               => &cmdDrop,
  77. dump               => &cmdDump,
  78. dumpnow            => &cmdDumpNow,
  79. e                  => &cmdEmotion,
  80. eq                 => &cmdEquip,
  81. eval               => &cmdEval,
  82. exp                => &cmdExp,
  83. falcon             => &cmdFalcon,
  84. follow             => &cmdFollow,
  85. friend             => &cmdFriend,
  86. homun              => &cmdSlave,
  87. merc               => &cmdSlave,
  88. g                  => &cmdGuildChat,
  89. getplayerinfo      => &cmdGetPlayerInfo,
  90. # GM Commands - Start
  91. gmb                => &cmdGmb,
  92. gmbb               => &cmdGmbb,
  93. gmnb               => &cmdGmnb,
  94. gmlb               => &cmdGmlb,
  95. gmlbb              => &cmdGmlbb,
  96. gmnlb              => &cmdGmnlb,
  97. gmmapmove          => &cmdGmmapmove,
  98. gmcreate           => &cmdGmcreate,
  99. gmhide             => &cmdGmhide,
  100. gmwarpto           => &cmdGmwarpto,
  101. gmsummon           => &cmdGmsummon,
  102. gmrecall           => &cmdGmrecall,
  103. gmremove           => &cmdGmremove,
  104. gmdc               => &cmdGmdc,
  105. gmresetskill       => &cmdGmresetskill,
  106. gmresetstate       => &cmdGmresetstate,
  107. gmmute             => &cmdGmmute,
  108. gmunmute           => &cmdGmunmute,
  109. gmkillall          => &cmdGmkillall,
  110. # GM Commands - End
  111. guild              => &cmdGuild,
  112. help               => &cmdHelp,
  113. i                  => &cmdInventory,
  114. identify           => &cmdIdentify,
  115. ignore             => &cmdIgnore,
  116. ihist              => &cmdIhist,
  117. il                 => &cmdItemList,
  118. im                 => &cmdUseItemOnMonster,
  119. ip                 => &cmdUseItemOnPlayer,
  120. is                 => &cmdUseItemOnSelf,
  121. kill               => &cmdKill,
  122. look               => &cmdLook,
  123. lookp              => &cmdLookPlayer,
  124. memo               => &cmdMemo,
  125. ml                 => &cmdMonsterList,
  126. move               => &cmdMove,
  127. nl                 => &cmdNPCList,
  128. openshop           => &cmdOpenShop,
  129. p                  => &cmdPartyChat,
  130. party              => &cmdParty,
  131. pecopeco           => &cmdPecopeco,  
  132. #pet               => &cmdPet,
  133. petl               => &cmdPetList,
  134. pl                 => &cmdPlayerList,
  135. plugin             => &cmdPlugin,
  136. pm                 => &cmdPrivateMessage,
  137. pml                => &cmdPMList,
  138. portals            => &cmdPortalList,
  139. quit               => &cmdQuit,
  140. rc                 => &cmdReloadCode,
  141. reload             => &cmdReload,
  142. relog              => &cmdRelog,
  143. repair             => &cmdRepair,
  144. respawn            => &cmdRespawn,
  145. s                  => &cmdStatus,
  146. sell               => &cmdSell,
  147. send               => &cmdSendRaw,
  148. sit                => &cmdSit,
  149. skills             => &cmdSkills,
  150. sll                => &cmdSlaveList,
  151. spells             => &cmdSpells,
  152. storage            => &cmdStorage,
  153. store              => &cmdStore,
  154. sl                 => &cmdUseSkill,
  155. sm                 => &cmdUseSkill,
  156. sp                 => &cmdUseSkill,
  157. ss                 => &cmdUseSkill,
  158. ssp                => &cmdUseSkill,
  159. st                 => &cmdStats,
  160. stand              => &cmdStand,
  161. stat_add           => &cmdStatAdd,
  162. switchconf         => &cmdSwitchConf,
  163. take               => &cmdTake,
  164. talk               => &cmdTalk,
  165. talknpc            => &cmdTalkNPC,
  166. tank               => &cmdTank,
  167. tele               => &cmdTeleport,
  168. testshop           => &cmdTestShop,
  169. timeout            => &cmdTimeout,
  170. top10              => &cmdTop10,
  171. uneq               => &cmdUnequip,
  172. vender             => &cmdVender,
  173. verbose            => &cmdVerbose,
  174. version            => &cmdVersion,
  175. vl                 => &cmdVenderList,
  176. warp               => &cmdWarp,
  177. weight             => &cmdWeight,
  178. where              => &cmdWhere,
  179. who                => &cmdWho,
  180. whoami             => &cmdWhoAmI,
  181. m                  => &cmdMail, # see commands
  182. ms                 => &cmdMail, # send
  183. mi                 => &cmdMail, # inbox
  184. mo                 => &cmdMail, # open
  185. md                 => &cmdMail, # delete
  186. mw                 => &cmdMail, # window
  187. mr                 => &cmdMail, # return
  188. ma                 => &cmdMail, # attachement
  189. au                 => &cmdAuction, # see commands
  190. aua                => &cmdAuction, # add item
  191. aur                => &cmdAuction, # remove item
  192. auc                => &cmdAuction, # create auction
  193. aue                => &cmdAuction, # auction end
  194. aus                => &cmdAuction, # search auction
  195. aub                => &cmdAuction, # make bid
  196. aui                => &cmdAuction, # info on buy/sell
  197. aud                => &cmdAuction, # delete auction
  198. north              => &cmdManualMove,
  199. south              => &cmdManualMove,
  200. east               => &cmdManualMove,
  201. west               => &cmdManualMove,
  202. northeast          => &cmdManualMove,
  203. northwest          => &cmdManualMove,
  204. southeast          => &cmdManualMove,
  205. southwest          => &cmdManualMove,
  206. );
  207. }
  208. sub initCompletions {
  209. %completions = ();
  210. }
  211. ##
  212. # Commands::run(input)
  213. # input: a command.
  214. #
  215. # Processes $input. See also <a href="http://openkore.sourceforge.net/docs.php">the user documentation</a>
  216. # for a list of commands.
  217. #
  218. # Example:
  219. # # Same effect as typing 's' in the console. Displays character status
  220. # Commands::run("s");
  221. sub run {
  222. my $input = shift;
  223. my $handler;
  224. initHandlers() if (!%handlers);
  225. # Resolve command aliases
  226. my ($switch, $args) = split(/ +/, $input, 2);
  227. if (my $alias = $config{"alias_$switch"}) {
  228. $input = $alias;
  229. $input .= " $args" if defined $args;
  230. }
  231. my @commands = split(';;', $input);
  232. # Loop through all of the commands...
  233. foreach my $command (@commands) {
  234. my ($switch, $args) = split(/ +/, $command, 2);
  235. $handler = $customCommands{$switch}{callback} if ($customCommands{$switch});
  236. $handler = $handlers{$switch} if (!$handler && $handlers{$switch});
  237. if (($switch eq 'pause') && (!$cmdQueue) && (!$AI_forcedOff) && ($net->getState() == Network::IN_GAME)) {
  238. $cmdQueue = 1;
  239. $cmdQueueStartTime = time;
  240. if ($args > 0) {
  241. $cmdQueueTime = $args;
  242. } else {
  243. $cmdQueueTime = 1;
  244. }
  245. debug "Command queueing startedn", "ai";
  246. } elsif (($switch eq 'pause') && ($cmdQueue > 0)) {
  247. push(@cmdQueueList, $command);
  248. } elsif (($switch eq 'pause') && (($AI_forcedOff == 1) || ($net->getState() != Network::IN_GAME))) {
  249. error TF("Cannot use pause command now.n");
  250. } elsif (($handler) && ($cmdQueue > 0) && (!defined binFind(@cmdQueuePriority,$switch) && ($command ne 'cart') && ($command ne 'storage'))) {
  251. push(@cmdQueueList, $command);
  252. } elsif ($handler) {
  253. my %params;
  254. $params{switch} = $switch;
  255. $params{args} = $args;
  256. Plugins::callHook("Commands::run/pre", %params);
  257. $handler->($switch, $args);
  258. Plugins::callHook("Commands::run/post", %params);
  259. # undef the handler here, this is needed to make sure the other commands in the chain (if any) are run properly.
  260. undef $handler;
  261. } else {
  262. my %params = ( switch => $switch, input => $command );
  263. Plugins::callHook('Command_post', %params);
  264. if (!$params{return}) {
  265. error TF("Unknown command '%s'. Please read the documentation for a list of commands.n", $switch);
  266. } else {
  267. return $params{return}
  268. }
  269. }
  270. }
  271. return 1;
  272. }
  273. ##
  274. # Commands::register([name, description, callback]...)
  275. # Returns: an ID for use with Commands::unregister()
  276. #
  277. # Register new commands.
  278. #
  279. # Example:
  280. # my $ID = Commands::register(
  281. #     ["my_command", "My custom command's description", &my_callback],
  282. #     ["another_command", "Yet another command description", &another_callback]
  283. # );
  284. # Commands::unregister($ID);
  285. sub register {
  286. my @result;
  287. foreach my $cmd (@_) {
  288. my $name = $cmd->[0];
  289. my %item = (
  290. desc => $cmd->[1],
  291. callback => $cmd->[2]
  292. );
  293. $customCommands{$name} = %item;
  294. push @result, $name;
  295. }
  296. return @result;
  297. }
  298. ##
  299. # Commands::unregister(ID)
  300. # ID: an ID returned by Commands::register()
  301. #
  302. # Unregisters a registered command.
  303. sub unregister {
  304. my $ID = shift;
  305. foreach my $name (@{$ID}) {
  306. delete $customCommands{$name};
  307. }
  308. }
  309. sub complete {
  310. my $input = shift;
  311. my ($switch, $args) = split(/ +/, $input, 2);
  312. return if ($input eq '');
  313. initCompletions() if (!%completions);
  314. # Resolve command aliases
  315. if (my $alias = $config{"alias_$switch"}) {
  316. $input = $alias;
  317. $input .= " $args" if defined $args;
  318. ($switch, $args) = split(/ +/, $input, 2);
  319. }
  320. my $completor;
  321. if ($completions{$switch}) {
  322. $completor = $completions{$switch};
  323. } else {
  324. $completor = &defaultCompletor;
  325. }
  326. my ($last_arg_pos, $matches) = $completor->($switch, $input, 'c');
  327. if (@{$matches} == 1) {
  328. my $arg = $matches->[0];
  329. $arg = ""$arg"" if ($arg =~ / /);
  330. my $new = substr($input, 0, $last_arg_pos) . $arg;
  331. if (length($new) > length($input)) {
  332. return "$new ";
  333. } elsif (length($new) == length($input)) {
  334. return "$input ";
  335. }
  336. } elsif (@{$matches} > 1) {
  337. $interface->writeOutput("message", "n" . join("t", @{$matches}) . "n", "info");
  338. ## Find largest common prefix
  339. # Find item with smallest length
  340. my $smallest;
  341. foreach (@{$matches}) {
  342. if (!defined $smallest || length($_) < $smallest) {
  343. $smallest = length($_);
  344. }
  345. }
  346. my $commonStr;
  347. for (my $len = $smallest; $len >= 0; $len--) {
  348. my $first = lc(substr($matches->[0], 0, $len));
  349. my $common = 1;
  350. foreach (@{$matches}) {
  351. if ($first ne lc(substr($_, 0, $len))) {
  352. $common = 0;
  353. last;
  354. }
  355. }
  356. if ($common) {
  357. $commonStr = $first;
  358. last;
  359. }
  360. }
  361. my $new = substr($input, 0, $last_arg_pos) . $commonStr;
  362. return $new if (length($new) > length($input));
  363. }
  364. return $input;
  365. }
  366. ##################################
  367. sub completePlayerName {
  368. my $arg = quotemeta shift;
  369. my @matches;
  370. foreach (@playersID) {
  371. next if (!$_);
  372. if ($players{$_}{name} =~ /^$arg/i) {
  373. push @matches, $players{$_}{name};
  374. }
  375. }
  376. return @matches;
  377. }
  378. sub defaultCompletor {
  379. my $switch = shift;
  380. my $last_arg_pos;
  381. my @args = parseArgs(shift, undef, undef, $last_arg_pos);
  382. my @matches;
  383. my $arg = $args[$#args];
  384. @matches = completePlayerName($arg);
  385. return ($last_arg_pos, @matches);
  386. }
  387. ##################################
  388. sub cmdAI {
  389. my (undef, $args) = @_;
  390. $args =~ s/ .*//;
  391. # Clear AI
  392. @cmdQueueList = ();
  393. $cmdQueue = 0;
  394. if ($args eq 'clear') {
  395. AI::clear;
  396. $taskManager->stopAll() if defined $taskManager;
  397. delete $ai_v{temp};
  398. undef $char->{dead};
  399. message T("AI sequences clearedn"), "success";
  400. } elsif ($args eq 'print') {
  401. # Display detailed info about current AI sequence
  402. message T("------ AI Sequence ---------------------n"), "list";
  403. my $index = 0;
  404. foreach (@ai_seq) {
  405. message("$index: $_ " . dumpHash(%{$ai_seq_args[$index]}) . "nn", "list");
  406. $index++;
  407. }
  408. message T("------ AI Sequences --------------------n"), "list";
  409. } elsif ($args eq 'ai_v') {
  410. message dumpHash(%ai_v) . "n", "list";
  411. } elsif ($args eq 'on' || $args eq 'auto') {
  412. # Set AI to auto mode
  413. if ($AI == 2) {
  414. message T("AI is already set to auto moden"), "success";
  415. } else {
  416. $AI = 2;
  417. undef $AI_forcedOff;
  418. message T("AI set to auto moden"), "success";
  419. }
  420. } elsif ($args eq 'manual') {
  421. # Set AI to manual mode
  422. if ($AI == 1) {
  423. message T("AI is already set to manual moden"), "success";
  424. } else {
  425. $AI = 1;
  426. $AI_forcedOff = 1;
  427. message T("AI set to manual moden"), "success";
  428. }
  429. } elsif ($args eq 'off') {
  430. # Turn AI off
  431. if ($AI) {
  432. undef $AI;
  433. $AI_forcedOff = 1;
  434. message T("AI turned offn"), "success";
  435. } else {
  436. message T("AI is already offn"), "success";
  437. }
  438. } elsif ($args eq '') {
  439. # Toggle AI
  440. if ($AI == 2) {
  441. undef $AI;
  442. $AI_forcedOff = 1;
  443. message T("AI turned offn"), "success";
  444. } elsif (!$AI) {
  445. $AI = 1;
  446. $AI_forcedOff = 1;
  447. message T("AI set to manual moden"), "success";
  448. } elsif ($AI == 1) {
  449. $AI = 2;
  450. undef $AI_forcedOff;
  451. message T("AI set to auto moden"), "success";
  452. }
  453. } else {
  454. error T("Syntax Error in function 'ai' (AI Commands)n" .
  455. "Usage: ai [ clear | print | ai_v | auto | manual | off ]n");
  456. }
  457. }
  458. sub cmdAIv {
  459. # Display current AI sequences
  460. my $on;
  461. if (!$AI) {
  462. message TF("ai_seq (off) = %sn", "@ai_seq"), "list";
  463. } elsif ($AI == 1) {
  464. message TF("ai_seq (manual) = %sn", "@ai_seq"), "list";
  465. } elsif ($AI == 2) {
  466. message TF("ai_seq (auto) = %sn", "@ai_seq"), "list";
  467. }
  468. message T("solutionn"), "list" if (AI::args->{'solution'});
  469. message TF("Active tasks: %sn", (defined $taskManager) ? $taskManager->activeTasksString() : ''), "info";
  470. message TF("Inactive tasks: %sn", (defined $taskManager) ? $taskManager->inactiveTasksString() : ''), "info";
  471. }
  472. sub cmdArrowCraft {
  473. if (!$net || $net->getState() != Network::IN_GAME) {
  474. error TF("You must be logged in the game to use this command (%s)n", shift);
  475. return;
  476. }
  477. my (undef, $args) = @_;
  478. my ($arg1) = $args =~ /^(w+)/;
  479. my ($arg2) = $args =~ /^w+ (d+)/;
  480. #print "-$arg1-n";
  481. if ($arg1 eq "") {
  482. if (@arrowCraftID) {
  483. message T("----------------- Item To Craft -----------------n"), "info";
  484. for (my $i = 0; $i < @arrowCraftID; $i++) {
  485. next if ($arrowCraftID[$i] eq "");
  486. message(swrite(
  487. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
  488. [$i, $char->inventory->get($arrowCraftID[$i])->{name}]),"list");
  489. }
  490. message("-------------------------------------------------n","list")
  491. } else {
  492. error T("Error in function 'arrowcraft' (Create Arrows)n" .
  493.   "Type 'arrowcraft use' to get list.n");
  494. }
  495. } elsif ($arg1 eq "use") {
  496. if (defined binFind(@skillsID, 'AC_MAKINGARROW')) {
  497. main::ai_skillUse('AC_MAKINGARROW', 1, 0, 0, $accountID);
  498. } else {
  499. error T("Error in function 'arrowcraft' (Create Arrows)n" . 
  500. "You don't have Arrow Making Skill.n");
  501. }
  502. } elsif ($arg1 eq "forceuse") {
  503. my $item = $char->inventory->get($arg2);
  504. if ($item) {
  505. $messageSender->sendArrowCraft($item->{nameID});
  506. } else {
  507. error TF("Error in function 'arrowcraft forceuse #' (Create Arrows)n" . 
  508. "You don't have item %s in your inventory.n", $arg2);
  509. }
  510. } else {
  511. if ($arrowCraftID[$arg1] ne "") {
  512. $messageSender->sendArrowCraft($char->inventory->get($arrowCraftID[$arg1])->{nameID});
  513. } else {
  514. error T("Error in function 'arrowcraft' (Create Arrows)n" .
  515. "Usage: arrowcraft [<identify #>]n" .
  516. "Type 'arrowcraft use' to get list.n");
  517. }
  518. }
  519. }
  520. sub cmdAttack {
  521. my (undef, $arg1) = @_;
  522. if ($arg1 =~ /^d+$/) {
  523. if ($monstersID[$arg1] eq "") {
  524. error TF("Error in function 'a' (Attack Monster)n" . 
  525. "Monster %s does not exist.n", $arg1);
  526. } else {
  527. main::attack($monstersID[$arg1]);
  528. }
  529. } elsif ($arg1 eq "no") {
  530. configModify("attackAuto", 1);
  531. } elsif ($arg1 eq "yes") {
  532. configModify("attackAuto", 2);
  533. } else {
  534. error T("Syntax Error in function 'a' (Attack Monster)n" . 
  535. "Usage: attack <monster # | no | yes >n");
  536. }
  537. }
  538. sub cmdAttackStop {
  539. my $index = AI::findAction("attack");
  540. if ($index ne "") {
  541. my $args = AI::args($index);
  542. my $monster = Actor::get($args->{ID});
  543. if ($monster) {
  544. $monster->{ignore} = 1;
  545. stopAttack();
  546. message TF("Stopped attacking %s (%s)n", 
  547. $monster->{name}, $monster->{binID}), "success";
  548. AI::clear("attack");
  549. }
  550. }
  551. }
  552. sub cmdAuthorize {
  553. my (undef, $args) = @_;
  554. my ($arg1, $arg2) = $args =~ /^([sS]*) ([sS]*?)$/;
  555. if ($arg1 eq "" || ($arg2 ne "1" && $arg2 ne "0")) {
  556. error T("Syntax Error in function 'auth' (Overall Authorize)n" . 
  557. "Usage: auth <username> <flag>n");
  558. } else {
  559. auth($arg1, $arg2);
  560. }
  561. }
  562. sub cmdAutoBuy {
  563. message T("Initiating auto-buy.n");
  564. AI::queue("buyAuto");
  565. }
  566. sub cmdAutoSell {
  567. message T("Initiating auto-sell.n");
  568. AI::queue("sellAuto");
  569. }
  570. sub cmdAutoStorage {
  571. message T("Initiating auto-storage.n");
  572. AI::queue("storageAuto");
  573. }
  574. sub cmdBangBang {
  575. if (!$net || $net->getState() != Network::IN_GAME) {
  576. error TF("You must be logged in the game to use this command (%s)n", shift);
  577. return;
  578. }
  579. my $bodydir = $char->{look}{body} - 1;
  580. $bodydir = 7 if ($bodydir == -1);
  581. $messageSender->sendLook($bodydir, $char->{look}{head});
  582. }
  583. sub cmdBingBing {
  584. if (!$net || $net->getState() != Network::IN_GAME) {
  585. error TF("You must be logged in the game to use this command (%s)n", shift);
  586. return;
  587. }
  588. my $bodydir = ($char->{look}{body} + 1) % 8;
  589. $messageSender->sendLook($bodydir, $char->{look}{head});
  590. }
  591. sub cmdBuy {
  592. if (!$net || $net->getState() != Network::IN_GAME) {
  593. error TF("You must be logged in the game to use this command (%s)n", shift);
  594. return;
  595. }
  596. my (undef, $args) = @_;
  597. my ($arg1) = $args =~ /^(d+)/;
  598. my ($arg2) = $args =~ /^d+ (d+)$/;
  599. if ($arg1 eq "") {
  600. error T("Syntax Error in function 'buy' (Buy Store Item)n" . 
  601. "Usage: buy <item #> [<amount>]n");
  602. } elsif ($storeList[$arg1] eq "") {
  603. error TF("Error in function 'buy' (Buy Store Item)n" . 
  604. "Store Item %s does not exist.n", $arg1);
  605. } else {
  606. if ($arg2 <= 0) {
  607. $arg2 = 1;
  608. }
  609. $messageSender->sendBuy($storeList[$arg1]{'nameID'}, $arg2);
  610. }
  611. }
  612. sub cmdCard {
  613. if (!$net || $net->getState() != Network::IN_GAME) {
  614. error TF("You must be logged in the game to use this command (%s)n", shift);
  615. return;
  616. }
  617. my (undef, $input) = @_;
  618. my ($arg1) = $input =~ /^(w+)/;
  619. my ($arg2) = $input =~ /^w+ (d+)/;
  620. my ($arg3) = $input =~ /^w+ d+ (d+)/;
  621. if ($arg1 eq "mergecancel") {
  622. if (!defined $messageSender) {
  623. error T("Error in function 'bingbing' (Change look direction)n" .
  624. "Can't use command while not connected to server.n");
  625. } elsif ($cardMergeIndex ne "") {
  626. undef $cardMergeIndex;
  627. $messageSender->sendCardMerge(-1, -1);
  628. message T("Cancelling card merge.n");
  629. } else {
  630. error T("Error in function 'card mergecancel' (Cancel a card merge request)n" . 
  631. "You are not currently in a card merge session.n");
  632. }
  633. } elsif ($arg1 eq "mergelist") {
  634. # FIXME: if your items change order or are used, this list will be wrong
  635. if (@cardMergeItemsID) {
  636. my $msg;
  637. $msg .= T("-----Card Merge Candidates-----n");
  638. foreach my $card (@cardMergeItemsID) {
  639. next if $card eq "" || !$char->inventory->get($card);
  640. $msg .= swrite(
  641. "@<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
  642. [$card, $char->inventory->get($card)]);
  643. }
  644. $msg .= "-------------------------------n";
  645. message $msg, "list";
  646. } else {
  647. error T("Error in function 'card mergelist' (List availible card merge items)n" . 
  648. "You are not currently in a card merge session.n");
  649. }
  650. } elsif ($arg1 eq "merge") {
  651. if ($arg2 =~ /^d+$/) {
  652. my $found = binFind(@cardMergeItemsID, $arg2);
  653. if (defined $found) {
  654. $messageSender->sendCardMerge($char->inventory->get($cardMergeIndex)->{index},
  655. $char->inventory->get($arg2)->{index});
  656. } else {
  657. if ($cardMergeIndex ne "") {
  658. error TF("Error in function 'card merge' (Finalize card merging onto item)n" . 
  659. "There is no item %s in the card mergelist.n", $arg2);
  660. } else {
  661. error T("Error in function 'card merge' (Finalize card merging onto item)n" . 
  662. "You are not currently in a card merge session.n");
  663. }
  664. }
  665. } else {
  666. error T("Syntax Error in function 'card merge' (Finalize card merging onto item)n" .
  667. "Usage: card merge <item number>n" . 
  668. "<item number> - Merge item number. Type 'card mergelist' to get number.n");
  669. }
  670. } elsif ($arg1 eq "use") {
  671. if ($arg2 =~ /^d+$/) {
  672. if ($char->inventory->get($arg2)) {
  673. $cardMergeIndex = $arg2;
  674. $messageSender->sendCardMergeRequest($char->inventory->get($cardMergeIndex)->{index});
  675. message TF("Sending merge list request for %s...n", 
  676. $char->inventory->get($cardMergeIndex)->{name});
  677. } else {
  678. error TF("Error in function 'card use' (Request list of items for merging with card)n" . 
  679. "Card %s does not exist.n", $arg2);
  680. }
  681. } else {
  682. error T("Syntax Error in function 'card use' (Request list of items for merging with card)n" .
  683. "Usage: card use <item number>n" .
  684. "<item number> - Card inventory number. Type 'i' to get number.n");
  685. }
  686. } elsif ($arg1 eq "list") {
  687. my $msg;
  688. $msg .= T("-----------Card List-----------n");
  689. foreach my $item (@{$char->inventory->getItems()}) {
  690. if ($item->{type} == 6) {
  691. $msg .= "$item->{invIndex} $item->{name} x $item->{amount}n";
  692. }
  693. }
  694. $msg .= "-------------------------------n";
  695. message $msg, "list";
  696. } elsif ($arg1 eq "forceuse") {
  697. if (!$char->inventory->get($arg2)) {
  698. error TF("Error in function 'arrowcraft forceuse #' (Create Arrows)n" .
  699. "You don't have item %s in your inventory.n", $arg2);
  700. } elsif (!$char->inventory->get($arg3)) {
  701. error TF("Error in function 'arrowcraft forceuse #' (Create Arrows)n" .
  702. "You don't have item %s in your inventory.n"), $arg3;
  703. } else {
  704. $messageSender->sendCardMerge($char->inventory->get($arg2)->{index},
  705. $char->inventory->get($arg3)->{index});
  706. }
  707. } else {
  708. error T("Syntax Error in function 'card' (Card Compounding)n" .
  709. "Usage: card <use|mergelist|mergecancel|merge>n");
  710. }
  711. }
  712. sub cmdCart {
  713. my (undef, $input) = @_;
  714. my ($arg1, $arg2) = split(' ', $input, 2);
  715. my $hasCart = $cart{exists};
  716. if ($char && $char->{statuses}) {
  717. foreach (keys %{$char->{statuses}}) {
  718. if ($_ =~ /^Level d Cart$/) {
  719. $hasCart = 1;
  720. last;
  721. }
  722. }
  723. }
  724. if (!$hasCart) {
  725. error T("Error in function 'cart' (Cart Management)n" .
  726. "You do not have a cart.n");
  727. return;
  728. } elsif (!defined $cart{'inventory'}) {
  729. error T("Cart inventory is not available.n");
  730. return;
  731. } elsif ($arg1 eq "") {
  732. my $msg = T("-------------Cart--------------n" .
  733. "#  Namen");
  734. for (my $i = 0; $i < @{$cart{'inventory'}}; $i++) {
  735. next if (!$cart{'inventory'}[$i] || !%{$cart{'inventory'}[$i]});
  736. my $display = "$cart{'inventory'}[$i]{'name'} x $cart{'inventory'}[$i]{'amount'}";
  737. $display .= T(" -- Not Identified") if !$cart{inventory}[$i]{identified};
  738. $msg .= sprintf("%-2d %-34sn", $i, $display);
  739. }
  740. $msg .= TF("nCapacity: %d/%d  Weight: %d/%dn", 
  741. int($cart{'items'}), int($cart{'items_max'}), int($cart{'weight'}), int($cart{'weight_max'}));
  742. $msg .= "-------------------------------n";
  743. message($msg, "list");
  744. } elsif ($arg1 eq "desc") {
  745. if (!($arg2 =~ /d+/)) {
  746. error TF("Syntax Error in function 'cart desc' (Show Cart Item Description)n" .
  747. "'%s' is not a valid cart item number.n", $arg2);
  748. } elsif (!$cart{'inventory'}[$arg2]) {
  749. error TF("Error in function 'cart desc' (Show Cart Item Description)n" .
  750. "Cart Item %s does not exist.n", $arg2);
  751. } else {
  752. printItemDesc($cart{'inventory'}[$arg2]{'nameID'});
  753. }
  754. } elsif ($arg1 eq "add") {
  755. if (!$net || $net->getState() != Network::IN_GAME) {
  756. error TF("You must be logged in the game to use this command (%s)n", 'cart ' . $arg1);
  757. return;
  758. }
  759. cmdCart_add($arg2);
  760. } elsif ($arg1 eq "get") {
  761. if (!$net || $net->getState() != Network::IN_GAME) {
  762. error TF("You must be logged in the game to use this command (%s)n", 'cart ' . $arg1);
  763. return;
  764. }
  765. cmdCart_get($arg2);
  766. } elsif ($arg1 eq "release") {
  767. if (!$net || $net->getState() != Network::IN_GAME) {
  768. error TF("You must be logged in the game to use this command (%s)n", 'cart ' . $arg1);
  769. return;
  770. }
  771. $messageSender->sendCompanionRelease();
  772. if ($net && $net->getState() == Network::IN_GAME) {
  773. message T("Cart released.n"), "success";
  774. $cart{exists} = 0;
  775. }
  776. } else {
  777. error TF("Error in function 'cart'n" .
  778. "Command '%s' is not a known command.n", $arg1);
  779. }
  780. }
  781. sub cmdCart_add {
  782. my ($name) = @_;
  783. if (!defined $name) {
  784. error T("Syntax Error in function 'cart add' (Add Item to Cart)n" . 
  785. "Usage: cart add <item>n");
  786. return;
  787. }
  788. my $amount;
  789. if ($name =~ /^(.*?) (d+)$/) {
  790. $name = $1;
  791. $amount = $2;
  792. }
  793. my $item = Match::inventoryItem($name);
  794. if (!$item) {
  795. error TF("Error in function 'cart add' (Add Item to Cart)n" .
  796. "Inventory Item %s does not exist.n", $name);
  797. return;
  798. }
  799. if (!$amount || $amount > $item->{amount}) {
  800. $amount = $item->{amount};
  801. }
  802. $messageSender->sendCartAdd($item->{index}, $amount);
  803. }
  804. sub cmdCart_get {
  805. my ($name) = @_;
  806. if (!defined $name) {
  807. error T("Syntax Error in function 'cart get' (Get Item from Cart)n" .
  808. "Usage: cart get <cart item>n");
  809. return;
  810. }
  811. my $amount;
  812. if ($name =~ /^(.*?) (d+)$/) {
  813. $name = $1;
  814. $amount = $2;
  815. }
  816. my $item = Match::cartItem($name);
  817. if (!$item) {
  818. error TF("Error in function 'cart get' (Get Item from Cart)n" .
  819. "Cart Item %s does not exist.n", $name);
  820. return;
  821. }
  822. if (!$amount || $amount > $item->{amount}) {
  823. $amount = $item->{amount};
  824. }
  825. $messageSender->sendCartGet($item->{index}, $amount);
  826. }
  827. sub cmdChat {
  828. if (!$net || $net->getState() != Network::IN_GAME) {
  829. error TF("You must be logged in the game to use this command (%s)n", shift);
  830. return;
  831. }
  832. my (undef, $arg1) = @_;
  833. if ($arg1 eq "") {
  834. error T("Syntax Error in function 'c' (Chat)n" .
  835. "Usage: c <message>n");
  836. } else {
  837. sendMessage($messageSender, "c", $arg1);
  838. }
  839. }
  840. sub cmdChatLogClear {
  841. chatLog_clear();
  842. message T("Chat log cleared.n"), "success";
  843. }
  844. sub cmdChatRoom {
  845. if (!$net || $net->getState() != Network::IN_GAME) {
  846. error TF("You must be logged in the game to use this command (%s)n", shift);
  847. return;
  848. }
  849. my (undef, $args) = @_;
  850. my ($arg1) = $args =~ /^(w+)/;
  851. if ($arg1 eq "bestow") {
  852. my ($arg2) = $args =~ /^w+ (d+)/;
  853. if ($currentChatRoom eq "") {
  854. error T("Error in function 'chat bestow' (Bestow Admin in Chat)n" .
  855. "You are not in a Chat Room.n");
  856. } elsif ($arg2 eq "") {
  857. error T("Syntax Error in function 'chat bestow' (Bestow Admin in Chat)n" .
  858. "Usage: chat bestow <user #>n");
  859. } elsif ($currentChatRoomUsers[$arg2] eq "") {
  860. error TF("Error in function 'chat bestow' (Bestow Admin in Chat)n" .
  861. "Chat Room User %s doesn't exist; type 'chat info' to see the list of usersn", $arg2);
  862. } else {
  863. $messageSender->sendChatRoomBestow($currentChatRoomUsers[$arg2]);
  864. }
  865. } elsif ($arg1 eq "modify") {
  866. my ($title) = $args =~ /^w+ "([sS]*?)"/;
  867. my ($users) = $args =~ /^w+ "[sS]*?" (d+)/;
  868. my ($public) = $args =~ /^w+ "[sS]*?" d+ (d+)/;
  869. my ($password) = $args =~ /^w+ "[sS]*?" d+ d+ ([sS]+)/;
  870. if ($title eq "") {
  871. error T("Syntax Error in function 'chatmod' (Modify Chat Room)n" .
  872. "Usage: chat modify "<title>" [<limit #> <public flag> <password>]n");
  873. } else {
  874. if ($users eq "") {
  875. $users = 20;
  876. }
  877. if ($public eq "") {
  878. $public = 1;
  879. }
  880. $messageSender->sendChatRoomChange($title, $users, $public, $password);
  881. }
  882. } elsif ($arg1 eq "kick") {
  883. my ($arg2) = $args =~ /^w+ (d+)/;
  884. if ($currentChatRoom eq "") {
  885. error T("Error in function 'chat kick' (Kick from Chat)n" .
  886. "You are not in a Chat Room.n");
  887. } elsif ($arg2 eq "") {
  888. error T("Syntax Error in function 'chat kick' (Kick from Chat)n" .
  889. "Usage: chat kick <user #>n");
  890. } elsif ($currentChatRoomUsers[$arg2] eq "") {
  891. error TF("Error in function 'chat kick' (Kick from Chat)n" .
  892. "Chat Room User %s doesn't existn", $arg2);
  893. } else {
  894. $messageSender->sendChatRoomKick($currentChatRoomUsers[$arg2]);
  895. }
  896. } elsif ($arg1 eq "join") {
  897. my ($arg2) = $args =~ /^w+ (d+)/;
  898. my ($arg3) = $args =~ /^w+ d+ (d+)/;
  899. if ($arg2 eq "") {
  900. error T("Syntax Error in function 'chat join' (Join Chat Room)n" .
  901. "Usage: chat join <chat room #> [<password>]n");
  902. } elsif ($currentChatRoom ne "") {
  903. error T("Error in function 'chat join' (Join Chat Room)n" .
  904. "You are already in a chat room.n");
  905. } elsif ($chatRoomsID[$arg2] eq "") {
  906. error TF("Error in function 'chat join' (Join Chat Room)n" .
  907. "Chat Room %s does not exist.n", $arg2);
  908. } else {
  909. $messageSender->sendChatRoomJoin($chatRoomsID[$arg2], $arg3);
  910. }
  911. } elsif ($arg1 eq "leave") {
  912. if ($currentChatRoom eq "") {
  913. error T("Error in function 'chat leave' (Leave Chat Room)n" .
  914. "You are not in a Chat Room.n");
  915. } else {
  916. $messageSender->sendChatRoomLeave();
  917. }
  918. } elsif ($arg1 eq "create") {
  919. my ($title) = $args =~ /^w+ "([sS]*?)"/;
  920. my ($users) = $args =~ /^w+ "[sS]*?" (d+)/;
  921. my ($public) = $args =~ /^w+ "[sS]*?" d+ (d+)/;
  922. my ($password) = $args =~ /^w+ "[sS]*?" d+ d+ ([sS]+)/;
  923. if ($title eq "") {
  924. error T("Syntax Error in function 'chat create' (Create Chat Room)n" .
  925. "Usage: chat create "<title>" [<limit #> <public flag> <password>]n");
  926. } elsif ($currentChatRoom ne "") {
  927. error T("Error in function 'chat create' (Create Chat Room)n" .
  928. "You are already in a chat room.n");
  929. } else {
  930. if ($users eq "") {
  931. $users = 20;
  932. }
  933. if ($public eq "") {
  934. $public = 1;
  935. }
  936. $title = ($config{chatTitleOversize}) ? $title : substr($title,0,36);
  937. $messageSender->sendChatRoomCreate($title, $users, $public, $password);
  938. %createdChatRoom = ();
  939. $createdChatRoom{title} = $title;
  940. $createdChatRoom{ownerID} = $accountID;
  941. $createdChatRoom{limit} = $users;
  942. $createdChatRoom{public} = $public;
  943. $createdChatRoom{num_users} = 1;
  944. $createdChatRoom{users}{$char->{name}} = 2;
  945. }
  946. } elsif ($arg1 eq "list") {
  947. message T("------------------------------- Chat Room List --------------------------------n" .
  948. "#   Title                                  Owner                Users   Typen"), "list";
  949. for (my $i = 0; $i < @chatRoomsID; $i++) {
  950. next if (!defined $chatRoomsID[$i]);
  951. my $room = $chatRooms{$chatRoomsID[$i]};
  952. my $owner_string = Actor::get($room->{ownerID})->name;
  953. my $public_string = ($room->{public}) ? "Public" : "Private";
  954. my $limit_string = $room->{num_users} . "/" . $room->{limit};
  955. message(swrite(
  956. "@<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<< @<<<<<< @<<<<<<",
  957. [$i, $room->{title}, $owner_string, $limit_string, $public_string]),
  958. "list");
  959. }
  960. message("-------------------------------------------------------------------------------n", "list");
  961. } elsif ($arg1 eq "info") {
  962. if ($currentChatRoom eq "") {
  963. error T("There is no chat room info - you are not in a chat roomn");
  964. } else {
  965. message T("-----------Chat Room Info-----------n" .
  966. "Title                     Users   Public/Privaten"), "list";
  967. my $public_string = ($chatRooms{$currentChatRoom}{'public'}) ? "Public" : "Private";
  968. my $limit_string = $chatRooms{$currentChatRoom}{'num_users'}."/".$chatRooms{$currentChatRoom}{'limit'};
  969. message(swrite(
  970. "@<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<< @<<<<<<<<<",
  971. [$chatRooms{$currentChatRoom}{'title'}, $limit_string, $public_string]),
  972. "list");
  973. # Translation Comment: Users in chat room
  974. message T("-- Users --n"), "list";
  975. for (my $i = 0; $i < @currentChatRoomUsers; $i++) {
  976. next if ($currentChatRoomUsers[$i] eq "");
  977. my $user_string = $currentChatRoomUsers[$i];
  978. my $admin_string = ($chatRooms{$currentChatRoom}{'users'}{$currentChatRoomUsers[$i]} > 1) ? "(Admin)" : "";
  979. message(swrite(
  980. "@<< @<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<",
  981. [$i, $user_string, $admin_string]),
  982. "list");
  983. }
  984. message("------------------------------------n", "list");
  985. }
  986. } else {
  987. error T("Syntax Error in function 'chat' (Chat room management)n" .
  988. "Usage: chat <create|modify|join|kick|leave|info|list|bestow>n");
  989. }
  990. }
  991. sub cmdChist {
  992. # Display chat history
  993. my (undef, $args) = @_;
  994. $args = 5 if ($args eq "");
  995. if (!($args =~ /^d+$/)) {
  996. error T("Syntax Error in function 'chist' (Show Chat History)n" .
  997. "Usage: chist [<number of entries #>]n");
  998. } elsif (open(CHAT, "<:utf8", $Settings::chat_log_file)) {
  999. my @chat = <CHAT>;
  1000. close(CHAT);
  1001. message T("------ Chat History --------------------n"), "list";
  1002. my $i = @chat - $args;
  1003. $i = 0 if ($i < 0);
  1004. for (; $i < @chat; $i++) {
  1005. message($chat[$i], "list");
  1006. }
  1007. message "----------------------------------------n", "list";
  1008. } else {
  1009. error TF("Unable to open %sn", $Settings::chat_log_file);
  1010. }
  1011. }
  1012. sub cmdCloseShop {
  1013. if (!$net || $net->getState() != Network::IN_GAME) {
  1014. error TF("You must be logged in the game to use this command (%s)n", shift);
  1015. return;
  1016. }
  1017. main::closeShop();
  1018. }
  1019. sub cmdConf {
  1020. my (undef, $args) = @_;
  1021. my ($arg1) = $args =~ /^(w*.*w+)/;
  1022. my ($arg2) = $args =~ /^w*.*w+s+([sS]+)s*$/;
  1023. # Basic Support for "label" in blocks. Thanks to "piroJOKE"
  1024. if ($arg1 =~ /./) {
  1025. $arg1 =~ s/.+/./; # Filter Out Unnececary dot's
  1026. my ($label, $param) = split /./, $arg1, 2; # Split the label form parameter
  1027. # This line is used for debug
  1028. # message TF("Params label '%s' param '%s' arg1 '%s' arg2 '%s'n", $label, $param, $arg1, $arg2), "info";
  1029. foreach (%config) {
  1030. if ($_ =~ /_d+_label/){ # we only need those blocks witch have labels
  1031. if ($config{$_} eq $label) {
  1032. my ($real_key, undef) = split /_label/, $_, 2;
  1033. # "<label>.block" param support. Thanks to "vit"
  1034. if ($param ne "block") {
  1035. $real_key .= "_";
  1036. $real_key .= $param;
  1037. }
  1038. $arg1 = $real_key;
  1039. last;
  1040. };
  1041. };
  1042. };
  1043. };
  1044. if ($arg1 eq "") {
  1045. error T("Syntax Error in function 'conf' (Change a Configuration Key)n" .
  1046. "Usage: conf <variable> [<value>|none]n");
  1047. } elsif (!exists $config{$arg1}) {
  1048. error TF("Config variable %s doesn't existn", $arg1);
  1049. } elsif ($arg2 eq "") {
  1050. my $value = $config{$arg1};
  1051. if ($arg1 =~ /password/i) {
  1052. message TF("Config '%s' is not displayedn", $arg1), "info";
  1053. } else {
  1054. if (defined $value) {
  1055. message TF("Config '%s' is %sn", $arg1, $value), "info";
  1056. } else {
  1057. message TF("Config '%s' is not setn", $arg1, $value), "info";
  1058. }
  1059. }
  1060. } else {
  1061. undef $arg2 if ($arg2 eq "none");
  1062. Plugins::callHook('Commands::cmdConf', {
  1063. key => $arg1,
  1064. val => $arg2
  1065. });
  1066. configModify($arg1, $arg2);
  1067. Log::initLogFiles();
  1068. }
  1069. }
  1070. sub cmdDamage {
  1071. my (undef, $args) = @_;
  1072. if ($args eq "") {
  1073. my $total = 0;
  1074. message T("Damage Taken Report:n"), "list";
  1075. message(sprintf("%-40s %-20s %-10sn", 'Name', 'Skill', 'Damage'), "list");
  1076. for my $monsterName (sort keys %damageTaken) {
  1077. my $monsterHref = $damageTaken{$monsterName};
  1078. for my $skillName (sort keys %{$monsterHref}) {
  1079. message sprintf("%-40s %-20s %10dn", $monsterName, $skillName, $monsterHref->{$skillName}), "list";
  1080. $total += $monsterHref->{$skillName};
  1081. }
  1082. }
  1083. message TF("Total Damage Taken: %sn", $total), "list";
  1084. message T("End of report.n"), "list";
  1085. } elsif ($args eq "reset") {
  1086. undef %damageTaken;
  1087. message T("Damage Taken Report reset.n"), "success";
  1088. } else {
  1089. error T("Syntax error in function 'damage' (Damage Report)n" .
  1090. "Usage: damage [reset]n");
  1091. }
  1092. }
  1093. sub cmdDeal {
  1094. if (!$net || $net->getState() != Network::IN_GAME) {
  1095. error TF("You must be logged in the game to use this command (%s)n", shift);
  1096. return;
  1097. }
  1098. my (undef, $args) = @_;
  1099. my @arg = split / /, $args;
  1100. if (%currentDeal && $arg[0] =~ /d+/) {
  1101. error T("Error in function 'deal' (Deal a Player)n" .
  1102. "You are already in a dealn");
  1103. } elsif (%incomingDeal && $arg[0] =~ /d+/) {
  1104. error T("Error in function 'deal' (Deal a Player)n" .
  1105. "You must first cancel the incoming dealn");
  1106. } elsif ($arg[0] =~ /d+/ && !$playersID[$arg[0]]) {
  1107. error TF("Error in function 'deal' (Deal a Player)n" .
  1108. "Player %s does not existn", $arg[0]);
  1109. } elsif ($arg[0] =~ /d+/) {
  1110. my $ID = $playersID[$arg[0]];
  1111. my $player = Actor::get($ID);
  1112. message TF("Attempting to deal %sn", $player);
  1113. deal($player);
  1114. } elsif ($arg[0] eq "no" && !%incomingDeal && !%outgoingDeal && !%currentDeal) {
  1115. error T("Error in function 'deal' (Deal a Player)n" .
  1116. "There is no incoming/current deal to canceln");
  1117. } elsif ($arg[0] eq "no" && (%incomingDeal || %outgoingDeal)) {
  1118. $messageSender->sendDealCancel();
  1119. } elsif ($arg[0] eq "no" && %currentDeal) {
  1120. $messageSender->sendCurrentDealCancel();
  1121. } elsif ($arg[0] eq "" && !%incomingDeal && !%currentDeal) {
  1122. error T("Error in function 'deal' (Deal a Player)n" .
  1123. "There is no deal to acceptn");
  1124. } elsif ($arg[0] eq "" && $currentDeal{'you_finalize'} && !$currentDeal{'other_finalize'}) {
  1125. error TF("Error in function 'deal' (Deal a Player)n" .
  1126. "Cannot make the trade - %s has not finalizedn", $currentDeal{'name'});
  1127. } elsif ($arg[0] eq "" && $currentDeal{'final'}) {
  1128. error T("Error in function 'deal' (Deal a Player)n" .
  1129. "You already accepted the final dealn");
  1130. } elsif ($arg[0] eq "" && %incomingDeal) {
  1131. $messageSender->sendDealAccept();
  1132. } elsif ($arg[0] eq "" && $currentDeal{'you_finalize'} && $currentDeal{'other_finalize'}) {
  1133. $messageSender->sendDealTrade();
  1134. $currentDeal{'final'} = 1;
  1135. message T("You accepted the final Dealn"), "deal";
  1136. } elsif ($arg[0] eq "" && %currentDeal) {
  1137. $messageSender->sendDealAddItem(0, $currentDeal{'you_zenny'});
  1138. $messageSender->sendDealFinalize();
  1139. } elsif ($arg[0] eq "add" && !%currentDeal) {
  1140. error T("Error in function 'deal_add' (Add Item to Deal)n" .
  1141. "No deal in progressn");
  1142. } elsif ($arg[0] eq "add" && $currentDeal{'you_finalize'}) {
  1143. error T("Error in function 'deal_add' (Add Item to Deal)n" .
  1144. "Can't add any Items - You already finalized the dealn");
  1145. } elsif ($arg[0] eq "add" && $arg[1] =~ /d+/ && !$char->inventory->get($arg[1])) {
  1146. error TF("Error in function 'deal_add' (Add Item to Deal)n" .
  1147. "Inventory Item %s does not exist.n", $arg[1]);
  1148. } elsif ($arg[0] eq "add" && $arg[2] && $arg[2] !~ /d+/) {
  1149. error T("Error in function 'deal_add' (Add Item to Deal)n" .
  1150. "Amount must either be a number, or not specified.n");
  1151. } elsif ($arg[0] eq "add" && $arg[1] =~ /d+/) {
  1152. if ($currentDeal{you_items} < 10) {
  1153. my $item = $char->inventory->get($arg[1]);
  1154. my $amount = $item->{amount};
  1155. if (!$arg[2] || $arg[2] > $amount) {
  1156. $arg[2] = $amount;
  1157. }
  1158. dealAddItem($item, $arg[2]);
  1159. } else {
  1160. error T("You can't add any more items to the dealn"), "deal";
  1161. }
  1162. } elsif ($arg[0] eq "add" && $arg[1] eq "z") {
  1163. if (!$arg[2] && !($arg[2] eq "0") || $arg[2] > $char->{'zenny'}) {
  1164. $arg[2] = $char->{'zenny'};
  1165. }
  1166. $currentDeal{'you_zenny'} = $arg[2];
  1167. message TF("You put forward %sz to Dealn", formatNumber($arg[2])), "deal";
  1168. } else {
  1169. error T("Syntax Error in function 'deal' (Deal a player)n" .
  1170. "Usage: deal [<Player # | no | add>] [<item #>] [<amount>]n");
  1171. }
  1172. }
  1173. sub cmdDealList {
  1174. if (!%currentDeal) {
  1175. error T("There is no deal list - You are not in a dealn");
  1176. } else {
  1177. message T("-----------Current Deal-----------n"), "list";
  1178. my $other_string = $currentDeal{'name'};
  1179. my $you_string = "You";
  1180. if ($currentDeal{'other_finalize'}) {
  1181. $other_string .= " - Finalized";
  1182. }
  1183. if ($currentDeal{'you_finalize'}) {
  1184. $you_string .= " - Finalized";
  1185. }
  1186. message(swrite(
  1187. "@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
  1188. [$you_string, $other_string]),
  1189. "list");
  1190. my @currentDealYou;
  1191. my @currentDealOther;
  1192. foreach (keys %{$currentDeal{'you'}}) {
  1193. push @currentDealYou, $_;
  1194. }
  1195. foreach (keys %{$currentDeal{'other'}}) {
  1196. push @currentDealOther, $_;
  1197. }
  1198. my ($lastindex, $display, $display2);
  1199. $lastindex = @currentDealOther;
  1200. $lastindex = @currentDealYou if (@currentDealYou > $lastindex);
  1201. for (my $i = 0; $i < $lastindex; $i++) {
  1202. if ($i < @currentDealYou) {
  1203. $display = ($items_lut{$currentDealYou[$i]} ne "")
  1204. ? $items_lut{$currentDealYou[$i]}
  1205. : "Unknown ".$currentDealYou[$i];
  1206. $display .= " x $currentDeal{'you'}{$currentDealYou[$i]}{'amount'}";
  1207. } else {
  1208. $display = "";
  1209. }
  1210. if ($i < @currentDealOther) {
  1211. $display2 = ($items_lut{$currentDealOther[$i]} ne "")
  1212. ? $items_lut{$currentDealOther[$i]}
  1213. : "Unknown ".$currentDealOther[$i];
  1214. $display2 .= " x $currentDeal{'other'}{$currentDealOther[$i]}{'amount'}";
  1215. } else {
  1216. $display2 = "";
  1217. }
  1218. message(swrite(
  1219. "@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
  1220. [$display, $display2]),
  1221. "list");
  1222. }
  1223. $you_string = ($currentDeal{'you_zenny'} ne "") ? $currentDeal{'you_zenny'} : 0;
  1224. $other_string = ($currentDeal{'other_zenny'} ne "") ? $currentDeal{'other_zenny'} : 0;
  1225. message TF("Zenny: %-25s Zenny: %-14s", 
  1226. formatNumber($you_string), formatNumber($other_string)), "list";
  1227. message("----------------------------------n", "list");
  1228. }
  1229. }
  1230. sub cmdDebug {
  1231. my (undef, $args) = @_;
  1232. my ($arg1) = $args =~ /^([wd]+)/;
  1233. if ($arg1 eq "0") {
  1234. configModify("debug", 0);
  1235. } elsif ($arg1 eq "1") {
  1236. configModify("debug", 1);
  1237. } elsif ($arg1 eq "2") {
  1238. configModify("debug", 2);
  1239. } elsif ($arg1 eq "info") {
  1240. my $connected = "server=".($net->serverAlive ? "yes" : "no").
  1241. ",client=".($net->clientAlive ? "yes" : "no");
  1242. my $time = sprintf("%.2f", time - $lastPacketTime);
  1243. my $ai_timeout = sprintf("%.2f", time - $timeout{'ai'}{'time'});
  1244. my $ai_time = sprintf("%.4f", time - $ai_v{'AI_last_finished'});
  1245. message TF("------------ Debug information ------------n" .
  1246. "ConState: %s             Connected: %sn" .
  1247. "AI enabled: %s            AI_forcedOff: %sn" .
  1248. "@ai_seq = %sn" .
  1249. "Last packet: %.2f secs agon" .
  1250. "$timeout{ai}: %.2f secs ago  (value should be >%s)n" .
  1251. "Last AI() call: %.2f secs agon" .
  1252. "-------------------------------------------n",
  1253. $conState, $connected, $AI, $AI_forcedOff, @ai_seq, $time, $ai_timeout, 
  1254. $timeout{'ai'}{'timeout'}, $ai_time), "list";
  1255. }
  1256. }
  1257. sub cmdDoriDori {
  1258. if (!$net || $net->getState() != Network::IN_GAME) {
  1259. error TF("You must be logged in the game to use this command (%s)n", shift);
  1260. return;
  1261. }
  1262. my $headdir;
  1263. if ($char->{look}{head} == 2) {
  1264. $headdir = 1;
  1265. } else {
  1266. $headdir = 2;
  1267. }
  1268. $messageSender->sendLook($char->{look}{body}, $headdir);
  1269. }
  1270. sub cmdDrop {
  1271. if (!$net || $net->getState() != Network::IN_GAME) {
  1272. error TF("You must be logged in the game to use this command (%s)n", shift);
  1273. return;
  1274. }
  1275. my (undef, $args) = @_;
  1276. my ($arg1) = $args =~ /^([d,-]+)/;
  1277. my ($arg2) = $args =~ /^[d,-]+ (d+)$/;
  1278. if ($arg1 eq "") {
  1279. error T("Syntax Error in function 'drop' (Drop Inventory Item)n" .
  1280. "Usage: drop <item #> [<amount>]n");
  1281. } else {
  1282. my @temp = split(/,/, $arg1);
  1283. @temp = grep(!/^$/, @temp); # Remove empty entries
  1284. my @items = ();
  1285. foreach (@temp) {
  1286. if (/(d+)-(d+)/) {
  1287. for ($1..$2) {
  1288. push(@items, $_) if ($char->inventory->get($_));
  1289. }
  1290. } else {
  1291. push @items, $_ if ($char->inventory->get($_));
  1292. }
  1293. }
  1294. if (@items > 0) {
  1295. main::ai_drop(@items, $arg2);
  1296. } else {
  1297. error T("No items were dropped.n");
  1298. }
  1299. }
  1300. }
  1301. sub cmdDump {
  1302. dumpData((defined $incomingMessages) ? $incomingMessages->getBuffer() : '');
  1303. quit();
  1304. }
  1305. sub cmdDumpNow {
  1306. dumpData((defined $incomingMessages) ? $incomingMessages->getBuffer() : '');
  1307. }
  1308. sub cmdEmotion {
  1309. # Show emotion
  1310. if (!$net || $net->getState() != Network::IN_GAME) {
  1311. error TF("You must be logged in the game to use this command (%s)n", shift);
  1312. return;
  1313. }
  1314. my (undef, $args) = @_;
  1315. my $num = getEmotionByCommand($args);
  1316. if (!defined $num) {
  1317. error T("Syntax Error in function 'e' (Emotion)n" .
  1318. "Usage: e <command>n");
  1319. } else {
  1320. $messageSender->sendEmotion($num);
  1321. }
  1322. }
  1323. sub cmdEquip {
  1324. # Equip an item
  1325. my (undef, $args) = @_;
  1326. my ($arg1,$arg2) = $args =~ /^(S+)s*(.*)/;
  1327. my $slot;
  1328. my $item;
  1329. if ($arg1 eq "") {
  1330. cmdEquip_list();
  1331. return;
  1332. }
  1333. if ($arg1 eq "slots") {
  1334. # Translation Comment: List of equiped items on each slot
  1335. message T("Slots:n") . join("n", @Actor::Item::slots). "n", "list";
  1336. return;
  1337. }
  1338. if (!$net || $net->getState() != Network::IN_GAME) {
  1339. error TF("You must be logged in the game to use this command (%s)n", 'eq ' . $args);
  1340. return;
  1341. }
  1342. if ($equipSlot_rlut{$arg1}) {
  1343. $slot = $arg1;
  1344. } else {
  1345. $arg1 .= " $arg2" if $arg2;
  1346. }
  1347. $item = Actor::Item::get(defined $slot ? $arg2 : $arg1, undef, 1);
  1348. if (!$item) {
  1349. $args =~ s/^($slot)s//g if ($slot);
  1350. error TF("No such non-equipped Inventory Item: %sn", $args);
  1351. return;
  1352. }
  1353. if (!$item->{type_equip} && $item->{type} != 10 && $item->{type} != 16 && $item->{type} != 17) {
  1354. error TF("Inventory Item %s (%s) can't be equipped.n", 
  1355. $item->{name}, $item->{invIndex});
  1356. return;
  1357. }
  1358. if ($slot) {
  1359. $item->equipInSlot($slot);
  1360. } else {
  1361. $item->equip();
  1362. }
  1363. }
  1364. sub cmdEquip_list {
  1365. if (!$char) {
  1366. error T("Character equipment not yet readyn");
  1367. return;
  1368. }
  1369. for my $slot (@Actor::Item::slots) {
  1370. my $item = $char->{equipment}{$slot};
  1371. my $name = $item ? $item->nameString : '-';
  1372. message sprintf("%-15s: %sn", $slot, $name), "list";
  1373. }
  1374. }
  1375. sub cmdEval {
  1376. if (!$Settings::lockdown) {
  1377. if ($_[1] eq "") {
  1378. error T("Syntax Error in function 'eval' (Evaluate a Perl expression)n" .
  1379. "Usage: eval <expression>n");
  1380. } else {
  1381. package main;
  1382. no strict;
  1383. undef $@;
  1384. eval $_[1];
  1385. if (defined $@ && $@ ne '') {
  1386. $@ .= "n" if ($@ !~ /n$/s);
  1387. Log::error($@);
  1388. }
  1389. }
  1390. }
  1391. }
  1392. sub cmdExp {
  1393. my (undef, $args) = @_;
  1394. my $knownArg;
  1395. # exp report
  1396. my ($arg1) = $args =~ /^(w+)/;
  1397. if ($arg1 eq "reset") {
  1398. $knownArg = 1;
  1399. ($bExpSwitch,$jExpSwitch,$totalBaseExp,$totalJobExp) = (2,2,0,0);
  1400. $startTime_EXP = time;
  1401. $startingZenny = $char->{zenny} if $char;
  1402. undef @monsters_Killed;
  1403. $dmgpsec = 0;
  1404. $totaldmg = 0;
  1405. $elasped = 0;
  1406. $totalelasped = 0;
  1407. undef %itemChange;
  1408. $bytesSent = 0;
  1409. $bytesReceived = 0;
  1410. message T("Exp counter reset.n"), "success";
  1411. return;
  1412. }
  1413. if (!$char) {
  1414. error T("Exp report not yet readyn");
  1415. return;
  1416. }
  1417. if (($arg1 eq "") || ($arg1 eq "report")) {
  1418. $knownArg = 1;
  1419. my ($endTime_EXP, $w_sec, $bExpPerHour, $jExpPerHour, $EstB_sec, $percentB, $percentJ, $zennyMade, $zennyPerHour, $EstJ_sec, $percentJhr, $percentBhr);
  1420. $endTime_EXP = time;
  1421. $w_sec = int($endTime_EXP - $startTime_EXP);
  1422. if ($w_sec > 0) {
  1423. $zennyMade = $char->{zenny} - $startingZenny;
  1424. $bExpPerHour = int($totalBaseExp / $w_sec * 3600);
  1425. $jExpPerHour = int($totalJobExp / $w_sec * 3600);
  1426. $zennyPerHour = int($zennyMade / $w_sec * 3600);
  1427. if ($char->{exp_max} && $bExpPerHour){
  1428. $percentB = "(".sprintf("%.2f",$totalBaseExp * 100 / $char->{exp_max})."%)";
  1429. $percentBhr = "(".sprintf("%.2f",$bExpPerHour * 100 / $char->{exp_max})."%)";
  1430. $EstB_sec = int(($char->{exp_max} - $char->{exp})/($bExpPerHour/3600));
  1431. }
  1432. if ($char->{exp_job_max} && $jExpPerHour){
  1433. $percentJ = "(".sprintf("%.2f",$totalJobExp * 100 / $char->{exp_job_max})."%)";
  1434. $percentJhr = "(".sprintf("%.2f",$jExpPerHour * 100 / $char->{exp_job_max})."%)";
  1435. $EstJ_sec = int(($char->{'exp_job_max'} - $char->{exp_job})/($jExpPerHour/3600));
  1436. }
  1437. }
  1438. $char->{deathCount} = 0 if (!defined $char->{deathCount});
  1439. message TF( "------------Exp Report------------n" .
  1440. "Botting time : %sn" .
  1441. "BaseExp      : %s %sn" .
  1442. "JobExp       : %s %sn" .
  1443. "BaseExp/Hour : %s %sn" .
  1444. "JobExp/Hour  : %s %sn" .
  1445. "Zenny        : %sn" .
  1446. "Zenny/Hour   : %sn" .
  1447. "Base Levelup Time Estimation : %sn" .
  1448. "Job Levelup Time Estimation  : %sn" .
  1449. "Died : %sn" .
  1450. "Bytes Sent   : %sn" .
  1451. "Bytes Rcvd   : %sn",
  1452. timeConvert($w_sec), formatNumber($totalBaseExp), $percentB, formatNumber($totalJobExp), $percentJ,
  1453. formatNumber($bExpPerHour), $percentBhr, formatNumber($jExpPerHour), $percentJhr,
  1454. formatNumber($zennyMade), formatNumber($zennyPerHour), timeConvert($EstB_sec), timeConvert($EstJ_sec), 
  1455. $char->{'deathCount'}, formatNumber($bytesSent), formatNumber($bytesReceived)), "info";
  1456. if ($arg1 eq "") {
  1457. message("---------------------------------n", "list");
  1458. }
  1459. }
  1460. if (($arg1 eq "monster") || ($arg1 eq "report")) {
  1461. my $total;
  1462.  
  1463. $knownArg = 1;
  1464. message T("-[Monster Killed Count]-----------------------n" .
  1465. "#   ID     Name                      Countn"), "list";
  1466. for (my $i = 0; $i < @monsters_Killed; $i++) {
  1467. next if ($monsters_Killed[$i] eq "");
  1468. message(swrite(
  1469. "@<< @<<<<< @<<<<<<<<<<<<<<<<<<<<<< @<<<<< ",
  1470. [$i, $monsters_Killed[$i]{nameID}, $monsters_Killed[$i]{name}, $monsters_Killed[$i]{count}]),
  1471. "list");
  1472. $total += $monsters_Killed[$i]{count};
  1473. }
  1474. message("----------------------------------------------n" .
  1475. TF("Total number of killed monsters: %sn", $total) .
  1476. "----------------------------------------------n",
  1477. "list");
  1478. }
  1479. if (($arg1 eq "item") || ($arg1 eq "report")) {
  1480. $knownArg = 1;
  1481. message T("-[Item Change Count]--------------------------n" .
  1482. "Name                                    Countn"), "list";
  1483. for my $item (sort keys %itemChange) {
  1484. next unless $itemChange{$item};
  1485. message(sprintf("%-40s %5dn", $item, $itemChange{$item}), "list");
  1486. }
  1487. message("----------------------------------------------n", "list");
  1488. }
  1489. if (!$knownArg) {
  1490. error T("Syntax error in function 'exp' (Exp Report)n" .
  1491. "Usage: exp [<report | monster | item | reset>]n");
  1492. }
  1493. }
  1494. sub cmdFalcon {
  1495. my (undef, $arg1) = @_;
  1496. my $hasFalcon;
  1497. if ($char) {
  1498. foreach my $ID (keys %{$char->{statuses}}) {
  1499. if ($ID eq "Falcon") {
  1500. $hasFalcon = 1;
  1501. last;
  1502. }
  1503. }
  1504. }
  1505. if ($arg1 eq "") {
  1506. if ($hasFalcon) {
  1507. message T("Your falcon is activen");
  1508. } else {
  1509. message T("Your falcon is inactiven");
  1510. }
  1511. } elsif ($arg1 eq "release") {
  1512. if (!$hasFalcon) {
  1513. error T("Error in function 'falcon release' (Remove Falcon Status)n" .
  1514. "You don't possess a falcon.n");
  1515. } elsif (!$net || $net->getState() != Network::IN_GAME) {
  1516. error TF("You must be logged in the game to use this command (%s)n", 'falcon release');
  1517. return;
  1518. } else {
  1519. $messageSender->sendCompanionRelease();
  1520. }
  1521. }
  1522. }
  1523. sub cmdFollow {
  1524. my (undef, $arg1) = @_;
  1525. if ($arg1 eq "") {
  1526. error T("Syntax Error in function 'follow' (Follow Player)n" .
  1527. "Usage: follow <player #>n");
  1528. } elsif ($arg1 eq "stop") {
  1529. AI::clear("follow");
  1530. configModify("follow", 0);
  1531. } elsif ($arg1 =~ /^d+$/) {
  1532. if (!$playersID[$arg1]) {
  1533. error TF("Error in function 'follow' (Follow Player)n" .
  1534. "Player %s either not visible or not online in party.n", $arg1);
  1535. } else {
  1536. AI::clear("follow");
  1537. main::ai_follow($players{$playersID[$arg1]}->name);
  1538. configModify("follow", 1);
  1539. configModify("followTarget", $players{$playersID[$arg1]}{name});
  1540. }
  1541. } else {
  1542. AI::clear("follow");
  1543. main::ai_follow($arg1);
  1544. configModify("follow", 1);
  1545. configModify("followTarget", $arg1);
  1546. }
  1547. }
  1548. sub cmdFriend {
  1549. my (undef, $args) = @_;
  1550. my ($arg1, $arg2) = split(' ', $args, 2);
  1551. if ($arg1 eq "") {
  1552. message T("------------- Friends --------------n" .
  1553. "#   Name                      Onlinen"), "list";
  1554. for (my $i = 0; $i < @friendsID; $i++) {
  1555. message(swrite(
  1556. "@<  @<<<<<<<<<<<<<<<<<<<<<<<  @",
  1557. [$i + 1, $friends{$i}{'name'}, $friends{$i}{'online'}? 'X':'']),
  1558. "list");
  1559. }
  1560. message("----------------------------------n", "list");
  1561. } elsif (!$net || $net->getState() != Network::IN_GAME) {
  1562. error TF("You must be logged in the game to use this command (%s)n", 'friend ' . $arg1);
  1563. return;
  1564. } elsif ($arg1 eq "request") {
  1565. my $player = Match::player($arg2);
  1566. if (!$player) {
  1567. error TF("Player %s does not existn", $arg2);
  1568. } elsif (!defined $player->{name}) {
  1569. error T("Player name has not been received, please try againn");
  1570. } else {
  1571. my $alreadyFriend = 0;
  1572. for (my $i = 0; $i < @friendsID; $i++) {
  1573. if ($friends{$i}{'name'} eq $player->{name}) {
  1574. $alreadyFriend = 1;
  1575. last;
  1576. }
  1577. }
  1578. if ($alreadyFriend) {
  1579. error TF("%s is already your friendn", $player->{name});
  1580. } else {
  1581. message TF("Requesting %s to be your friendn", $player->{name});
  1582. $messageSender->sendFriendRequest($players{$playersID[$arg2]}{name});
  1583. }
  1584. }
  1585. } elsif ($arg1 eq "remove") {
  1586. if ($arg2 < 1 || $arg2 > @friendsID) {
  1587. error TF("Friend #%s does not existn", $arg2);
  1588. } else {
  1589. $arg2--;
  1590. message TF("Attempting to remove %s from your friend listn", $friends{$arg2}{'name'});
  1591. $messageSender->sendFriendRemove($friends{$arg2}{'accountID'}, $friends{$arg2}{'charID'});
  1592. }
  1593. } elsif ($arg1 eq "accept") {
  1594. if ($incomingFriend{'accountID'} eq "") {
  1595. error T("Can't accept the friend request, no incoming requestn");
  1596. } else {
  1597. message TF("Accepting the friend request from %sn", $incomingFriend{'name'});
  1598. $messageSender->sendFriendAccept($incomingFriend{'accountID'}, $incomingFriend{'charID'});
  1599. undef %incomingFriend;
  1600. }
  1601. } elsif ($arg1 eq "reject") {
  1602. if ($incomingFriend{'accountID'} eq "") {
  1603. error T("Can't reject the friend request - no incoming requestn");
  1604. } else {
  1605. message TF("Rejecting the friend request from %sn", $incomingFriend{'name'});
  1606. $messageSender->sendFriendReject($incomingFriend{'accountID'}, $incomingFriend{'charID'});
  1607. undef %incomingFriend;
  1608. }
  1609. } elsif ($arg1 eq "pm") {
  1610. if ($arg2 < 1 || $arg2 > @friendsID) {
  1611. error TF("Friend #%s does not existn", $arg2);
  1612. } else {
  1613. $arg2--;
  1614. if (binFind(@privMsgUsers, $friends{$arg2}{'name'}) eq "") {
  1615. message TF("Friend %s has been added to the PM list as %sn", $friends{$arg2}{'name'}, @privMsgUsers);
  1616. $privMsgUsers[@privMsgUsers] = $friends{$arg2}{'name'};
  1617. } else {
  1618. message TF("Friend %s is already in the PM listn", $friends{$arg2}{'name'});
  1619. }
  1620. }
  1621. } else {
  1622. error T("Syntax Error in function 'friend' (Manage Friends List)n" .
  1623. "Usage: friend [request|remove|accept|reject|pm]n");
  1624. }
  1625. }
  1626. sub cmdSlave {
  1627. my ($cmd, $subcmd) = @_;
  1628. my @args = parseArgs($subcmd);
  1629. if (!$char) {
  1630. error T("Error: Can't detect slaves - character is not yet readyn");
  1631. return;
  1632. }
  1633. my $slave;
  1634. if ($cmd eq 'homun') {
  1635. $slave = $char->{homunculus};
  1636. } elsif ($cmd eq 'merc') {
  1637. $slave = $char->{mercenary};
  1638. } else {
  1639. error T("Error: Unknown command in cmdSlaven");
  1640. }
  1641. if (
  1642. !$slave || !$slave->{appear_time} || (
  1643. $slave->{actorType} eq 'Homunculus' and $slave->{state} & 2 || $slave->{state} & 4
  1644. )
  1645. ) {
  1646. error T("Error: No slave detected.n");
  1647. } elsif ($subcmd eq "s" || $subcmd eq "status") {
  1648. my $hp_string = $slave->{'hp'}. '/' .$slave->{'hp_max'} . ' (' . sprintf("%.2f",$slave->{'hpPercent'}) . '%)';
  1649. my $sp_string = $slave->{'sp'}."/".$slave->{'sp_max'}." (".sprintf("%.2f",$slave->{'spPercent'})."%)";
  1650. my $exp_string = (
  1651. defined $slave->{'exp'}
  1652. ? formatNumber($slave->{'exp'})."/".formatNumber($slave->{'exp_max'})." (".sprintf("%.2f",$slave->{'expPercent'})."%)"
  1653. : (
  1654. defined $slave->{kills}
  1655. ? formatNumber($slave->{kills})
  1656. : ''
  1657. )
  1658. );
  1659. my ($intimacy_label, $intimacy_string) = (
  1660. defined $slave->{intimacy}
  1661. ? ('Intimacy:', $slave->{intimacy})
  1662. : (
  1663. defined $slave->{faith}
  1664. ? ('Faith:', $slave->{faith})
  1665. : ('', '')
  1666. )
  1667. );
  1668. my $hunger_string = defined $slave->{hunger} ? $slave->{hunger} : 'N/A';
  1669. my $accessory_string = defined $slave->{accessory} ? $slave->{accessory} : 'N/A';
  1670. my $faith_string = defined $slave->{faith} ? $slave->{faith} : 'N/A';
  1671. my $summons_string = defined $slave->{summons} ? $slave->{summons} : 'N/A';
  1672. my $msg = swrite(
  1673. T("-------------------- Slave Status ----------------------n" .
  1674. "Name: @<<<<<<<<<<<<<<<<<<<<<<<<< HP: @>>>>>>>>>>>>>>>>>>n" .
  1675. "Type: @<<<<<<<<<<<<<<<<<<<<<<<<< SP: @>>>>>>>>>>>>>>>>>>n" .
  1676. "Level: @<<   @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>n" .
  1677. "--------------------------------------------------------n" .
  1678. "Atk: @>>>    Matk:     @>>>    Hunger:    @>>>n" .
  1679. "Hit: @>>>    Critical: @>>>    @<<<<<<<<< @>>>n" .
  1680. "Def: @>>>    Mdef:     @>>>    Accessory: @>>>n" .
  1681. "Flee:@>>>    Aspd:     @>>>    Summons:   @>>>n"),
  1682. [$slave->{'name'}, $hp_string,
  1683. $slave->{actorType}, $sp_string,
  1684. $slave->{'level'}, $exp_string, $slave->{'atk'}, $slave->{'matk'}, $hunger_string,
  1685. $slave->{'hit'}, $slave->{'critical'}, $intimacy_label, $intimacy_string,
  1686. $slave->{'def'}, $slave->{'mdef'}, $accessory_string,
  1687. $slave->{'flee'}, $slave->{'aspdDisp'}, $summons_string]);
  1688. #############################################################
  1689. #Statuses
  1690. #############################################################
  1691. my $statuses = 'none';
  1692. if (defined $slave->{statuses} && %{$slave->{statuses}}) {
  1693. $statuses = join(", ", keys %{$slave->{statuses}});
  1694. }
  1695. $msg .= TF("Statuses: %s n", $statuses);
  1696. $msg .= "-------------------------------------------------n";
  1697. message $msg, "info";
  1698. } elsif ($subcmd eq "feed") {
  1699. unless (defined $slave->{hunger}) {
  1700. error T("This slave can not be feededn");
  1701. return;
  1702. }
  1703. if (!$net || $net->getState() != Network::IN_GAME) {
  1704. error TF("You must be logged in the game to use this command (%s)n", $cmd . ' ' . $subcmd);
  1705. return;
  1706. }
  1707. if ($slave->{hunger} >= 76) {
  1708. message T("Your homunculus is not yet hungry. Feeding it now will lower intimacy.n"), "homunculus";
  1709. } else {
  1710. $messageSender->sendHomunculusFeed();
  1711. message T("Feeding your homunculus.n"), "homunculus";
  1712. }
  1713. } elsif ($subcmd eq "fire") {
  1714. unless ($slave->{actorType} eq 'Mercenary') {
  1715. error T("This slave can not be firedn");
  1716. return;
  1717. }
  1718. if (!$net || $net->getState() != Network::IN_GAME) {
  1719. error TF("You must be logged in the game to use this command (%s)n", $cmd . ' ' . $subcmd);
  1720. return;
  1721. }
  1722. $messageSender->sendMercenaryCommand (2);
  1723. } elsif ($args[0] eq "move") {
  1724. if (!$net || $net->getState() != Network::IN_GAME) {
  1725. error TF("You must be logged in the game to use this command (%s)n", $cmd . ' ' . $subcmd);
  1726. return;
  1727. }
  1728. if (!($args[1] =~ /^d+$/) || !($args[2] =~ /^d+$/)) {
  1729. error TF("Error in function '%s move' (Slave Move)n" .
  1730. "Invalid coordinates (%s, %s) specified.n", $cmd, $args[1], $args[2]);
  1731. return;
  1732. } else {
  1733. # max distance that homunculus can follow: 17
  1734. $messageSender->sendHomunculusMove($slave->{ID}, $args[1], $args[2]);
  1735. }
  1736. } elsif ($subcmd eq "standby") {
  1737. if (!$net || $net->getState() != Network::IN_GAME) {
  1738. error TF("You must be logged in the game to use this command (%s)n", $cmd . ' ' . $subcmd);
  1739. return;
  1740. }
  1741. $messageSender->sendHomunculusStandBy($slave->{ID});
  1742. } elsif ($args[0] eq 'ai') {
  1743. if ($args[1] eq 'clear') {
  1744. $slave->clear();
  1745. message T("Slave AI sequences clearedn"), "success";
  1746. } elsif ($args[1] eq 'print') {
  1747. # Display detailed info about current AI sequence
  1748. message T("--------- Slave AI Sequence ------------n"), "list";
  1749. my $index = 0;
  1750. foreach (@{$slave->{slave_ai_seq}}) {
  1751. message("$index: $_ " . dumpHash(%{$slave->{slave_ai_seq_args}[$index]}) . "nn", "list");
  1752. $index++;
  1753. }
  1754. message T("--------- Slave AI Sequence ------------n"), "list";
  1755. } elsif ($args[1] eq 'on' || $args[1] eq 'auto') {
  1756. # Set AI to auto mode
  1757. if ($slave->{slave_AI} == 2) {
  1758. message T("Slave AI is already set to auto moden"), "success";
  1759. } else {
  1760. $slave->{slave_AI} = 2;
  1761. undef $slave->{slave_AI_forcedOff};
  1762. message T("Slave AI set to auto moden"), "success";
  1763. }
  1764. } elsif ($args[1] eq 'manual') {
  1765. # Set AI to manual mode
  1766. if ($slave->{slave_AI} == 1) {
  1767. message T("Slave AI is already set to manual moden"), "success";
  1768. } else {
  1769. $slave->{slave_AI} = 1;
  1770. $slave->{slave_AI_forcedOff} = 1;
  1771. message T("Slave AI set to manual moden"), "success";
  1772. }
  1773. } elsif ($args[1] eq 'off') {
  1774. # Turn AI off
  1775. if ($slave->{slave_AI}) {
  1776. undef $slave->{slave_AI};
  1777. $slave->{slave_AI_forcedOff} = 1;
  1778. message T("Slave AI turned offn"), "success";
  1779. } else {
  1780. message T("Slave AI is already offn"), "success";
  1781. }
  1782. } elsif ($args[1] eq '') {
  1783. # Toggle AI
  1784. if ($slave->{slave_AI} == 2) {
  1785. undef $slave->{slave_AI};
  1786. $slave->{slave_AI_forcedOff} = 1;
  1787. message T("Slave AI turned offn"), "success";
  1788. } elsif (!$slave->{slave_AI}) {
  1789. $slave->{slave_AI} = 1;
  1790. $slave->{slave_AI_forcedOff} = 1;
  1791. message T("Slave AI set to manual moden"), "success";
  1792. } elsif ($slave->{slave_AI} == 1) {
  1793. $slave->{slave_AI} = 2;
  1794. undef $slave->{slave_AI_forcedOff};
  1795. message T("Slave AI set to auto moden"), "success";
  1796. }
  1797. } else {
  1798. error T("Syntax Error in function 'slave ai' (Slave AI Commands)n" .
  1799. "Usage: homun ai [ clear | print | auto | manual | off ]n");
  1800. }
  1801. } elsif ($subcmd eq "aiv") {
  1802. if (!$slave->{slave_AI}) {
  1803. message TF("ai_seq (off) = %sn", "@{$slave->{slave_ai_seq}}"), "list";
  1804. } elsif ($slave->{slave_AI} == 1) {
  1805. message TF("ai_seq (manual) = %sn", "@{$slave->{slave_ai_seq}}"), "list";
  1806. } elsif ($slave->{slave_AI} == 2) {
  1807. message TF("ai_seq (auto) = %sn", "@{$slave->{slave_ai_seq}}"), "list";
  1808. }
  1809. message T("solutionn"), "list" if ($slave->args()->{'solution'});
  1810. } elsif ($args[0] eq "skills") {
  1811. if ($args[1] eq '') {
  1812. my $msg = T("--------Slave Skill List-------n" .
  1813. "   # Skill Name                     Lv      SPn");
  1814. foreach my $handle (@{$slave->{slave_skillsID}}) {
  1815. my $skill = new Skill(handle => $handle);
  1816. my $sp = $char->{skills}{$handle}{sp} || '';
  1817. $msg .= swrite(
  1818. "@>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>    @>>>",
  1819. [$skill->getIDN(), $skill->getName(), $char->getSkillLevel($skill), $sp]);
  1820. }
  1821. $msg .= TF("nSkill Points: %dn", $slave->{points_skill}) if defined $slave->{points_skill};
  1822. $msg .= "-------------------------------n";
  1823. message($msg, "list");
  1824. } elsif ($args[1] eq "add" && $args[2] =~ /d+/) {
  1825. if (!$net || $net->getState() != Network::IN_GAME) {
  1826. error TF("You must be logged in the game to use this command (%s)n", $cmd . ' ' . $subcmd);
  1827. return;
  1828. }
  1829. my $skill = new Skill(idn => $args[2]);
  1830. if (!$skill->getIDN() || !$char->{skills}{$skill->getHandle()}) {
  1831. error TF("Error in function '%s skills add' (Add Skill Point)n" .
  1832. "Skill %s does not exist.n", $cmd, $args[2]);
  1833. } elsif ($slave->{points_skill} < 1) {
  1834. error TF("Error in function '%s skills add' (Add Skill Point)n" .
  1835. "Not enough skill points to increase %sn", $cmd, $skill->getName());
  1836. } else {
  1837. $messageSender->sendAddSkillPoint($skill->getIDN());
  1838. }
  1839. } elsif ($args[1] eq "desc" && $args[2] =~ /d+/) {
  1840. my $skill = new Skill(idn => $args[2]);
  1841. if (!$skill->getIDN()) {
  1842. error TF("Error in function '%s skills desc' (Skill Description)n" .
  1843. "Skill %s does not exist.n", $cmd, $args[2]);
  1844. } else {
  1845. my $description = $skillsDesc_lut{$skill->getHandle()} || T("Error: No description available.n");
  1846. message TF("===============Skill Description===============n" .
  1847. "Skill: %snn", $skill->getName()), "info";
  1848. message $description, "info";
  1849. message "==============================================n", "info";
  1850. }
  1851. } else {
  1852. error T("Syntax Error in function 'slave skills' (Slave Skills Functions)n" .
  1853. "Usage: homun skills [(<add | desc>) [<skill #>]]n");
  1854. }
  1855.   } else {
  1856. error T("Usage: slave < feed | s | status | move | standby | ai | aiv | skills>n");
  1857. }
  1858. }
  1859. sub cmdGetPlayerInfo {
  1860. if (!$net || $net->getState() != Network::IN_GAME) {
  1861. error TF("You must be logged in the game to use this command (%s)n", shift);
  1862. return;
  1863. }
  1864. my (undef, $args) = @_;
  1865. $messageSender->sendGetPlayerInfo(pack("V", $args));
  1866. }
  1867. sub cmdGmb {
  1868. if (!$net || $net->getState() != Network::IN_GAME) {
  1869. error TF("You must be logged in the game to use this command (%s)n", shift);
  1870. return;
  1871. }
  1872. my (undef, $args) = @_;
  1873. return unless ($char);
  1874. if ($args eq '') {
  1875. error "Usage: gmb <MESSAGE>n";
  1876. return;
  1877. }
  1878. my $msg = "$char->{name}: $args" . chr(0);
  1879. my $packet = pack("C*", 0x99, 0x00) . pack("v", length($msg) + 4) . stringToBytes($msg);
  1880. $messageSender->sendToServer($packet);
  1881. }
  1882. sub cmdGmbb {
  1883. if (!$net || $net->getState() != Network::IN_GAME) {
  1884. error TF("You must be logged in the game to use this command (%s)n", shift);
  1885. return;
  1886. }
  1887. my (undef, $args) = @_;
  1888. return unless ($char);
  1889. if ($args eq '') {
  1890. error "Usage: gmbb <MESSAGE>n";
  1891. return;
  1892. }
  1893. my $msg = "blue$args" . chr(0);
  1894. my $packet = pack("C*", 0x99, 0x00) . pack("v", length($msg) + 4) . stringToBytes($msg);
  1895. $messageSender->sendToServer($packet);
  1896. }
  1897. sub cmdGmnb {
  1898. if (!$net || $net->getState() != Network::IN_GAME) {
  1899. error TF("You must be logged in the game to use this command (%s)n", shift);
  1900. return;
  1901. }
  1902. my (undef, $args) = @_;
  1903. return unless ($char);
  1904. if ($args eq '') {
  1905. error "Usage: gmnb <MESSAGE>n";
  1906. return;
  1907. }
  1908. my $msg = $args . chr(0);
  1909. my $packet = pack("C*", 0x99, 0x00) . pack("v", length($msg) + 4) . stringToBytes($msg);
  1910. $messageSender->sendToServer($packet);
  1911. }
  1912. sub cmdGmlb {
  1913. if (!$net || $net->getState() != Network::IN_GAME) {
  1914. error TF("You must be logged in the game to use this command (%s)n", shift);
  1915. return;
  1916. }
  1917. my (undef, $args) = @_;
  1918. return unless ($char);
  1919. if ($args eq '') {
  1920. error "Usage: gmlb <MESSAGE>n";
  1921. return;
  1922. }
  1923. my $msg = "$char->{name}: $args" . chr(0);
  1924. my $packet = pack("C*", 0x9c, 0x01) . pack("v", length($msg) + 4) . stringToBytes($msg);
  1925. $messageSender->sendToServer($packet);
  1926. }
  1927. sub cmdGmlbb {
  1928. if (!$net || $net->getState() != Network::IN_GAME) {
  1929. error TF("You must be logged in the game to use this command (%s)n", shift);
  1930. return;
  1931. }
  1932. my (undef, $args) = @_;
  1933. return unless ($char);
  1934. if ($args eq '') {
  1935. error "Usage: gmlbb <MESSAGE>n";
  1936. return;
  1937. }
  1938. my $msg = "blue$args" . chr(0);
  1939. my $packet = pack("C*", 0x9c, 0x01) . pack("v", length($msg) + 4) . stringToBytes($msg);
  1940. $messageSender->sendToServer($packet);
  1941. }
  1942. sub cmdGmnlb {
  1943. if (!$net || $net->getState() != Network::IN_GAME) {
  1944. error TF("You must be logged in the game to use this command (%s)n", shift);
  1945. return;
  1946. }
  1947. my (undef, $args) = @_;
  1948. return unless ($char);
  1949. if ($args eq '') {
  1950. error "Usage: gmnlb <MESSAGE>n";
  1951. return;
  1952. }
  1953. my $msg = $args . chr(0);
  1954. my $packet = pack("C*", 0x9c, 0x01) . pack("v", length($msg) + 4) . stringToBytes($msg);
  1955. $messageSender->sendToServer($packet);
  1956. }
  1957. sub cmdGmmapmove {
  1958. if (!$net || $net->getState() != Network::IN_GAME) {
  1959. error TF("You must be logged in the game to use this command (%s)n", shift);
  1960. return;
  1961. }
  1962. my (undef, $args) = @_;
  1963. my ($map_name) = $args =~ /(S+)/;
  1964. # this will pack as 0 if it fails to match
  1965. my ($x, $y) = $args =~ /w+ (d+) (d+)/;
  1966. if ($map_name eq '') {
  1967. error "Usage: gmmapmove <FIELD>n";
  1968. error "FIELD is a field name including .gat extension, like: gef_fild01.gatn";
  1969. return;
  1970. }
  1971. my $packet = pack("C*", 0x40, 0x01) . pack("a16", $map_name) . pack("v1 v1", $x, $y);
  1972. $messageSender->sendToServer($packet);
  1973. }
  1974. sub cmdGmsummon {
  1975. if (!$net || $net->getState() != Network::IN_GAME) {
  1976. error TF("You must be logged in the game to use this command (%s)n", shift);
  1977. return;
  1978. }
  1979. my (undef, $args) = @_;
  1980. if ($args eq '') {
  1981. error "Usage: gmsummon <player name>n" .
  1982. "Summon a player.n";
  1983. } else {
  1984. $messageSender->sendGmSummon($args);
  1985. }
  1986. }
  1987. sub cmdGmdc {
  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. if ($args !~ /^d+$/) {
  1994. error "Usage: gmdc <player_AID>n";
  1995. return;
  1996. }
  1997. my $packet = pack("C*", 0xCC, 0x00).pack("V1", $args);
  1998. $messageSender->sendToServer($packet);
  1999. }
  2000. sub cmdGmkillall {
  2001. if (!$net || $net->getState() != Network::IN_GAME) {
  2002. error TF("You must be logged in the game to use this command (%s)n", shift);
  2003. return;
  2004. }
  2005. my $packet = pack("C*", 0xCE, 0x00);
  2006. $messageSender->sendToServer($packet);
  2007. }
  2008. sub cmdGmcreate {
  2009. if (!$net || $net->getState() != Network::IN_GAME) {
  2010. error TF("You must be logged in the game to use this command (%s)n", shift);
  2011. return;
  2012. }
  2013. my (undef, $args) = @_;
  2014. if ($args eq '') {
  2015. error "Usage: gmcreate (<MONSTER_NAME> || <Item_Name>) n";
  2016. return;
  2017. }
  2018. my $packet = pack("C*", 0x3F, 0x01).pack("a24", $args);
  2019. $messageSender->sendToServer($packet);
  2020. }
  2021. sub cmdGmhide {
  2022. if (!$net || $net->getState() != Network::IN_GAME) {
  2023. error TF("You must be logged in the game to use this command (%s)n", shift);
  2024. return;
  2025. }
  2026. my $packet = pack("C*", 0x9D, 0x01, 0x40, 0x00, 0x00, 0x00);
  2027. $messageSender->sendToServer($packet);
  2028. }
  2029. sub cmdGmresetstate {
  2030. if (!$net || $net->getState() != Network::IN_GAME) {
  2031. error TF("You must be logged in the game to use this command (%s)n", shift);
  2032. return;
  2033. }
  2034. my $packet = pack("C1 C1 v1", 0x97, 0x01, 0);
  2035. $messageSender->sendToServer($packet);
  2036. }
  2037. sub cmdGmresetskill {
  2038. if (!$net || $net->getState() != Network::IN_GAME) {
  2039. error TF("You must be logged in the game to use this command (%s)n", shift);
  2040. return;
  2041. }
  2042. my $packet = pack("C1 C1 v1", 0x97, 0x01, 1);
  2043. $messageSender->sendToServer($packet);
  2044. }
  2045. sub cmdGmmute {
  2046. if (!$net || $net->getState() != Network::IN_GAME) {
  2047. error TF("You must be logged in the game to use this command (%s)n", shift);
  2048. return;
  2049. }
  2050. my (undef, $args) = @_;
  2051. my ($ID, $time) = $args =~ /^(d+) (d+)/;
  2052. if (!$ID) {
  2053. error "Usage: gmmute <ID> <minutes>n";
  2054. return;
  2055. }
  2056. my $packet = pack("C1 C1 V1 C1 v1", 0x49, 0x01, $ID, 1, $time);
  2057. $messageSender->sendToServer($packet);
  2058. }
  2059. sub cmdGmunmute {
  2060. if (!$net || $net->getState() != Network::IN_GAME) {
  2061. error TF("You must be logged in the game to use this command (%s)n", shift);
  2062. return;
  2063. }
  2064. my (undef, $args) = @_;
  2065. my ($ID, $time) = $args =~ /^(d+) (d+)/;
  2066. if (!$ID) {
  2067. error "Usage: gmunmute <ID> <minutes>n";
  2068. return;
  2069. }
  2070. my $packet = pack("C1 C1 V1 C1 v1", 0x49, 0x01, $ID, 0, $time);
  2071. $messageSender->sendToServer($packet);
  2072. }
  2073. sub cmdGmwarpto {
  2074. if (!$net || $net->getState() != Network::IN_GAME) {
  2075. error TF("You must be logged in the game to use this command (%s)n", shift);
  2076. return;
  2077. }
  2078. my (undef, $args) = @_;
  2079. if ($args eq '') {
  2080. error "Usage: gmwarpto <Player Name>n";
  2081. return;
  2082. }
  2083. my $packet = pack("C*", 0xBB, 0x01).pack("a24", $args);
  2084. $messageSender->sendToServer($packet);
  2085. }
  2086. sub cmdGmrecall {
  2087. if (!$net || $net->getState() != Network::IN_GAME) {
  2088. error TF("You must be logged in the game to use this command (%s)n", shift);
  2089. return;
  2090. }
  2091. my (undef, $args) = @_;
  2092. if ($args eq '') {
  2093. error "Usage: gmrecall [<Character Name> | <User Name>]n";
  2094. return;
  2095. }
  2096. my $packet = pack("C*", 0xBC, 0x01).pack("a24", $args);
  2097. $messageSender->sendToServer($packet);
  2098. }
  2099. sub cmdGmremove {
  2100. if (!$net || $net->getState() != Network::IN_GAME) {
  2101. error TF("You must be logged in the game to use this command (%s)n", shift);
  2102. return;
  2103. }
  2104. my (undef, $args) = @_;
  2105. if ($args eq '') {
  2106. error "Usage: gmremove [<Character Name> | <User Name>]n";
  2107. return;
  2108. }
  2109. my $packet = pack("C*", 0xBA, 0x01).pack("a24", $args);
  2110. $messageSender->sendToServer($packet);
  2111. }
  2112. sub cmdGuild {
  2113. my (undef, $args) = @_;
  2114. my ($arg1, $arg2) = split(' ', $args, 2);
  2115. if ($arg1 eq "" || (!%guild && ($arg1 eq "info" || $arg1 eq "member" || $arg1 eq "kick"))) {
  2116. if (!$net || $net->getState() != Network::IN_GAME) {
  2117. if ($arg1 eq "") {
  2118. error T("You must be logged in the game to request guild informationn");
  2119. } else {
  2120. error TF("Guild information is not yet available. You must login to the game and use the '%s' command firstn", 'guild');
  2121. }
  2122. return;
  2123. }
  2124. message T("Requesting guild information...n"), "info";
  2125. $messageSender->sendGuildInfoRequest();
  2126. # Replies 01B6 (Guild Info) and 014C (Guild Ally/Enemy List)
  2127. $messageSender->sendGuildRequest(0);
  2128. # Replies 0166 (Guild Member Titles List) and 0154 (Guild Members List)
  2129. $messageSender->sendGuildRequest(1);
  2130. if ($arg1 eq "") {
  2131. message T("Enter command to view guild information: guild <info | member>n"), "info";
  2132. } else {
  2133. message TF("Type 'guild %s' again to view the information.n", $args), "info";
  2134. }
  2135. } elsif ($arg1 eq "info") {
  2136. message swrite(T("---------- Guild Information ----------n" .
  2137. "Name    : @<<<<<<<<<<<<<<<<<<<<<<<<n" .
  2138. "Lv      : @<<n" .
  2139. "Exp     : @>>>>>>>>>/@<<<<<<<<<<n" .
  2140. "Master  : @<<<<<<<<<<<<<<<<<<<<<<<<n" .
  2141. "Connect : @>>/@<<"),
  2142. [$guild{name}, $guild{lvl}, $guild{exp}, $guild{next_exp}, $guild{master}, 
  2143. $guild{conMember}, $guild{maxMember}]), "info";
  2144. for my $ally (keys %{$guild{ally}}) {
  2145. # Translation Comment: List of allies. Keep the same spaces of the - Guild Information - tag.
  2146. message TF("Ally    : %s (%s)n", $guild{ally}{$ally}, $ally), "info";
  2147. }
  2148. message("---------------------------------------n", "info");
  2149. } elsif ($arg1 eq "member") {
  2150. if (!$guild{member}) {
  2151. error T("No guild member information available.n");
  2152. return;
  2153. }
  2154. my $msg = T("------------ Guild  Member ------------n" .
  2155. "#  Name                       Job        Lv  Title                    Onlinen");
  2156. my ($i, $name, $job, $lvl, $title, $online, $ID, $charID);
  2157. my $count = @{$guild{member}};
  2158. for ($i = 0; $i < $count; $i++) {
  2159. $name  = $guild{member}[$i]{name};
  2160. next if (!defined $name);
  2161. $job   = $jobs_lut{$guild{member}[$i]{jobID}};
  2162. $lvl   = $guild{member}[$i]{lvl};
  2163. $title = $guild{member}[$i]{title};
  2164.   # Translation Comment: Guild member online
  2165. $online = $guild{member}[$i]{online} ? T("Yes") : T("No");
  2166. $ID = unpack("V",$guild{member}[$i]{ID});
  2167. $charID = unpack("V",$guild{member}[$i]{charID});
  2168. $msg .= swrite("@< @<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<< @>  @<<<<<<<<<<<<<<<<<<<<<<< @<<",
  2169. [$i, $name, $job, $lvl, $title, $online, $ID, $charID]);
  2170. }
  2171. $msg .= "---------------------------------------n";
  2172. message $msg, "list";
  2173. } elsif (!$net || $net->getState() != Network::IN_GAME) {
  2174. error TF("You must be logged in the game to use this command (%s)n", 'guild ' . $arg1);
  2175. return;
  2176. } elsif ($arg1 eq "join") {
  2177. if ($arg2 ne "1" && $arg2 ne "0") {
  2178. error T("Syntax Error in function 'guild join' (Accept/Deny Guild Join Request)n" .
  2179. "Usage: guild join <flag>n");
  2180. return;
  2181. } elsif ($incomingGuild{'ID'} eq "") {
  2182. error T("Error in function 'guild join' (Join/Request to Join Guild)n" .
  2183. "Can't accept/deny guild request - no incoming request.n");
  2184. return;
  2185. }
  2186. $messageSender->sendGuildJoin($incomingGuild{ID}, $arg2);
  2187. undef %incomingGuild;
  2188. if ($arg2) {
  2189. message T("You accepted the guild join request.n"), "success";
  2190. } else {
  2191. message T("You denied the guild join request.n"), "info";
  2192. }
  2193. } elsif ($arg1 eq "create") {
  2194. if (!$arg2) {
  2195. error T("Syntax Error in function 'guild create' (Create Guild)n" .
  2196. "Usage: guild create <name>n");
  2197. } else {
  2198. $messageSender->sendGuildCreate($arg2);
  2199. }
  2200. } elsif (!defined $char->{guild}) {
  2201. error T("You are not in a guild.n");
  2202. } elsif ($arg1 eq "request") {
  2203. my $player = Match::player($arg2);
  2204. if (!$player) {
  2205. error TF("Player %s does not exist.n", $arg2);
  2206. } else {
  2207. $messageSender->sendGuildJoinRequest($player->{ID});
  2208. message TF("Sent guild join request to %sn", $player->{name});
  2209. }
  2210. } elsif ($arg1 eq "ally") {
  2211. if (!$guild{master}) {
  2212. error T("No guild information available. Type guild to refresh and then try again.n");
  2213. return;
  2214. }
  2215. my $player = Match::player($arg2);
  2216. if (!$player) {
  2217. error TF("Player %s does not exist.n", $arg2);
  2218. } elsif (!$char->{name} eq $guild{master}) {
  2219. error T("You must be guildmaster to set an alliancen");
  2220. return;
  2221. } else {
  2222. $messageSender->sendGuildSetAlly($net,$player->{ID},$accountID,$charID);
  2223. message TF("Sent guild alliance request to %sn", $player->{name});
  2224. }
  2225. } elsif ($arg1 eq "leave") {
  2226. $messageSender->sendGuildLeave($arg2);
  2227. message TF("Sending guild leave: %sn", $arg2);
  2228. } elsif ($arg1 eq "break") {
  2229. if (!$arg2) {
  2230. error T("Syntax Error in function 'guild break' (Break Guild)n" .
  2231. "Usage: guild break <guild name>n");
  2232. } else {
  2233. $messageSender->sendGuildBreak($arg2);
  2234. message TF("Sending guild break: %sn", $arg2);
  2235. }
  2236. } elsif ($arg1 eq "kick") {
  2237. if (!$guild{member}) {
  2238. error T("No guild member information available.n");
  2239. return;
  2240. }
  2241. my @params = split(' ', $arg2, 2);
  2242. if ($params[0] =~ /^d+$/) {
  2243. if ($guild{'member'}[$params[0]]) {
  2244. $messageSender->sendGuildMemberKick($char->{guildID},
  2245. $guild{member}[$params[0]]{ID},
  2246. $guild{member}[$params[0]]{charID},
  2247. $params[1]);
  2248. } else {
  2249. error TF("Error in function 'guild kick' (Kick Guild Member)n" .
  2250. "Invalid guild member '%s' specified.n", $params[0]);
  2251. }
  2252. } else {
  2253. error T("Syntax Error in function 'guild kick' (Kick Guild Member)n" .
  2254. "Usage: guild kick <number> <reason>n");
  2255. }
  2256. }
  2257. }
  2258. sub cmdGuildChat {
  2259. if (!$net || $net->getState() != Network::IN_GAME) {
  2260. error TF("You must be logged in the game to use this command (%s)n", shift);
  2261. return;
  2262. }
  2263. my (undef, $arg1) = @_;
  2264. if ($arg1 eq "") {
  2265. error T("Syntax Error in function 'g' (Guild Chat)n" .
  2266. "Usage: g <message>n");
  2267. } else {
  2268. sendMessage($messageSender, "g", $arg1);
  2269. }
  2270. }
  2271. sub cmdHelp {
  2272. # Display help message
  2273. my (undef, $args) = @_;
  2274. my @commands_req = split(/ +/, $args);
  2275. my @unknown;
  2276. my @found;
  2277. my @commands = (@commands_req)? @commands_req : (sort keys %descriptions);
  2278. my ($message,$cmd);
  2279. $message .= T("--------------- Available commands ---------------n") unless @commands_req;
  2280. foreach my $switch (@commands) {
  2281. if ($descriptions{$switch}) {
  2282. if (ref($descriptions{$switch}) eq 'ARRAY') {
  2283. if (@commands_req) {
  2284. helpIndent($switch,$descriptions{$switch});
  2285. } else {
  2286. $message .= sprintf("%-11s  %sn",$switch, $descriptions{$switch}->[0]);
  2287. }
  2288. }
  2289. push @found, $switch;
  2290. } else {
  2291. push @unknown, $switch;
  2292. }
  2293. }
  2294. @commands = (@commands_req)? @commands_req : (sort keys %customCommands);
  2295. foreach my $switch (@commands) {
  2296. if ($customCommands{$switch}) {
  2297. if (ref($customCommands{$switch}{desc}) eq 'ARRAY') {
  2298. if (@commands_req) {
  2299. helpIndent($switch,$customCommands{$switch}{desc});
  2300. } else {
  2301. $message .= sprintf("%-11s  %sn",$switch, $customCommands{$switch}{desc}->[0]);
  2302. }
  2303. }
  2304. push @found, $switch;
  2305. } else {
  2306. push @unknown, $switch unless defined binFind(@unknown,$switch);
  2307. }
  2308. }
  2309. foreach (@found) {
  2310. binRemoveAndShift(@unknown,$_);
  2311. }
  2312. if (@unknown) {
  2313. if (@unknown == 1) {
  2314. error TF("The command "%s" doesn't exist.n", $unknown[0]);
  2315. } else {
  2316. error TF("These commands don't exist: %sn", join(', ', @unknown));
  2317. }
  2318. error T("Type 'help' to see a list of all available commands.n");
  2319. }
  2320. $message .= "--------------------------------------------------n"unless @commands_req;
  2321. message $message, "list" unless @commands_req;
  2322. }
  2323. sub helpIndent {
  2324. my $cmd = shift;
  2325. my $desc = shift;
  2326. my @tmp = @{$desc};
  2327. my $message;
  2328. my $messageTmp;
  2329. my @words;
  2330. my $length = 0;
  2331. $message = TF("------------ Help for '%s' ------------n", $cmd);