PageRenderTime 94ms CodeModel.GetById 28ms RepoModel.GetById 5ms app.codeStats 2ms

/src/map/atcommand.c

https://gitlab.com/evol/hercules
C | 10340 lines | 8018 code | 1401 blank | 921 comment | 2647 complexity | 60a1d92ffe0296710d30b4bd5c365bc9 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /**
  2. * This file is part of Hercules.
  3. * http://herc.ws - http://github.com/HerculesWS/Hercules
  4. *
  5. * Copyright (C) 2012-2016 Hercules Dev Team
  6. * Copyright (C) Athena Dev Teams
  7. *
  8. * Hercules is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #define HERCULES_CORE
  22. #include "config/core.h" // AUTOLOOTITEM_SIZE, AUTOTRADE_PERSISTENCY, MAX_SUGGESTIONS, MOB_FLEE(), MOB_HIT(), RENEWAL, RENEWAL_DROP, RENEWAL_EXP
  23. #include "atcommand.h"
  24. #include "map/HPMmap.h"
  25. #include "map/battle.h"
  26. #include "map/channel.h"
  27. #include "map/chat.h"
  28. #include "map/chrif.h"
  29. #include "map/clif.h"
  30. #include "map/duel.h"
  31. #include "map/elemental.h"
  32. #include "map/guild.h"
  33. #include "map/homunculus.h"
  34. #include "map/intif.h"
  35. #include "map/itemdb.h"
  36. #include "map/log.h"
  37. #include "map/mail.h"
  38. #include "map/map.h"
  39. #include "map/mapreg.h"
  40. #include "map/mercenary.h"
  41. #include "map/mob.h"
  42. #include "map/npc.h"
  43. #include "map/party.h"
  44. #include "map/pc.h"
  45. #include "map/pc_groups.h" // groupid2name
  46. #include "map/pet.h"
  47. #include "map/quest.h"
  48. #include "map/script.h"
  49. #include "map/searchstore.h"
  50. #include "map/skill.h"
  51. #include "map/status.h"
  52. #include "map/storage.h"
  53. #include "map/trade.h"
  54. #include "map/unit.h"
  55. #include "common/cbasetypes.h"
  56. #include "common/conf.h"
  57. #include "common/core.h"
  58. #include "common/memmgr.h"
  59. #include "common/mmo.h" // MAX_CARTS
  60. #include "common/nullpo.h"
  61. #include "common/random.h"
  62. #include "common/showmsg.h"
  63. #include "common/socket.h"
  64. #include "common/strlib.h"
  65. #include "common/sysinfo.h"
  66. #include "common/timer.h"
  67. #include "common/utils.h"
  68. #include <math.h>
  69. #include <stdio.h>
  70. #include <stdlib.h>
  71. #include <string.h>
  72. struct atcommand_interface atcommand_s;
  73. struct atcommand_interface *atcommand;
  74. static char atcmd_output[CHAT_SIZE_MAX];
  75. static char atcmd_player_name[NAME_LENGTH];
  76. // @commands (script-based)
  77. struct atcmd_binding_data* get_atcommandbind_byname(const char* name) {
  78. int i = 0;
  79. nullpo_retr(NULL, name);
  80. if( *name == atcommand->at_symbol || *name == atcommand->char_symbol )
  81. name++; // for backwards compatibility
  82. ARR_FIND( 0, atcommand->binding_count, i, strcmpi(atcommand->binding[i]->command, name) == 0 );
  83. return ( i < atcommand->binding_count ) ? atcommand->binding[i] : NULL;
  84. }
  85. const char* atcommand_msgsd(struct map_session_data *sd, int msg_number) {
  86. Assert_retr("??", msg_number >= 0 && msg_number < MAX_MSG && atcommand->msg_table[0][msg_number] != NULL);
  87. if (!sd || sd->lang_id >= atcommand->max_message_table || !atcommand->msg_table[sd->lang_id][msg_number])
  88. return atcommand->msg_table[0][msg_number];
  89. return atcommand->msg_table[sd->lang_id][msg_number];
  90. }
  91. const char* atcommand_msgfd(int fd, int msg_number) {
  92. struct map_session_data *sd = sockt->session_is_valid(fd) ? sockt->session[fd]->session_data : NULL;
  93. Assert_retr("??", msg_number >= 0 && msg_number < MAX_MSG && atcommand->msg_table[0][msg_number] != NULL);
  94. if (!sd || sd->lang_id >= atcommand->max_message_table || !atcommand->msg_table[sd->lang_id][msg_number])
  95. return atcommand->msg_table[0][msg_number];
  96. return atcommand->msg_table[sd->lang_id][msg_number];
  97. }
  98. //-----------------------------------------------------------
  99. // Return the message string of the specified number by [Yor]
  100. //-----------------------------------------------------------
  101. const char* atcommand_msg(int msg_number) {
  102. Assert_retr("??", msg_number >= 0 && msg_number < MAX_MSG);
  103. if (atcommand->msg_table[map->default_lang_id][msg_number] != NULL && atcommand->msg_table[map->default_lang_id][msg_number][0] != '\0')
  104. return atcommand->msg_table[map->default_lang_id][msg_number];
  105. if(atcommand->msg_table[0][msg_number] != NULL && atcommand->msg_table[0][msg_number][0] != '\0')
  106. return atcommand->msg_table[0][msg_number];
  107. return "??";
  108. }
  109. /**
  110. * Reads Message Data
  111. *
  112. * @param[in] cfg_name configuration filename to read.
  113. * @param[in] allow_override whether to allow duplicate message IDs to override the original value.
  114. * @return success state.
  115. */
  116. bool msg_config_read(const char *cfg_name, bool allow_override) {
  117. int msg_number;
  118. char line[1024], w1[1024], w2[1024];
  119. FILE *fp;
  120. static int called = 1;
  121. nullpo_retr(false, cfg_name);
  122. if ((fp = fopen(cfg_name, "r")) == NULL) {
  123. ShowError("Messages file not found: %s\n", cfg_name);
  124. return false;
  125. }
  126. if( !atcommand->max_message_table )
  127. atcommand->expand_message_table();
  128. while(fgets(line, sizeof(line), fp)) {
  129. if (line[0] == '/' && line[1] == '/')
  130. continue;
  131. if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) != 2)
  132. continue;
  133. if (strcmpi(w1, "import") == 0) {
  134. atcommand->msg_read(w2, true);
  135. } else {
  136. msg_number = atoi(w1);
  137. if (msg_number >= 0 && msg_number < MAX_MSG) {
  138. if (atcommand->msg_table[0][msg_number] != NULL) {
  139. if (!allow_override) {
  140. ShowError("Duplicate message: ID '%d' was already used for '%s'. Message '%s' will be ignored.\n",
  141. msg_number, w2, atcommand->msg_table[0][msg_number]);
  142. continue;
  143. }
  144. aFree(atcommand->msg_table[0][msg_number]);
  145. }
  146. /* this could easily become consecutive memory like get_str() and save the malloc overhead for over 1k calls [Ind] */
  147. atcommand->msg_table[0][msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char));
  148. strcpy(atcommand->msg_table[0][msg_number],w2);
  149. }
  150. }
  151. }
  152. fclose(fp);
  153. if( ++called == 1 ) { //Original
  154. if( script->lang_export_fp ) {
  155. int i;
  156. for(i = 0; i < MAX_MSG;i++) {
  157. if( atcommand->msg_table[0][i] != NULL ) {
  158. fprintf(script->lang_export_fp, "msgctxt \"messages.conf\"\n"
  159. "msgid \"%s\"\n"
  160. "msgstr \"\"\n",
  161. atcommand->msg_table[0][i]
  162. );
  163. }
  164. }
  165. }
  166. }
  167. return true;
  168. }
  169. /*==========================================
  170. * Cleanup Message Data
  171. *------------------------------------------*/
  172. void do_final_msg(void) {
  173. int i, j;
  174. for(i = 0; i < atcommand->max_message_table; i++) {
  175. for (j = 0; j < MAX_MSG; j++) {
  176. if( atcommand->msg_table[i][j] )
  177. aFree(atcommand->msg_table[i][j]);
  178. }
  179. aFree(atcommand->msg_table[i]);
  180. }
  181. if( atcommand->msg_table )
  182. aFree(atcommand->msg_table);
  183. }
  184. /**
  185. * retrieves the help string associated with a given command.
  186. */
  187. static inline const char* atcommand_help_string(AtCommandInfo *info) {
  188. return info->help;
  189. }
  190. /*==========================================
  191. * @send (used for testing packet sends from the client)
  192. *------------------------------------------*/
  193. ACMD(send)
  194. {
  195. int len=0,type;
  196. long num;
  197. // read message type as hex number (without the 0x)
  198. if (!*message
  199. || !((sscanf(message, "len %x", &type)==1 && (len=1, true))
  200. || sscanf(message, "%x", &type)==1)
  201. ) {
  202. clif->message(fd, msg_fd(fd,900)); // Usage:
  203. clif->message(fd, msg_fd(fd,901)); // @send len <packet hex number>
  204. clif->message(fd, msg_fd(fd,902)); // @send <packet hex number> {<value>}*
  205. clif->message(fd, msg_fd(fd,903)); // Value: <type=B(default),W,L><number> or S<length>"<string>"
  206. return false;
  207. }
  208. #define PARSE_ERROR(error,p) do {\
  209. clif->message(fd, (error));\
  210. safesnprintf(atcmd_output, sizeof(atcmd_output), ">%s", (p));\
  211. clif->message(fd, atcmd_output);\
  212. } while(0) //define PARSE_ERROR
  213. #define CHECK_EOS(p) do { \
  214. if(*(p) == 0){ \
  215. clif->message(fd, "Unexpected end of string");\
  216. return false;\
  217. } \
  218. } while(0) //define CHECK_EOS
  219. #define SKIP_VALUE(p) do { \
  220. while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\
  221. while(*(p) && ISSPACE(*(p))) ++(p); /* space */\
  222. } while(0) //define SKIP_VALUE
  223. #define GET_VALUE(p,num) do { \
  224. if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\
  225. PARSE_ERROR("Invalid number in:",(p));\
  226. return false;\
  227. }\
  228. } while(0) //define GET_VALUE
  229. if (type >= MIN_PACKET_DB && type <= MAX_PACKET_DB) {
  230. int off = 2;
  231. if (len) {
  232. // show packet length
  233. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,904), type, clif->packet(type)->len); // Packet 0x%x length: %d
  234. clif->message(fd, atcmd_output);
  235. return true;
  236. }
  237. len = clif->packet(type)->len;
  238. if (len == 0) {
  239. // unknown packet - ERROR
  240. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,905), type); // Unknown packet: 0x%x
  241. clif->message(fd, atcmd_output);
  242. return false;
  243. } else if (len == -1) {
  244. // dynamic packet
  245. len = SHRT_MAX-4; // maximum length
  246. off = 4;
  247. }
  248. WFIFOHEAD(sd->fd, len);
  249. WFIFOW(sd->fd,0)=TOW(type);
  250. // parse packet contents
  251. SKIP_VALUE(message);
  252. while(*message != 0 && off < len){
  253. if(ISDIGIT(*message) || *message == '-' || *message == '+')
  254. {// default (byte)
  255. GET_VALUE(message,num);
  256. WFIFOB(sd->fd,off)=TOB(num);
  257. ++off;
  258. } else if(TOUPPER(*message) == 'B')
  259. {// byte
  260. ++message;
  261. GET_VALUE(message,num);
  262. WFIFOB(sd->fd,off)=TOB(num);
  263. ++off;
  264. } else if(TOUPPER(*message) == 'W')
  265. {// word (2 bytes)
  266. ++message;
  267. GET_VALUE(message,num);
  268. WFIFOW(sd->fd,off)=TOW(num);
  269. off+=2;
  270. } else if(TOUPPER(*message) == 'L')
  271. {// long word (4 bytes)
  272. ++message;
  273. GET_VALUE(message,num);
  274. WFIFOL(sd->fd,off)=TOL(num);
  275. off+=4;
  276. } else if(TOUPPER(*message) == 'S')
  277. {// string - escapes are valid
  278. // get string length - num <= 0 means not fixed length (default)
  279. int end;
  280. ++message;
  281. if(*message == '"'){
  282. num=0;
  283. } else {
  284. GET_VALUE(message,num);
  285. while(*message != '"')
  286. {// find start of string
  287. if(*message == 0 || ISSPACE(*message)){
  288. PARSE_ERROR(msg_fd(fd,906),message); // Not a string:
  289. return false;
  290. }
  291. ++message;
  292. }
  293. }
  294. // parse string
  295. ++message;
  296. CHECK_EOS(message);
  297. end=(num<=0? 0: min(off+((int)num),len));
  298. for(; *message != '"' && (off < end || end == 0); ++off){
  299. if(*message == '\\'){
  300. ++message;
  301. CHECK_EOS(message);
  302. switch(*message){
  303. case 'a': num=0x07; break; // Bell
  304. case 'b': num=0x08; break; // Backspace
  305. case 't': num=0x09; break; // Horizontal tab
  306. case 'n': num=0x0A; break; // Line feed
  307. case 'v': num=0x0B; break; // Vertical tab
  308. case 'f': num=0x0C; break; // Form feed
  309. case 'r': num=0x0D; break; // Carriage return
  310. case 'e': num=0x1B; break; // Escape
  311. default: num=*message; break;
  312. case 'x': // Hexadecimal
  313. {
  314. ++message;
  315. CHECK_EOS(message);
  316. if(!ISXDIGIT(*message)){
  317. PARSE_ERROR(msg_fd(fd,907),message); // Not a hexadecimal digit:
  318. return false;
  319. }
  320. num=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10);
  321. if(ISXDIGIT(*message)){
  322. ++message;
  323. CHECK_EOS(message);
  324. num<<=8;
  325. num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10);
  326. }
  327. WFIFOB(sd->fd,off)=TOB(num);
  328. ++message;
  329. CHECK_EOS(message);
  330. continue;
  331. }
  332. case '0':
  333. case '1':
  334. case '2':
  335. case '3':
  336. case '4':
  337. case '5':
  338. case '6':
  339. case '7': // Octal
  340. {
  341. num=*message-'0'; // 1st octal digit
  342. ++message;
  343. CHECK_EOS(message);
  344. if(ISDIGIT(*message) && *message < '8'){
  345. num<<=3;
  346. num+=*message-'0'; // 2nd octal digit
  347. ++message;
  348. CHECK_EOS(message);
  349. if(ISDIGIT(*message) && *message < '8'){
  350. num<<=3;
  351. num+=*message-'0'; // 3rd octal digit
  352. ++message;
  353. CHECK_EOS(message);
  354. }
  355. }
  356. WFIFOB(sd->fd,off)=TOB(num);
  357. continue;
  358. }
  359. }
  360. } else
  361. num=*message;
  362. WFIFOB(sd->fd,off)=TOB(num);
  363. ++message;
  364. CHECK_EOS(message);
  365. }//for
  366. while(*message != '"')
  367. {// ignore extra characters
  368. ++message;
  369. CHECK_EOS(message);
  370. }
  371. // terminate the string
  372. if(off < end)
  373. {// fill the rest with 0's
  374. memset(WFIFOP(sd->fd,off),0,end-off);
  375. off=end;
  376. }
  377. } else
  378. {// unknown
  379. PARSE_ERROR(msg_fd(fd,908),message); // Unknown type of value in:
  380. return false;
  381. }
  382. SKIP_VALUE(message);
  383. }
  384. if (clif->packet(type)->len == -1) { // send dynamic packet
  385. WFIFOW(sd->fd,2)=TOW(off);
  386. WFIFOSET(sd->fd,off);
  387. } else {// send static packet
  388. if(off < len)
  389. memset(WFIFOP(sd->fd,off),0,len-off);
  390. WFIFOSET(sd->fd,len);
  391. }
  392. } else {
  393. clif->message(fd, msg_fd(fd,259)); // Invalid packet
  394. return false;
  395. }
  396. sprintf (atcmd_output, msg_fd(fd,258), type, type); // Sent packet 0x%x (%d)
  397. clif->message(fd, atcmd_output);
  398. return true;
  399. #undef PARSE_ERROR
  400. #undef CHECK_EOS
  401. #undef SKIP_VALUE
  402. #undef GET_VALUE
  403. }
  404. /*==========================================
  405. * @rura, @warp, @mapmove
  406. *------------------------------------------*/
  407. ACMD(mapmove) {
  408. char map_name[MAP_NAME_LENGTH_EXT];
  409. unsigned short map_index;
  410. short x = 0, y = 0;
  411. int16 m = -1;
  412. memset(map_name, '\0', sizeof(map_name));
  413. if (!*message ||
  414. (sscanf(message, "%15s %5hd %5hd", map_name, &x, &y) < 3 &&
  415. sscanf(message, "%15[^,],%5hd,%5hd", map_name, &x, &y) < 1)) {
  416. clif->message(fd, msg_fd(fd,909)); // Please enter a map (usage: @warp/@rura/@mapmove <mapname> <x> <y>).
  417. return false;
  418. }
  419. map_index = mapindex->name2id(map_name);
  420. if (map_index)
  421. m = map->mapindex2mapid(map_index);
  422. if (!map_index || m < 0) { // m < 0 means on different server or that map is disabled! [Kevin]
  423. clif->message(fd, msg_fd(fd,1)); // Map not found.
  424. return false;
  425. }
  426. if( sd->bl.m == m && sd->bl.x == x && sd->bl.y == y ) {
  427. clif->message(fd, msg_fd(fd,253)); // You already are at your destination!
  428. return false;
  429. }
  430. if ((x || y) && map->getcell(m, &sd->bl, x, y, CELL_CHKNOPASS) && pc_get_group_level(sd) < battle_config.gm_ignore_warpable_area) {
  431. //This is to prevent the pc->setpos call from printing an error.
  432. clif->message(fd, msg_fd(fd,2));
  433. if (!map->search_freecell(NULL, m, &x, &y, 10, 10, 1))
  434. x = y = 0; //Invalid cell, use random spot.
  435. }
  436. if (map->list[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
  437. clif->message(fd, msg_fd(fd,247));
  438. return false;
  439. }
  440. if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
  441. clif->message(fd, msg_fd(fd,248));
  442. return false;
  443. }
  444. if (pc->setpos(sd, map_index, x, y, CLR_TELEPORT) != 0) {
  445. clif->message(fd, msg_fd(fd,1)); // Map not found.
  446. return false;
  447. }
  448. clif->message(fd, msg_fd(fd,0)); // Warped.
  449. return true;
  450. }
  451. /*==========================================
  452. * Displays where a character is. Corrected version by Silent. [Skotlex]
  453. *------------------------------------------*/
  454. ACMD(where) {
  455. struct map_session_data* pl_sd;
  456. memset(atcmd_player_name, '\0', sizeof atcmd_player_name);
  457. if (!*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
  458. clif->message(fd, msg_fd(fd,910)); // Please enter a player name (usage: @where <char name>).
  459. return false;
  460. }
  461. pl_sd = map->nick2sd(atcmd_player_name);
  462. if (pl_sd == NULL ||
  463. strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 ||
  464. (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID))
  465. ) {
  466. clif->message(fd, msg_fd(fd,3)); // Character not found.
  467. return false;
  468. }
  469. snprintf(atcmd_output, sizeof atcmd_output, "%s %s %d %d", pl_sd->status.name, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y);
  470. clif->message(fd, atcmd_output);
  471. return true;
  472. }
  473. /*==========================================
  474. *
  475. *------------------------------------------*/
  476. ACMD(jumpto) {
  477. struct map_session_data *pl_sd = NULL;
  478. if (!*message) {
  479. clif->message(fd, msg_fd(fd,911)); // Please enter a player name (usage: @jumpto/@warpto/@goto <char name/ID>).
  480. return false;
  481. }
  482. if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
  483. clif->message(fd, msg_fd(fd,248)); // You are not authorized to warp from your current map.
  484. return false;
  485. }
  486. if( pc_isdead(sd) ) {
  487. clif->message(fd, msg_fd(fd,864)); // "You cannot use this command when dead."
  488. return false;
  489. }
  490. if((pl_sd=map->nick2sd((char *)message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) {
  491. clif->message(fd, msg_fd(fd,3)); // Character not found.
  492. return false;
  493. }
  494. if (pl_sd->bl.m >= 0 && map->list[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
  495. clif->message(fd, msg_fd(fd,247)); // You are not authorized to warp to this map.
  496. return false;
  497. }
  498. if( pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y ) {
  499. clif->message(fd, msg_fd(fd,253)); // You already are at your destination!
  500. return false;
  501. }
  502. pc->setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
  503. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,4), pl_sd->status.name); // Jumped to %s
  504. clif->message(fd, atcmd_output);
  505. return true;
  506. }
  507. /*==========================================
  508. *
  509. *------------------------------------------*/
  510. ACMD(jump)
  511. {
  512. short x = 0, y = 0;
  513. memset(atcmd_output, '\0', sizeof(atcmd_output));
  514. sscanf(message, "%5hd %5hd", &x, &y);
  515. if (map->list[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
  516. clif->message(fd, msg_fd(fd,248)); // You are not authorized to warp from your current map.
  517. return false;
  518. }
  519. if( pc_isdead(sd) ) {
  520. clif->message(fd, msg_fd(fd,864)); // "You cannot use this command when dead."
  521. return false;
  522. }
  523. if ((x || y) && map->getcell(sd->bl.m, &sd->bl, x, y, CELL_CHKNOPASS)) {
  524. //This is to prevent the pc->setpos call from printing an error.
  525. clif->message(fd, msg_fd(fd,2));
  526. if (!map->search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1))
  527. x = y = 0; //Invalid cell, use random spot.
  528. }
  529. if (x && y && sd->bl.x == x && sd->bl.y == y) {
  530. clif->message(fd, msg_fd(fd,253)); // You already are at your destination!
  531. return false;
  532. }
  533. pc->setpos(sd, sd->mapindex, x, y, CLR_TELEPORT);
  534. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,5), sd->bl.x, sd->bl.y); // Jumped to %d %d
  535. clif->message(fd, atcmd_output);
  536. return true;
  537. }
  538. /*==========================================
  539. * Display list of online characters with
  540. * various info.
  541. *------------------------------------------*/
  542. ACMD(who) {
  543. const struct map_session_data *pl_sd = NULL;
  544. struct s_mapiterator *iter = NULL;
  545. char player_name[NAME_LENGTH] = "";
  546. int count = 0;
  547. int level = 0;
  548. StringBuf buf;
  549. /**
  550. * 1 = @who : Player name, [Title], [Party name], [Guild name]
  551. * 2 = @who2 : Player name, [Title], BLvl, JLvl, Job
  552. * 3 = @who3 : [CID/AID] Player name [Title], Map, X, Y
  553. */
  554. int display_type = 1;
  555. int map_id = -1;
  556. if (stristr(info->command, "map") != NULL) {
  557. char map_name[MAP_NAME_LENGTH_EXT] = "";
  558. if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map->mapname2mapid(map_name)) < 0)
  559. map_id = sd->bl.m;
  560. } else {
  561. sscanf(message, "%23s", player_name);
  562. }
  563. if (stristr(info->command, "2") != NULL)
  564. display_type = 2;
  565. else if (stristr(info->command, "3") != NULL)
  566. display_type = 3;
  567. level = pc_get_group_level(sd);
  568. StrBuf->Init(&buf);
  569. iter = mapit_getallusers();
  570. for (pl_sd = BL_UCCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); pl_sd = BL_UCCAST(BL_PC, mapit->next(iter))) {
  571. if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || pc_isinvisible(pl_sd)) && pc_get_group_level(pl_sd) > level)) { // you can look only lower or same level
  572. if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive
  573. || (map_id >= 0 && pl_sd->bl.m != map_id))
  574. continue;
  575. switch (display_type) {
  576. case 2: {
  577. StrBuf->Printf(&buf, msg_fd(fd,343), pl_sd->status.name); // "Name: %s "
  578. if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
  579. StrBuf->Printf(&buf, msg_fd(fd,344), pcg->get_name(pl_sd->group)); // "(%s) "
  580. StrBuf->Printf(&buf, msg_fd(fd,347), pl_sd->status.base_level, pl_sd->status.job_level,
  581. pc->job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s"
  582. break;
  583. }
  584. case 3: {
  585. if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID))
  586. StrBuf->Printf(&buf, msg_fd(fd,912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) "
  587. StrBuf->Printf(&buf, msg_fd(fd,343), pl_sd->status.name); // "Name: %s "
  588. if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
  589. StrBuf->Printf(&buf, msg_fd(fd,344), pcg->get_name(pl_sd->group)); // "(%s) "
  590. StrBuf->Printf(&buf, msg_fd(fd,348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d"
  591. break;
  592. }
  593. default: {
  594. struct party_data *p = party->search(pl_sd->status.party_id);
  595. struct guild *g = pl_sd->guild;
  596. StrBuf->Printf(&buf, msg_fd(fd,343), pl_sd->status.name); // "Name: %s "
  597. if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
  598. StrBuf->Printf(&buf, msg_fd(fd,344), pcg->get_name(pl_sd->group)); // "(%s) "
  599. if (p != NULL)
  600. StrBuf->Printf(&buf, msg_fd(fd,345), p->party.name); // " | Party: '%s'"
  601. if (g != NULL)
  602. StrBuf->Printf(&buf, msg_fd(fd,346), g->name); // " | Guild: '%s'"
  603. break;
  604. }
  605. }
  606. clif->messagecolor_self(fd, COLOR_DEFAULT, StrBuf->Value(&buf));/** for whatever reason clif->message crashes with some patterns, see bugreport:8186 **/
  607. StrBuf->Clear(&buf);
  608. count++;
  609. }
  610. }
  611. mapit->free(iter);
  612. if (map_id < 0) {
  613. if (count == 0)
  614. StrBuf->AppendStr(&buf, msg_fd(fd,28)); // No player found.
  615. else if (count == 1)
  616. StrBuf->AppendStr(&buf, msg_fd(fd,29)); // 1 player found.
  617. else
  618. StrBuf->Printf(&buf, msg_fd(fd,30), count); // %d players found.
  619. } else {
  620. if (count == 0)
  621. StrBuf->Printf(&buf, msg_fd(fd,54), map->list[map_id].name); // No player found in map '%s'.
  622. else if (count == 1)
  623. StrBuf->Printf(&buf, msg_fd(fd,55), map->list[map_id].name); // 1 player found in map '%s'.
  624. else
  625. StrBuf->Printf(&buf, msg_fd(fd,56), count, map->list[map_id].name); // %d players found in map '%s'.
  626. }
  627. clif->message(fd, StrBuf->Value(&buf));
  628. StrBuf->Destroy(&buf);
  629. return true;
  630. }
  631. /*==========================================
  632. *
  633. *------------------------------------------*/
  634. ACMD(whogm)
  635. {
  636. const struct map_session_data *pl_sd;
  637. struct s_mapiterator* iter;
  638. int j, count;
  639. int level;
  640. char match_text[CHAT_SIZE_MAX];
  641. char player_name[NAME_LENGTH];
  642. struct guild *g;
  643. struct party_data *p;
  644. memset(atcmd_output, '\0', sizeof(atcmd_output));
  645. memset(match_text, '\0', sizeof(match_text));
  646. memset(player_name, '\0', sizeof(player_name));
  647. if (sscanf(message, "%199[^\n]", match_text) < 1)
  648. strcpy(match_text, "");
  649. for (j = 0; match_text[j]; j++)
  650. match_text[j] = TOLOWER(match_text[j]);
  651. count = 0;
  652. level = pc_get_group_level(sd);
  653. iter = mapit_getallusers();
  654. for (pl_sd = BL_UCCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); pl_sd = BL_UCCAST(BL_PC, mapit->next(iter))) {
  655. int pl_level = pc_get_group_level(pl_sd);
  656. if (!pl_level)
  657. continue;
  658. if (match_text[0]) {
  659. memcpy(player_name, pl_sd->status.name, NAME_LENGTH);
  660. for (j = 0; player_name[j]; j++)
  661. player_name[j] = TOLOWER(player_name[j]);
  662. // search with no case sensitive
  663. if (strstr(player_name, match_text) == NULL)
  664. continue;
  665. }
  666. if (pl_level > level) {
  667. if (pc_isinvisible(pl_sd))
  668. continue;
  669. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,913), pl_sd->status.name); // Name: %s (GM)
  670. clif->message(fd, atcmd_output);
  671. count++;
  672. continue;
  673. }
  674. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,914), // Name: %s (GM:%d) | Location: %s %d %d
  675. pl_sd->status.name, pl_level,
  676. mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y);
  677. clif->message(fd, atcmd_output);
  678. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,915), // BLvl: %d | Job: %s (Lvl: %d)
  679. pl_sd->status.base_level,
  680. pc->job_name(pl_sd->status.class_), pl_sd->status.job_level);
  681. clif->message(fd, atcmd_output);
  682. p = party->search(pl_sd->status.party_id);
  683. g = pl_sd->guild;
  684. safesnprintf(atcmd_output, sizeof(atcmd_output),msg_fd(fd,916), // Party: '%s' | Guild: '%s'
  685. p?p->party.name:msg_fd(fd,917), g?g->name:msg_fd(fd,917)); // None.
  686. clif->message(fd, atcmd_output);
  687. count++;
  688. }
  689. mapit->free(iter);
  690. if (count == 0)
  691. clif->message(fd, msg_fd(fd,150)); // No GM found.
  692. else if (count == 1)
  693. clif->message(fd, msg_fd(fd,151)); // 1 GM found.
  694. else {
  695. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,152), count); // %d GMs found.
  696. clif->message(fd, atcmd_output);
  697. }
  698. return true;
  699. }
  700. /*==========================================
  701. *
  702. *------------------------------------------*/
  703. ACMD(save)
  704. {
  705. pc->setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y);
  706. if (sd->status.pet_id > 0 && sd->pd)
  707. intif->save_petdata(sd->status.account_id, &sd->pd->pet);
  708. chrif->save(sd,0);
  709. clif->message(fd, msg_fd(fd,6)); // Your save point has been changed.
  710. return true;
  711. }
  712. /*==========================================
  713. *
  714. *------------------------------------------*/
  715. ACMD(load) {
  716. int16 m;
  717. m = map->mapindex2mapid(sd->status.save_point.map);
  718. if (m >= 0 && map->list[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
  719. clif->message(fd, msg_fd(fd,249)); // You are not authorized to warp to your save map.
  720. return false;
  721. }
  722. if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
  723. clif->message(fd, msg_fd(fd,248)); // You are not authorized to warp from your current map.
  724. return false;
  725. }
  726. pc->setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT);
  727. clif->message(fd, msg_fd(fd,7)); // Warping to save point..
  728. return true;
  729. }
  730. /*==========================================
  731. *
  732. *------------------------------------------*/
  733. ACMD(speed)
  734. {
  735. int speed;
  736. memset(atcmd_output, '\0', sizeof(atcmd_output));
  737. if (!*message || sscanf(message, "%12d", &speed) < 1) {
  738. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,918), MIN_WALK_SPEED, MAX_WALK_SPEED); // Please enter a speed value (usage: @speed <%d-%d>).
  739. clif->message(fd, atcmd_output);
  740. return false;
  741. }
  742. sd->state.permanent_speed = 0;
  743. if (speed < 0)
  744. sd->base_status.speed = DEFAULT_WALK_SPEED;
  745. else
  746. sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED);
  747. if( sd->base_status.speed != DEFAULT_WALK_SPEED ) {
  748. sd->state.permanent_speed = 1; // Set lock when set to non-default speed.
  749. clif->message(fd, msg_fd(fd,8)); // Speed changed.
  750. } else
  751. clif->message(fd, msg_fd(fd,172)); //Speed returned to normal.
  752. status_calc_bl(&sd->bl, SCB_SPEED);
  753. return true;
  754. }
  755. /*==========================================
  756. *
  757. *------------------------------------------*/
  758. ACMD(storage)
  759. {
  760. if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag)
  761. return false;
  762. if (storage->open(sd) == 1) { //Already open.
  763. clif->message(fd, msg_fd(fd,250));
  764. return false;
  765. }
  766. clif->message(fd, msg_fd(fd,919)); // Storage opened.
  767. return true;
  768. }
  769. /*==========================================
  770. *
  771. *------------------------------------------*/
  772. ACMD(guildstorage)
  773. {
  774. if (!sd->status.guild_id) {
  775. clif->message(fd, msg_fd(fd,252));
  776. return false;
  777. }
  778. if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading)
  779. return false;
  780. if (sd->state.storage_flag == STORAGE_FLAG_NORMAL) {
  781. clif->message(fd, msg_fd(fd,250));
  782. return false;
  783. }
  784. if (sd->state.storage_flag == STORAGE_FLAG_GUILD) {
  785. clif->message(fd, msg_fd(fd,251));
  786. return false;
  787. }
  788. if( gstorage->open(sd) ) {
  789. clif->message(fd, msg_fd(fd,1201)); // Your guild's storage has already been opened by another member, try again later.
  790. return false;
  791. }
  792. clif->message(fd, msg_fd(fd,920)); // Guild storage opened.
  793. return true;
  794. }
  795. /*==========================================
  796. *
  797. *------------------------------------------*/
  798. ACMD(option)
  799. {
  800. int param1 = 0, param2 = 0, param3 = 0;
  801. if (!*message || sscanf(message, "%12d %12d %12d", &param1, &param2, &param3) < 1 || param1 < 0 || param2 < 0 || param3 < 0)
  802. {// failed to match the parameters so inform the user of the options
  803. const char* text;
  804. // attempt to find the setting information for this command
  805. text = atcommand_help_string( info );
  806. // notify the user of the requirement to enter an option
  807. clif->message(fd, msg_fd(fd,921)); // Please enter at least one option.
  808. if( text ) {// send the help text associated with this command
  809. clif->messageln( fd, text );
  810. }
  811. return false;
  812. }
  813. sd->sc.opt1 = param1;
  814. sd->sc.opt2 = param2;
  815. pc->setoption(sd, param3);
  816. clif->message(fd, msg_fd(fd,9)); // Options changed.
  817. return true;
  818. }
  819. /*==========================================
  820. *
  821. *------------------------------------------*/
  822. ACMD(hide) {
  823. if (pc_isinvisible(sd)) {
  824. sd->sc.option &= ~OPTION_INVISIBLE;
  825. if (sd->disguise != -1 )
  826. status->set_viewdata(&sd->bl, sd->disguise);
  827. else
  828. status->set_viewdata(&sd->bl, sd->status.class_);
  829. clif->message(fd, msg_fd(fd,10)); // Invisible: Off
  830. // increment the number of pvp players on the map
  831. map->list[sd->bl.m].users_pvp++;
  832. if( map->list[sd->bl.m].flag.pvp && !map->list[sd->bl.m].flag.pvp_nocalcrank ) {
  833. // register the player for ranking calculations
  834. sd->pvp_timer = timer->add( timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0 );
  835. }
  836. //bugreport:2266
  837. map->foreachinmovearea(clif->insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl);
  838. } else {
  839. sd->sc.option |= OPTION_INVISIBLE;
  840. sd->vd.class_ = INVISIBLE_CLASS;
  841. clif->message(fd, msg_fd(fd,11)); // Invisible: On
  842. // decrement the number of pvp players on the map
  843. map->list[sd->bl.m].users_pvp--;
  844. if( map->list[sd->bl.m].flag.pvp && !map->list[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) {
  845. // unregister the player for ranking
  846. timer->delete( sd->pvp_timer, pc->calc_pvprank_timer );
  847. sd->pvp_timer = INVALID_TIMER;
  848. }
  849. }
  850. clif->changeoption(&sd->bl);
  851. return true;
  852. }
  853. /*==========================================
  854. * Changes a character's class
  855. *------------------------------------------*/
  856. ACMD(jobchange)
  857. {
  858. int job = 0, upper = 0;
  859. bool found = false;
  860. if (*message == '\0') { // No message, just show the list
  861. found = false;
  862. } else if (sscanf(message, "%12d %12d", &job, &upper) >= 1) { // Numeric job ID
  863. found = true;
  864. } else { // Job name
  865. int i;
  866. // Normal Jobs
  867. for (i = JOB_NOVICE; !found && i < JOB_MAX_BASIC; i++) {
  868. if (strncmpi(message, pc->job_name(i), 16) == 0) {
  869. job = i;
  870. found = true;
  871. break;
  872. }
  873. }
  874. // High Jobs, Babies and Third
  875. for (i = JOB_NOVICE_HIGH; !found && i < JOB_MAX; i++) {
  876. if (strncmpi(message, pc->job_name(i), 16) == 0) {
  877. job = i;
  878. found = true;
  879. break;
  880. }
  881. }
  882. }
  883. if (!found || !pc->db_checkid(job)) {
  884. const char *text = atcommand_help_string(info);
  885. if (text)
  886. clif->messageln(fd, text);
  887. return false;
  888. }
  889. // Deny direct transformation into dummy jobs
  890. if (job == JOB_KNIGHT2 || job == JOB_CRUSADER2
  891. || job == JOB_WEDDING || job == JOB_XMAS || job == JOB_SUMMER
  892. || job == JOB_LORD_KNIGHT2 || job == JOB_PALADIN2
  893. || job == JOB_BABY_KNIGHT2 || job == JOB_BABY_CRUSADER2
  894. || job == JOB_STAR_GLADIATOR2
  895. || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2)
  896. || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2)
  897. ) {
  898. /* WHY DO WE LIST THEM THEN? */
  899. clif->message(fd, msg_fd(fd,923)); //"You can not change to this job by command."
  900. return true;
  901. }
  902. if (pc->jobchange(sd, job, upper) != 0) {
  903. clif->message(fd, msg_fd(fd,155)); // You are unable to change your job.
  904. return false;
  905. }
  906. clif->message(fd, msg_fd(fd,12)); // Your job has been changed.
  907. return true;
  908. }
  909. /*==========================================
  910. *
  911. *------------------------------------------*/
  912. ACMD(kill)
  913. {
  914. status_kill(&sd->bl);
  915. clif->message(sd->fd, msg_fd(fd,13)); // A pity! You've died.
  916. if (fd != sd->fd)
  917. clif->message(fd, msg_fd(fd,14)); // Character killed.
  918. return true;
  919. }
  920. /*==========================================
  921. *
  922. *------------------------------------------*/
  923. ACMD(alive)
  924. {
  925. if (!status->revive(&sd->bl, 100, 100)) {
  926. clif->message(fd, msg_fd(fd,867)); // "You're not dead."
  927. return false;
  928. }
  929. clif->skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1);
  930. clif->message(fd, msg_fd(fd,16)); // You've been revived! It's a miracle!
  931. return true;
  932. }
  933. /*==========================================
  934. * +kamic [LuzZza]
  935. *------------------------------------------*/
  936. ACMD(kami)
  937. {
  938. unsigned int color=0;
  939. memset(atcmd_output, '\0', sizeof(atcmd_output));
  940. if(*(info->command + 4) != 'c' && *(info->command + 4) != 'C') {
  941. if (!*message) {
  942. clif->message(fd, msg_fd(fd,980)); // Please enter a message (usage: @kami <message>).
  943. return false;
  944. }
  945. sscanf(message, "%199[^\n]", atcmd_output);
  946. if (stristr(info->command, "l") != NULL)
  947. clif->broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP);
  948. else
  949. intif->broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(info->command + 4) == 'b' || *(info->command + 4) == 'B') ? BC_BLUE : BC_YELLOW);
  950. } else {
  951. if(!*message || (sscanf(message, "%10u %199[^\n]", &color, atcmd_output) < 2)) {
  952. clif->message(fd, msg_fd(fd,981)); // Please enter color and message (usage: @kamic <color> <message>).
  953. return false;
  954. }
  955. if(color > 0xFFFFFF) {
  956. clif->message(fd, msg_fd(fd,982)); // Invalid color.
  957. return false;
  958. }
  959. intif->broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0);
  960. }
  961. return true;
  962. }
  963. /*==========================================
  964. *
  965. *------------------------------------------*/
  966. ACMD(heal)
  967. {
  968. int hp = 0, sp = 0; // [Valaris] thanks to fov
  969. sscanf(message, "%12d %12d", &hp, &sp);
  970. // some overflow checks
  971. if( hp == INT_MIN ) hp++;
  972. if( sp == INT_MIN ) sp++;
  973. if ( hp == 0 && sp == 0 ) {
  974. if (!status_percent_heal(&sd->bl, 100, 100))
  975. clif->message(fd, msg_fd(fd,157)); // HP and SP have already been recovered.
  976. else
  977. clif->message(fd, msg_fd(fd,17)); // HP, SP recovered.
  978. return true;
  979. }
  980. if ( hp > 0 && sp >= 0 ) {
  981. if(!status->heal(&sd->bl, hp, sp, 0))
  982. clif->message(fd, msg_fd(fd,157)); // HP and SP are already with the good value.
  983. else
  984. clif->message(fd, msg_fd(fd,17)); // HP, SP recovered.
  985. return true;
  986. }
  987. if ( hp < 0 && sp <= 0 ) {
  988. status->damage(NULL, &sd->bl, -hp, -sp, 0, 0);
  989. clif->damage(&sd->bl,&sd->bl, 0, 0, -hp, 0, BDT_ENDURE, 0);
  990. clif->message(fd, msg_fd(fd,156)); // HP or/and SP modified.
  991. return true;
  992. }
  993. //Opposing signs.
  994. if ( hp ) {
  995. if (hp > 0)
  996. status->heal(&sd->bl, hp, 0, 0);
  997. else {
  998. status->damage(NULL, &sd->bl, -hp, 0, 0, 0);
  999. clif->damage(&sd->bl,&sd->bl, 0, 0, -hp, 0, BDT_ENDURE, 0);
  1000. }
  1001. }
  1002. if ( sp ) {
  1003. if (sp > 0)
  1004. status->heal(&sd->bl, 0, sp, 0);
  1005. else
  1006. status->damage(NULL, &sd->bl, 0, -sp, 0, 0);
  1007. }
  1008. clif->message(fd, msg_fd(fd,156)); // HP or/and SP modified.
  1009. return true;
  1010. }
  1011. /*==========================================
  1012. * @item command (usage: @item <name/id_of_item> <quantity>) (modified by [Yor] for pet_egg)
  1013. * @itembound command (usage: @itembound <name/id_of_item> <quantity> <bound type>) (revised by [Mhalicot])
  1014. *------------------------------------------*/
  1015. ACMD(item)
  1016. {
  1017. char item_name[100];
  1018. int number = 0, item_id, flag = 0, bound = 0;
  1019. struct item item_tmp;
  1020. struct item_data *item_data;
  1021. int get_count, i;
  1022. memset(item_name, '\0', sizeof(item_name));
  1023. if (!strcmpi(info->command,"itembound") && (!*message || (
  1024. sscanf(message, "\"%99[^\"]\" %12d %12d", item_name, &number, &bound) < 2 &&
  1025. sscanf(message, "%99s %12d %12d", item_name, &number, &bound) < 2
  1026. ))) {
  1027. clif->message(fd, msg_fd(fd,295)); // Please enter an item name or ID (usage: @itembound <item name/ID> <quantity> <bound_type>).
  1028. return false;
  1029. } else if (!*message
  1030. || ( sscanf(message, "\"%99[^\"]\" %12d", item_name, &number) < 1
  1031. && sscanf(message, "%99s %12d", item_name, &number) < 1
  1032. )) {
  1033. clif->message(fd, msg_fd(fd,983)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity>).
  1034. return false;
  1035. }
  1036. if (number <= 0)
  1037. number = 1;
  1038. if ((item_data = itemdb->search_name(item_name)) == NULL &&
  1039. (item_data = itemdb->exists(atoi(item_name))) == NULL)
  1040. {
  1041. clif->message(fd, msg_fd(fd,19)); // Invalid item ID or name.
  1042. return false;
  1043. }
  1044. if(!strcmpi(info->command,"itembound") ) {
  1045. if( !(bound >= IBT_MIN && bound <= IBT_MAX) ) {
  1046. clif->message(fd, msg_fd(fd,298)); // Invalid bound type
  1047. return false;
  1048. }
  1049. switch( (enum e_item_bound_type)bound ) {
  1050. case IBT_CHARACTER:
  1051. case IBT_ACCOUNT:
  1052. break; /* no restrictions */
  1053. case IBT_PARTY:
  1054. if( !sd->status.party_id ) {
  1055. clif->message(fd, msg_fd(fd,1498)); //You can't add a party bound item to a character without party!
  1056. return false;
  1057. }
  1058. break;
  1059. case IBT_GUILD:
  1060. if( !sd->status.guild_id ) {
  1061. clif->message(fd, msg_fd(fd,1499)); //You can't add a guild bound item to a character without guild!
  1062. return false;
  1063. }
  1064. break;
  1065. }
  1066. }
  1067. item_id = item_data->nameid;
  1068. get_count = number;
  1069. //Check if it's stackable.
  1070. if (!itemdb->isstackable2(item_data)) {
  1071. if( bound && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) {
  1072. clif->message(fd, msg_fd(fd,498)); // Cannot create bounded pet eggs or pet armors.
  1073. return false;
  1074. }
  1075. get_count = 1;
  1076. }
  1077. for (i = 0; i < number; i += get_count) {
  1078. // if not pet egg
  1079. if (!pet->create_egg(sd, item_id)) {
  1080. memset(&item_tmp, 0, sizeof(item_tmp));
  1081. item_tmp.nameid = item_id;
  1082. item_tmp.identify = 1;
  1083. item_tmp.bound = (unsigned char)bound;
  1084. if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
  1085. clif->additem(sd, 0, 0, flag);
  1086. }
  1087. }
  1088. if (flag == 0)
  1089. clif->message(fd, msg_fd(fd,18)); // Item created.
  1090. return true;
  1091. }
  1092. /*==========================================
  1093. * @item2 and @itembound2 command (revised by [Mhalicot])
  1094. *------------------------------------------*/
  1095. ACMD(item2)
  1096. {
  1097. struct item item_tmp;
  1098. struct item_data *item_data;
  1099. char item_name[100];
  1100. int item_id, number = 0, bound = 0;
  1101. int identify = 0, refine = 0, attr = 0;
  1102. int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
  1103. memset(item_name, '\0', sizeof(item_name));
  1104. if (!strcmpi(info->command,"itembound2") && (!*message || (
  1105. sscanf(message, "\"%99[^\"]\" %12d %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 &&
  1106. sscanf(message, "%99s %12d %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 ))) {
  1107. clif->message(fd, msg_fd(fd,296)); // Please enter all parameters (usage: @itembound2 <item name/ID> <quantity>
  1108. clif->message(fd, msg_fd(fd,297)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4> <bound_type>).
  1109. return false;
  1110. } else if (!*message
  1111. || ( sscanf(message, "\"%99[^\"]\" %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9
  1112. && sscanf(message, "%99s %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9
  1113. )) {
  1114. clif->message(fd, msg_fd(fd,984)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity>
  1115. clif->message(fd, msg_fd(fd,985)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4>).
  1116. return false;
  1117. }
  1118. if (number <= 0)
  1119. number = 1;
  1120. if( !strcmpi(info->command,"itembound2") && !(bound >= IBT_MIN && bound <= IBT_MAX) ) {
  1121. clif->message(fd, msg_fd(fd,298)); // Invalid bound type
  1122. return false;
  1123. }
  1124. item_id = 0;
  1125. if ((item_data = itemdb->search_name(item_name)) != NULL ||
  1126. (item_data = itemdb->exists(atoi(item_name))) != NULL)
  1127. item_id = item_data->nameid;
  1128. if (item_id > 500) {
  1129. int flag = 0;
  1130. int loop, get_count, i;
  1131. loop = 1;
  1132. get_count = number;
  1133. if( !strcmpi(info->command,"itembound2") )
  1134. bound = 1;
  1135. if( !itemdb->isstackable2(item_data) ) {
  1136. if( bound && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) {
  1137. clif->message(fd, msg_fd(fd,498)); // Cannot create bounded pet eggs or pet armors.
  1138. return false;
  1139. }
  1140. loop = number;
  1141. get_count = 1;
  1142. if (item_data->type == IT_PETEGG) {
  1143. identify = 1;
  1144. refine = 0;
  1145. }
  1146. if (item_data->type == IT_PETARMOR)
  1147. refine = 0;
  1148. } else {
  1149. identify = 1;
  1150. refine = attr = 0;
  1151. }
  1152. refine = cap_value(refine, 0, MAX_REFINE);
  1153. for (i = 0; i < loop; i++) {
  1154. memset(&item_tmp, 0, sizeof(item_tmp));
  1155. item_tmp.nameid = item_id;
  1156. item_tmp.identify = identify;
  1157. item_tmp.refine = refine;
  1158. item_tmp.attribute = attr;
  1159. item_tmp.bound = (unsigned char)bound;
  1160. item_tmp.card[0] = c1;
  1161. item_tmp.card[1] = c2;
  1162. item_tmp.card[2] = c3;
  1163. item_tmp.card[3] = c4;
  1164. if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
  1165. clif->additem(sd, 0, 0, flag);
  1166. }
  1167. if (flag == 0)
  1168. clif->message(fd, msg_fd(fd,18)); // Item created.
  1169. } else {
  1170. clif->message(fd, msg_fd(fd,19)); // Invalid item ID or name.
  1171. return false;
  1172. }
  1173. return true;
  1174. }
  1175. /*==========================================
  1176. *
  1177. *------------------------------------------*/
  1178. ACMD(itemreset)
  1179. {
  1180. int i;
  1181. for (i = 0; i < MAX_INVENTORY; i++) {
  1182. if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) {
  1183. pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_COMMAND);
  1184. }
  1185. }
  1186. clif->message(fd, msg_fd(fd,20)); // All of your items have been removed.
  1187. return true;
  1188. }
  1189. /*==========================================
  1190. * Atcommand @lvlup
  1191. *------------------------------------------*/
  1192. ACMD(baselevelup)
  1193. {
  1194. int level=0, i=0, status_point=0;
  1195. if (!*message || !(level = atoi(message))) {
  1196. clif->message(fd, msg_fd(fd,986)); // Please enter a level adjustment (usage: @lvup/@blevel/@baselvlup <number of levels>).
  1197. return false;
  1198. }
  1199. if (level > 0) {
  1200. if (sd->status.base_level >= pc->maxbaselv(sd)) { // check for max level by Valaris
  1201. clif->message(fd, msg_fd(fd,47)); // Base level can't go any higher.
  1202. return false;
  1203. } // End Addition
  1204. if ((unsigned int)level > pc->maxbaselv(sd) || (unsigned int)level > pc->maxbaselv(sd) - sd->status.base_level) // fix positive overflow
  1205. level = pc->maxbaselv(sd) - sd->status.base_level;
  1206. for (i = 0; i < level; i++)
  1207. status_point += pc->gets_status_point(sd->status.base_level + i);
  1208. sd->status.status_point += status_point;
  1209. sd->status.base_level += (unsigned int)level;
  1210. status_calc_pc(sd, SCO_FORCE);
  1211. status_percent_heal(&sd->bl, 100, 100);
  1212. clif->misceffect(&sd->bl, 0);
  1213. clif->message(fd, msg_fd(fd,21)); // Base level raised.
  1214. } else {
  1215. if (sd->status.base_level == 1) {
  1216. clif->message(fd, msg_fd(fd,158)); // Base level can't go any lower.
  1217. return false;
  1218. }
  1219. level*=-1;
  1220. if ((unsigned int)level >= sd->status.base_level)
  1221. level = sd->status.base_level-1;
  1222. for (i = 0; i > -level; i--)
  1223. status_point += pc->gets_status_point(sd->status.base_level + i - 1);
  1224. if (sd->status.status_point < status_point)
  1225. pc->resetstate(sd);
  1226. if (sd->status.status_point < status_point)
  1227. sd->status.status_point = 0;
  1228. else
  1229. sd->status.status_point -= status_point;
  1230. sd->status.base_level -= (unsigned int)level;
  1231. clif->message(fd, msg_fd(fd,22)); // Base level lowered.
  1232. status_calc_pc(sd, SCO_FORCE);
  1233. }
  1234. sd->status.base_exp = 0;
  1235. clif->updatestatus(sd, SP_STATUSPOINT);
  1236. clif->updatestatus(sd, SP_BASELEVEL);
  1237. clif->updatestatus(sd, SP_BASEEXP);
  1238. clif->updatestatus(sd, SP_NEXTBASEEXP);
  1239. pc->baselevelchanged(sd);
  1240. if(sd->status.party_id)
  1241. party->send_levelup(sd);
  1242. return true;
  1243. }
  1244. /*==========================================
  1245. *
  1246. *------------------------------------------*/
  1247. ACMD(joblevelup)
  1248. {
  1249. int level=0;
  1250. if (!*message || !(level = atoi(message))) {
  1251. clif->message(fd, msg_fd(fd,987)); // Please enter a level adjustment (usage: @joblvup/@jlevel/@joblvlup <number of levels>).
  1252. return false;
  1253. }
  1254. if (level > 0) {
  1255. if (sd->status.job_level >= pc->maxjoblv(sd)) {
  1256. clif->message(fd, msg_fd(fd,23)); // Job level can't go any higher.
  1257. return false;
  1258. }
  1259. if ((unsigned int)level > pc->maxjoblv(sd) || (unsigned int)level > pc->maxjoblv(sd) - sd->status.job_level) // fix positive overflow
  1260. level = pc->maxjoblv(sd) - sd->status.job_level;
  1261. sd->status.job_level += (unsigned int)level;
  1262. sd->status.skill_point += level;
  1263. clif->misceffect(&sd->bl, 1);
  1264. clif->message(fd, msg_fd(fd,24)); // Job level raised.
  1265. } else {
  1266. if (sd->status.job_level == 1) {
  1267. clif->message(fd, msg_fd(fd,159)); // Job level can't go any lower.
  1268. return false;
  1269. }
  1270. level *=-1;
  1271. if ((unsigned int)level >= sd->status.job_level) // fix negative overflow
  1272. level = sd->status.job_level-1;
  1273. sd->status.job_level -= (unsigned int)level;
  1274. if (sd->status.skill_point < level)
  1275. pc->resetskill(sd, PCRESETSKILL_NONE); //Reset skills since we need to subtract more points.
  1276. if (sd->status.skill_point < level)
  1277. sd->status.skill_point = 0;
  1278. else
  1279. sd->status.skill_point -= level;
  1280. clif->message(fd, msg_fd(fd,25)); // Job level lowered.
  1281. }
  1282. sd->status.job_exp = 0;
  1283. clif->updatestatus(sd, SP_JOBLEVEL);
  1284. clif->updatestatus(sd, SP_JOBEXP);
  1285. clif->updatestatus(sd, SP_NEXTJOBEXP);
  1286. clif->updatestatus(sd, SP_SKILLPOINT);
  1287. status_calc_pc(sd, SCO_FORCE);
  1288. return true;
  1289. }
  1290. /*==========================================
  1291. * @help
  1292. *------------------------------------------*/
  1293. ACMD(help) {
  1294. const char *command_name = NULL;
  1295. char *default_command = "help";
  1296. AtCommandInfo *tinfo = NULL;
  1297. if (!*message) {
  1298. command_name = default_command; // If no command_name specified, display help for @help.
  1299. } else {
  1300. if (*message == atcommand->at_symbol || *message == atcommand->char_symbol)
  1301. ++message;
  1302. command_name = atcommand->check_alias(message);
  1303. }
  1304. if (!atcommand->can_use2(sd, command_name, COMMAND_ATCOMMAND)) {
  1305. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,153), message); // "%s is Unknown Command"
  1306. clif->message(fd, atcmd_output);
  1307. atcommand->get_suggestions(sd, command_name, true);
  1308. return false;
  1309. }
  1310. tinfo = atcommand->get_info_byname(atcommand->check_alias(command_name));
  1311. if ( !tinfo || tinfo->help == NULL ) {
  1312. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,988), atcommand->at_symbol, command_name); // There is no help for %c%s.
  1313. clif->message(fd, atcmd_output);
  1314. atcommand->get_suggestions(sd, command_name, true);
  1315. return false;
  1316. }
  1317. safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,989), atcommand->at_symbol, command_name); // Help for command %c%s:
  1318. clif->message(fd, atcmd_output);
  1319. { // Display aliases
  1320. DBIterator* iter;
  1321. AtCommandInfo *command_info;
  1322. AliasInfo *alias_info = NULL;
  1323. StringBuf buf;
  1324. bool has_aliases = false;
  1325. StrBuf->Init(&buf);
  1326. StrBuf->AppendStr(&buf, msg_fd(fd,990)); // Available aliases:
  1327. command_info = atcommand->get_info_byname(command_name);
  1328. iter = db_iterator(atcommand->alias_db);
  1329. for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) {
  1330. if (alias_info->command == command_info) {
  1331. StrBuf->Printf(&buf, " %s", alias_info->alias);
  1332. has_aliases = true;
  1333. }
  1334. }
  1335. dbi_destroy(iter);
  1336. if (has_aliases)
  1337. clif->message(fd, StrBuf->Value(&buf));
  1338. StrBuf->Destroy(&buf);
  1339. }
  1340. // Display help contents
  1341. clif->messageln(fd, tinfo->help);
  1342. return true;
  1343. }
  1344. /**
  1345. * Helper function, used in foreach calls to stop auto-attack timers.
  1346. *
  1347. * @see map_foreachinmap
  1348. *
  1349. * Arglist parameters:
  1350. * - (int) id: If 0, stop any attacks. Otherwise, the target block list id to stop attacking.
  1351. */
  1352. int atcommand_stopattack(struct block_list *bl,va_list ap)
  1353. {
  1354. struct unit_data *ud = NULL;
  1355. int id = 0;
  1356. nullpo_ret(bl);
  1357. ud = unit->bl2ud(bl);
  1358. id = va_arg(ap, int);
  1359. if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target)) {
  1360. unit->stop_attack(bl);
  1361. return 1;
  1362. }
  1363. return 0;
  1364. }
  1365. /*==========================================
  1366. *
  1367. *------------------------------------------*/
  1368. int atcommand_pvpoff_sub(struct block_list *bl,va_list ap)
  1369. {
  1370. struct map_session_data *sd = NULL;
  1371. nullpo_ret(bl);
  1372. Assert_ret(bl->type == BL_PC);
  1373. sd = BL_UCAST(BL_PC, bl);
  1374. clif->pvpset(sd, 0, 0, 2);
  1375. if (sd->pvp_timer != INVALID_TIMER) {
  1376. timer->delete(sd->pvp_timer, pc->calc_pvprank_timer);
  1377. sd->pvp_timer = INVALID_TIMER;
  1378. }
  1379. return 0;
  1380. }
  1381. ACMD(pvpoff)
  1382. {
  1383. if (!map->list[sd->bl.m].flag.pvp) {
  1384. clif->message(fd, msg_fd(fd,160)); // PvP is already Off.
  1385. return false;
  1386. }
  1387. map->zone_change2(sd->bl.m,map->list[sd->bl.m].prev_zone);
  1388. map->list[sd->bl.m].flag.pvp = 0;
  1389. if (!battle_config.pk_mode) {
  1390. clif->map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING);
  1391. clif->maptypeproperty2(&sd->bl,ALL_SAMEMAP);
  1392. }
  1393. map->foreachinmap(atcommand->pvpoff_sub,sd->bl.m, BL_PC);
  1394. map->foreachinmap(atcommand->stopattack,sd->bl.m, BL_CHAR, 0);
  1395. clif->message(fd, msg_fd(fd,31)); // PvP: Off.
  1396. return true;
  1397. }
  1398. /*==========================================
  1399. *
  1400. *------------------------------------------*/
  1401. int atcommand_pvpon_sub(struct block_list *bl,va_list ap)
  1402. {
  1403. struct map_session_data *sd = NULL;
  1404. nullpo_ret(bl);
  1405. Assert_ret(bl->type == BL_PC);
  1406. sd = BL_UCAST(BL_PC, bl);
  1407. if (sd->pvp_timer == INVALID_TIMER) {
  1408. sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0);
  1409. sd->pvp_rank = 0;
  1410. sd->pvp_lastusers = 0;
  1411. sd->pvp_point = 5;
  1412. sd->pvp_won = 0;
  1413. sd->pvp_lost = 0;
  1414. }
  1415. return 0;
  1416. }
  1417. ACMD(pvpon)
  1418. {
  1419. if (map->list[sd->bl.m].flag.pvp) {
  1420. clif->message(fd, msg_fd(fd,161)); // PvP is already On.
  1421. return false;
  1422. }
  1423. map->zone_change2(sd->bl.m,strdb_get(map->zone_db, MAP_ZONE_PVP_NAME));
  1424. map-

Large files files are truncated, but you can click here to view the full file