· 7 years ago · Jan 16, 2019, 08:18 AM
1// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
2// For more information, see LICENCE in the main folder
3
4#include "../common/cbasetypes.h"
5#include "../common/mmo.h"
6#include "../common/timer.h"
7#include "../common/nullpo.h"
8#include "../common/core.h"
9#include "../common/showmsg.h"
10#include "../common/malloc.h"
11#include "../common/random.h"
12#include "../common/socket.h"
13#include "../common/strlib.h"
14#include "../common/utils.h"
15#include "../common/conf.h"
16
17#include "atcommand.h"
18#include "battle.h"
19#include "battleground.h"
20#include "chat.h"
21#include "channel.h"
22#include "clif.h"
23#include "chrif.h"
24#include "duel.h"
25#include "intif.h"
26#include "itemdb.h"
27#include "log.h"
28#include "map.h"
29#include "pc.h"
30#include "pc_groups.h" // groupid2name
31#include "status.h"
32#include "skill.h"
33#include "mob.h"
34#include "npc.h"
35#include "pet.h"
36#include "homunculus.h"
37#include "mail.h"
38#include "mercenary.h"
39#include "elemental.h"
40#include "party.h"
41#include "guild.h"
42#include "script.h"
43#include "storage.h"
44#include "trade.h"
45#include "unit.h"
46#include "mapreg.h"
47#include "quest.h"
48#include "achievement.h"
49#include "faction.h"
50
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <math.h>
55
56
57#define ATCOMMAND_LENGTH 50
58#define ACMD_FUNC(x) static int atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message)
59#define MAX_MSG 1400
60
61
62typedef struct AtCommandInfo AtCommandInfo;
63typedef struct AliasInfo AliasInfo;
64
65int atcmd_binding_count = 0;
66
67struct AtCommandInfo {
68 char command[ATCOMMAND_LENGTH];
69 AtCommandFunc func;
70 char* at_groups;/* quick @commands "can-use" lookup */
71 char* char_groups;/* quick @charcommands "can-use" lookup */
72};
73
74struct AliasInfo {
75 AtCommandInfo *command;
76 char alias[ATCOMMAND_LENGTH];
77};
78
79
80char atcommand_symbol = '@'; // first char of the commands
81char charcommand_symbol = '#';
82
83static char* msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others)
84static DBMap* atcommand_db = NULL; //name -> AtCommandInfo
85static DBMap* atcommand_alias_db = NULL; //alias -> AtCommandInfo
86static config_t atcommand_config;
87
88static char atcmd_output[CHAT_SIZE_MAX];
89static char atcmd_player_name[NAME_LENGTH];
90
91static AtCommandInfo* get_atcommandinfo_byname(const char *name); // @help
92static const char* atcommand_checkalias(const char *aliasname); // @help
93static void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool atcommand); // @help
94
95// @commands (script-based)
96struct atcmd_binding_data* get_atcommandbind_byname(const char* name) {
97 int i = 0;
98
99 if( *name == atcommand_symbol || *name == charcommand_symbol )
100 name++; // for backwards compatibility
101
102 ARR_FIND( 0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, name) == 0 );
103
104 return ( i < atcmd_binding_count ) ? atcmd_binding[i] : NULL;
105}
106
107//-----------------------------------------------------------
108// Return the message string of the specified number by [Yor]
109//-----------------------------------------------------------
110const char* msg_txt(int msg_number)
111{
112 if (msg_number >= 0 && msg_number < MAX_MSG &&
113 msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0')
114 return msg_table[msg_number];
115
116 return "??";
117}
118
119/*==========================================
120 * Read Message Data
121 *------------------------------------------*/
122int msg_config_read(const char* cfgName)
123{
124 int msg_number;
125 char line[1024], w1[1024], w2[1024];
126 FILE *fp;
127 static int called = 1;
128
129 if ((fp = fopen(cfgName, "r")) == NULL) {
130 ShowError("Messages file not found: %s\n", cfgName);
131 return 1;
132 }
133
134 if ((--called) == 0)
135 memset(msg_table, 0, sizeof(msg_table[0]) * MAX_MSG);
136
137 while(fgets(line, sizeof(line), fp))
138 {
139 if (line[0] == '/' && line[1] == '/')
140 continue;
141 if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
142 continue;
143
144 if (strcmpi(w1, "import") == 0)
145 msg_config_read(w2);
146 else
147 {
148 msg_number = atoi(w1);
149 if (msg_number >= 0 && msg_number < MAX_MSG)
150 {
151 if (msg_table[msg_number] != NULL)
152 aFree(msg_table[msg_number]);
153 msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char));
154 strcpy(msg_table[msg_number],w2);
155 }
156 }
157 }
158
159 fclose(fp);
160
161 return 0;
162}
163
164/*==========================================
165 * Cleanup Message Data
166 *------------------------------------------*/
167void do_final_msg(void)
168{
169 int i;
170 for (i = 0; i < MAX_MSG; i++)
171 aFree(msg_table[i]);
172}
173
174/**
175 * retrieves the help string associated with a given command.
176 *
177 * @param name the name of the command to retrieve help information for
178 * @return the string associated with the command, or NULL
179 */
180static const char* atcommand_help_string(const char* command)
181{
182 const char* str = NULL;
183 config_setting_t* info;
184
185 if( *command == atcommand_symbol || *command == charcommand_symbol )
186 {// remove the prefix symbol for the raw name of the command
187 command ++;
188 }
189
190 // convert alias to the real command name
191 command = atcommand_checkalias(command);
192
193 // attept to find the first default help command
194 info = config_lookup(&atcommand_config, "help");
195
196 if( info == NULL )
197 {// failed to find the help property in the configuration file
198 return NULL;
199 }
200
201 if( !config_setting_lookup_string( info, command, &str ) )
202 {// failed to find the matching help string
203 return NULL;
204 }
205
206 // push the result from the method
207 return str;
208}
209
210
211/*==========================================
212 * @send (used for testing packet sends from the client)
213 *------------------------------------------*/
214ACMD_FUNC(send)
215{
216 int len=0,off,end,type;
217 long num;
218
219 // read message type as hex number (without the 0x)
220 if(!message || !*message ||
221 !((sscanf(message, "len %x", &type)==1 && (len=1))
222 || sscanf(message, "%x", &type)==1) )
223 {
224 int i;
225 for (i = 900; i <= 903; ++i)
226 clif_displaymessage(fd, msg_txt(i));
227 return -1;
228 }
229
230#define PARSE_ERROR(error,p) \
231 {\
232 clif_displaymessage(fd, (error));\
233 sprintf(atcmd_output, ">%s", (p));\
234 clif_displaymessage(fd, atcmd_output);\
235 }
236//define PARSE_ERROR
237
238#define CHECK_EOS(p) \
239 if(*(p) == 0){\
240 clif_displaymessage(fd, "Unexpected end of string");\
241 return -1;\
242 }
243//define CHECK_EOS
244
245#define SKIP_VALUE(p) \
246 {\
247 while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\
248 while(*(p) && ISSPACE(*(p))) ++(p); /* space */\
249 }
250//define SKIP_VALUE
251
252#define GET_VALUE(p,num) \
253 {\
254 if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\
255 PARSE_ERROR("Invalid number in:",(p));\
256 return -1;\
257 }\
258 }
259//define GET_VALUE
260
261 if (type > 0 && type < MAX_PACKET_DB) {
262
263 if(len)
264 {// show packet length
265 sprintf(atcmd_output, msg_txt(904), type, packet_db[sd->packet_ver][type].len); // Packet 0x%x length: %d
266 clif_displaymessage(fd, atcmd_output);
267 return 0;
268 }
269
270 len=packet_db[sd->packet_ver][type].len;
271 off=2;
272 if(len == 0)
273 {// unknown packet - ERROR
274 sprintf(atcmd_output, msg_txt(905), type); // Unknown packet: 0x%x
275 clif_displaymessage(fd, atcmd_output);
276 return -1;
277 } else if(len == -1)
278 {// dynamic packet
279 len=SHRT_MAX-4; // maximum length
280 off=4;
281 }
282 WFIFOHEAD(fd, len);
283 WFIFOW(fd,0)=TOW(type);
284
285 // parse packet contents
286 SKIP_VALUE(message);
287 while(*message != 0 && off < len){
288 if(ISDIGIT(*message) || *message == '-' || *message == '+')
289 {// default (byte)
290 GET_VALUE(message,num);
291 WFIFOB(fd,off)=TOB(num);
292 ++off;
293 } else if(TOUPPER(*message) == 'B')
294 {// byte
295 ++message;
296 GET_VALUE(message,num);
297 WFIFOB(fd,off)=TOB(num);
298 ++off;
299 } else if(TOUPPER(*message) == 'W')
300 {// word (2 bytes)
301 ++message;
302 GET_VALUE(message,num);
303 WFIFOW(fd,off)=TOW(num);
304 off+=2;
305 } else if(TOUPPER(*message) == 'L')
306 {// long word (4 bytes)
307 ++message;
308 GET_VALUE(message,num);
309 WFIFOL(fd,off)=TOL(num);
310 off+=4;
311 } else if(TOUPPER(*message) == 'S')
312 {// string - escapes are valid
313 // get string length - num <= 0 means not fixed length (default)
314 ++message;
315 if(*message == '"'){
316 num=0;
317 } else {
318 GET_VALUE(message,num);
319 while(*message != '"')
320 {// find start of string
321 if(*message == 0 || ISSPACE(*message)){
322 PARSE_ERROR(msg_txt(906),message); // Not a string:
323 return -1;
324 }
325 ++message;
326 }
327 }
328
329 // parse string
330 ++message;
331 CHECK_EOS(message);
332 end=(num<=0? 0: min(off+((int)num),len));
333 for(; *message != '"' && (off < end || end == 0); ++off){
334 if(*message == '\\'){
335 ++message;
336 CHECK_EOS(message);
337 switch(*message){
338 case 'a': num=0x07; break; // Bell
339 case 'b': num=0x08; break; // Backspace
340 case 't': num=0x09; break; // Horizontal tab
341 case 'n': num=0x0A; break; // Line feed
342 case 'v': num=0x0B; break; // Vertical tab
343 case 'f': num=0x0C; break; // Form feed
344 case 'r': num=0x0D; break; // Carriage return
345 case 'e': num=0x1B; break; // Escape
346 default: num=*message; break;
347 case 'x': // Hexadecimal
348 {
349 ++message;
350 CHECK_EOS(message);
351 if(!ISXDIGIT(*message)){
352 PARSE_ERROR(msg_txt(907),message); // Not a hexadecimal digit:
353 return -1;
354 }
355 num=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10);
356 if(ISXDIGIT(*message)){
357 ++message;
358 CHECK_EOS(message);
359 num<<=8;
360 num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10);
361 }
362 WFIFOB(fd,off)=TOB(num);
363 ++message;
364 CHECK_EOS(message);
365 continue;
366 }
367 case '0':
368 case '1':
369 case '2':
370 case '3':
371 case '4':
372 case '5':
373 case '6':
374 case '7': // Octal
375 {
376 num=*message-'0'; // 1st octal digit
377 ++message;
378 CHECK_EOS(message);
379 if(ISDIGIT(*message) && *message < '8'){
380 num<<=3;
381 num+=*message-'0'; // 2nd octal digit
382 ++message;
383 CHECK_EOS(message);
384 if(ISDIGIT(*message) && *message < '8'){
385 num<<=3;
386 num+=*message-'0'; // 3rd octal digit
387 ++message;
388 CHECK_EOS(message);
389 }
390 }
391 WFIFOB(fd,off)=TOB(num);
392 continue;
393 }
394 }
395 } else
396 num=*message;
397 WFIFOB(fd,off)=TOB(num);
398 ++message;
399 CHECK_EOS(message);
400 }//for
401 while(*message != '"')
402 {// ignore extra characters
403 ++message;
404 CHECK_EOS(message);
405 }
406
407 // terminate the string
408 if(off < end)
409 {// fill the rest with 0's
410 memset(WFIFOP(fd,off),0,end-off);
411 off=end;
412 }
413 } else
414 {// unknown
415 PARSE_ERROR(msg_txt(908),message); // Unknown type of value in:
416 return -1;
417 }
418 SKIP_VALUE(message);
419 }
420
421 if(packet_db[sd->packet_ver][type].len == -1)
422 {// send dynamic packet
423 WFIFOW(fd,2)=TOW(off);
424 WFIFOSET(fd,off);
425 } else
426 {// send static packet
427 if(off < len)
428 memset(WFIFOP(fd,off),0,len-off);
429 WFIFOSET(fd,len);
430 }
431 } else {
432 clif_displaymessage(fd, msg_txt(259)); // Invalid packet
433 return -1;
434 }
435 sprintf (atcmd_output, msg_txt(258), type, type); // Sent packet 0x%x (%d)
436 clif_displaymessage(fd, atcmd_output);
437 return 0;
438#undef PARSE_ERROR
439#undef CHECK_EOS
440#undef SKIP_VALUE
441#undef GET_VALUE
442}
443
444/*==========================================
445 * @rura, @warp, @mapmove
446 *------------------------------------------*/
447ACMD_FUNC(mapmove)
448{
449 char map_name[MAP_NAME_LENGTH_EXT];
450 unsigned short mapindex;
451 short x = 0, y = 0;
452 int m = -1;
453
454 nullpo_retr(-1, sd);
455
456 memset(map_name, '\0', sizeof(map_name));
457
458 if (!message || !*message ||
459 (sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 &&
460 sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) {
461
462 clif_displaymessage(fd, msg_txt(909)); // Please enter a map (usage: @warp/@rura/@mapmove <mapname> <x> <y>).
463 return -1;
464 }
465
466 if( battle_config.pvpmode_nowarp_cmd && sd->state.pvpmode )
467 {
468 clif_displaymessage(sd->fd,"You can not use @go while on PVP Mode.");
469 return -1;
470 }
471
472 mapindex = mapindex_name2id(map_name);
473 if (mapindex)
474 m = map_mapindex2mapid(mapindex);
475
476 if (!mapindex) { // m < 0 means on different server! [Kevin]
477 clif_displaymessage(fd, msg_txt(1)); // Map not found.
478 return -1;
479 }
480
481 if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS))
482 { //This is to prevent the pc_setpos call from printing an error.
483 clif_displaymessage(fd, msg_txt(2));
484 if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1))
485 x = y = 0; //Invalid cell, use random spot.
486 }
487 if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
488 clif_displaymessage(fd, msg_txt(247));
489 return -1;
490 }
491 if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
492 clif_displaymessage(fd, msg_txt(248));
493 return -1;
494 }
495 if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) {
496 clif_displaymessage(fd, msg_txt(1)); // Map not found.
497 return -1;
498 }
499
500 clif_displaymessage(fd, msg_txt(0)); // Warped.
501 return 0;
502}
503
504/*==========================================
505 * Displays where a character is. Corrected version by Silent. [Skotlex]
506 *------------------------------------------*/
507ACMD_FUNC(where)
508{
509 struct map_session_data* pl_sd;
510
511 nullpo_retr(-1, sd);
512 memset(atcmd_player_name, '\0', sizeof atcmd_player_name);
513
514 if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
515 clif_displaymessage(fd, msg_txt(910)); // Please enter a player name (usage: @where <char name>).
516 return -1;
517 }
518
519 pl_sd = map_nick2sd(atcmd_player_name);
520 if (pl_sd == NULL ||
521 strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 ||
522 (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))
523 ) {
524 clif_displaymessage(fd, msg_txt(3)); // Character not found.
525 return -1;
526 }
527
528 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);
529 clif_displaymessage(fd, atcmd_output);
530
531 return 0;
532}
533
534/*==========================================
535 *
536 *------------------------------------------*/
537ACMD_FUNC(jumpto)
538{
539 struct map_session_data *pl_sd = NULL;
540
541 nullpo_retr(-1, sd);
542
543 if (!message || !*message) {
544 clif_displaymessage(fd, msg_txt(911)); // Please enter a player name (usage: @jumpto/@warpto/@goto <char name/ID>).
545 return -1;
546 }
547
548 if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL)
549 {
550 clif_displaymessage(fd, msg_txt(3)); // Character not found.
551 return -1;
552 }
553
554 if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
555 {
556 clif_displaymessage(fd, msg_txt(247)); // You are not authorized to warp to this map.
557 return -1;
558 }
559
560 if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
561 {
562 clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map.
563 return -1;
564 }
565
566 if( pc_isdead(sd) )
567 {
568 clif_displaymessage(fd, msg_txt(664));
569 return -1;
570 }
571
572 pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
573 sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s
574 clif_displaymessage(fd, atcmd_output);
575
576 return 0;
577}
578
579/*==========================================
580 *
581 *------------------------------------------*/
582ACMD_FUNC(jump)
583{
584 short x = 0, y = 0;
585
586 nullpo_retr(-1, sd);
587
588 memset(atcmd_output, '\0', sizeof(atcmd_output));
589
590 sscanf(message, "%hd %hd", &x, &y);
591
592 if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
593 clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map.
594 return -1;
595 }
596
597 if( pc_isdead(sd) )
598 {
599 clif_displaymessage(fd, msg_txt(664));
600 return -1;
601 }
602
603 if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS))
604 { //This is to prevent the pc_setpos call from printing an error.
605 clif_displaymessage(fd, msg_txt(2));
606 if (!map_search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1))
607 x = y = 0; //Invalid cell, use random spot.
608 }
609
610 pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT);
611 sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d
612 clif_displaymessage(fd, atcmd_output);
613 return 0;
614}
615
616/*==========================================
617 * Display list of online characters with
618 * various info.
619 *------------------------------------------*/
620ACMD_FUNC(who)
621{
622 struct map_session_data *pl_sd = NULL;
623 struct s_mapiterator *iter = NULL;
624 char map_name[MAP_NAME_LENGTH_EXT] = "";
625 char player_name[NAME_LENGTH] = "";
626 int count = 0;
627 int level = 0;
628 StringBuf buf;
629 /**
630 * 1 = @who : Player name, [Title], [Party name], [Guild name]
631 * 2 = @who2 : Player name, [Title], BLvl, JLvl, Job
632 * 3 = @who3 : [CID/AID] Player name [Title], Map, X, Y
633 */
634 int display_type = 1;
635 int map_id = -1;
636
637 nullpo_retr(-1, sd);
638
639 if (strstr(command, "map") != NULL) {
640 if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map_mapname2mapid(map_name)) < 0)
641 map_id = sd->bl.m;
642 } else {
643 sscanf(message, "%23s", player_name);
644 }
645
646 if (strstr(command, "2") != NULL)
647 display_type = 2;
648 else if (strstr(command, "3") != NULL)
649 display_type = 3;
650
651 level = pc_get_group_level(sd);
652 StringBuf_Init(&buf);
653
654 iter = mapit_getallusers();
655 for (pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter)) {
656 if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level)) { // you can look only lower or same level
657 if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive
658 || (map_id >= 0 && pl_sd->bl.m != map_id))
659 continue;
660 switch (display_type) {
661 case 2: {
662 StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s "
663 if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
664 StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
665 StringBuf_Printf(&buf, msg_txt(347), pl_sd->status.base_level, pl_sd->status.job_level,
666 job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s"
667 break;
668 }
669 case 3: {
670 if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID))
671 StringBuf_Printf(&buf, msg_txt(912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) "
672 StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s "
673 if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
674 StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
675 StringBuf_Printf(&buf, msg_txt(348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d"
676 break;
677 }
678 default: {
679 struct party_data *p = party_search(pl_sd->status.party_id);
680 struct guild *g = guild_search(pl_sd->status.guild_id);
681
682 StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s "
683 if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
684 StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
685 if (p != NULL)
686 StringBuf_Printf(&buf, msg_txt(345), p->party.name); // " | Party: '%s'"
687 if (g != NULL)
688 StringBuf_Printf(&buf, msg_txt(346), g->name); // " | Guild: '%s'"
689 break;
690 }
691 }
692 clif_displaymessage(fd, StringBuf_Value(&buf));
693 StringBuf_Clear(&buf);
694 count++;
695 }
696 }
697 mapit_free(iter);
698
699 if (map_id < 0) {
700 if (count == 0)
701 StringBuf_Printf(&buf, msg_txt(28)); // No player found.
702 else if (count == 1)
703 StringBuf_Printf(&buf, msg_txt(29)); // 1 player found.
704 else
705 StringBuf_Printf(&buf, msg_txt(30), count); // %d players found.
706 } else {
707 if (count == 0)
708 StringBuf_Printf(&buf, msg_txt(54), map[map_id].name); // No player found in map '%s'.
709 else if (count == 1)
710 StringBuf_Printf(&buf, msg_txt(55), map[map_id].name); // 1 player found in map '%s'.
711 else
712 StringBuf_Printf(&buf, msg_txt(56), count, map[map_id].name); // %d players found in map '%s'.
713 }
714 clif_displaymessage(fd, StringBuf_Value(&buf));
715 StringBuf_Destroy(&buf);
716 return 0;
717}
718
719/*==========================================
720 *
721 *------------------------------------------*/
722ACMD_FUNC(whogm)
723{
724 struct map_session_data* pl_sd;
725 struct s_mapiterator* iter;
726 int j, count;
727 int pl_level, level;
728 char match_text[CHAT_SIZE_MAX];
729 char player_name[NAME_LENGTH];
730 struct guild *g;
731 struct party_data *p;
732
733 nullpo_retr(-1, sd);
734
735 memset(atcmd_output, '\0', sizeof(atcmd_output));
736 memset(match_text, '\0', sizeof(match_text));
737 memset(player_name, '\0', sizeof(player_name));
738
739 if (sscanf(message, "%199[^\n]", match_text) < 1)
740 strcpy(match_text, "");
741 for (j = 0; match_text[j]; j++)
742 match_text[j] = TOLOWER(match_text[j]);
743
744 count = 0;
745 level = pc_get_group_level(sd);
746
747 iter = mapit_getallusers();
748 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
749 {
750 pl_level = pc_get_group_level(pl_sd);
751 if (!pl_level)
752 continue;
753
754 if (match_text[0])
755 {
756 memcpy(player_name, pl_sd->status.name, NAME_LENGTH);
757 for (j = 0; player_name[j]; j++)
758 player_name[j] = TOLOWER(player_name[j]);
759 // search with no case sensitive
760 if (strstr(player_name, match_text) == NULL)
761 continue;
762 }
763 if (pl_level > level) {
764 if (pl_sd->sc.option & OPTION_INVISIBLE)
765 continue;
766 sprintf(atcmd_output, msg_txt(913), pl_sd->status.name); // Name: %s (GM)
767 clif_displaymessage(fd, atcmd_output);
768 count++;
769 continue;
770 }
771
772 sprintf(atcmd_output, msg_txt(914), // Name: %s (GM:%d) | Location: %s %d %d
773 pl_sd->status.name, pl_level,
774 mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y);
775 clif_displaymessage(fd, atcmd_output);
776
777 sprintf(atcmd_output, msg_txt(915), // BLvl: %d | Job: %s (Lvl: %d)
778 pl_sd->status.base_level,
779 job_name(pl_sd->status.class_), pl_sd->status.job_level);
780 clif_displaymessage(fd, atcmd_output);
781
782 p = party_search(pl_sd->status.party_id);
783 g = guild_search(pl_sd->status.guild_id);
784
785 sprintf(atcmd_output,msg_txt(916), // Party: '%s' | Guild: '%s'
786 p?p->party.name:msg_txt(917), g?g->name:msg_txt(917)); // None.
787
788 clif_displaymessage(fd, atcmd_output);
789 count++;
790 }
791 mapit_free(iter);
792
793 if (count == 0)
794 clif_displaymessage(fd, msg_txt(150)); // No GM found.
795 else if (count == 1)
796 clif_displaymessage(fd, msg_txt(151)); // 1 GM found.
797 else {
798 sprintf(atcmd_output, msg_txt(152), count); // %d GMs found.
799 clif_displaymessage(fd, atcmd_output);
800 }
801
802 return 0;
803}
804
805/*==========================================
806 *
807 *------------------------------------------*/
808ACMD_FUNC(save)
809{
810 nullpo_retr(-1, sd);
811
812 pc_setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y);
813 if (sd->status.pet_id > 0 && sd->pd)
814 intif_save_petdata(sd->status.account_id, &sd->pd->pet);
815
816 chrif_save(sd,0);
817
818 clif_displaymessage(fd, msg_txt(6)); // Your save point has been changed.
819
820 return 0;
821}
822
823/*==========================================
824 *
825 *------------------------------------------*/
826ACMD_FUNC(load)
827{
828 int m;
829
830 nullpo_retr(-1, sd);
831
832 m = map_mapindex2mapid(sd->status.save_point.map);
833 if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
834 clif_displaymessage(fd, msg_txt(249)); // You are not authorized to warp to your save map.
835 return -1;
836 }
837 if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
838 clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map.
839 return -1;
840 }
841
842 pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT);
843 clif_displaymessage(fd, msg_txt(7)); // Warping to save point..
844
845 return 0;
846}
847
848/*==========================================
849 *
850 *------------------------------------------*/
851ACMD_FUNC(speed)
852{
853 int speed;
854
855 nullpo_retr(-1, sd);
856
857 memset(atcmd_output, '\0', sizeof(atcmd_output));
858
859 if (!message || !*message || sscanf(message, "%d", &speed) < 1) {
860 sprintf(atcmd_output, msg_txt(918), MIN_WALK_SPEED, MAX_WALK_SPEED); // Please enter a speed value (usage: @speed <%d-%d>).
861 clif_displaymessage(fd, atcmd_output);
862 return -1;
863 }
864
865 sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED);
866 status_calc_bl(&sd->bl, SCB_SPEED);
867 clif_displaymessage(fd, msg_txt(8)); // Speed changed.
868 return 0;
869}
870
871/*==========================================
872 *
873 *------------------------------------------*/
874ACMD_FUNC(storage)
875{
876 nullpo_retr(-1, sd);
877
878 if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag)
879 return -1;
880
881 if (storage_storageopen(sd) == 1)
882 { //Already open.
883 clif_displaymessage(fd, msg_txt(250));
884 return -1;
885 }
886
887 clif_displaymessage(fd, msg_txt(919)); // Storage opened.
888
889 return 0;
890}
891
892
893/*==========================================
894 *
895 *------------------------------------------*/
896ACMD_FUNC(guildstorage)
897{
898 nullpo_retr(-1, sd);
899
900 if (!sd->status.guild_id) {
901 clif_displaymessage(fd, msg_txt(252));
902 return -1;
903 }
904
905 if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading)
906 return -1;
907
908 if (sd->state.storage_flag == 1 || sd->state.storage_flag == 3) {
909 clif_displaymessage(fd, msg_txt(250));
910 return -1;
911 }
912
913 if (sd->state.storage_flag == 2) {
914 clif_displaymessage(fd, msg_txt(251));
915 return -1;
916 }
917
918 storage_guild_storageopen(sd);
919 clif_displaymessage(fd, msg_txt(920)); // Guild storage opened.
920 return 0;
921}
922
923/*==========================================
924 *
925 *------------------------------------------*/
926ACMD_FUNC(option)
927{
928 int param1 = 0, param2 = 0, param3 = 0;
929 nullpo_retr(-1, sd);
930
931 if (!message || !*message || sscanf(message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 || param1 < 0 || param2 < 0 || param3 < 0)
932 {// failed to match the parameters so inform the user of the options
933 const char* text = NULL;
934
935 // attempt to find the setting information for this command
936 text = atcommand_help_string( command );
937
938 // notify the user of the requirement to enter an option
939 clif_displaymessage(fd, msg_txt(921)); // Please enter at least one option.
940
941 if( text )
942 {// send the help text associated with this command
943 clif_displaymessage( fd, text );
944 }
945
946 return -1;
947 }
948
949 sd->sc.opt1 = param1;
950 sd->sc.opt2 = param2;
951 pc_setoption(sd, param3);
952
953 clif_displaymessage(fd, msg_txt(9)); // Options changed.
954
955 return 0;
956}
957
958/*==========================================
959 *
960 *------------------------------------------*/
961ACMD_FUNC(hide)
962{
963 nullpo_retr(-1, sd);
964 if (sd->sc.option & OPTION_INVISIBLE) {
965 sd->sc.option &= ~OPTION_INVISIBLE;
966 if (sd->disguise)
967 status_set_viewdata(&sd->bl, sd->disguise);
968 else
969 status_set_viewdata(&sd->bl, sd->status.class_);
970 clif_displaymessage(fd, msg_txt(10)); // Invisible: Off
971
972 // increment the number of pvp players on the map
973 map[sd->bl.m].users_pvp++;
974
975 if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank )
976 {// register the player for ranking calculations
977 sd->pvp_timer = add_timer( gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0 );
978 }
979 //bugreport:2266
980 map_foreachinmovearea(clif_insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl);
981 } else {
982 sd->sc.option |= OPTION_INVISIBLE;
983 sd->vd.class_ = INVISIBLE_CLASS;
984 clif_displaymessage(fd, msg_txt(11)); // Invisible: On
985
986 // decrement the number of pvp players on the map
987 map[sd->bl.m].users_pvp--;
988
989 if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER )
990 {// unregister the player for ranking
991 delete_timer( sd->pvp_timer, pc_calc_pvprank_timer );
992 sd->pvp_timer = INVALID_TIMER;
993 }
994 }
995 clif_changeoption(&sd->bl);
996
997 return 0;
998}
999
1000/*==========================================
1001 * Changes a character's class
1002 *------------------------------------------*/
1003ACMD_FUNC(jobchange)
1004{
1005 //FIXME: redundancy, potentially wrong code, should use job_name() or similar instead of hardcoding the table [ultramage]
1006 int job = 0, upper = 0;
1007 const char* text;
1008 nullpo_retr(-1, sd);
1009
1010 if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1)
1011 {
1012 int i, found = 0;
1013 const struct { char name[24]; int id; } jobs[] = {
1014 { "novice", 0 },
1015 { "swordman", 1 },
1016 { "swordsman", 1 },
1017 { "magician", 2 },
1018 { "mage", 2 },
1019 { "archer", 3 },
1020 { "acolyte", 4 },
1021 { "merchant", 5 },
1022 { "thief", 6 },
1023 { "knight", 7 },
1024 { "priest", 8 },
1025 { "priestess", 8 },
1026 { "wizard", 9 },
1027 { "blacksmith", 10 },
1028 { "hunter", 11 },
1029 { "assassin", 12 },
1030 { "crusader", 14 },
1031 { "monk", 15 },
1032 { "sage", 16 },
1033 { "rogue", 17 },
1034 { "alchemist", 18 },
1035 { "bard", 19 },
1036 { "dancer", 20 },
1037 { "super novice", 23 },
1038 { "supernovice", 23 },
1039 { "gunslinger", 24 },
1040 { "gunner", 24 },
1041 { "ninja", 25 },
1042 { "novice high", 4001 },
1043 { "high novice", 4001 },
1044 { "swordman high", 4002 },
1045 { "swordsman high", 4002 },
1046 { "magician high", 4003 },
1047 { "mage high", 4003 },
1048 { "archer high", 4004 },
1049 { "acolyte high", 4005 },
1050 { "merchant high", 4006 },
1051 { "thief high", 4007 },
1052 { "lord knight", 4008 },
1053 { "high priest", 4009 },
1054 { "high priestess", 4009 },
1055 { "high wizard", 4010 },
1056 { "whitesmith", 4011 },
1057 { "sniper", 4012 },
1058 { "assassin cross", 4013 },
1059 { "paladin", 4015 },
1060 { "champion", 4016 },
1061 { "professor", 4017 },
1062 { "stalker", 4018 },
1063 { "creator", 4019 },
1064 { "clown", 4020 },
1065 { "gypsy", 4021 },
1066 { "baby novice", 4023 },
1067 { "baby swordman", 4024 },
1068 { "baby swordsman", 4024 },
1069 { "baby magician", 4025 },
1070 { "baby mage", 4025 },
1071 { "baby archer", 4026 },
1072 { "baby acolyte", 4027 },
1073 { "baby merchant", 4028 },
1074 { "baby thief", 4029 },
1075 { "baby knight", 4030 },
1076 { "baby priest", 4031 },
1077 { "baby priestess", 4031 },
1078 { "baby wizard", 4032 },
1079 { "baby blacksmith",4033 },
1080 { "baby hunter", 4034 },
1081 { "baby assassin", 4035 },
1082 { "baby crusader", 4037 },
1083 { "baby monk", 4038 },
1084 { "baby sage", 4039 },
1085 { "baby rogue", 4040 },
1086 { "baby alchemist", 4041 },
1087 { "baby bard", 4042 },
1088 { "baby dancer", 4043 },
1089 { "super baby", 4045 },
1090 { "taekwon", 4046 },
1091 { "taekwon boy", 4046 },
1092 { "taekwon girl", 4046 },
1093 { "star gladiator", 4047 },
1094 { "soul linker", 4049 },
1095 { "gangsi", 4050 },
1096 { "bongun", 4050 },
1097 { "munak", 4050 },
1098 { "death knight", 4051 },
1099 { "dark collector", 4052 },
1100 { "rune knight", 4054 },
1101 { "warlock", 4055 },
1102 { "ranger", 4056 },
1103 { "arch bishop", 4057 },
1104 { "mechanic", 4058 },
1105 { "guillotine", 4059 },
1106 { "rune knight2", 4060 },
1107 { "warlock2", 4061 },
1108 { "ranger2", 4062 },
1109 { "arch bishop2", 4063 },
1110 { "mechanic2", 4064 },
1111 { "guillotine2", 4065 },
1112 { "royal guard", 4066 },
1113 { "sorcerer", 4067 },
1114 { "minstrel", 4068 },
1115 { "wanderer", 4069 },
1116 { "sura", 4070 },
1117 { "genetic", 4071 },
1118 { "shadow chaser", 4072 },
1119 { "royal guard2", 4073 },
1120 { "sorcerer2", 4074 },
1121 { "minstrel2", 4075 },
1122 { "wanderer2", 4076 },
1123 { "sura2", 4077 },
1124 { "genetic2", 4078 },
1125 { "shadow chaser2", 4079 },
1126 { "baby rune", 4096 },
1127 { "baby warlock", 4097 },
1128 { "baby ranger", 4098 },
1129 { "baby bishop", 4099 },
1130 { "baby mechanic", 4100 },
1131 { "baby cross", 4101 },
1132 { "baby guard", 4102 },
1133 { "baby sorcerer", 4103 },
1134 { "baby minstrel", 4104 },
1135 { "baby wanderer", 4105 },
1136 { "baby sura", 4106 },
1137 { "baby genetic", 4107 },
1138 { "baby chaser", 4108 },
1139 { "super novice e", 4190 },
1140 { "super baby e", 4191 },
1141 { "kagerou", 4211 },
1142 { "oboro", 4212 },
1143 };
1144
1145 for (i=0; i < ARRAYLENGTH(jobs); i++) {
1146 if (strncmpi(message, jobs[i].name, 16) == 0) {
1147 job = jobs[i].id;
1148 upper = 0;
1149 found = 1;
1150 break;
1151 }
1152 }
1153
1154 if (!found) {
1155 text = atcommand_help_string(command);
1156 if (text) clif_displaymessage(fd, text);
1157 return -1;
1158 }
1159 }
1160
1161 if (job == 13 || job == 21 || job == 22 || job == 26 || job == 27 || job == 4014 || job == 4022 || job == 4036 || job == 4044 || job == 4048
1162 || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2)
1163 ) // Deny direct transformation into dummy jobs
1164 {clif_displaymessage(fd, "You can not change to this job by command.");
1165 return 0;}
1166
1167 if (pcdb_checkid(job))
1168 {
1169 if (pc_jobchange(sd, job, upper) == 0)
1170 clif_displaymessage(fd, msg_txt(12)); // Your job has been changed.
1171 else {
1172 clif_displaymessage(fd, msg_txt(155)); // You are unable to change your job.
1173 return -1;
1174 }
1175 } else {
1176 text = atcommand_help_string(command);
1177 if (text) clif_displaymessage(fd, text);
1178 return -1;
1179 }
1180
1181 return 0;
1182}
1183
1184/*==========================================
1185 *
1186 *------------------------------------------*/
1187ACMD_FUNC(kill)
1188{
1189 nullpo_retr(-1, sd);
1190 status_kill(&sd->bl);
1191 clif_displaymessage(sd->fd, msg_txt(13)); // A pity! You've died.
1192 if (fd != sd->fd)
1193 clif_displaymessage(fd, msg_txt(14)); // Character killed.
1194 return 0;
1195}
1196
1197/*==========================================
1198 *
1199 *------------------------------------------*/
1200ACMD_FUNC(alive)
1201{
1202 nullpo_retr(-1, sd);
1203 if (!status_revive(&sd->bl, 100, 100))
1204 {
1205 clif_displaymessage(fd, msg_txt(667));
1206 return -1;
1207 }
1208 clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1);
1209 clif_displaymessage(fd, msg_txt(16)); // You've been revived! It's a miracle!
1210 return 0;
1211}
1212
1213/*==========================================
1214 * +kamic [LuzZza]
1215 *------------------------------------------*/
1216ACMD_FUNC(kami)
1217{
1218 unsigned long color=0;
1219 nullpo_retr(-1, sd);
1220
1221 memset(atcmd_output, '\0', sizeof(atcmd_output));
1222
1223 if(*(command + 5) != 'c' && *(command + 5) != 'C') {
1224 if (!message || !*message) {
1225 clif_displaymessage(fd, msg_txt(980)); // Please enter a message (usage: @kami <message>).
1226 return -1;
1227 }
1228
1229 sscanf(message, "%199[^\n]", atcmd_output);
1230 if (strstr(command, "l") != NULL)
1231 clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP);
1232 else
1233 intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? 0x10 : 0);
1234 } else {
1235 if(!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) {
1236 clif_displaymessage(fd, msg_txt(981)); // Please enter color and message (usage: @kamic <color> <message>).
1237 return -1;
1238 }
1239
1240 if(color > 0xFFFFFF) {
1241 clif_displaymessage(fd, msg_txt(982)); // Invalid color.
1242 return -1;
1243 }
1244 intif_broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0);
1245 }
1246 return 0;
1247}
1248
1249/*==========================================
1250 *
1251 *------------------------------------------*/
1252ACMD_FUNC(heal)
1253{
1254 int hp = 0, sp = 0; // [Valaris] thanks to fov
1255 nullpo_retr(-1, sd);
1256
1257 sscanf(message, "%d %d", &hp, &sp);
1258
1259 // some overflow checks
1260 if( hp == INT_MIN ) hp++;
1261 if( sp == INT_MIN ) sp++;
1262
1263 if ( hp == 0 && sp == 0 ) {
1264 if (!status_percent_heal(&sd->bl, 100, 100))
1265 clif_displaymessage(fd, msg_txt(157)); // HP and SP have already been recovered.
1266 else
1267 clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered.
1268 return 0;
1269 }
1270
1271 if ( hp > 0 && sp >= 0 ) {
1272 if(!status_heal(&sd->bl, hp, sp, 0))
1273 clif_displaymessage(fd, msg_txt(157)); // HP and SP are already with the good value.
1274 else
1275 clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered.
1276 return 0;
1277 }
1278
1279 if ( hp < 0 && sp <= 0 ) {
1280 status_damage(NULL, &sd->bl, -hp, -sp, 0, 0);
1281 clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0);
1282 clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified.
1283 return 0;
1284 }
1285
1286 //Opposing signs.
1287 if ( hp ) {
1288 if (hp > 0)
1289 status_heal(&sd->bl, hp, 0, 0);
1290 else {
1291 status_damage(NULL, &sd->bl, -hp, 0, 0, 0);
1292 clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0);
1293 }
1294 }
1295
1296 if ( sp ) {
1297 if (sp > 0)
1298 status_heal(&sd->bl, 0, sp, 0);
1299 else
1300 status_damage(NULL, &sd->bl, 0, -sp, 0, 0);
1301 }
1302
1303 clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified.
1304 return 0;
1305}
1306
1307/*==========================================
1308 * @item command (usage: @item <name/id_of_item> <quantity>) (modified by [Yor] for pet_egg)
1309 *------------------------------------------*/
1310ACMD_FUNC(item)
1311{
1312 char item_name[100];
1313 int number = 0, item_id, flag = 0, type = 0;
1314 struct item item_tmp;
1315 struct item_data *item_data;
1316 int get_count, i;
1317 nullpo_retr(-1, sd);
1318
1319 memset(item_name, '\0', sizeof(item_name));
1320
1321 if (!message || !*message || (
1322 sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 &&
1323 sscanf(message, "%99s %d", item_name, &number) < 1
1324 )) {
1325 clif_displaymessage(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity>).
1326 return -1;
1327 }
1328
1329 if (number <= 0)
1330 number = 1;
1331
1332 if ((item_data = itemdb_searchname(item_name)) == NULL &&
1333 (item_data = itemdb_exists(atoi(item_name))) == NULL)
1334 {
1335 clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
1336 return -1;
1337 }
1338
1339 if( !strcmpi(command+1,"bounditem") )
1340 type = 1;
1341 else if( !strcmpi(command+1,"costumeitem") )
1342 {
1343 if( !battle_config.costume_reserved_char_id )
1344 {
1345 clif_displaymessage(fd, "Costume convertion is disable. Set a value for costume_reserved_char_id on your eAmod.conf file.");
1346 return -1;
1347 }
1348 if( !(item_data->equip&EQP_HEAD_LOW) &&
1349 !(item_data->equip&EQP_HEAD_MID) &&
1350 !(item_data->equip&EQP_HEAD_TOP) &&
1351 !(item_data->equip&EQP_COS_HEAD_LOW) &&
1352 !(item_data->equip&EQP_COS_HEAD_MID) &&
1353 !(item_data->equip&EQP_COS_HEAD_TOP) )
1354 {
1355 clif_displaymessage(fd, "You cannot costume this item. Costume only work for headgears");
1356 return -1;
1357 }
1358 type = 2;
1359 }
1360
1361 item_id = item_data->nameid;
1362 get_count = number;
1363 //Check if it's stackable.
1364 if( !itemdb_isstackable2(item_data) )
1365 {
1366 if( type == 1 && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) )
1367 {
1368 clif_displaymessage(fd, "Cannot create bounded pet eggs or pet armors.");
1369 return -1;
1370 }
1371 get_count = 1;
1372 }
1373 else if( type == 1 )
1374 {
1375 clif_displaymessage(fd, "Cannot create bounded stackable items.");
1376 return -1;
1377 }
1378
1379 for( i = 0; i < number; i += get_count )
1380 {
1381 // if not pet egg
1382 if( !pet_create_egg(sd, item_id) )
1383 {
1384 memset(&item_tmp, 0, sizeof(item_tmp));
1385 item_tmp.nameid = item_id;
1386 item_tmp.identify = 1;
1387 if( type == 1 )
1388 item_tmp.bound = 1;
1389 else if( type == 2 )
1390 { // Costume Item
1391 item_tmp.card[0] = CARD0_CREATE;
1392 item_tmp.card[2] = GetWord(battle_config.costume_reserved_char_id, 0);
1393 item_tmp.card[3] = GetWord(battle_config.costume_reserved_char_id, 1);
1394 }
1395
1396 if( (flag = pc_additem(sd, &item_tmp, get_count,LOG_TYPE_COMMAND)) )
1397 clif_additem(sd, 0, 0, flag);
1398 }
1399 }
1400
1401 if (flag == 0)
1402 clif_displaymessage(fd, msg_txt(18)); // Item created.
1403 return 0;
1404}
1405
1406/*==========================================
1407 *
1408 *------------------------------------------*/
1409ACMD_FUNC(item2)
1410{
1411 struct item item_tmp;
1412 struct item_data *item_data;
1413 char item_name[100];
1414 int item_id, number = 0, bound = 0;
1415 int identify = 0, refine = 0, attr = 0;
1416 int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1417 int flag = 0;
1418 int loop, get_count, i;
1419 nullpo_retr(-1, sd);
1420
1421 memset(item_name, '\0', sizeof(item_name));
1422
1423 if (!message || !*message || (
1424 sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 &&
1425 sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9
1426 )) {
1427 clif_displaymessage(fd, msg_txt(984)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity>
1428 clif_displaymessage(fd, msg_txt(985)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4>).
1429 return -1;
1430 }
1431
1432 if (number <= 0)
1433 number = 1;
1434
1435 item_id = 0;
1436 if ((item_data = itemdb_searchname(item_name)) != NULL ||
1437 (item_data = itemdb_exists(atoi(item_name))) != NULL)
1438 item_id = item_data->nameid;
1439
1440 if( item_id > 500 )
1441 {
1442 if( !strcmpi(command+1,"bounditem2") )
1443 bound = 1;
1444
1445 if( !itemdb_isstackable2(item_data) )
1446 {
1447 if( bound && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) )
1448 {
1449 clif_displaymessage(fd, "Cannot create bounded pet eggs or pet armors.");
1450 return -1;
1451 }
1452
1453 loop = number;
1454 get_count = 1;
1455 if( item_data->type == IT_PETEGG )
1456 {
1457 identify = 1;
1458 refine = 0;
1459 }
1460 if( item_data->type == IT_PETARMOR )
1461 refine = 0;
1462 if( refine > MAX_REFINE )
1463 refine = MAX_REFINE;
1464 }
1465 else
1466 {
1467 if( bound )
1468 {
1469 clif_displaymessage(fd, "Cannot create bounded stackable items.");
1470 return -1;
1471 }
1472
1473 loop = 1;
1474 get_count = number;
1475 identify = 1;
1476 refine = attr = 0;
1477 }
1478
1479 for( i = 0; i < loop; i++ )
1480 {
1481 memset(&item_tmp, 0, sizeof(item_tmp));
1482 item_tmp.nameid = item_id;
1483 item_tmp.identify = identify;
1484 item_tmp.refine = refine;
1485 item_tmp.attribute = attr;
1486 item_tmp.card[0] = c1;
1487 item_tmp.card[1] = c2;
1488 item_tmp.card[2] = c3;
1489 item_tmp.card[3] = c4;
1490 item_tmp.bound = bound;
1491
1492 if( (flag = pc_additem(sd, &item_tmp, get_count,LOG_TYPE_COMMAND)) )
1493 clif_additem(sd, 0, 0, flag);
1494 }
1495
1496 if (flag == 0)
1497 clif_displaymessage(fd, msg_txt(18)); // Item created.
1498 }
1499 else
1500 {
1501 clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
1502 return -1;
1503 }
1504
1505 return 0;
1506}
1507
1508/*==========================================
1509 *
1510 *------------------------------------------*/
1511ACMD_FUNC(itemreset)
1512{
1513 int i;
1514 nullpo_retr(-1, sd);
1515
1516 for (i = 0; i < MAX_INVENTORY; i++) {
1517 if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) {
1518 pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_COMMAND);
1519 }
1520 }
1521 clif_displaymessage(fd, msg_txt(20)); // All of your items have been removed.
1522
1523 return 0;
1524}
1525
1526/*==========================================
1527 * Atcommand @lvlup
1528 *------------------------------------------*/
1529ACMD_FUNC(baselevelup)
1530{
1531 int level=0, i=0, status_point=0;
1532 nullpo_retr(-1, sd);
1533 level = atoi(message);
1534
1535 if (!message || !*message || !level) {
1536 clif_displaymessage(fd, msg_txt(986)); // Please enter a level adjustment (usage: @lvup/@blevel/@baselvlup <number of levels>).
1537 return -1;
1538 }
1539
1540 if (level > 0) {
1541 if (sd->status.base_level >= pc_maxbaselv(sd)) { // check for max level by Valaris
1542 clif_displaymessage(fd, msg_txt(47)); // Base level can't go any higher.
1543 return -1;
1544 } // End Addition
1545 if ((unsigned int)level > pc_maxbaselv(sd) || (unsigned int)level > pc_maxbaselv(sd) - sd->status.base_level) // fix positiv overflow
1546 level = pc_maxbaselv(sd) - sd->status.base_level;
1547 for (i = 0; i < level; i++)
1548 status_point += pc_gets_status_point(sd->status.base_level + i);
1549
1550 sd->status.status_point += status_point;
1551 sd->status.base_level += (unsigned int)level;
1552 status_percent_heal(&sd->bl, 100, 100);
1553 clif_misceffect(&sd->bl, 0);
1554 clif_displaymessage(fd, msg_txt(21)); // Base level raised.
1555 } else {
1556 if (sd->status.base_level == 1) {
1557 clif_displaymessage(fd, msg_txt(158)); // Base level can't go any lower.
1558 return -1;
1559 }
1560 level*=-1;
1561 if ((unsigned int)level >= sd->status.base_level)
1562 level = sd->status.base_level-1;
1563 for (i = 0; i > -level; i--)
1564 status_point += pc_gets_status_point(sd->status.base_level + i - 1);
1565 if (sd->status.status_point < status_point)
1566 pc_resetstate(sd);
1567 if (sd->status.status_point < status_point)
1568 sd->status.status_point = 0;
1569 else
1570 sd->status.status_point -= status_point;
1571 sd->status.base_level -= (unsigned int)level;
1572 clif_displaymessage(fd, msg_txt(22)); // Base level lowered.
1573 }
1574 sd->status.base_exp = 0;
1575 clif_updatestatus(sd, SP_STATUSPOINT);
1576 clif_updatestatus(sd, SP_BASELEVEL);
1577 clif_updatestatus(sd, SP_BASEEXP);
1578 clif_updatestatus(sd, SP_NEXTBASEEXP);
1579 status_calc_pc(sd, 0);
1580 pc_baselevelchanged(sd);
1581 if(sd->status.party_id)
1582 party_send_levelup(sd);
1583 return 0;
1584}
1585
1586/*==========================================
1587 *
1588 *------------------------------------------*/
1589ACMD_FUNC(joblevelup)
1590{
1591 int level=0;
1592 nullpo_retr(-1, sd);
1593
1594 level = atoi(message);
1595
1596 if (!message || !*message || !level) {
1597 clif_displaymessage(fd, msg_txt(987)); // Please enter a level adjustment (usage: @joblvup/@jlevel/@joblvlup <number of levels>).
1598 return -1;
1599 }
1600 if (level > 0) {
1601 if (sd->status.job_level >= pc_maxjoblv(sd)) {
1602 clif_displaymessage(fd, msg_txt(23)); // Job level can't go any higher.
1603 return -1;
1604 }
1605 if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positiv overflow
1606 level = pc_maxjoblv(sd) - sd->status.job_level;
1607 sd->status.job_level += (unsigned int)level;
1608 sd->status.skill_point += level;
1609 clif_misceffect(&sd->bl, 1);
1610 clif_displaymessage(fd, msg_txt(24)); // Job level raised.
1611 } else {
1612 if (sd->status.job_level == 1) {
1613 clif_displaymessage(fd, msg_txt(159)); // Job level can't go any lower.
1614 return -1;
1615 }
1616 level *=-1;
1617 if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow
1618 level = sd->status.job_level-1;
1619 sd->status.job_level -= (unsigned int)level;
1620 if (sd->status.skill_point < level)
1621 pc_resetskill(sd,0); //Reset skills since we need to substract more points.
1622 if (sd->status.skill_point < level)
1623 sd->status.skill_point = 0;
1624 else
1625 sd->status.skill_point -= level;
1626 clif_displaymessage(fd, msg_txt(25)); // Job level lowered.
1627 }
1628 sd->status.job_exp = 0;
1629 clif_updatestatus(sd, SP_JOBLEVEL);
1630 clif_updatestatus(sd, SP_JOBEXP);
1631 clif_updatestatus(sd, SP_NEXTJOBEXP);
1632 clif_updatestatus(sd, SP_SKILLPOINT);
1633 status_calc_pc(sd, 0);
1634
1635 return 0;
1636}
1637
1638/*==========================================
1639 * @help
1640 *------------------------------------------*/
1641ACMD_FUNC(help)
1642{
1643 config_setting_t *help;
1644 const char *text = NULL;
1645 const char *command_name = NULL;
1646 char *default_command = "help";
1647
1648 nullpo_retr(-1, sd);
1649
1650 help = config_lookup(&atcommand_config, "help");
1651 if (help == NULL) {
1652 clif_displaymessage(fd, msg_txt(27)); // "Commands help is not available."
1653 return -1;
1654 }
1655
1656 if (!message || !*message) {
1657 command_name = default_command; // If no command_name specified, display help for @help.
1658 } else {
1659 if (*message == atcommand_symbol || *message == charcommand_symbol)
1660 ++message;
1661 command_name = atcommand_checkalias(message);
1662 }
1663
1664 if (!pc_can_use_command(sd, command_name, COMMAND_ATCOMMAND)) {
1665 sprintf(atcmd_output, msg_txt(153), message); // "%s is Unknown Command"
1666 clif_displaymessage(fd, atcmd_output);
1667 atcommand_get_suggestions(sd, command_name, true);
1668 return -1;
1669 }
1670
1671 if (!config_setting_lookup_string(help, command_name, &text)) {
1672 sprintf(atcmd_output, msg_txt(988), atcommand_symbol, command_name); // There is no help for %c%s.
1673 clif_displaymessage(fd, atcmd_output);
1674 atcommand_get_suggestions(sd, command_name, true);
1675 return -1;
1676 }
1677
1678 sprintf(atcmd_output, msg_txt(989), atcommand_symbol, command_name); // Help for command %c%s:
1679 clif_displaymessage(fd, atcmd_output);
1680
1681 { // Display aliases
1682 DBIterator* iter;
1683 AtCommandInfo *command_info;
1684 AliasInfo *alias_info = NULL;
1685 StringBuf buf;
1686 bool has_aliases = false;
1687
1688 StringBuf_Init(&buf);
1689 StringBuf_AppendStr(&buf, msg_txt(990)); // Available aliases:
1690 command_info = get_atcommandinfo_byname(command_name);
1691 iter = db_iterator(atcommand_alias_db);
1692 for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) {
1693 if (alias_info->command == command_info) {
1694 StringBuf_Printf(&buf, " %s", alias_info->alias);
1695 has_aliases = true;
1696 }
1697 }
1698 dbi_destroy(iter);
1699 if (has_aliases)
1700 clif_displaymessage(fd, StringBuf_Value(&buf));
1701 StringBuf_Destroy(&buf);
1702 }
1703
1704 // Display help contents
1705 clif_displaymessage(fd, text);
1706 return 0;
1707}
1708
1709// helper function, used in foreach calls to stop auto-attack timers
1710// parameter: '0' - everyone, 'id' - only those attacking someone with that id
1711static int atcommand_stopattack(struct block_list *bl,va_list ap)
1712{
1713 struct unit_data *ud = unit_bl2ud(bl);
1714 int id = va_arg(ap, int);
1715 if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target))
1716 {
1717 unit_stop_attack(bl);
1718 return 1;
1719 }
1720 return 0;
1721}
1722/*==========================================
1723 *
1724 *------------------------------------------*/
1725static int atcommand_pvpoff_sub(struct block_list *bl,va_list ap)
1726{
1727 TBL_PC* sd = (TBL_PC*)bl;
1728 clif_pvpset(sd, 0, 0, 2);
1729 if (sd->pvp_timer != INVALID_TIMER) {
1730 delete_timer(sd->pvp_timer, pc_calc_pvprank_timer);
1731 sd->pvp_timer = INVALID_TIMER;
1732 }
1733 return 0;
1734}
1735
1736ACMD_FUNC(pvpoff)
1737{
1738 nullpo_retr(-1, sd);
1739
1740 if (!map[sd->bl.m].flag.pvp) {
1741 clif_displaymessage(fd, msg_txt(160)); // PvP is already Off.
1742 return -1;
1743 }
1744
1745 map[sd->bl.m].flag.pvp = 0;
1746
1747 if (!battle_config.pk_mode)
1748 clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING);
1749 map_foreachinmap(atcommand_pvpoff_sub,sd->bl.m, BL_PC);
1750 map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0);
1751 clif_displaymessage(fd, msg_txt(31)); // PvP: Off.
1752 return 0;
1753}
1754
1755/*==========================================
1756 *
1757 *------------------------------------------*/
1758static int atcommand_pvpon_sub(struct block_list *bl,va_list ap)
1759{
1760 TBL_PC* sd = (TBL_PC*)bl;
1761 if (sd->state.pvpmode)
1762 pc_pvpmodeoff(sd, 1, 1);
1763 if (sd->pvp_timer == INVALID_TIMER) {
1764 sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0);
1765 sd->pvp_rank = 0;
1766 sd->pvp_lastusers = 0;
1767 sd->pvp_point = 5;
1768 sd->pvp_won = 0;
1769 sd->pvp_lost = 0;
1770 }
1771 return 0;
1772}
1773
1774ACMD_FUNC(pvpon)
1775{
1776 nullpo_retr(-1, sd);
1777
1778 if (map[sd->bl.m].flag.pvp) {
1779 clif_displaymessage(fd, msg_txt(161)); // PvP is already On.
1780 return -1;
1781 }
1782
1783 map[sd->bl.m].flag.pvp = 1;
1784
1785 if (!battle_config.pk_mode)
1786 {// display pvp circle and rank
1787 clif_map_property_mapall(sd->bl.m, MAPPROPERTY_FREEPVPZONE);
1788 map_foreachinmap(atcommand_pvpon_sub,sd->bl.m, BL_PC);
1789 }
1790
1791 clif_displaymessage(fd, msg_txt(32)); // PvP: On.
1792
1793 return 0;
1794}
1795
1796/*==========================================
1797 *
1798 *------------------------------------------*/
1799ACMD_FUNC(gvgoff)
1800{
1801 nullpo_retr(-1, sd);
1802
1803 if (!map[sd->bl.m].flag.gvg) {
1804 clif_displaymessage(fd, msg_txt(162)); // GvG is already Off.
1805 return -1;
1806 }
1807
1808 map[sd->bl.m].flag.gvg = 0;
1809 clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING);
1810 map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0);
1811 clif_displaymessage(fd, msg_txt(33)); // GvG: Off.
1812
1813 return 0;
1814}
1815
1816/*==========================================
1817 *
1818 *------------------------------------------*/
1819ACMD_FUNC(gvgon)
1820{
1821 nullpo_retr(-1, sd);
1822
1823 if (map[sd->bl.m].flag.gvg) {
1824 clif_displaymessage(fd, msg_txt(163)); // GvG is already On.
1825 return -1;
1826 }
1827
1828 map[sd->bl.m].flag.gvg = 1;
1829 clif_map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE);
1830 clif_displaymessage(fd, msg_txt(34)); // GvG: On.
1831
1832 return 0;
1833}
1834
1835/*==========================================
1836 *
1837 *------------------------------------------*/
1838ACMD_FUNC(model)
1839{
1840 int hair_style = 0, hair_color = 0, cloth_color = 0;
1841 nullpo_retr(-1, sd);
1842
1843 memset(atcmd_output, '\0', sizeof(atcmd_output));
1844
1845 if (!message || !*message || sscanf(message, "%d %d %d", &hair_style, &hair_color, &cloth_color) < 1) {
1846 sprintf(atcmd_output, msg_txt(991), // Please enter at least one value (usage: @model <hair ID: %d-%d> <hair color: %d-%d> <clothes color: %d-%d>).
1847 MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
1848 clif_displaymessage(fd, atcmd_output);
1849 return -1;
1850 }
1851
1852 if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE &&
1853 hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR &&
1854 cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) {
1855 pc_changelook(sd, LOOK_HAIR, hair_style);
1856 pc_changelook(sd, LOOK_HAIR_COLOR, hair_color);
1857 pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color);
1858 clif_displaymessage(fd, msg_txt(36)); // Appearence changed.
1859 } else {
1860 clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified.
1861 return -1;
1862 }
1863
1864 return 0;
1865}
1866
1867/*==========================================
1868 * @dye && @ccolor
1869 *------------------------------------------*/
1870ACMD_FUNC(dye)
1871{
1872 int cloth_color = 0;
1873 nullpo_retr(-1, sd);
1874
1875 memset(atcmd_output, '\0', sizeof(atcmd_output));
1876
1877 if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) {
1878 sprintf(atcmd_output, msg_txt(992), MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); // Please enter a clothes color (usage: @dye/@ccolor <clothes color: %d-%d>).
1879 clif_displaymessage(fd, atcmd_output);
1880 return -1;
1881 }
1882
1883 if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) {
1884 pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color);
1885 clif_displaymessage(fd, msg_txt(36)); // Appearence changed.
1886 } else {
1887 clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified.
1888 return -1;
1889 }
1890
1891 return 0;
1892}
1893
1894/*==========================================
1895 * @hairstyle && @hstyle
1896 *------------------------------------------*/
1897ACMD_FUNC(hair_style)
1898{
1899 int hair_style = 0;
1900 nullpo_retr(-1, sd);
1901
1902 memset(atcmd_output, '\0', sizeof(atcmd_output));
1903
1904 if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) {
1905 sprintf(atcmd_output, msg_txt(993), MIN_HAIR_STYLE, MAX_HAIR_STYLE); // Please enter a hair style (usage: @hairstyle/@hstyle <hair ID: %d-%d>).
1906 clif_displaymessage(fd, atcmd_output);
1907 return -1;
1908 }
1909
1910 if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) {
1911 pc_changelook(sd, LOOK_HAIR, hair_style);
1912 clif_displaymessage(fd, msg_txt(36)); // Appearence changed.
1913 } else {
1914 clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified.
1915 return -1;
1916 }
1917
1918 return 0;
1919}
1920
1921/*==========================================
1922 * @haircolor && @hcolor
1923 *------------------------------------------*/
1924ACMD_FUNC(hair_color)
1925{
1926 int hair_color = 0;
1927 nullpo_retr(-1, sd);
1928
1929 memset(atcmd_output, '\0', sizeof(atcmd_output));
1930
1931 if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) {
1932 sprintf(atcmd_output, msg_txt(994), MIN_HAIR_COLOR, MAX_HAIR_COLOR); // Please enter a hair color (usage: @haircolor/@hcolor <hair color: %d-%d>).
1933 clif_displaymessage(fd, atcmd_output);
1934 return -1;
1935 }
1936
1937 if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) {
1938 pc_changelook(sd, LOOK_HAIR_COLOR, hair_color);
1939 clif_displaymessage(fd, msg_txt(36)); // Appearence changed.
1940 } else {
1941 clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified.
1942 return -1;
1943 }
1944
1945 return 0;
1946}
1947
1948/*==========================================
1949 * @go [city_number or city_name] - Updated by Harbin
1950 *------------------------------------------*/
1951ACMD_FUNC(go)
1952{
1953 int i;
1954 int town;
1955 char map_name[MAP_NAME_LENGTH];
1956 int m;
1957
1958 const struct {
1959 char map[MAP_NAME_LENGTH];
1960 int x, y;
1961 } data[] = {
1962 { MAP_PRONTERA, 156, 191 }, // 0=Prontera
1963 { MAP_MORROC, 156, 93 }, // 1=Morroc
1964 { MAP_GEFFEN, 119, 59 }, // 2=Geffen
1965 { MAP_PAYON, 162, 233 }, // 3=Payon
1966 { MAP_ALBERTA, 192, 147 }, // 4=Alberta
1967#ifdef RENEWAL
1968 { MAP_IZLUDE, 128, 146 }, // 5=Izlude (Renewal)
1969#else
1970 { MAP_IZLUDE, 128, 114 }, // 5=Izlude
1971#endif
1972 { MAP_ALDEBARAN, 140, 131 }, // 6=Al de Baran
1973 { MAP_LUTIE, 147, 134 }, // 7=Lutie
1974 { MAP_COMODO, 209, 143 }, // 8=Comodo
1975 { MAP_YUNO, 157, 51 }, // 9=Yuno
1976 { MAP_AMATSU, 198, 84 }, // 10=Amatsu
1977 { MAP_GONRYUN, 160, 120 }, // 11=Gonryun
1978 { MAP_UMBALA, 89, 157 }, // 12=Umbala
1979 { MAP_NIFLHEIM, 21, 153 }, // 13=Niflheim
1980 { MAP_LOUYANG, 217, 40 }, // 14=Louyang
1981 { MAP_NOVICE, 53, 111 }, // 15=Training Grounds
1982 { MAP_JAIL, 23, 61 }, // 16=Prison
1983 { MAP_JAWAII, 249, 127 }, // 17=Jawaii
1984 { MAP_AYOTHAYA, 151, 117 }, // 18=Ayothaya
1985 { MAP_EINBROCH, 64, 200 }, // 19=Einbroch
1986 { MAP_LIGHTHALZEN, 158, 92 }, // 20=Lighthalzen
1987 { MAP_EINBECH, 70, 95 }, // 21=Einbech
1988 { MAP_HUGEL, 96, 145 }, // 22=Hugel
1989 { MAP_RACHEL, 130, 110 }, // 23=Rachel
1990 { MAP_VEINS, 216, 123 }, // 24=Veins
1991 { MAP_MOSCOVIA, 223, 184 }, // 25=Moscovia
1992 { MAP_MIDCAMP, 180, 240 }, // 26=Midgard Camp
1993 { MAP_MANUK, 282, 138 }, // 27=Manuk
1994 { MAP_SPLENDIDE, 197, 176 }, // 28=Splendide
1995 { MAP_BRASILIS, 182, 239 }, // 29=Brasilis
1996 { MAP_DICASTES, 198, 187 }, // 30=El Dicastes
1997 { MAP_MORA, 44, 151 }, // 31=Mora
1998 { MAP_DEWATA, 200, 180 }, // 32=Dewata
1999 { MAP_MALANGDO, 140, 114 }, // 33=Malangdo Island
2000 { MAP_MALAYA, 242, 211 }, // 34=Malaya Port
2001 { MAP_ECLAGE, 110, 39 }, // 35=Eclage
2002 };
2003
2004 nullpo_retr(-1, sd);
2005
2006 if( map[sd->bl.m].flag.nogo && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) {
2007 clif_displaymessage(sd->fd,msg_txt(995)); // You cannot use @go on this map.
2008 return 0;
2009 }
2010
2011 if( battle_config.pvpmode_nowarp_cmd && sd->state.pvpmode )
2012 {
2013 clif_displaymessage(sd->fd,"You can not use @go while on PVP Mode.");
2014 return -1;
2015 }
2016
2017 memset(map_name, '\0', sizeof(map_name));
2018 memset(atcmd_output, '\0', sizeof(atcmd_output));
2019
2020 // get the number
2021 town = atoi(message);
2022
2023 if (!message || !*message || sscanf(message, "%11s", map_name) < 1 || town < 0 || town >= ARRAYLENGTH(data))
2024 {// no value matched so send the list of locations
2025 const char* text;
2026
2027 // attempt to find the text help string
2028 text = atcommand_help_string( command );
2029
2030 clif_displaymessage(fd, msg_txt(38)); // Invalid location number, or name.
2031
2032 if( text )
2033 {// send the text to the client
2034 clif_displaymessage( fd, text );
2035 }
2036
2037 return -1;
2038 }
2039
2040 // get possible name of the city
2041 map_name[MAP_NAME_LENGTH-1] = '\0';
2042 for (i = 0; map_name[i]; i++)
2043 map_name[i] = TOLOWER(map_name[i]);
2044 // try to identify the map name
2045 if (strncmp(map_name, "prontera", 3) == 0) {
2046 town = 0;
2047 } else if (strncmp(map_name, "morocc", 4) == 0 ||
2048 strncmp(map_name, "morroc", 4) == 0) {
2049 town = 1;
2050 } else if (strncmp(map_name, "geffen", 3) == 0) {
2051 town = 2;
2052 } else if (strncmp(map_name, "payon", 3) == 0) {
2053 town = 3;
2054 } else if (strncmp(map_name, "alberta", 3) == 0) {
2055 town = 4;
2056 } else if (strncmp(map_name, "izlude", 3) == 0) {
2057 town = 5;
2058 } else if (strncmp(map_name, "aldebaran", 3) == 0) {
2059 town = 6;
2060 } else if (strncmp(map_name, "lutie", 3) == 0 ||
2061 strcmp(map_name, "christmas") == 0 ||
2062 strncmp(map_name, "xmas", 3) == 0 ||
2063 strncmp(map_name, "x-mas", 3) == 0) {
2064 town = 7;
2065 } else if (strncmp(map_name, "comodo", 3) == 0) {
2066 town = 8;
2067 } else if (strncmp(map_name, "juno", 3) == 0 ||
2068 strncmp(map_name, "yuno", 3) == 0) {
2069 town = 9;
2070 } else if (strncmp(map_name, "amatsu", 3) == 0) {
2071 town = 10;
2072 } else if (strncmp(map_name, "kunlun", 3) == 0 ||
2073 strncmp(map_name, "gonryun", 3) == 0) {
2074 town = 11;
2075 } else if (strncmp(map_name, "umbala", 3) == 0) {
2076 town = 12;
2077 } else if (strncmp(map_name, "niflheim", 3) == 0) {
2078 town = 13;
2079 } else if (strncmp(map_name, "louyang", 3) == 0) {
2080 town = 14;
2081 } else if (strncmp(map_name, "new_1-1", 3) == 0 ||
2082 strncmp(map_name, "startpoint", 3) == 0 ||
2083 strncmp(map_name, "beginning", 3) == 0) {
2084 town = 15;
2085 } else if (strncmp(map_name, "sec_pri", 3) == 0 ||
2086 strncmp(map_name, "prison", 3) == 0 ||
2087 strncmp(map_name, "jail", 3) == 0) {
2088 town = 16;
2089 } else if (strncmp(map_name, "jawaii", 3) == 0) {
2090 town = 17;
2091 } else if (strncmp(map_name, "ayothaya", 3) == 0) {
2092 town = 18;
2093 } else if (strncmp(map_name, "einbroch", 5) == 0) {
2094 town = 19;
2095 } else if (strncmp(map_name, "lighthalzen", 3) == 0) {
2096 town = 20;
2097 } else if (strncmp(map_name, "einbech", 5) == 0) {
2098 town = 21;
2099 } else if (strncmp(map_name, "hugel", 3) == 0) {
2100 town = 22;
2101 } else if (strncmp(map_name, "rachel", 3) == 0) {
2102 town = 23;
2103 } else if (strncmp(map_name, "veins", 3) == 0) {
2104 town = 24;
2105 } else if (strncmp(map_name, "moscovia", 3) == 0) {
2106 town = 25;
2107 } else if (strncmp(map_name, "mid_camp", 3) == 0) {
2108 town = 26;
2109 } else if (strncmp(map_name, "manuk", 3) == 0) {
2110 town = 27;
2111 } else if (strncmp(map_name, "splendide", 3) == 0) {
2112 town = 28;
2113 } else if (strncmp(map_name, "brasilis", 3) == 0) {
2114 town = 29;
2115 } else if (strncmp(map_name, "dicastes01", 3) == 0) {
2116 town = 30;
2117 } else if (strcmp(map_name, "mora") == 0) {
2118 town = 31;
2119 } else if (strncmp(map_name, "dewata", 3) == 0) {
2120 town = 32;
2121 } else if (strncmp(map_name, "malangdo", 5) == 0) {
2122 town = 33;
2123 } else if (strncmp(map_name, "malaya", 5) == 0) {
2124 town = 34;
2125 } else if (strncmp(map_name, "eclage", 3) == 0) {
2126 town = 35;
2127 }
2128
2129 if (town >= 0 && town < ARRAYLENGTH(data))
2130 {
2131 m = map_mapname2mapid(data[town].map);
2132 if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
2133 clif_displaymessage(fd, msg_txt(247));
2134 return -1;
2135 }
2136 if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
2137 clif_displaymessage(fd, msg_txt(248));
2138 return -1;
2139 }
2140 if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) {
2141 clif_displaymessage(fd, msg_txt(0)); // Warped.
2142 } else {
2143 clif_displaymessage(fd, msg_txt(1)); // Map not found.
2144 return -1;
2145 }
2146 } else { // if you arrive here, you have an error in town variable when reading of names
2147 clif_displaymessage(fd, msg_txt(38)); // Invalid location number or name.
2148 return -1;
2149 }
2150
2151 return 0;
2152}
2153
2154/*==========================================
2155 *
2156 *------------------------------------------*/
2157ACMD_FUNC(monster)
2158{
2159 char name[NAME_LENGTH];
2160 char monster[NAME_LENGTH];
2161 char eventname[EVENT_NAME_LENGTH] = "";
2162 int mob_id;
2163 int number = 0;
2164 int count;
2165 int i, k, range;
2166 short mx, my;
2167 nullpo_retr(-1, sd);
2168
2169 memset(name, '\0', sizeof(name));
2170 memset(monster, '\0', sizeof(monster));
2171 memset(atcmd_output, '\0', sizeof(atcmd_output));
2172
2173 if (!message || !*message) {
2174 clif_displaymessage(fd, msg_txt(80)); // Give the display name or monster name/id please.
2175 return -1;
2176 }
2177 if (sscanf(message, "\"%23[^\"]\" %23s %d", name, monster, &number) > 1 ||
2178 sscanf(message, "%23s \"%23[^\"]\" %d", monster, name, &number) > 1) {
2179 //All data can be left as it is.
2180 } else if ((count=sscanf(message, "%23s %d %23s", monster, &number, name)) > 1) {
2181 //Here, it is possible name was not given and we are using monster for it.
2182 if (count < 3) //Blank mob's name.
2183 name[0] = '\0';
2184 } else if (sscanf(message, "%23s %23s %d", name, monster, &number) > 1) {
2185 //All data can be left as it is.
2186 } else if (sscanf(message, "%23s", monster) > 0) {
2187 //As before, name may be already filled.
2188 name[0] = '\0';
2189 } else {
2190 clif_displaymessage(fd, msg_txt(80)); // Give a display name and monster name/id please.
2191 return -1;
2192 }
2193
2194 if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number)
2195 mob_id = mobdb_checkid(atoi(monster));
2196
2197 if (mob_id == 0) {
2198 clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name.
2199 return -1;
2200 }
2201
2202 if (mob_id == MOBID_EMPERIUM) {
2203 clif_displaymessage(fd, msg_txt(83)); // Monster 'Emperium' cannot be spawned.
2204 return -1;
2205 }
2206
2207 if (number <= 0)
2208 number = 1;
2209
2210 if( !name[0] )
2211 strcpy(name, "--ja--");
2212
2213 // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive
2214 if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit)
2215 number = battle_config.atc_spawn_quantity_limit;
2216
2217 if (strcmp(command+1, "monstersmall") == 0)
2218 strcpy(eventname, "2");
2219 else if (strcmp(command+1, "monsterbig") == 0)
2220 strcpy(eventname, "4");
2221
2222 if (battle_config.etc_log)
2223 ShowInfo("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, sd->bl.x, sd->bl.y);
2224
2225 count = 0;
2226 range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around)
2227 for (i = 0; i < number; i++) {
2228 map_search_freecell(&sd->bl, 0, &mx, &my, range, range, 0);
2229 k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname);
2230 count += (k != 0) ? 1 : 0;
2231 }
2232
2233 if (count != 0)
2234 if (number == count)
2235 clif_displaymessage(fd, msg_txt(39)); // All monster summoned!
2236 else {
2237 sprintf(atcmd_output, msg_txt(240), count); // %d monster(s) summoned!
2238 clif_displaymessage(fd, atcmd_output);
2239 }
2240 else {
2241 clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name.
2242 return -1;
2243 }
2244
2245 return 0;
2246}
2247
2248/*==========================================
2249 *
2250 *------------------------------------------*/
2251static int atkillmonster_sub(struct block_list *bl, va_list ap)
2252{
2253 struct mob_data *md;
2254 int flag;
2255
2256 nullpo_ret(md=(struct mob_data *)bl);
2257 flag = va_arg(ap, int);
2258
2259 if (md->guardian_data)
2260 return 0; //Do not touch WoE mobs!
2261
2262 if (flag)
2263 status_zap(bl,md->status.hp, 0);
2264 else
2265 status_kill(bl);
2266 return 1;
2267}
2268
2269void atcommand_killmonster_sub(const int fd, struct map_session_data* sd, const char* message, const int drop)
2270{
2271 int map_id;
2272 char map_name[MAP_NAME_LENGTH_EXT];
2273
2274 if (!sd) return;
2275
2276 memset(map_name, '\0', sizeof(map_name));
2277
2278 if (!message || !*message || sscanf(message, "%15s", map_name) < 1)
2279 map_id = sd->bl.m;
2280 else {
2281 if ((map_id = map_mapname2mapid(map_name)) < 0)
2282 map_id = sd->bl.m;
2283 }
2284
2285 map_foreachinmap(atkillmonster_sub, map_id, BL_MOB, drop);
2286
2287 clif_displaymessage(fd, msg_txt(165)); // All monsters killed!
2288
2289 return;
2290}
2291
2292ACMD_FUNC(killmonster)
2293{
2294 atcommand_killmonster_sub(fd, sd, message, 1);
2295 return 0;
2296}
2297
2298/*==========================================
2299 *
2300 *------------------------------------------*/
2301ACMD_FUNC(killmonster2)
2302{
2303 atcommand_killmonster_sub(fd, sd, message, 0);
2304 return 0;
2305}
2306
2307/*==========================================
2308 *
2309 *------------------------------------------*/
2310ACMD_FUNC(refine)
2311{
2312 int i,j, position = 0, refine = 0, current_position, final_refine;
2313 int count;
2314 nullpo_retr(-1, sd);
2315
2316 memset(atcmd_output, '\0', sizeof(atcmd_output));
2317
2318 if (!message || !*message || sscanf(message, "%d %d", &position, &refine) < 2) {
2319 clif_displaymessage(fd, msg_txt(996)); // Please enter a position and an amount (usage: @refine <equip position> <+/- amount>).
2320 sprintf(atcmd_output, msg_txt(997), EQP_HEAD_LOW); // %d: Lower Headgear
2321 clif_displaymessage(fd, atcmd_output);
2322 sprintf(atcmd_output, msg_txt(998), EQP_HAND_R); // %d: Right Hand
2323 clif_displaymessage(fd, atcmd_output);
2324 sprintf(atcmd_output, msg_txt(999), EQP_GARMENT); // %d: Garment
2325 clif_displaymessage(fd, atcmd_output);
2326 sprintf(atcmd_output, msg_txt(1000), EQP_ACC_L); // %d: Left Accessory
2327 clif_displaymessage(fd, atcmd_output);
2328 sprintf(atcmd_output, msg_txt(1001), EQP_ARMOR); // %d: Body Armor
2329 clif_displaymessage(fd, atcmd_output);
2330 sprintf(atcmd_output, msg_txt(1002), EQP_HAND_L); // %d: Left Hand
2331 clif_displaymessage(fd, atcmd_output);
2332 sprintf(atcmd_output, msg_txt(1003), EQP_SHOES); // %d: Shoes
2333 clif_displaymessage(fd, atcmd_output);
2334 sprintf(atcmd_output, msg_txt(1004), EQP_ACC_R); // %d: Right Accessory
2335 clif_displaymessage(fd, atcmd_output);
2336 sprintf(atcmd_output, msg_txt(1005), EQP_HEAD_TOP); // %d: Top Headgear
2337 clif_displaymessage(fd, atcmd_output);
2338 sprintf(atcmd_output, msg_txt(1006), EQP_HEAD_MID); // %d: Mid Headgear
2339 clif_displaymessage(fd, atcmd_output);
2340 return -1;
2341 }
2342
2343 refine = cap_value(refine, -MAX_REFINE, MAX_REFINE);
2344
2345 count = 0;
2346 for (j = 0; j < EQI_MAX_BONUS; j++) {
2347 if ((i = sd->equip_index[j]) < 0)
2348 continue;
2349 if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == i)
2350 continue;
2351 if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == i)
2352 continue;
2353 if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == i || sd->equip_index[EQI_HEAD_LOW] == i))
2354 continue;
2355
2356 if(position && !(sd->status.inventory[i].equip & position))
2357 continue;
2358
2359 final_refine = cap_value(sd->status.inventory[i].refine + refine, 0, MAX_REFINE);
2360 if (sd->status.inventory[i].refine != final_refine) {
2361 sd->status.inventory[i].refine = final_refine;
2362 current_position = sd->status.inventory[i].equip;
2363 pc_unequipitem(sd, i, 3);
2364 clif_refine(fd, 0, i, sd->status.inventory[i].refine);
2365 clif_delitem(sd, i, 1, 3);
2366 clif_additem(sd, i, 1, 0);
2367 pc_equipitem(sd, i, current_position);
2368 clif_misceffect(&sd->bl, 3);
2369 count++;
2370 }
2371 }
2372
2373 if (count == 0)
2374 clif_displaymessage(fd, msg_txt(166)); // No item has been refined.
2375 else if (count == 1)
2376 clif_displaymessage(fd, msg_txt(167)); // 1 item has been refined.
2377 else {
2378 sprintf(atcmd_output, msg_txt(168), count); // %d items have been refined.
2379 clif_displaymessage(fd, atcmd_output);
2380 }
2381
2382 return 0;
2383}
2384
2385/*==========================================
2386 *
2387 *------------------------------------------*/
2388ACMD_FUNC(produce)
2389{
2390 char item_name[100];
2391 int item_id, attribute = 0, star = 0;
2392 int flag = 0;
2393 struct item_data *item_data;
2394 struct item tmp_item;
2395 nullpo_retr(-1, sd);
2396
2397 memset(atcmd_output, '\0', sizeof(atcmd_output));
2398 memset(item_name, '\0', sizeof(item_name));
2399
2400 if (!message || !*message || (
2401 sscanf(message, "\"%99[^\"]\" %d %d", item_name, &attribute, &star) < 1 &&
2402 sscanf(message, "%99s %d %d", item_name, &attribute, &star) < 1
2403 )) {
2404 clif_displaymessage(fd, msg_txt(1007)); // Please enter at least one item name/ID (usage: @produce <equip name/ID> <element> <# of very's>).
2405 return -1;
2406 }
2407
2408 if ( (item_data = itemdb_searchname(item_name)) == NULL &&
2409 (item_data = itemdb_exists(atoi(item_name))) == NULL ) {
2410 clif_displaymessage(fd, msg_txt(170)); //This item is not an equipment.
2411 return -1;
2412 }
2413
2414 item_id = item_data->nameid;
2415
2416 if (itemdb_isequip2(item_data)) {
2417 if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE)
2418 attribute = ATTRIBUTE_NORMAL;
2419 if (star < MIN_STAR || star > MAX_STAR)
2420 star = 0;
2421 memset(&tmp_item, 0, sizeof tmp_item);
2422 tmp_item.nameid = item_id;
2423 tmp_item.amount = 1;
2424 tmp_item.identify = 1;
2425 tmp_item.card[0] = CARD0_FORGE;
2426 tmp_item.card[1] = item_data->type==IT_WEAPON?
2427 ((star*5) << 8) + attribute:0;
2428 tmp_item.card[2] = GetWord(sd->status.char_id, 0);
2429 tmp_item.card[3] = GetWord(sd->status.char_id, 1);
2430 clif_produceeffect(sd, 0, item_id);
2431 clif_misceffect(&sd->bl, 3);
2432
2433 if ((flag = pc_additem(sd, &tmp_item, 1, LOG_TYPE_COMMAND)))
2434 clif_additem(sd, 0, 0, flag);
2435 } else {
2436 sprintf(atcmd_output, msg_txt(169), item_id, item_data->name); // The item (%d: '%s') is not equipable.
2437 clif_displaymessage(fd, atcmd_output);
2438 return -1;
2439 }
2440
2441 return 0;
2442}
2443
2444/*==========================================
2445 *
2446 *------------------------------------------*/
2447ACMD_FUNC(memo)
2448{
2449 int position = 0;
2450 nullpo_retr(-1, sd);
2451
2452 memset(atcmd_output, '\0', sizeof(atcmd_output));
2453
2454 if( !message || !*message || sscanf(message, "%d", &position) < 1 )
2455 {
2456 int i;
2457 clif_displaymessage(sd->fd, msg_txt(668));
2458 for( i = 0; i < MAX_MEMOPOINTS; i++ )
2459 {
2460 if( sd->status.memo_point[i].map )
2461 sprintf(atcmd_output, "%d - %s (%d,%d)", i, mapindex_id2name(sd->status.memo_point[i].map), sd->status.memo_point[i].x, sd->status.memo_point[i].y);
2462 else
2463 sprintf(atcmd_output, msg_txt(171), i); // %d - void
2464 clif_displaymessage(sd->fd, atcmd_output);
2465 }
2466 return 0;
2467 }
2468
2469 if( position < 0 || position >= MAX_MEMOPOINTS )
2470 {
2471 sprintf(atcmd_output, msg_txt(1008), 0, MAX_MEMOPOINTS-1); // Please enter a valid position (usage: @memo <memo_position:%d-%d>).
2472 clif_displaymessage(fd, atcmd_output);
2473 return -1;
2474 }
2475
2476 pc_memo(sd, position);
2477 return 0;
2478}
2479
2480/*==========================================
2481 *
2482 *------------------------------------------*/
2483ACMD_FUNC(gat)
2484{
2485 int y;
2486 nullpo_retr(-1, sd);
2487
2488 memset(atcmd_output, '\0', sizeof(atcmd_output));
2489
2490 for (y = 2; y >= -2; y--) {
2491 sprintf(atcmd_output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X",
2492 map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y,
2493 map_getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE),
2494 map_getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE),
2495 map_getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE),
2496 map_getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE),
2497 map_getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE));
2498
2499 clif_displaymessage(fd, atcmd_output);
2500 }
2501
2502 return 0;
2503}
2504
2505/*==========================================
2506 *
2507 *------------------------------------------*/
2508ACMD_FUNC(displaystatus)
2509{
2510 int i, type, flag, tick, val1 = 0, val2 = 0, val3 = 0;
2511 nullpo_retr(-1, sd);
2512
2513 if (!message || !*message || (i = sscanf(message, "%d %d %d %d %d %d", &type, &flag, &tick, &val1, &val2, &val3)) < 1) {
2514 clif_displaymessage(fd, msg_txt(1009)); // Please enter a status type/flag (usage: @displaystatus <status type> <flag> <tick> {<val1> {<val2> {<val3>}}}).
2515 return -1;
2516 }
2517 if (i < 2) flag = 1;
2518 if (i < 3) tick = 0;
2519
2520 clif_status_change(&sd->bl, type, flag, tick, val1, val2, val3);
2521
2522 return 0;
2523}
2524
2525/*==========================================
2526 * @stpoint (Rewritten by [Yor])
2527 *------------------------------------------*/
2528ACMD_FUNC(statuspoint)
2529{
2530 int point;
2531 unsigned int new_status_point;
2532
2533 if (!message || !*message || (point = atoi(message)) == 0) {
2534 clif_displaymessage(fd, msg_txt(1010)); // Please enter a number (usage: @stpoint <number of points>).
2535 return -1;
2536 }
2537
2538 if(point < 0)
2539 {
2540 if(sd->status.status_point < (unsigned int)(-point))
2541 {
2542 new_status_point = 0;
2543 }
2544 else
2545 {
2546 new_status_point = sd->status.status_point + point;
2547 }
2548 }
2549 else if(UINT_MAX - sd->status.status_point < (unsigned int)point)
2550 {
2551 new_status_point = UINT_MAX;
2552 }
2553 else
2554 {
2555 new_status_point = sd->status.status_point + point;
2556 }
2557
2558 if (new_status_point != sd->status.status_point) {
2559 sd->status.status_point = new_status_point;
2560 clif_updatestatus(sd, SP_STATUSPOINT);
2561 clif_displaymessage(fd, msg_txt(174)); // Number of status points changed.
2562 } else {
2563 if (point < 0)
2564 clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value.
2565 else
2566 clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value.
2567 return -1;
2568 }
2569
2570 return 0;
2571}
2572
2573/*==========================================
2574 * @skpoint (Rewritten by [Yor])
2575 *------------------------------------------*/
2576ACMD_FUNC(skillpoint)
2577{
2578 int point;
2579 unsigned int new_skill_point;
2580 nullpo_retr(-1, sd);
2581
2582 if (!message || !*message || (point = atoi(message)) == 0) {
2583 clif_displaymessage(fd, msg_txt(1011)); // Please enter a number (usage: @skpoint <number of points>).
2584 return -1;
2585 }
2586
2587 if(point < 0)
2588 {
2589 if(sd->status.skill_point < (unsigned int)(-point))
2590 {
2591 new_skill_point = 0;
2592 }
2593 else
2594 {
2595 new_skill_point = sd->status.skill_point + point;
2596 }
2597 }
2598 else if(UINT_MAX - sd->status.skill_point < (unsigned int)point)
2599 {
2600 new_skill_point = UINT_MAX;
2601 }
2602 else
2603 {
2604 new_skill_point = sd->status.skill_point + point;
2605 }
2606
2607 if (new_skill_point != sd->status.skill_point) {
2608 sd->status.skill_point = new_skill_point;
2609 clif_updatestatus(sd, SP_SKILLPOINT);
2610 clif_displaymessage(fd, msg_txt(175)); // Number of skill points changed.
2611 } else {
2612 if (point < 0)
2613 clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value.
2614 else
2615 clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value.
2616 return -1;
2617 }
2618
2619 return 0;
2620}
2621
2622/*==========================================
2623 * @zeny (Rewritten by [Yor])
2624 *------------------------------------------*/
2625ACMD_FUNC(zeny)
2626{
2627 int zeny, new_zeny;
2628 nullpo_retr(-1, sd);
2629
2630 if (!message || !*message || (zeny = atoi(message)) == 0) {
2631 clif_displaymessage(fd, msg_txt(1012)); // Please enter an amount (usage: @zeny <amount>).
2632 return -1;
2633 }
2634
2635 new_zeny = sd->status.zeny + zeny;
2636 if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY)) // fix positiv overflow
2637 new_zeny = MAX_ZENY;
2638 else if (zeny < 0 && (zeny < -MAX_ZENY || new_zeny < 0)) // fix negativ overflow
2639 new_zeny = 0;
2640
2641 if (new_zeny != sd->status.zeny) {
2642 sd->status.zeny = new_zeny;
2643 clif_updatestatus(sd, SP_ZENY);
2644 clif_displaymessage(fd, msg_txt(176)); // Current amount of zeny changed.
2645 } else {
2646 if (zeny < 0)
2647 clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value.
2648 else
2649 clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value.
2650 return -1;
2651 }
2652
2653 return 0;
2654}
2655
2656/*==========================================
2657 *
2658 *------------------------------------------*/
2659ACMD_FUNC(param)
2660{
2661 int i, value = 0, new_value, max;
2662 const char* param[] = { "str", "agi", "vit", "int", "dex", "luk" };
2663 short* status[6];
2664 //we don't use direct initialization because it isn't part of the c standard.
2665 nullpo_retr(-1, sd);
2666
2667 memset(atcmd_output, '\0', sizeof(atcmd_output));
2668
2669 if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) {
2670 clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>).
2671 return -1;
2672 }
2673
2674 ARR_FIND( 0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0 );
2675
2676 if( i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible...
2677 clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>).
2678 return -1;
2679 }
2680
2681 status[0] = &sd->status.str;
2682 status[1] = &sd->status.agi;
2683 status[2] = &sd->status.vit;
2684 status[3] = &sd->status.int_;
2685 status[4] = &sd->status.dex;
2686 status[5] = &sd->status.luk;
2687
2688 if( battle_config.atcommand_max_stat_bypass )
2689 max = SHRT_MAX;
2690 else
2691 max = pc_maxparameter(sd);
2692
2693 if(value < 0 && *status[i] <= -value) {
2694 new_value = 1;
2695 } else if(max - *status[i] < value) {
2696 new_value = max;
2697 } else {
2698 new_value = *status[i] + value;
2699 }
2700
2701 if (new_value != *status[i]) {
2702 *status[i] = new_value;
2703 clif_updatestatus(sd, SP_STR + i);
2704 clif_updatestatus(sd, SP_USTR + i);
2705 status_calc_pc(sd, 0);
2706 clif_displaymessage(fd, msg_txt(42)); // Stat changed.
2707 } else {
2708 if (value < 0)
2709 clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value.
2710 else
2711 clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value.
2712 return -1;
2713 }
2714
2715 return 0;
2716}
2717
2718/*==========================================
2719 * Stat all by fritz (rewritten by [Yor])
2720 *------------------------------------------*/
2721ACMD_FUNC(stat_all)
2722{
2723 int index, count, value, max, new_value;
2724 short* status[6];
2725 //we don't use direct initialization because it isn't part of the c standard.
2726 nullpo_retr(-1, sd);
2727
2728 status[0] = &sd->status.str;
2729 status[1] = &sd->status.agi;
2730 status[2] = &sd->status.vit;
2731 status[3] = &sd->status.int_;
2732 status[4] = &sd->status.dex;
2733 status[5] = &sd->status.luk;
2734
2735 if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) {
2736 value = pc_maxparameter(sd);
2737 max = pc_maxparameter(sd);
2738 } else {
2739 if( battle_config.atcommand_max_stat_bypass )
2740 max = SHRT_MAX;
2741 else
2742 max = pc_maxparameter(sd);
2743 }
2744
2745 count = 0;
2746 for (index = 0; index < ARRAYLENGTH(status); index++) {
2747
2748 if (value > 0 && *status[index] > max - value)
2749 new_value = max;
2750 else if (value < 0 && *status[index] <= -value)
2751 new_value = 1;
2752 else
2753 new_value = *status[index] +value;
2754
2755 if (new_value != (int)*status[index]) {
2756 *status[index] = new_value;
2757 clif_updatestatus(sd, SP_STR + index);
2758 clif_updatestatus(sd, SP_USTR + index);
2759 count++;
2760 }
2761 }
2762
2763 if (count > 0) { // if at least 1 stat modified
2764 status_calc_pc(sd, 0);
2765 clif_displaymessage(fd, msg_txt(84)); // All stats changed!
2766 } else {
2767 if (value < 0)
2768 clif_displaymessage(fd, msg_txt(177)); // You cannot decrease that stat anymore.
2769 else
2770 clif_displaymessage(fd, msg_txt(178)); // You cannot increase that stat anymore.
2771 return -1;
2772 }
2773
2774 return 0;
2775}
2776
2777/*==========================================
2778 *
2779 *------------------------------------------*/
2780ACMD_FUNC(guildlevelup)
2781{
2782 int level = 0;
2783 short added_level;
2784 struct guild *guild_info;
2785 nullpo_retr(-1, sd);
2786
2787 if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) {
2788 clif_displaymessage(fd, msg_txt(1014)); // Please enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>).
2789 return -1;
2790 }
2791
2792 if (sd->status.guild_id <= 0 || (guild_info = guild_search(sd->status.guild_id)) == NULL) {
2793 clif_displaymessage(fd, msg_txt(43)); // You're not in a guild.
2794 return -1;
2795 }
2796 //if (strcmp(sd->status.name, guild_info->master) != 0) {
2797 // clif_displaymessage(fd, msg_txt(44)); // You're not the master of your guild.
2798 // return -1;
2799 //}
2800
2801 added_level = (short)level;
2802 if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow
2803 added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv;
2804 else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow
2805 added_level = 1 - guild_info->guild_lv;
2806
2807 if (added_level != 0) {
2808 intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level));
2809 clif_displaymessage(fd, msg_txt(179)); // Guild level changed.
2810 } else {
2811 clif_displaymessage(fd, msg_txt(45)); // Guild level change failed.
2812 return -1;
2813 }
2814
2815 return 0;
2816}
2817
2818/*==========================================
2819 *
2820 *------------------------------------------*/
2821ACMD_FUNC(makeegg)
2822{
2823 struct item_data *item_data;
2824 int id, pet_id;
2825 nullpo_retr(-1, sd);
2826
2827 if (!message || !*message) {
2828 clif_displaymessage(fd, msg_txt(1015)); // Please enter a monster/egg name/ID (usage: @makeegg <pet>).
2829 return -1;
2830 }
2831
2832 if ((item_data = itemdb_searchname(message)) != NULL) // for egg name
2833 id = item_data->nameid;
2834 else
2835 if ((id = mobdb_searchname(message)) != 0) // for monster name
2836 ;
2837 else
2838 id = atoi(message);
2839
2840 pet_id = search_petDB_index(id, PET_CLASS);
2841 if (pet_id < 0)
2842 pet_id = search_petDB_index(id, PET_EGG);
2843 if (pet_id >= 0) {
2844 sd->catch_target_class = pet_db[pet_id].class_;
2845 intif_create_pet(
2846 sd->status.account_id, sd->status.char_id,
2847 (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv,
2848 (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate,
2849 100, 0, 1, pet_db[pet_id].jname);
2850 } else {
2851 clif_displaymessage(fd, msg_txt(180)); // The monster/egg name/id doesn't exist.
2852 return -1;
2853 }
2854
2855 return 0;
2856}
2857
2858/*==========================================
2859 *
2860 *------------------------------------------*/
2861ACMD_FUNC(hatch)
2862{
2863 nullpo_retr(-1, sd);
2864 if (sd->status.pet_id <= 0)
2865 clif_sendegg(sd);
2866 else {
2867 clif_displaymessage(fd, msg_txt(181)); // You already have a pet.
2868 return -1;
2869 }
2870
2871 return 0;
2872}
2873
2874/*==========================================
2875 *
2876 *------------------------------------------*/
2877ACMD_FUNC(petfriendly)
2878{
2879 int friendly;
2880 struct pet_data *pd;
2881 nullpo_retr(-1, sd);
2882
2883 if (!message || !*message || (friendly = atoi(message)) < 0) {
2884 clif_displaymessage(fd, msg_txt(1016)); // Please enter a valid value (usage: @petfriendly <0-1000>).
2885 return -1;
2886 }
2887
2888 pd = sd->pd;
2889 if (!pd) {
2890 clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet.
2891 return -1;
2892 }
2893
2894 if (friendly < 0 || friendly > 1000)
2895 {
2896 clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified.
2897 return -1;
2898 }
2899
2900 if (friendly == pd->pet.intimate) {
2901 clif_displaymessage(fd, msg_txt(183)); // Pet intimacy is already at maximum.
2902 return -1;
2903 }
2904
2905 pet_set_intimate(pd, friendly);
2906 clif_send_petstatus(sd);
2907 clif_displaymessage(fd, msg_txt(182)); // Pet intimacy changed.
2908 return 0;
2909}
2910
2911/*==========================================
2912 *
2913 *------------------------------------------*/
2914ACMD_FUNC(pethungry)
2915{
2916 int hungry;
2917 struct pet_data *pd;
2918 nullpo_retr(-1, sd);
2919
2920 if (!message || !*message || (hungry = atoi(message)) < 0) {
2921 clif_displaymessage(fd, msg_txt(1017)); // Please enter a valid number (usage: @pethungry <0-100>).
2922 return -1;
2923 }
2924
2925 pd = sd->pd;
2926 if (!sd->status.pet_id || !pd) {
2927 clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet.
2928 return -1;
2929 }
2930 if (hungry < 0 || hungry > 100) {
2931 clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified.
2932 return -1;
2933 }
2934 if (hungry == pd->pet.hungry) {
2935 clif_displaymessage(fd, msg_txt(186)); // Pet hunger is already at maximum.
2936 return -1;
2937 }
2938
2939 pd->pet.hungry = hungry;
2940 clif_send_petstatus(sd);
2941 clif_displaymessage(fd, msg_txt(185)); // Pet hunger changed.
2942
2943 return 0;
2944}
2945
2946/*==========================================
2947 *
2948 *------------------------------------------*/
2949ACMD_FUNC(petrename)
2950{
2951 struct pet_data *pd;
2952 nullpo_retr(-1, sd);
2953 if (!sd->status.pet_id || !sd->pd) {
2954 clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet.
2955 return -1;
2956 }
2957 pd = sd->pd;
2958 if (!pd->pet.rename_flag) {
2959 clif_displaymessage(fd, msg_txt(188)); // You can already rename your pet.
2960 return -1;
2961 }
2962
2963 pd->pet.rename_flag = 0;
2964 intif_save_petdata(sd->status.account_id, &pd->pet);
2965 clif_send_petstatus(sd);
2966 clif_displaymessage(fd, msg_txt(187)); // You can now rename your pet.
2967
2968 return 0;
2969}
2970
2971/*==========================================
2972 *
2973 *------------------------------------------*/
2974ACMD_FUNC(recall) {
2975 struct map_session_data *pl_sd = NULL;
2976
2977 nullpo_retr(-1, sd);
2978
2979 if (!message || !*message) {
2980 clif_displaymessage(fd, msg_txt(1018)); // Please enter a player name (usage: @recall <char name/ID>).
2981 return -1;
2982 }
2983
2984 if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL)
2985 {
2986 clif_displaymessage(fd, msg_txt(3)); // Character not found.
2987 return -1;
2988 }
2989
2990 if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
2991 {
2992 clif_displaymessage(fd, msg_txt(81)); // Your GM level doesn't authorize you to preform this action on the specified player.
2993 return -1;
2994 }
2995
2996 if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
2997 clif_displaymessage(fd, msg_txt(1019)); // You are not authorized to warp someone to this map.
2998 return -1;
2999 }
3000 if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
3001 clif_displaymessage(fd, msg_txt(1020)); // You are not authorized to warp this player from their map.
3002 return -1;
3003 }
3004 pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
3005 sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled!
3006 clif_displaymessage(fd, atcmd_output);
3007
3008 return 0;
3009}
3010
3011/*==========================================
3012 * charblock command (usage: charblock <player_name>)
3013 * This command do a definitiv ban on a player
3014 *------------------------------------------*/
3015ACMD_FUNC(char_block)
3016{
3017 nullpo_retr(-1, sd);
3018
3019 memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
3020
3021 if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
3022 clif_displaymessage(fd, msg_txt(1021)); // Please enter a player name (usage: @charblock/@block <char name>).
3023 return -1;
3024 }
3025
3026 chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block
3027 clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it.
3028
3029 return 0;
3030}
3031
3032/*==========================================
3033 * charban command (usage: charban <time> <player_name>)
3034 * This command do a limited ban on a player
3035 * Time is done as follows:
3036 * Adjustment value (-1, 1, +1, etc...)
3037 * Modified element:
3038 * a or y: year
3039 * m: month
3040 * j or d: day
3041 * h: hour
3042 * mn: minute
3043 * s: second
3044 * <example> @ban +1m-2mn1s-6y test_player
3045 * this example adds 1 month and 1 second, and substracts 2 minutes and 6 years at the same time.
3046 *------------------------------------------*/
3047ACMD_FUNC(char_ban)
3048{
3049 char * modif_p;
3050 int year, month, day, hour, minute, second, value;
3051 time_t timestamp;
3052 struct tm *tmtime;
3053 nullpo_retr(-1, sd);
3054
3055 memset(atcmd_output, '\0', sizeof(atcmd_output));
3056 memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
3057
3058 if (!message || !*message || sscanf(message, "%s %23[^\n]", atcmd_output, atcmd_player_name) < 2) {
3059 clif_displaymessage(fd, msg_txt(1022)); // Please enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish <time> <char name>).
3060 return -1;
3061 }
3062
3063 atcmd_output[sizeof(atcmd_output)-1] = '\0';
3064
3065 modif_p = atcmd_output;
3066 year = month = day = hour = minute = second = 0;
3067 while (modif_p[0] != '\0') {
3068 value = atoi(modif_p);
3069 if (value == 0)
3070 modif_p++;
3071 else {
3072 if (modif_p[0] == '-' || modif_p[0] == '+')
3073 modif_p++;
3074 while (modif_p[0] >= '0' && modif_p[0] <= '9')
3075 modif_p++;
3076 if (modif_p[0] == 's') {
3077 second = value;
3078 modif_p++;
3079 } else if (modif_p[0] == 'n') {
3080 minute = value;
3081 modif_p++;
3082 } else if (modif_p[0] == 'm' && modif_p[1] == 'n') {
3083 minute = value;
3084 modif_p = modif_p + 2;
3085 } else if (modif_p[0] == 'h') {
3086 hour = value;
3087 modif_p++;
3088 } else if (modif_p[0] == 'd' || modif_p[0] == 'j') {
3089 day = value;
3090 modif_p++;
3091 } else if (modif_p[0] == 'm') {
3092 month = value;
3093 modif_p++;
3094 } else if (modif_p[0] == 'y' || modif_p[0] == 'a') {
3095 year = value;
3096 modif_p++;
3097 } else if (modif_p[0] != '\0') {
3098 modif_p++;
3099 }
3100 }
3101 }
3102 if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 && second == 0) {
3103 clif_displaymessage(fd, msg_txt(85)); // Invalid time for ban command.
3104 return -1;
3105 }
3106 /**
3107 * We now check if you can adjust the ban to negative (and if this is the case)
3108 **/
3109 timestamp = time(NULL);
3110 tmtime = localtime(×tamp);
3111 tmtime->tm_year = tmtime->tm_year + year;
3112 tmtime->tm_mon = tmtime->tm_mon + month;
3113 tmtime->tm_mday = tmtime->tm_mday + day;
3114 tmtime->tm_hour = tmtime->tm_hour + hour;
3115 tmtime->tm_min = tmtime->tm_min + minute;
3116 tmtime->tm_sec = tmtime->tm_sec + second;
3117 timestamp = mktime(tmtime);
3118 if( timestamp <= time(NULL) && !pc_can_use_command(sd, "unban", COMMAND_ATCOMMAND) ) {
3119 clif_displaymessage(fd,msg_txt(1023)); // You are not allowed to reduce the length of a ban.
3120 return -1;
3121 }
3122
3123 chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 2, year, month, day, hour, minute, second); // type: 2 - ban
3124 clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it.
3125
3126 return 0;
3127}
3128
3129/*==========================================
3130 * charunblock command (usage: charunblock <player_name>)
3131 *------------------------------------------*/
3132ACMD_FUNC(char_unblock)
3133{
3134 nullpo_retr(-1, sd);
3135
3136 memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
3137
3138 if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
3139 clif_displaymessage(fd, msg_txt(1024)); // Please enter a player name (usage: @charunblock <char name>).
3140 return -1;
3141 }
3142
3143 // send answer to login server via char-server
3144 chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 3, 0, 0, 0, 0, 0, 0); // type: 3 - unblock
3145 clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it.
3146
3147 return 0;
3148}
3149
3150/*==========================================
3151 * charunban command (usage: charunban <player_name>)
3152 *------------------------------------------*/
3153ACMD_FUNC(char_unban)
3154{
3155 nullpo_retr(-1, sd);
3156
3157 memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
3158
3159 if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
3160 clif_displaymessage(fd, msg_txt(1025)); // Please enter a player name (usage: @charunban <char name>).
3161 return -1;
3162 }
3163
3164 // send answer to login server via char-server
3165 chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 4, 0, 0, 0, 0, 0, 0); // type: 4 - unban
3166 clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it.
3167
3168 return 0;
3169}
3170
3171/*==========================================
3172 *
3173 *------------------------------------------*/
3174ACMD_FUNC(night)
3175{
3176 nullpo_retr(-1, sd);
3177
3178 if (night_flag != 1) {
3179 map_night_timer(night_timer_tid, 0, 0, 1);
3180 } else {
3181 clif_displaymessage(fd, msg_txt(89)); // Night mode is already enabled.
3182 return -1;
3183 }
3184
3185 return 0;
3186}
3187
3188/*==========================================
3189 *
3190 *------------------------------------------*/
3191ACMD_FUNC(day)
3192{
3193 nullpo_retr(-1, sd);
3194
3195 if (night_flag != 0) {
3196 map_day_timer(day_timer_tid, 0, 0, 1);
3197 } else {
3198 clif_displaymessage(fd, msg_txt(90)); // Day mode is already enabled.
3199 return -1;
3200 }
3201
3202 return 0;
3203}
3204
3205/*==========================================
3206 *
3207 *------------------------------------------*/
3208ACMD_FUNC(doom)
3209{
3210 struct map_session_data* pl_sd;
3211 struct s_mapiterator* iter;
3212
3213 nullpo_retr(-1, sd);
3214
3215 iter = mapit_getallusers();
3216 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
3217 {
3218 if (pl_sd->fd != fd && pc_get_group_level(sd) >= pc_get_group_level(pl_sd))
3219 {
3220 status_kill(&pl_sd->bl);
3221 clif_specialeffect(&pl_sd->bl,450,AREA);
3222 clif_displaymessage(pl_sd->fd, msg_txt(61)); // The holy messenger has given judgement.
3223 }
3224 }
3225 mapit_free(iter);
3226
3227 clif_displaymessage(fd, msg_txt(62)); // Judgement was made.
3228
3229 return 0;
3230}
3231
3232/*==========================================
3233 *
3234 *------------------------------------------*/
3235ACMD_FUNC(doommap)
3236{
3237 struct map_session_data* pl_sd;
3238 struct s_mapiterator* iter;
3239
3240 nullpo_retr(-1, sd);
3241
3242 iter = mapit_getallusers();
3243 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
3244 {
3245 if (pl_sd->fd != fd && sd->bl.m == pl_sd->bl.m && pc_get_group_level(sd) >= pc_get_group_level(pl_sd))
3246 {
3247 status_kill(&pl_sd->bl);
3248 clif_specialeffect(&pl_sd->bl,450,AREA);
3249 clif_displaymessage(pl_sd->fd, msg_txt(61)); // The holy messenger has given judgement.
3250 }
3251 }
3252 mapit_free(iter);
3253
3254 clif_displaymessage(fd, msg_txt(62)); // Judgement was made.
3255
3256 return 0;
3257}
3258
3259/*==========================================
3260 *
3261 *------------------------------------------*/
3262static void atcommand_raise_sub(struct map_session_data* sd) {
3263
3264 status_revive(&sd->bl, 100, 100);
3265
3266 clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1);
3267 clif_displaymessage(sd->fd, msg_txt(63)); // Mercy has been shown.
3268}
3269
3270/*==========================================
3271 *
3272 *------------------------------------------*/
3273ACMD_FUNC(raise)
3274{
3275 struct map_session_data* pl_sd;
3276 struct s_mapiterator* iter;
3277
3278 nullpo_retr(-1, sd);
3279
3280 iter = mapit_getallusers();
3281 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
3282 if( pc_isdead(pl_sd) )
3283 atcommand_raise_sub(pl_sd);
3284 mapit_free(iter);
3285
3286 clif_displaymessage(fd, msg_txt(64)); // Mercy has been granted.
3287
3288 return 0;
3289}
3290
3291/*==========================================
3292 *
3293 *------------------------------------------*/
3294ACMD_FUNC(raisemap)
3295{
3296 struct map_session_data* pl_sd;
3297 struct s_mapiterator* iter;
3298
3299 nullpo_retr(-1, sd);
3300
3301 iter = mapit_getallusers();
3302 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
3303 if (sd->bl.m == pl_sd->bl.m && pc_isdead(pl_sd) )
3304 atcommand_raise_sub(pl_sd);
3305 mapit_free(iter);
3306
3307 clif_displaymessage(fd, msg_txt(64)); // Mercy has been granted.
3308
3309 return 0;
3310}
3311
3312/*==========================================
3313 *
3314 *------------------------------------------*/
3315ACMD_FUNC(kick)
3316{
3317 struct map_session_data *pl_sd;
3318 nullpo_retr(-1, sd);
3319
3320 memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
3321
3322 if (!message || !*message) {
3323 clif_displaymessage(fd, msg_txt(1026)); // Please enter a player name (usage: @kick <char name/ID>).
3324 return -1;
3325 }
3326
3327 if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL)
3328 {
3329 clif_displaymessage(fd, msg_txt(3)); // Character not found.
3330 return -1;
3331 }
3332
3333 if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
3334 {
3335 clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
3336 return -1;
3337 }
3338
3339 clif_GM_kick(sd, pl_sd);
3340
3341 return 0;
3342}
3343
3344/*==========================================
3345 *
3346 *------------------------------------------*/
3347ACMD_FUNC(kickall)
3348{
3349 struct map_session_data* pl_sd;
3350 struct s_mapiterator* iter;
3351 nullpo_retr(-1, sd);
3352
3353 iter = mapit_getallusers();
3354 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
3355 {
3356 if (pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { // you can kick only lower or same gm level
3357 if (sd->status.account_id != pl_sd->status.account_id)
3358 clif_GM_kick(NULL, pl_sd);
3359 }
3360 }
3361 mapit_free(iter);
3362
3363 clif_displaymessage(fd, msg_txt(195)); // All players have been kicked!
3364
3365 return 0;
3366}
3367
3368/*==========================================
3369 *
3370 *------------------------------------------*/
3371ACMD_FUNC(allskill)
3372{
3373 nullpo_retr(-1, sd);
3374 pc_allskillup(sd); // all skills
3375 sd->status.skill_point = 0; // 0 skill points
3376 clif_updatestatus(sd, SP_SKILLPOINT); // update
3377 clif_displaymessage(fd, msg_txt(76)); // All skills have been added to your skill tree.
3378
3379 return 0;
3380}
3381
3382/*==========================================
3383 *
3384 *------------------------------------------*/
3385ACMD_FUNC(questskill)
3386{
3387 int skill_id;
3388 nullpo_retr(-1, sd);
3389
3390 if (!message || !*message || (skill_id = atoi(message)) < 0)
3391 {// also send a list of skills applicable to this command
3392 const char* text;
3393
3394 // attempt to find the text corresponding to this command
3395 text = atcommand_help_string( command );
3396
3397 // send the error message as always
3398 clif_displaymessage(fd, msg_txt(1027)); // Please enter a quest skill number.
3399
3400 if( text )
3401 {// send the skill ID list associated with this command
3402 clif_displaymessage( fd, text );
3403 }
3404
3405 return -1;
3406 }
3407 if (skill_id < 0 && skill_id >= MAX_SKILL_DB) {
3408 clif_displaymessage(fd, msg_txt(198)); // This skill number doesn't exist.
3409 return -1;
3410 }
3411 if (!(skill_get_inf2(skill_id) & INF2_QUEST_SKILL)) {
3412 clif_displaymessage(fd, msg_txt(197)); // This skill number doesn't exist or isn't a quest skill.
3413 return -1;
3414 }
3415 if (pc_checkskill(sd, skill_id) > 0) {
3416 clif_displaymessage(fd, msg_txt(196)); // You already have this quest skill.
3417 return -1;
3418 }
3419
3420 pc_skill(sd, skill_id, 1, 0);
3421 clif_displaymessage(fd, msg_txt(70)); // You have learned the skill.
3422
3423 return 0;
3424}
3425
3426/*==========================================
3427 *
3428 *------------------------------------------*/
3429ACMD_FUNC(lostskill)
3430{
3431 int skill_id;
3432 nullpo_retr(-1, sd);
3433
3434 if (!message || !*message || (skill_id = atoi(message)) < 0)
3435 {// also send a list of skills applicable to this command
3436 const char* text;
3437
3438 // attempt to find the text corresponding to this command
3439 text = atcommand_help_string( command );
3440
3441 // send the error message as always
3442 clif_displaymessage(fd, msg_txt(1027)); // Please enter a quest skill number.
3443
3444 if( text )
3445 {// send the skill ID list associated with this command
3446 clif_displaymessage( fd, text );
3447 }
3448
3449 return -1;
3450 }
3451 if (skill_id < 0 && skill_id >= MAX_SKILL) {
3452 clif_displaymessage(fd, msg_txt(198)); // This skill number doesn't exist.
3453 return -1;
3454 }
3455 if (!(skill_get_inf2(skill_id) & INF2_QUEST_SKILL)) {
3456 clif_displaymessage(fd, msg_txt(197)); // This skill number doesn't exist or isn't a quest skill.
3457 return -1;
3458 }
3459 if (pc_checkskill(sd, skill_id) == 0) {
3460 clif_displaymessage(fd, msg_txt(201)); // You don't have this quest skill.
3461 return -1;
3462 }
3463
3464 sd->status.skill[skill_id].lv = 0;
3465 sd->status.skill[skill_id].flag = 0;
3466 clif_deleteskill(sd,skill_id);
3467 clif_displaymessage(fd, msg_txt(71)); // You have forgotten the skill.
3468
3469 return 0;
3470}
3471
3472/*==========================================
3473 *
3474 *------------------------------------------*/
3475ACMD_FUNC(spiritball)
3476{
3477 int max_spiritballs;
3478 int number;
3479 nullpo_retr(-1, sd);
3480
3481 max_spiritballs = min(ARRAYLENGTH(sd->spirit_timer), 0x7FFF);
3482
3483 if( !message || !*message || (number = atoi(message)) < 0 || number > max_spiritballs )
3484 {
3485 char msg[CHAT_SIZE_MAX];
3486 safesnprintf(msg, sizeof(msg), msg_txt(1028), max_spiritballs); // Please enter a party name (usage: @party <party_name>).
3487 clif_displaymessage(fd, msg);
3488 return -1;
3489 }
3490
3491 if( sd->spiritball > 0 )
3492 pc_delspiritball(sd, sd->spiritball, 1);
3493 sd->spiritball = number;
3494 clif_spiritball(sd);
3495 // no message, player can look the difference
3496
3497 return 0;
3498}
3499
3500/*==========================================
3501 *
3502 *------------------------------------------*/
3503ACMD_FUNC(party)
3504{
3505 char party[NAME_LENGTH];
3506 nullpo_retr(-1, sd);
3507
3508 memset(party, '\0', sizeof(party));
3509
3510 if (!message || !*message || sscanf(message, "%23[^\n]", party) < 1) {
3511 clif_displaymessage(fd, msg_txt(1029)); // Please enter a party name (usage: @party <party_name>).
3512 return -1;
3513 }
3514
3515 party_create(sd, party, 0, 0);
3516
3517 return 0;
3518}
3519
3520/*==========================================
3521 *
3522 *------------------------------------------*/
3523ACMD_FUNC(guild)
3524{
3525 char guild[NAME_LENGTH];
3526 int prev;
3527 nullpo_retr(-1, sd);
3528
3529 memset(guild, '\0', sizeof(guild));
3530
3531 if (!message || !*message || sscanf(message, "%23[^\n]", guild) < 1) {
3532 clif_displaymessage(fd, msg_txt(1030)); // Please enter a guild name (usage: @guild <guild_name>).
3533 return -1;
3534 }
3535
3536 prev = battle_config.guild_emperium_check;
3537 battle_config.guild_emperium_check = 0;
3538 guild_create(sd, guild);
3539 battle_config.guild_emperium_check = prev;
3540
3541 return 0;
3542}
3543
3544/*==========================================
3545 *
3546 *------------------------------------------*/
3547ACMD_FUNC(agitstart)
3548{
3549 int i;
3550
3551 nullpo_retr(-1, sd);
3552 if (agit_flag == 1) {
3553 clif_displaymessage(fd, msg_txt(73)); // War of Emperium is currently in progress.
3554 return -1;
3555 }
3556
3557 if( (i = atoi(message)) > 0 )
3558 woe_set = i;
3559
3560 agit_flag = 1;
3561 guild_agit_start();
3562 clif_displaymessage(fd, msg_txt(72)); // War of Emperium has been initiated.
3563
3564 return 0;
3565}
3566
3567/*==========================================
3568 *
3569 *------------------------------------------*/
3570ACMD_FUNC(agitstart2)
3571{
3572 int i;
3573
3574 nullpo_retr(-1, sd);
3575 if (agit2_flag == 1) {
3576 clif_displaymessage(fd, msg_txt(404)); // "War of Emperium SE is currently in progress."
3577 return -1;
3578 }
3579
3580 if( (i = atoi(message)) > 0 )
3581 woe_set = i;
3582
3583 agit2_flag = 1;
3584 guild_agit2_start();
3585 clif_displaymessage(fd, msg_txt(403)); // "War of Emperium SE has been initiated."
3586
3587 return 0;
3588}
3589
3590/*==========================================
3591 *
3592 *------------------------------------------*/
3593ACMD_FUNC(agitend)
3594{
3595 nullpo_retr(-1, sd);
3596 if (agit_flag == 0) {
3597 clif_displaymessage(fd, msg_txt(75)); // War of Emperium is currently not in progress.
3598 return -1;
3599 }
3600
3601 guild_agit_end();
3602 agit_flag = 0;
3603 woe_set = 0;
3604 clif_displaymessage(fd, msg_txt(74)); // War of Emperium has been ended.
3605
3606 return 0;
3607}
3608
3609/*==========================================
3610 *
3611 *------------------------------------------*/
3612ACMD_FUNC(agitend2)
3613{
3614 nullpo_retr(-1, sd);
3615 if (agit2_flag == 0) {
3616 clif_displaymessage(fd, msg_txt(406)); // "War of Emperium SE is currently not in progress."
3617 return -1;
3618 }
3619
3620 guild_agit2_end();
3621 agit2_flag = 0;
3622 woe_set = 0;
3623 clif_displaymessage(fd, msg_txt(405)); // "War of Emperium SE has been ended."
3624
3625 return 0;
3626}
3627
3628/*==========================================
3629 * @mapexit - shuts down the map server
3630 *------------------------------------------*/
3631ACMD_FUNC(mapexit)
3632{
3633 nullpo_retr(-1, sd);
3634
3635 do_shutdown();
3636 return 0;
3637}
3638
3639/*==========================================
3640 * idsearch <part_of_name>: revrited by [Yor]
3641 *------------------------------------------*/
3642ACMD_FUNC(idsearch)
3643{
3644 char item_name[100];
3645 unsigned int i, match;
3646 struct item_data *item_array[MAX_SEARCH];
3647 nullpo_retr(-1, sd);
3648
3649 memset(item_name, '\0', sizeof(item_name));
3650 memset(atcmd_output, '\0', sizeof(atcmd_output));
3651
3652 if (!message || !*message || sscanf(message, "%99s", item_name) < 0) {
3653 clif_displaymessage(fd, msg_txt(1031)); // Please enter part of an item name (usage: @idsearch <part_of_item_name>).
3654 return -1;
3655 }
3656
3657 sprintf(atcmd_output, msg_txt(77), item_name); // The reference result of '%s' (name: id):
3658 clif_displaymessage(fd, atcmd_output);
3659 match = itemdb_searchname_array(item_array, MAX_SEARCH, item_name);
3660 if (match > MAX_SEARCH) {
3661 sprintf(atcmd_output, msg_txt(269), MAX_SEARCH, match);
3662 clif_displaymessage(fd, atcmd_output);
3663 match = MAX_SEARCH;
3664 }
3665 for(i = 0; i < match; i++) {
3666 sprintf(atcmd_output, msg_txt(78), item_array[i]->jname, item_array[i]->nameid); // %s: %d
3667 clif_displaymessage(fd, atcmd_output);
3668 }
3669 sprintf(atcmd_output, msg_txt(79), match); // It is %d affair above.
3670 clif_displaymessage(fd, atcmd_output);
3671
3672 return 0;
3673}
3674
3675/*==========================================
3676 * Recall All Characters Online To Your Location
3677 *------------------------------------------*/
3678ACMD_FUNC(recallall)
3679{
3680 struct map_session_data* pl_sd;
3681 struct s_mapiterator* iter;
3682 int count;
3683 nullpo_retr(-1, sd);
3684
3685 memset(atcmd_output, '\0', sizeof(atcmd_output));
3686
3687 if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
3688 clif_displaymessage(fd, msg_txt(1032)); // You are not authorized to warp somenone to your current map.
3689 return -1;
3690 }
3691
3692 count = 0;
3693 iter = mapit_getallusers();
3694 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
3695 {
3696 if (sd->status.account_id != pl_sd->status.account_id && pc_get_group_level(sd) >= pc_get_group_level(pl_sd))
3697 {
3698 if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
3699 count++;
3700 else {
3701 if (pc_isdead(pl_sd)) { //Wake them up
3702 pc_setstand(pl_sd);
3703 pc_setrestartvalue(pl_sd,1);
3704 }
3705 pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
3706 }
3707 }
3708 }
3709 mapit_free(iter);
3710
3711 clif_displaymessage(fd, msg_txt(92)); // All characters recalled!
3712 if (count) {
3713 sprintf(atcmd_output, msg_txt(1033), count); // Because you are not authorized to warp from some maps, %d player(s) have not been recalled.
3714 clif_displaymessage(fd, atcmd_output);
3715 }
3716
3717 return 0;
3718}
3719
3720/*==========================================
3721 * Recall online characters of a guild to your location
3722 *------------------------------------------*/
3723ACMD_FUNC(guildrecall)
3724{
3725 struct map_session_data* pl_sd;
3726 struct s_mapiterator* iter;
3727 int count;
3728 char guild_name[NAME_LENGTH];
3729 struct guild *g;
3730 nullpo_retr(-1, sd);
3731
3732 memset(guild_name, '\0', sizeof(guild_name));
3733 memset(atcmd_output, '\0', sizeof(atcmd_output));
3734
3735 if (!message || !*message || sscanf(message, "%23[^\n]", guild_name) < 1) {
3736 clif_displaymessage(fd, msg_txt(1034)); // Please enter a guild name/ID (usage: @guildrecall <guild_name/ID>).
3737 return -1;
3738 }
3739
3740 if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
3741 clif_displaymessage(fd, msg_txt(1032)); // You are not authorized to warp somenone to your current map.
3742 return -1;
3743 }
3744
3745 if ((g = guild_searchname(guild_name)) == NULL && // name first to avoid error when name begin with a number
3746 (g = guild_search(atoi(message))) == NULL)
3747 {
3748 clif_displaymessage(fd, msg_txt(94)); // Incorrect name/ID, or no one from the guild is online.
3749 return -1;
3750 }
3751
3752 count = 0;
3753
3754 iter = mapit_getallusers();
3755 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
3756 {
3757 if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.guild_id == g->guild_id)
3758 {
3759 if (pc_get_group_level(pl_sd) > pc_get_group_level(sd))
3760 continue; //Skip GMs greater than you.
3761 if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
3762 count++;
3763 else
3764 pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
3765 }
3766 }
3767 mapit_free(iter);
3768
3769 sprintf(atcmd_output, msg_txt(93), g->name); // All online characters of the %s guild have been recalled to your position.
3770 clif_displaymessage(fd, atcmd_output);
3771 if (count) {
3772 sprintf(atcmd_output, msg_txt(1033), count); // Because you are not authorized to warp from some maps, %d player(s) have not been recalled.
3773 clif_displaymessage(fd, atcmd_output);
3774 }
3775
3776 return 0;
3777}
3778
3779/*==========================================
3780 * Recall online characters of a party to your location
3781 *------------------------------------------*/
3782ACMD_FUNC(partyrecall)
3783{
3784 struct map_session_data* pl_sd;
3785 struct s_mapiterator* iter;
3786 char party_name[NAME_LENGTH];
3787 struct party_data *p;
3788 int count;
3789 nullpo_retr(-1, sd);
3790
3791 memset(party_name, '\0', sizeof(party_name));
3792 memset(atcmd_output, '\0', sizeof(atcmd_output));
3793
3794 if (!message || !*message || sscanf(message, "%23[^\n]", party_name) < 1) {
3795 clif_displaymessage(fd, msg_txt(1035)); // Please enter a party name/ID (usage: @partyrecall <party_name/ID>).
3796 return -1;
3797 }
3798
3799 if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
3800 clif_displaymessage(fd, msg_txt(1032)); // You are not authorized to warp somenone to your current map.
3801 return -1;
3802 }
3803
3804 if ((p = party_searchname(party_name)) == NULL && // name first to avoid error when name begin with a number
3805 (p = party_search(atoi(message))) == NULL)
3806 {
3807 clif_displaymessage(fd, msg_txt(96)); // Incorrect name or ID, or no one from the party is online.
3808 return -1;
3809 }
3810
3811 count = 0;
3812
3813 iter = mapit_getallusers();
3814 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
3815 {
3816 if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.party_id == p->party.party_id)
3817 {
3818 if (pc_get_group_level(pl_sd) > pc_get_group_level(sd))
3819 continue; //Skip GMs greater than you.
3820 if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
3821 count++;
3822 else
3823 pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
3824 }
3825 }
3826 mapit_free(iter);
3827
3828 sprintf(atcmd_output, msg_txt(95), p->party.name); // All online characters of the %s party have been recalled to your position.
3829 clif_displaymessage(fd, atcmd_output);
3830 if (count) {
3831 sprintf(atcmd_output, msg_txt(1033), count); // Because you are not authorized to warp from some maps, %d player(s) have not been recalled.
3832 clif_displaymessage(fd, atcmd_output);
3833 }
3834
3835 return 0;
3836}
3837
3838/*==========================================
3839 *
3840 *------------------------------------------*/
3841ACMD_FUNC(reloaditemdb)
3842{
3843 nullpo_retr(-1, sd);
3844 itemdb_reload();
3845 clif_displaymessage(fd, msg_txt(97)); // Item database has been reloaded.
3846
3847 return 0;
3848}
3849
3850/*==========================================
3851 *
3852 *------------------------------------------*/
3853ACMD_FUNC(reloadmobdb)
3854{
3855 nullpo_retr(-1, sd);
3856 mob_reload();
3857 read_petdb();
3858 merc_reload();
3859 read_mercenarydb();
3860 read_mercenary_skilldb();
3861 reload_elementaldb();
3862 clif_displaymessage(fd, msg_txt(98)); // Monster database has been reloaded.
3863
3864 return 0;
3865}
3866
3867/*==========================================
3868 *
3869 *------------------------------------------*/
3870ACMD_FUNC(reloadskilldb)
3871{
3872 nullpo_retr(-1, sd);
3873 skill_reload();
3874 merc_skill_reload();
3875 reload_elemental_skilldb();
3876 read_mercenary_skilldb();
3877 clif_displaymessage(fd, msg_txt(99)); // Skill database has been reloaded.
3878
3879 return 0;
3880}
3881
3882/*==========================================
3883 * @reloadatcommand - reloads atcommand_athena.conf groups.conf
3884 *------------------------------------------*/
3885void atcommand_doload();
3886ACMD_FUNC(reloadatcommand) {
3887 config_t run_test;
3888
3889 if (conf_read_file(&run_test, "conf/groups.conf")) {
3890 clif_displaymessage(fd, msg_txt(1036)); // Error reading groups.conf, reload failed.
3891 return -1;
3892 }
3893
3894 config_destroy(&run_test);
3895
3896 if (conf_read_file(&run_test, ATCOMMAND_CONF_FILENAME)) {
3897 clif_displaymessage(fd, msg_txt(1037)); // Error reading atcommand_athena.conf, reload failed.
3898 return -1;
3899 }
3900
3901 config_destroy(&run_test);
3902
3903 atcommand_doload();
3904 pc_groups_reload();
3905 clif_displaymessage(fd, msg_txt(254));
3906 return 0;
3907}
3908/*==========================================
3909 * @reloadbattleconf - reloads battle_athena.conf
3910 *------------------------------------------*/
3911ACMD_FUNC(reloadbattleconf)
3912{
3913 struct Battle_Config prev_config;
3914 memcpy(&prev_config, &battle_config, sizeof(prev_config));
3915
3916 battle_config_read(BATTLE_CONF_FILENAME);
3917 // It can cause serius problems if we change this setting while server is UP.
3918 battle_config.anti_mayapurple_hack = prev_config.anti_mayapurple_hack;
3919
3920 if( prev_config.item_rate_mvp != battle_config.item_rate_mvp
3921 || prev_config.item_rate_common != battle_config.item_rate_common
3922 || prev_config.item_rate_common_boss != battle_config.item_rate_common_boss
3923 || prev_config.item_rate_card != battle_config.item_rate_card
3924 || prev_config.item_rate_card_boss != battle_config.item_rate_card_boss
3925 || prev_config.item_rate_equip != battle_config.item_rate_equip
3926 || prev_config.item_rate_equip_boss != battle_config.item_rate_equip_boss
3927 || prev_config.item_rate_heal != battle_config.item_rate_heal
3928 || prev_config.item_rate_heal_boss != battle_config.item_rate_heal_boss
3929 || prev_config.item_rate_use != battle_config.item_rate_use
3930 || prev_config.item_rate_use_boss != battle_config.item_rate_use_boss
3931 || prev_config.item_rate_treasure != battle_config.item_rate_treasure
3932 || prev_config.item_rate_adddrop != battle_config.item_rate_adddrop
3933 || prev_config.logarithmic_drops != battle_config.logarithmic_drops
3934 || prev_config.item_drop_common_min != battle_config.item_drop_common_min
3935 || prev_config.item_drop_common_max != battle_config.item_drop_common_max
3936 || prev_config.item_drop_card_min != battle_config.item_drop_card_min
3937 || prev_config.item_drop_card_max != battle_config.item_drop_card_max
3938 || prev_config.item_drop_equip_min != battle_config.item_drop_equip_min
3939 || prev_config.item_drop_equip_max != battle_config.item_drop_equip_max
3940 || prev_config.item_drop_mvp_min != battle_config.item_drop_mvp_min
3941 || prev_config.item_drop_mvp_max != battle_config.item_drop_mvp_max
3942 || prev_config.item_drop_heal_min != battle_config.item_drop_heal_min
3943 || prev_config.item_drop_heal_max != battle_config.item_drop_heal_max
3944 || prev_config.item_drop_use_min != battle_config.item_drop_use_min
3945 || prev_config.item_drop_use_max != battle_config.item_drop_use_max
3946 || prev_config.item_drop_treasure_min != battle_config.item_drop_treasure_min
3947 || prev_config.item_drop_treasure_max != battle_config.item_drop_treasure_max
3948 || prev_config.base_exp_rate != battle_config.base_exp_rate
3949 || prev_config.job_exp_rate != battle_config.job_exp_rate
3950 )
3951 { // Exp or Drop rates changed.
3952 mob_reload(); //Needed as well so rate changes take effect.
3953 chrif_ragsrvinfo(battle_config.base_exp_rate, battle_config.job_exp_rate, battle_config.item_rate_common);
3954 }
3955 clif_displaymessage(fd, msg_txt(255));
3956 return 0;
3957}
3958/*==========================================
3959 * @reloadstatusdb - reloads job_db1.txt job_db2.txt job_db2-2.txt refine_db.txt size_fix.txt
3960 *------------------------------------------*/
3961ACMD_FUNC(reloadstatusdb)
3962{
3963 status_readdb();
3964 clif_displaymessage(fd, msg_txt(256));
3965 return 0;
3966}
3967/*==========================================
3968 * @reloadpcdb - reloads exp.txt skill_tree.txt attr_fix.txt statpoint.txt
3969 *------------------------------------------*/
3970ACMD_FUNC(reloadpcdb)
3971{
3972 pc_readdb();
3973 clif_displaymessage(fd, msg_txt(257));
3974 return 0;
3975}
3976
3977/*==========================================
3978 * @reloadmotd - reloads motd.txt
3979 *------------------------------------------*/
3980ACMD_FUNC(reloadmotd)
3981{
3982 pc_read_motd();
3983 clif_displaymessage(fd, msg_txt(268));
3984 return 0;
3985}
3986
3987/*==========================================
3988 * @reloadscript - reloads all scripts (npcs, warps, mob spawns, ...)
3989 *------------------------------------------*/
3990ACMD_FUNC(reloadscript)
3991{
3992 nullpo_retr(-1, sd);
3993 //atcommand_broadcast( fd, sd, "@broadcast", "Server is reloading scripts..." );
3994 //atcommand_broadcast( fd, sd, "@broadcast", "You will feel a bit of lag at this point !" );
3995
3996 flush_fifos();
3997 map_reloadnpc(true); // reload config files seeking for npcs
3998 script_reload();
3999 npc_reload();
4000
4001 clif_displaymessage(fd, msg_txt(100)); // Scripts have been reloaded.
4002
4003 return 0;
4004}
4005
4006/*==========================================
4007 * @mapinfo [0-3] <map name> by MC_Cameri
4008 * => Shows information about the map [map name]
4009 * 0 = no additional information
4010 * 1 = Show users in that map and their location
4011 * 2 = Shows NPCs in that map
4012 * 3 = Shows the shops/chats in that map (not implemented)
4013 *------------------------------------------*/
4014ACMD_FUNC(mapinfo)
4015{
4016 struct map_session_data* pl_sd;
4017 struct s_mapiterator* iter;
4018 struct npc_data *nd = NULL;
4019 struct chat_data *cd = NULL;
4020 char direction[12];
4021 int i, m_id, chat_num, list = 0;
4022 unsigned short m_index;
4023 char mapname[24];
4024
4025 nullpo_retr(-1, sd);
4026
4027 memset(atcmd_output, '\0', sizeof(atcmd_output));
4028 memset(mapname, '\0', sizeof(mapname));
4029 memset(direction, '\0', sizeof(direction));
4030
4031 sscanf(message, "%d %23[^\n]", &list, mapname);
4032
4033 if (list < 0 || list > 3) {
4034 clif_displaymessage(fd, msg_txt(1038)); // Please enter at least one valid list number (usage: @mapinfo <0-3> <map>).
4035 return -1;
4036 }
4037
4038 if (mapname[0] == '\0') {
4039 safestrncpy(mapname, mapindex_id2name(sd->mapindex), MAP_NAME_LENGTH);
4040 m_id = map_mapindex2mapid(sd->mapindex);
4041 } else {
4042 m_id = map_mapname2mapid(mapname);
4043 }
4044
4045 if (m_id < 0) {
4046 clif_displaymessage(fd, msg_txt(1)); // Map not found.
4047 return -1;
4048 }
4049 m_index = mapindex_name2id(mapname); //This one shouldn't fail since the previous seek did not.
4050
4051 clif_displaymessage(fd, msg_txt(1039)); // ------ Map Info ------
4052
4053 // count chats (for initial message)
4054 chat_num = 0;
4055 iter = mapit_getallusers();
4056 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
4057 if( (cd = (struct chat_data*)map_id2bl(pl_sd->chatID)) != NULL && pl_sd->mapindex == m_index && cd->usersd[0] == pl_sd )
4058 chat_num++;
4059 mapit_free(iter);
4060
4061 sprintf(atcmd_output, msg_txt(1040), mapname, map[m_id].users, map[m_id].npc_num, chat_num); // Map Name: %s | Players In Map: %d | NPCs In Map: %d | Chats In Map: %d
4062 clif_displaymessage(fd, atcmd_output);
4063 clif_displaymessage(fd, msg_txt(1041)); // ------ Map Flags ------
4064 if (map[m_id].flag.town)
4065 clif_displaymessage(fd, msg_txt(1042)); // Town Map
4066
4067 if (battle_config.autotrade_mapflag == map[m_id].flag.autotrade)
4068 clif_displaymessage(fd, msg_txt(1043)); // Autotrade Enabled
4069 else
4070 clif_displaymessage(fd, msg_txt(1044)); // Autotrade Disabled
4071
4072 if (map[m_id].flag.battleground)
4073 clif_displaymessage(fd, msg_txt(1045)); // Battlegrounds ON
4074
4075 strcpy(atcmd_output,msg_txt(1046)); // PvP Flags:
4076 if (map[m_id].flag.pvp)
4077 strcat(atcmd_output, msg_txt(1047)); // Pvp ON |
4078 if (map[m_id].flag.pvp_noguild)
4079 strcat(atcmd_output, msg_txt(1048)); // NoGuild |
4080 if (map[m_id].flag.pvp_noparty)
4081 strcat(atcmd_output, msg_txt(1049)); // NoParty |
4082 if (map[m_id].flag.pvp_nightmaredrop)
4083 strcat(atcmd_output, msg_txt(1050)); // NightmareDrop |
4084 if (map[m_id].flag.pvp_nocalcrank)
4085 strcat(atcmd_output, msg_txt(1051)); // NoCalcRank |
4086 clif_displaymessage(fd, atcmd_output);
4087
4088 if (map[m_id].flag.pvp_event)
4089 {
4090 sprintf(atcmd_output,"PVP Event Flag: x1 %d | x2 %d | y1 %d | y2 %d", map[m_id].pvpe_x1, map[m_id].pvpe_x2, map[m_id].pvpe_y1, map[m_id].pvpe_y2);
4091 clif_displaymessage(fd, atcmd_output);
4092 }
4093
4094 strcpy(atcmd_output,msg_txt(1052)); // GvG Flags:
4095 if (map[m_id].flag.gvg)
4096 strcat(atcmd_output, msg_txt(1053)); // GvG ON |
4097 if (map[m_id].flag.gvg_dungeon)
4098 strcat(atcmd_output, msg_txt(1054)); // GvG Dungeon |
4099 if (map[m_id].flag.gvg_castle)
4100 strcat(atcmd_output, msg_txt(1055)); // GvG Castle |
4101 if (map[m_id].flag.gvg_noparty)
4102 strcat(atcmd_output, msg_txt(1056)); // NoParty |
4103 if (map[m_id].flag.woe_set)
4104 {
4105 char output[64];
4106 sprintf(output,"WoE Set %d | ", map[m_id].flag.woe_set);
4107 strcat(atcmd_output, output);
4108 }
4109
4110 clif_displaymessage(fd, atcmd_output);
4111
4112 strcpy(atcmd_output,msg_txt(1057)); // Teleport Flags:
4113 if (map[m_id].flag.noteleport)
4114 strcat(atcmd_output, msg_txt(1058)); // NoTeleport |
4115 if (map[m_id].flag.monster_noteleport)
4116 strcat(atcmd_output, msg_txt(1059)); // Monster NoTeleport |
4117 if (map[m_id].flag.nowarp)
4118 strcat(atcmd_output, msg_txt(1060)); // NoWarp |
4119 if (map[m_id].flag.nowarpto)
4120 strcat(atcmd_output, msg_txt(1061)); // NoWarpTo |
4121 if (map[m_id].flag.noreturn)
4122 strcat(atcmd_output, msg_txt(1062)); // NoReturn |
4123 if (map[m_id].flag.nogo)
4124 strcat(atcmd_output, msg_txt(1063)); // NoGo |
4125 if (map[m_id].flag.nomemo)
4126 strcat(atcmd_output, msg_txt(1064)); // NoMemo |
4127 if (map[m_id].flag.blocked)
4128 strcat(atcmd_output, "Blocked | ");
4129 clif_displaymessage(fd, atcmd_output);
4130
4131 sprintf(atcmd_output, msg_txt(1065), // No Exp Penalty: %s | No Zeny Penalty: %s
4132 (map[m_id].flag.noexppenalty) ? msg_txt(1066) : msg_txt(1067), (map[m_id].flag.nozenypenalty) ? msg_txt(1066) : msg_txt(1067)); // On / Off
4133 clif_displaymessage(fd, atcmd_output);
4134
4135 if (map[m_id].flag.nosave) {
4136 if (!map[m_id].save.map)
4137 clif_displaymessage(fd, msg_txt(1068)); // No Save (Return to last Save Point)
4138 else if (map[m_id].save.x == -1 || map[m_id].save.y == -1 ) {
4139 sprintf(atcmd_output, msg_txt(1069), mapindex_id2name(map[m_id].save.map)); // No Save, Save Point: %s,Random
4140 clif_displaymessage(fd, atcmd_output);
4141 }
4142 else {
4143 sprintf(atcmd_output, msg_txt(1070), // No Save, Save Point: %s,%d,%d
4144 mapindex_id2name(map[m_id].save.map),map[m_id].save.x,map[m_id].save.y);
4145 clif_displaymessage(fd, atcmd_output);
4146 }
4147 }
4148
4149 strcpy(atcmd_output,msg_txt(1071)); // Weather Flags:
4150 if (map[m_id].flag.snow)
4151 strcat(atcmd_output, msg_txt(1072)); // Snow |
4152 if (map[m_id].flag.fog)
4153 strcat(atcmd_output, msg_txt(1073)); // Fog |
4154 if (map[m_id].flag.sakura)
4155 strcat(atcmd_output, msg_txt(1074)); // Sakura |
4156 if (map[m_id].flag.clouds)
4157 strcat(atcmd_output, msg_txt(1075)); // Clouds |
4158 if (map[m_id].flag.clouds2)
4159 strcat(atcmd_output, msg_txt(1076)); // Clouds2 |
4160 if (map[m_id].flag.fireworks)
4161 strcat(atcmd_output, msg_txt(1077)); // Fireworks |
4162 if (map[m_id].flag.leaves)
4163 strcat(atcmd_output, msg_txt(1078)); // Leaves |
4164 /**
4165 * No longer available, keeping here just in case it's back someday. [Ind]
4166 **/
4167 //if (map[m_id].flag.rain)
4168 // strcat(atcmd_output, msg_txt(1079)); // Rain |
4169 if (map[m_id].flag.nightenabled)
4170 strcat(atcmd_output, msg_txt(1080)); // Displays Night |
4171 clif_displaymessage(fd, atcmd_output);
4172
4173 strcpy(atcmd_output,msg_txt(1081)); // Other Flags:
4174 if (map[m_id].flag.nobranch)
4175 strcat(atcmd_output, msg_txt(1082)); // NoBranch |
4176 if (map[m_id].flag.notrade)
4177 strcat(atcmd_output, msg_txt(1083)); // NoTrade |
4178 if (map[m_id].flag.novending)
4179 strcat(atcmd_output, msg_txt(1084)); // NoVending |
4180 if (map[m_id].flag.nodrop)
4181 strcat(atcmd_output, msg_txt(1085)); // NoDrop |
4182 if (map[m_id].flag.noskill)
4183 strcat(atcmd_output, msg_txt(1086)); // NoSkill |
4184 if (map[m_id].flag.noicewall)
4185 strcat(atcmd_output, msg_txt(1087)); // NoIcewall |
4186 if (map[m_id].flag.allowks)
4187 strcat(atcmd_output, msg_txt(1088)); // AllowKS |
4188 if (map[m_id].flag.reset)
4189 strcat(atcmd_output, msg_txt(1089)); // Reset |
4190 clif_displaymessage(fd, atcmd_output);
4191
4192 strcpy(atcmd_output,msg_txt(1090)); // Other Flags:
4193 if (map[m_id].nocommand)
4194 strcat(atcmd_output, msg_txt(1091)); // NoCommand |
4195 if (map[m_id].flag.nobaseexp)
4196 strcat(atcmd_output, msg_txt(1092)); // NoBaseEXP |
4197 if (map[m_id].flag.nojobexp)
4198 strcat(atcmd_output, msg_txt(1093)); // NoJobEXP |
4199 if (map[m_id].flag.nomobloot)
4200 strcat(atcmd_output, msg_txt(1094)); // NoMobLoot |
4201 if (map[m_id].flag.nomvploot)
4202 strcat(atcmd_output, msg_txt(1095)); // NoMVPLoot |
4203 if (map[m_id].flag.partylock)
4204 strcat(atcmd_output, msg_txt(1096)); // PartyLock |
4205 if (map[m_id].flag.guildlock)
4206 strcat(atcmd_output, msg_txt(1097)); // GuildLock |
4207 clif_displaymessage(fd, atcmd_output);
4208
4209 switch (list) {
4210 case 0:
4211 // Do nothing. It's list 0, no additional display.
4212 break;
4213 case 1:
4214 clif_displaymessage(fd, msg_txt(1098)); // ----- Players in Map -----
4215 iter = mapit_getallusers();
4216 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
4217 {
4218 if (pl_sd->mapindex == m_index) {
4219 sprintf(atcmd_output, msg_txt(1099), // Player '%s' (session #%d) | Location: %d,%d
4220 pl_sd->status.name, pl_sd->fd, pl_sd->bl.x, pl_sd->bl.y);
4221 clif_displaymessage(fd, atcmd_output);
4222 }
4223 }
4224 mapit_free(iter);
4225 break;
4226 case 2:
4227 clif_displaymessage(fd, msg_txt(1100)); // ----- NPCs in Map -----
4228 for (i = 0; i < map[m_id].npc_num;)
4229 {
4230 nd = map[m_id].npc[i];
4231 switch(nd->ud.dir) {
4232 case 0: strcpy(direction, msg_txt(1101)); break; // North
4233 case 1: strcpy(direction, msg_txt(1102)); break; // North West
4234 case 2: strcpy(direction, msg_txt(1103)); break; // West
4235 case 3: strcpy(direction, msg_txt(1104)); break; // South West
4236 case 4: strcpy(direction, msg_txt(1105)); break; // South
4237 case 5: strcpy(direction, msg_txt(1106)); break; // South East
4238 case 6: strcpy(direction, msg_txt(1107)); break; // East
4239 case 7: strcpy(direction, msg_txt(1108)); break; // North East
4240 case 9: strcpy(direction, msg_txt(1109)); break; // North
4241 default: strcpy(direction, msg_txt(1110)); break; // Unknown
4242 }
4243 if(strcmp(nd->name,nd->exname) == 0)
4244 sprintf(atcmd_output, msg_txt(1111), // NPC %d: %s | Direction: %s | Sprite: %d | Location: %d %d
4245 ++i, nd->name, direction, nd->class_, nd->bl.x, nd->bl.y);
4246 else
4247 sprintf(atcmd_output, msg_txt(1112), // NPC %d: %s::%s | Direction: %s | Sprite: %d | Location: %d %d
4248 ++i, nd->name, nd->exname, direction, nd->class_, nd->bl.x, nd->bl.y);
4249 clif_displaymessage(fd, atcmd_output);
4250 }
4251 break;
4252 case 3:
4253 clif_displaymessage(fd, msg_txt(1113)); // ----- Chats in Map -----
4254 iter = mapit_getallusers();
4255 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
4256 {
4257 if ((cd = (struct chat_data*)map_id2bl(pl_sd->chatID)) != NULL &&
4258 pl_sd->mapindex == m_index &&
4259 cd->usersd[0] == pl_sd)
4260 {
4261 sprintf(atcmd_output, msg_txt(1114), // Chat: %s | Player: %s | Location: %d %d
4262 cd->title, pl_sd->status.name, cd->bl.x, cd->bl.y);
4263 clif_displaymessage(fd, atcmd_output);
4264 sprintf(atcmd_output, msg_txt(1115), // Users: %d/%d | Password: %s | Public: %s
4265 cd->users, cd->limit, cd->pass, (cd->pub) ? msg_txt(1116) : msg_txt(1117)); // Yes / No
4266 clif_displaymessage(fd, atcmd_output);
4267 }
4268 }
4269 mapit_free(iter);
4270 break;
4271 default: // normally impossible to arrive here
4272 clif_displaymessage(fd, msg_txt(1118)); // Please enter at least one valid list number (usage: @mapinfo <0-3> <map>).
4273 return -1;
4274 break;
4275 }
4276
4277 return 0;
4278}
4279
4280/*==========================================
4281 *
4282 *------------------------------------------*/
4283ACMD_FUNC(mount_peco)
4284{
4285 nullpo_retr(-1, sd);
4286
4287 if (sd->disguise) {
4288 clif_displaymessage(fd, msg_txt(212)); // Cannot mount while in disguise.
4289 return -1;
4290 }
4291
4292 if( (sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT && pc_checkskill(sd,RK_DRAGONTRAINING) > 0 ) {
4293 if( !(sd->sc.option&OPTION_DRAGON1) ) {
4294 clif_displaymessage(sd->fd,msg_txt(1119)); // You have mounted your Dragon.
4295 pc_setoption(sd, sd->sc.option|OPTION_DRAGON1);
4296 } else {
4297 clif_displaymessage(sd->fd,msg_txt(1120)); // You have released your Dragon.
4298 pc_setoption(sd, sd->sc.option&~OPTION_DRAGON1);
4299 }
4300 return 0;
4301 }
4302 if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER && pc_checkskill(sd,RA_WUGRIDER) > 0 ) {
4303 if( !pc_isridingwug(sd) ) {
4304 clif_displaymessage(sd->fd,msg_txt(1121)); // You have mounted your Warg.
4305 pc_setoption(sd, sd->sc.option|OPTION_WUGRIDER);
4306 } else {
4307 clif_displaymessage(sd->fd,msg_txt(1122)); // You have released your Warg.
4308 pc_setoption(sd, sd->sc.option&~OPTION_WUGRIDER);
4309 }
4310 return 0;
4311 }
4312 if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) {
4313 if( !pc_ismadogear(sd) ) {
4314 clif_displaymessage(sd->fd,msg_txt(1123)); // You have mounted your Mado Gear.
4315 pc_setoption(sd, sd->sc.option|OPTION_MADOGEAR);
4316 } else {
4317 clif_displaymessage(sd->fd,msg_txt(1124)); // You have released your Mado Gear.
4318 pc_setoption(sd, sd->sc.option&~OPTION_MADOGEAR);
4319 }
4320 return 0;
4321 }
4322 if (!pc_isriding(sd)) { // if actually no peco
4323
4324 if (!pc_checkskill(sd, KN_RIDING)) {
4325 clif_displaymessage(fd, msg_txt(213)); // You can not mount a Peco Peco with your current job.
4326 return -1;
4327 }
4328
4329 pc_setoption(sd, sd->sc.option | OPTION_RIDING);
4330 clif_displaymessage(fd, msg_txt(102)); // You have mounted a Peco Peco.
4331 } else {//Dismount
4332 pc_setoption(sd, sd->sc.option & ~OPTION_RIDING);
4333 clif_displaymessage(fd, msg_txt(214)); // You have released your Peco Peco.
4334 }
4335
4336 return 0;
4337}
4338
4339/*==========================================
4340 *Spy Commands by Syrus22
4341 *------------------------------------------*/
4342ACMD_FUNC(guildspy)
4343{
4344 char guild_name[NAME_LENGTH];
4345 struct guild *g;
4346 nullpo_retr(-1, sd);
4347
4348 memset(guild_name, '\0', sizeof(guild_name));
4349 memset(atcmd_output, '\0', sizeof(atcmd_output));
4350
4351 if (!enable_spy)
4352 {
4353 clif_displaymessage(fd, msg_txt(1125)); // The mapserver has spy command support disabled.
4354 return -1;
4355 }
4356 if (!message || !*message || sscanf(message, "%23[^\n]", guild_name) < 1) {
4357 clif_displaymessage(fd, msg_txt(1126)); // Please enter a guild name/ID (usage: @guildspy <guild_name/ID>).
4358 return -1;
4359 }
4360
4361 if ((g = guild_searchname(guild_name)) != NULL || // name first to avoid error when name begin with a number
4362 (g = guild_search(atoi(message))) != NULL) {
4363 if (sd->guildspy == g->guild_id) {
4364 sd->guildspy = 0;
4365 sprintf(atcmd_output, msg_txt(103), g->name); // No longer spying on the %s guild.
4366 clif_displaymessage(fd, atcmd_output);
4367 } else {
4368 sd->guildspy = g->guild_id;
4369 sprintf(atcmd_output, msg_txt(104), g->name); // Spying on the %s guild.
4370 clif_displaymessage(fd, atcmd_output);
4371 }
4372 } else {
4373 clif_displaymessage(fd, msg_txt(94)); // Incorrect name/ID, or no one from the specified guild is online.
4374 return -1;
4375 }
4376
4377 return 0;
4378}
4379
4380/*==========================================
4381 *
4382 *------------------------------------------*/
4383ACMD_FUNC(partyspy)
4384{
4385 char party_name[NAME_LENGTH];
4386 struct party_data *p;
4387 nullpo_retr(-1, sd);
4388
4389 memset(party_name, '\0', sizeof(party_name));
4390 memset(atcmd_output, '\0', sizeof(atcmd_output));
4391
4392 if (!enable_spy)
4393 {
4394 clif_displaymessage(fd, msg_txt(1125)); // The mapserver has spy command support disabled.
4395 return -1;
4396 }
4397
4398 if (!message || !*message || sscanf(message, "%23[^\n]", party_name) < 1) {
4399 clif_displaymessage(fd, msg_txt(1127)); // Please enter a party name/ID (usage: @partyspy <party_name/ID>).
4400 return -1;
4401 }
4402
4403 if ((p = party_searchname(party_name)) != NULL || // name first to avoid error when name begin with a number
4404 (p = party_search(atoi(message))) != NULL) {
4405 if (sd->partyspy == p->party.party_id) {
4406 sd->partyspy = 0;
4407 sprintf(atcmd_output, msg_txt(105), p->party.name); // No longer spying on the %s party.
4408 clif_displaymessage(fd, atcmd_output);
4409 } else {
4410 sd->partyspy = p->party.party_id;
4411 sprintf(atcmd_output, msg_txt(106), p->party.name); // Spying on the %s party.
4412 clif_displaymessage(fd, atcmd_output);
4413 }
4414 } else {
4415 clif_displaymessage(fd, msg_txt(96)); // Incorrect name/ID, or no one from the specified party is online.
4416 return -1;
4417 }
4418
4419 return 0;
4420}
4421
4422/*==========================================
4423 * @repairall [Valaris]
4424 *------------------------------------------*/
4425ACMD_FUNC(repairall)
4426{
4427 int count, i;
4428 nullpo_retr(-1, sd);
4429
4430 count = 0;
4431 for (i = 0; i < MAX_INVENTORY; i++) {
4432 if (sd->status.inventory[i].nameid && sd->status.inventory[i].attribute == 1) {
4433 sd->status.inventory[i].attribute = 0;
4434 clif_produceeffect(sd, 0, sd->status.inventory[i].nameid);
4435 count++;
4436 }
4437 }
4438
4439 if (count > 0) {
4440 clif_misceffect(&sd->bl, 3);
4441 clif_equiplist(sd);
4442 clif_displaymessage(fd, msg_txt(107)); // All items have been repaired.
4443 } else {
4444 clif_displaymessage(fd, msg_txt(108)); // No item need to be repaired.
4445 return -1;
4446 }
4447
4448 return 0;
4449}
4450
4451/*==========================================
4452 * @nuke [Valaris]
4453 *------------------------------------------*/
4454ACMD_FUNC(nuke)
4455{
4456 struct map_session_data *pl_sd;
4457 nullpo_retr(-1, sd);
4458
4459 memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
4460
4461 if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
4462 clif_displaymessage(fd, msg_txt(1128)); // Please enter a player name (usage: @nuke <char name>).
4463 return -1;
4464 }
4465
4466 if ((pl_sd = map_nick2sd(atcmd_player_name)) != NULL) {
4467 if (pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { // you can kill only lower or same GM level
4468 skill_castend_nodamage_id(&pl_sd->bl, &pl_sd->bl, NPC_SELFDESTRUCTION, 99, gettick(), 0);
4469 clif_displaymessage(fd, msg_txt(109)); // Player has been nuked!
4470 } else {
4471 clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
4472 return -1;
4473 }
4474 } else {
4475 clif_displaymessage(fd, msg_txt(3)); // Character not found.
4476 return -1;
4477 }
4478
4479 return 0;
4480}
4481
4482/*==========================================
4483 * @tonpc
4484 *------------------------------------------*/
4485ACMD_FUNC(tonpc)
4486{
4487 char npcname[NAME_LENGTH+1];
4488 struct npc_data *nd;
4489
4490 nullpo_retr(-1, sd);
4491
4492 memset(npcname, 0, sizeof(npcname));
4493
4494 if (!message || !*message || sscanf(message, "%23[^\n]", npcname) < 1) {
4495 clif_displaymessage(fd, msg_txt(1129)); // Please enter a NPC name (usage: @tonpc <NPC_name>).
4496 return -1;
4497 }
4498
4499 if ((nd = npc_name2id(npcname)) != NULL) {
4500 if (pc_setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, CLR_TELEPORT) == 0)
4501 clif_displaymessage(fd, msg_txt(0)); // Warped.
4502 else
4503 return -1;
4504 } else {
4505 clif_displaymessage(fd, msg_txt(111)); // This NPC doesn't exist.
4506 return -1;
4507 }
4508
4509 return 0;
4510}
4511
4512/*==========================================
4513 *
4514 *------------------------------------------*/
4515ACMD_FUNC(shownpc)
4516{
4517 char NPCname[NAME_LENGTH+1];
4518 nullpo_retr(-1, sd);
4519
4520 memset(NPCname, '\0', sizeof(NPCname));
4521
4522 if (!message || !*message || sscanf(message, "%23[^\n]", NPCname) < 1) {
4523 clif_displaymessage(fd, msg_txt(1130)); // Please enter a NPC name (usage: @enablenpc <NPC_name>).
4524 return -1;
4525 }
4526
4527 if (npc_name2id(NPCname) != NULL) {
4528 npc_enable(NPCname, 1);
4529 clif_displaymessage(fd, msg_txt(110)); // Npc Enabled.
4530 } else {
4531 clif_displaymessage(fd, msg_txt(111)); // This NPC doesn't exist.
4532 return -1;
4533 }
4534
4535 return 0;
4536}
4537
4538/*==========================================
4539 *
4540 *------------------------------------------*/
4541ACMD_FUNC(hidenpc)
4542{
4543 char NPCname[NAME_LENGTH+1];
4544 nullpo_retr(-1, sd);
4545
4546 memset(NPCname, '\0', sizeof(NPCname));
4547
4548 if (!message || !*message || sscanf(message, "%23[^\n]", NPCname) < 1) {
4549 clif_displaymessage(fd, msg_txt(1131)); // Please enter a NPC name (usage: @hidenpc <NPC_name>).
4550 return -1;
4551 }
4552
4553 if (npc_name2id(NPCname) == NULL) {
4554 clif_displaymessage(fd, msg_txt(111)); // This NPC doesn't exist.
4555 return -1;
4556 }
4557
4558 npc_enable(NPCname, 0);
4559 clif_displaymessage(fd, msg_txt(112)); // Npc Disabled.
4560 return 0;
4561}
4562
4563ACMD_FUNC(loadnpc)
4564{
4565 FILE *fp;
4566
4567 if (!message || !*message) {
4568 clif_displaymessage(fd, msg_txt(1132)); // Please enter a script file name (usage: @loadnpc <file name>).
4569 return -1;
4570 }
4571
4572 // check if script file exists
4573 if ((fp = fopen(message, "r")) == NULL) {
4574 clif_displaymessage(fd, msg_txt(261));
4575 return -1;
4576 }
4577 fclose(fp);
4578
4579 // add to list of script sources and run it
4580 npc_addsrcfile(message);
4581 npc_parsesrcfile(message,true);
4582 npc_read_event_script();
4583
4584 clif_displaymessage(fd, msg_txt(262));
4585
4586 return 0;
4587}
4588
4589ACMD_FUNC(unloadnpc)
4590{
4591 struct npc_data *nd;
4592 char NPCname[NAME_LENGTH+1];
4593 nullpo_retr(-1, sd);
4594
4595 memset(NPCname, '\0', sizeof(NPCname));
4596
4597 if (!message || !*message || sscanf(message, "%24[^\n]", NPCname) < 1) {
4598 clif_displaymessage(fd, msg_txt(1133)); // Please enter a NPC name (usage: @npcoff <NPC_name>).
4599 return -1;
4600 }
4601
4602 if ((nd = npc_name2id(NPCname)) == NULL) {
4603 clif_displaymessage(fd, msg_txt(111)); // This NPC doesn't exist.
4604 return -1;
4605 }
4606
4607 npc_unload_duplicates(nd);
4608 npc_unload(nd,true);
4609 npc_read_event_script();
4610 clif_displaymessage(fd, msg_txt(112)); // Npc Disabled.
4611 return 0;
4612}
4613
4614/*==========================================
4615 * time in txt for time command (by [Yor])
4616 *------------------------------------------*/
4617char* txt_time(unsigned int duration)
4618{
4619 int days, hours, minutes, seconds;
4620 char temp[CHAT_SIZE_MAX];
4621 static char temp1[CHAT_SIZE_MAX];
4622
4623 memset(temp, '\0', sizeof(temp));
4624 memset(temp1, '\0', sizeof(temp1));
4625
4626 days = duration / (60 * 60 * 24);
4627 duration = duration - (60 * 60 * 24 * days);
4628 hours = duration / (60 * 60);
4629 duration = duration - (60 * 60 * hours);
4630 minutes = duration / 60;
4631 seconds = duration - (60 * minutes);
4632
4633 if (days == 1)
4634 sprintf(temp, msg_txt(219), days); // %d day
4635 else if (days > 1)
4636 sprintf(temp, msg_txt(220), days); // %d days
4637 if (hours == 1)
4638 sprintf(temp1, msg_txt(221), temp, hours); // %s %d hour
4639 else if (hours > 1)
4640 sprintf(temp1, msg_txt(222), temp, hours); // %s %d hours
4641 if (minutes < 2)
4642 sprintf(temp, msg_txt(223), temp1, minutes); // %s %d minute
4643 else
4644 sprintf(temp, msg_txt(224), temp1, minutes); // %s %d minutes
4645 if (seconds == 1)
4646 sprintf(temp1, msg_txt(225), temp, seconds); // %s and %d second
4647 else if (seconds > 1)
4648 sprintf(temp1, msg_txt(226), temp, seconds); // %s and %d seconds
4649
4650 return temp1;
4651}
4652
4653/*==========================================
4654 * @time/@date/@serverdate/@servertime: Display the date/time of the server (by [Yor]
4655 * Calculation management of GM modification (@day/@night GM commands) is done
4656 *------------------------------------------*/
4657ACMD_FUNC(servertime)
4658{
4659 const struct TimerData * timer_data;
4660 const struct TimerData * timer_data2;
4661 time_t time_server; // variable for number of seconds (used with time() function)
4662 struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ...
4663 char temp[CHAT_SIZE_MAX];
4664 nullpo_retr(-1, sd);
4665
4666 memset(temp, '\0', sizeof(temp));
4667
4668 time(&time_server); // get time in seconds since 1/1/1970
4669 datetime = localtime(&time_server); // convert seconds in structure
4670 // like sprintf, but only for date/time (Sunday, November 02 2003 15:12:52)
4671 strftime(temp, sizeof(temp)-1, msg_txt(230), datetime); // Server time (normal time): %A, %B %d %Y %X.
4672 clif_displaymessage(fd, temp);
4673
4674 if (battle_config.night_duration == 0 && battle_config.day_duration == 0) {
4675 if (night_flag == 0)
4676 clif_displaymessage(fd, msg_txt(231)); // Game time: The game is in permanent daylight.
4677 else
4678 clif_displaymessage(fd, msg_txt(232)); // Game time: The game is in permanent night.
4679 } else if (battle_config.night_duration == 0)
4680 if (night_flag == 1) { // we start with night
4681 timer_data = get_timer(day_timer_tid);
4682 sprintf(temp, msg_txt(233), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is actualy in night for %s.
4683 clif_displaymessage(fd, temp);
4684 clif_displaymessage(fd, msg_txt(234)); // Game time: After, the game will be in permanent daylight.
4685 } else
4686 clif_displaymessage(fd, msg_txt(231)); // Game time: The game is in permanent daylight.
4687 else if (battle_config.day_duration == 0)
4688 if (night_flag == 0) { // we start with day
4689 timer_data = get_timer(night_timer_tid);
4690 sprintf(temp, msg_txt(235), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is actualy in daylight for %s.
4691 clif_displaymessage(fd, temp);
4692 clif_displaymessage(fd, msg_txt(236)); // Game time: After, the game will be in permanent night.
4693 } else
4694 clif_displaymessage(fd, msg_txt(232)); // Game time: The game is in permanent night.
4695 else {
4696 if (night_flag == 0) {
4697 timer_data = get_timer(night_timer_tid);
4698 timer_data2 = get_timer(day_timer_tid);
4699 sprintf(temp, msg_txt(235), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is actualy in daylight for %s.
4700 clif_displaymessage(fd, temp);
4701 if (DIFF_TICK(timer_data->tick, timer_data2->tick) > 0)
4702 sprintf(temp, msg_txt(237), txt_time(DIFF_TICK(timer_data->interval,DIFF_TICK(timer_data->tick,timer_data2->tick)) / 1000)); // Game time: After, the game will be in night for %s.
4703 else
4704 sprintf(temp, msg_txt(237), txt_time(DIFF_TICK(timer_data2->tick,timer_data->tick)/1000)); // Game time: After, the game will be in night for %s.
4705 clif_displaymessage(fd, temp);
4706 sprintf(temp, msg_txt(238), txt_time(timer_data->interval / 1000)); // Game time: A day cycle has a normal duration of %s.
4707 clif_displaymessage(fd, temp);
4708 } else {
4709 timer_data = get_timer(day_timer_tid);
4710 timer_data2 = get_timer(night_timer_tid);
4711 sprintf(temp, msg_txt(233), txt_time(DIFF_TICK(timer_data->tick,gettick()) / 1000)); // Game time: The game is actualy in night for %s.
4712 clif_displaymessage(fd, temp);
4713 if (DIFF_TICK(timer_data->tick,timer_data2->tick) > 0)
4714 sprintf(temp, msg_txt(239), txt_time((timer_data->interval - DIFF_TICK(timer_data->tick, timer_data2->tick)) / 1000)); // Game time: After, the game will be in daylight for %s.
4715 else
4716 sprintf(temp, msg_txt(239), txt_time(DIFF_TICK(timer_data2->tick, timer_data->tick) / 1000)); // Game time: After, the game will be in daylight for %s.
4717 clif_displaymessage(fd, temp);
4718 sprintf(temp, msg_txt(238), txt_time(timer_data->interval / 1000)); // Game time: A day cycle has a normal duration of %s.
4719 clif_displaymessage(fd, temp);
4720 }
4721 }
4722
4723 return 0;
4724}
4725
4726//Added by Coltaro
4727//We're using this function here instead of using time_t so that it only counts player's jail time when he/she's online (and since the idea is to reduce the amount of minutes one by one in status_change_timer...).
4728//Well, using time_t could still work but for some reason that looks like more coding x_x
4729static void get_jail_time(int jailtime, int* year, int* month, int* day, int* hour, int* minute)
4730{
4731 const int factor_year = 518400; //12*30*24*60 = 518400
4732 const int factor_month = 43200; //30*24*60 = 43200
4733 const int factor_day = 1440; //24*60 = 1440
4734 const int factor_hour = 60;
4735
4736 *year = jailtime/factor_year;
4737 jailtime -= *year*factor_year;
4738 *month = jailtime/factor_month;
4739 jailtime -= *month*factor_month;
4740 *day = jailtime/factor_day;
4741 jailtime -= *day*factor_day;
4742 *hour = jailtime/factor_hour;
4743 jailtime -= *hour*factor_hour;
4744 *minute = jailtime;
4745
4746 *year = *year > 0? *year : 0;
4747 *month = *month > 0? *month : 0;
4748 *day = *day > 0? *day : 0;
4749 *hour = *hour > 0? *hour : 0;
4750 *minute = *minute > 0? *minute : 0;
4751 return;
4752}
4753
4754/*==========================================
4755 * @jail <char_name> by [Yor]
4756 * Special warp! No check with nowarp and nowarpto flag
4757 *------------------------------------------*/
4758ACMD_FUNC(jail)
4759{
4760 struct map_session_data *pl_sd;
4761 int x, y;
4762 unsigned short m_index;
4763 nullpo_retr(-1, sd);
4764
4765 memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
4766
4767 if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
4768 clif_displaymessage(fd, msg_txt(1134)); // Please enter a player name (usage: @jail <char_name>).
4769 return -1;
4770 }
4771
4772 if ((pl_sd = map_nick2sd(atcmd_player_name)) == NULL) {
4773 clif_displaymessage(fd, msg_txt(3)); // Character not found.
4774 return -1;
4775 }
4776
4777 if (pc_get_group_level(sd) < pc_get_group_level(pl_sd))
4778 { // you can jail only lower or same GM
4779 clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
4780 return -1;
4781 }
4782
4783 if (pl_sd->sc.data[SC_JAILED])
4784 {
4785 clif_displaymessage(fd, msg_txt(118)); // Player warped in jails.
4786 return -1;
4787 }
4788
4789 switch(rnd() % 2) { //Jail Locations
4790 case 0:
4791 m_index = mapindex_name2id(MAP_JAIL);
4792 x = 24;
4793 y = 75;
4794 break;
4795 default:
4796 m_index = mapindex_name2id(MAP_JAIL);
4797 x = 49;
4798 y = 75;
4799 break;
4800 }
4801
4802 //Duration of INT_MAX to specify infinity.
4803 sc_start4(&pl_sd->bl,SC_JAILED,100,INT_MAX,m_index,x,y,1000);
4804 clif_displaymessage(pl_sd->fd, msg_txt(117)); // GM has send you in jails.
4805 clif_displaymessage(fd, msg_txt(118)); // Player warped in jails.
4806 return 0;
4807}
4808
4809/*==========================================
4810 * @unjail/@discharge <char_name> by [Yor]
4811 * Special warp! No check with nowarp and nowarpto flag
4812 *------------------------------------------*/
4813ACMD_FUNC(unjail)
4814{
4815 struct map_session_data *pl_sd;
4816
4817 memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
4818
4819 if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
4820 clif_displaymessage(fd, msg_txt(1135)); // Please enter a player name (usage: @unjail/@discharge <char_name>).
4821 return -1;
4822 }
4823
4824 if ((pl_sd = map_nick2sd(atcmd_player_name)) == NULL) {
4825 clif_displaymessage(fd, msg_txt(3)); // Character not found.
4826 return -1;
4827 }
4828
4829 if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) { // you can jail only lower or same GM
4830
4831 clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
4832 return -1;
4833 }
4834
4835 if (!pl_sd->sc.data[SC_JAILED])
4836 {
4837 clif_displaymessage(fd, msg_txt(119)); // This player is not in jails.
4838 return -1;
4839 }
4840
4841 //Reset jail time to 1 sec.
4842 sc_start(&pl_sd->bl,SC_JAILED,100,1,1000);
4843 clif_displaymessage(pl_sd->fd, msg_txt(120)); // A GM has discharged you from jail.
4844 clif_displaymessage(fd, msg_txt(121)); // Player unjailed.
4845 return 0;
4846}
4847
4848ACMD_FUNC(jailfor)
4849{
4850 struct map_session_data *pl_sd = NULL;
4851 int year, month, day, hour, minute, value;
4852 char * modif_p;
4853 int jailtime = 0,x,y;
4854 short m_index = 0;
4855 nullpo_retr(-1, sd);
4856
4857 if (!message || !*message || sscanf(message, "%s %23[^\n]",atcmd_output,atcmd_player_name) < 2) {
4858 clif_displaymessage(fd, msg_txt(400)); //Usage: @jailfor <time> <character name>
4859 return -1;
4860 }
4861
4862 atcmd_output[sizeof(atcmd_output)-1] = '\0';
4863
4864 modif_p = atcmd_output;
4865 year = month = day = hour = minute = 0;
4866 while (modif_p[0] != '\0') {
4867 value = atoi(modif_p);
4868 if (value == 0)
4869 modif_p++;
4870 else {
4871 if (modif_p[0] == '-' || modif_p[0] == '+')
4872 modif_p++;
4873 while (modif_p[0] >= '0' && modif_p[0] <= '9')
4874 modif_p++;
4875 if (modif_p[0] == 'n') {
4876 minute = value;
4877 modif_p++;
4878 } else if (modif_p[0] == 'm' && modif_p[1] == 'n') {
4879 minute = value;
4880 modif_p = modif_p + 2;
4881 } else if (modif_p[0] == 'h') {
4882 hour = value;
4883 modif_p++;
4884 } else if (modif_p[0] == 'd' || modif_p[0] == 'j') {
4885 day = value;
4886 modif_p++;
4887 } else if (modif_p[0] == 'm') {
4888 month = value;
4889 modif_p++;
4890 } else if (modif_p[0] == 'y' || modif_p[0] == 'a') {
4891 year = value;
4892 modif_p++;
4893 } else if (modif_p[0] != '\0') {
4894 modif_p++;
4895 }
4896 }
4897 }
4898
4899 if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0) {
4900 clif_displaymessage(fd, msg_txt(1136)); // Invalid time for jail command.
4901 return -1;
4902 }
4903
4904 if ((pl_sd = map_nick2sd(atcmd_player_name)) == NULL) {
4905 clif_displaymessage(fd, msg_txt(3)); // Character not found.
4906 return -1;
4907 }
4908
4909 if (pc_get_group_level(pl_sd) > pc_get_group_level(sd)) {
4910 clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player.
4911 return -1;
4912 }
4913
4914 jailtime = year*12*30*24*60 + month*30*24*60 + day*24*60 + hour*60 + minute; //In minutes
4915
4916 if(jailtime==0) {
4917 clif_displaymessage(fd, msg_txt(1136)); // Invalid time for jail command.
4918 return -1;
4919 }
4920
4921 //Added by Coltaro
4922 if(pl_sd->sc.data[SC_JAILED] &&
4923 pl_sd->sc.data[SC_JAILED]->val1 != INT_MAX)
4924 { //Update the player's jail time
4925 jailtime += pl_sd->sc.data[SC_JAILED]->val1;
4926 if (jailtime <= 0) {
4927 jailtime = 0;
4928 clif_displaymessage(pl_sd->fd, msg_txt(120)); // GM has discharge you.
4929 clif_displaymessage(fd, msg_txt(121)); // Player unjailed
4930 } else {
4931 get_jail_time(jailtime,&year,&month,&day,&hour,&minute);
4932 sprintf(atcmd_output,msg_txt(402),msg_txt(1137),year,month,day,hour,minute); //%s in jail for %d years, %d months, %d days, %d hours and %d minutes
4933 clif_displaymessage(pl_sd->fd, atcmd_output);
4934 sprintf(atcmd_output,msg_txt(402),msg_txt(1138),year,month,day,hour,minute); //This player is now in jail for %d years, %d months, %d days, %d hours and %d minutes
4935 clif_displaymessage(fd, atcmd_output);
4936 }
4937 } else if (jailtime < 0) {
4938 clif_displaymessage(fd, msg_txt(1136));
4939 return -1;
4940 }
4941
4942 //Jail locations, add more as you wish.
4943 switch(rnd()%2)
4944 {
4945 case 1: //Jail #1
4946 m_index = mapindex_name2id(MAP_JAIL);
4947 x = 49; y = 75;
4948 break;
4949 default: //Default Jail
4950 m_index = mapindex_name2id(MAP_JAIL);
4951 x = 24; y = 75;
4952 break;
4953 }
4954
4955 sc_start4(&pl_sd->bl,SC_JAILED,100,jailtime,m_index,x,y,jailtime?60000:1000); //jailtime = 0: Time was reset to 0. Wait 1 second to warp player out (since it's done in status_change_timer).
4956 return 0;
4957}
4958
4959
4960//By Coltaro
4961ACMD_FUNC(jailtime)
4962{
4963 int year, month, day, hour, minute;
4964
4965 nullpo_retr(-1, sd);
4966
4967 if (!sd->sc.data[SC_JAILED]) {
4968 clif_displaymessage(fd, msg_txt(1139)); // You are not in jail.
4969 return -1;
4970 }
4971
4972 if (sd->sc.data[SC_JAILED]->val1 == INT_MAX) {
4973 clif_displaymessage(fd, msg_txt(1140)); // You have been jailed indefinitely.
4974 return 0;
4975 }
4976
4977 if (sd->sc.data[SC_JAILED]->val1 <= 0) { // Was not jailed with @jailfor (maybe @jail? or warped there? or got recalled?)
4978 clif_displaymessage(fd, msg_txt(1141)); // You have been jailed for an unknown amount of time.
4979 return -1;
4980 }
4981
4982 //Get remaining jail time
4983 get_jail_time(sd->sc.data[SC_JAILED]->val1,&year,&month,&day,&hour,&minute);
4984 sprintf(atcmd_output,msg_txt(402),msg_txt(1142),year,month,day,hour,minute); // You will remain in jail for %d years, %d months, %d days, %d hours and %d minutes
4985
4986 clif_displaymessage(fd, atcmd_output);
4987
4988 return 0;
4989}
4990
4991/*==========================================
4992 * @disguise <mob_id> by [Valaris] (simplified by [Yor])
4993 *------------------------------------------*/
4994ACMD_FUNC(disguise)
4995{
4996 int id = 0;
4997 nullpo_retr(-1, sd);
4998
4999 if (!message || !*message) {
5000 clif_displaymessage(fd, msg_txt(1143)); // Please enter a Monster/NPC name/ID (usage: @disguise <name/ID>).
5001 return -1;
5002 }
5003
5004 if ((id = atoi(message)) > 0)
5005 { //Acquired an ID
5006 if (!mobdb_checkid(id) && !npcdb_checkid(id))
5007 id = 0; //Invalid id for either mobs or npcs.
5008 } else { //Acquired a Name
5009 if ((id = mobdb_searchname(message)) == 0)
5010 {
5011 struct npc_data* nd = npc_name2id(message);
5012 if (nd != NULL)
5013 id = nd->class_;
5014 }
5015 }
5016
5017 if (id == 0)
5018 {
5019 clif_displaymessage(fd, msg_txt(123)); // Invalid Monster/NPC name/ID specified.
5020 return -1;
5021 }
5022
5023 if(pc_isriding(sd))
5024 {
5025 clif_displaymessage(fd, msg_txt(1144)); // Character cannot be disguised while mounted.
5026 return -1;
5027 }
5028
5029 pc_disguise(sd, id);
5030 clif_displaymessage(fd, msg_txt(122)); // Disguise applied.
5031
5032 return 0;
5033}
5034
5035/*==========================================
5036 * DisguiseAll
5037 *------------------------------------------*/
5038ACMD_FUNC(disguiseall)
5039{
5040 int mob_id=0;
5041 struct map_session_data *pl_sd;
5042 struct s_mapiterator* iter;
5043 nullpo_retr(-1, sd);
5044
5045 if (!message || !*message) {
5046 clif_displaymessage(fd, msg_txt(1145)); // Please enter a Monster/NPC name/ID (usage: @disguiseall <name/ID>).
5047 return -1;
5048 }
5049
5050 if ((mob_id = mobdb_searchname(message)) == 0) // check name first (to avoid possible name begining by a number)
5051 mob_id = atoi(message);
5052
5053 if (!mobdb_checkid(mob_id) && !npcdb_checkid(mob_id)) { //if mob or npc...
5054 clif_displaymessage(fd, msg_txt(123)); // Monster/NPC name/id not found.
5055 return -1;
5056 }
5057
5058 iter = mapit_getallusers();
5059 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
5060 {
5061 if( !pc_isriding(pl_sd) )
5062 pc_disguise(pl_sd, mob_id);
5063 }
5064 mapit_free(iter);
5065
5066 clif_displaymessage(fd, msg_txt(122)); // Disguise applied.
5067 return 0;
5068}
5069
5070/*==========================================
5071 * DisguiseGuild
5072 *------------------------------------------*/
5073ACMD_FUNC(disguiseguild)
5074{
5075 int id = 0, i;
5076 char monster[NAME_LENGTH], guild[NAME_LENGTH];
5077 struct map_session_data *pl_sd;
5078 struct guild *g;
5079
5080 memset(monster, '\0', sizeof(monster));
5081 memset(guild, '\0', sizeof(guild));
5082
5083 if( !message || !*message || sscanf(message, "%23[^,], %23[^\r\n]", monster, guild) < 2 ) {
5084 clif_displaymessage(fd, msg_txt(1146)); // Please enter a mob name/ID and guild name/ID (usage: @disguiseguild <mob name/ID>, <guild name/ID>).
5085 return -1;
5086 }
5087
5088 if( (id = atoi(monster)) > 0 ) {
5089 if( !mobdb_checkid(id) && !npcdb_checkid(id) )
5090 id = 0;
5091 } else {
5092 if( (id = mobdb_searchname(monster)) == 0 ) {
5093 struct npc_data* nd = npc_name2id(monster);
5094 if( nd != NULL )
5095 id = nd->class_;
5096 }
5097 }
5098
5099 if( id == 0 ) {
5100 clif_displaymessage(fd, msg_txt(123)); // Monster/NPC name/id hasn't been found.
5101 return -1;
5102 }
5103
5104 if( (g = guild_searchname(guild)) == NULL && (g = guild_search(atoi(guild))) == NULL ) {
5105 clif_displaymessage(fd, msg_txt(94)); // Incorrect name/ID, or no one from the guild is online.
5106 return -1;
5107 }
5108
5109 for( i = 0; i < g->max_member; i++ )
5110 if( (pl_sd = g->member[i].sd) && !pc_isriding(pl_sd) )
5111 pc_disguise(pl_sd, id);
5112
5113 clif_displaymessage(fd, msg_txt(122)); // Disguise applied.
5114 return 0;
5115}
5116
5117
5118/*==========================================
5119 * @undisguise by [Yor]
5120 *------------------------------------------*/
5121ACMD_FUNC(undisguise)
5122{
5123 nullpo_retr(-1, sd);
5124 if (sd->disguise) {
5125 pc_disguise(sd, 0);
5126 clif_displaymessage(fd, msg_txt(124)); // Undisguise applied.
5127 } else {
5128 clif_displaymessage(fd, msg_txt(125)); // You're not disguised.
5129 return -1;
5130 }
5131
5132 return 0;
5133}
5134
5135/*==========================================
5136 * UndisguiseAll
5137 *------------------------------------------*/
5138ACMD_FUNC(undisguiseall)
5139{
5140 struct map_session_data *pl_sd;
5141 struct s_mapiterator* iter;
5142 nullpo_retr(-1, sd);
5143
5144 iter = mapit_getallusers();
5145 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
5146 if( pl_sd->disguise )
5147 pc_disguise(pl_sd, 0);
5148 mapit_free(iter);
5149
5150 clif_displaymessage(fd, msg_txt(124)); // Undisguise applied.
5151
5152 return 0;
5153}
5154
5155/*==========================================
5156 * UndisguiseGuild
5157 *------------------------------------------*/
5158ACMD_FUNC(undisguiseguild)
5159{
5160 char guild_name[NAME_LENGTH];
5161 struct map_session_data *pl_sd;
5162 struct guild *g;
5163 int i;
5164 nullpo_retr(-1, sd);
5165
5166 memset(guild_name, '\0', sizeof(guild_name));
5167
5168 if(!message || !*message || sscanf(message, "%23[^\n]", guild_name) < 1) {
5169 clif_displaymessage(fd, msg_txt(1147)); // Please enter guild name/ID (usage: @undisguiseguild <guild name/ID>).
5170 return -1;
5171 }
5172
5173 if( (g = guild_searchname(guild_name)) == NULL && (g = guild_search(atoi(message))) == NULL ) {
5174 clif_displaymessage(fd, msg_txt(94)); // Incorrect name/ID, or no one from the guild is online.
5175 return -1;
5176 }
5177
5178 for(i = 0; i < g->max_member; i++)
5179 if( (pl_sd = g->member[i].sd) && pl_sd->disguise )
5180 pc_disguise(pl_sd, 0);
5181
5182 clif_displaymessage(fd, msg_txt(124)); // Undisguise applied.
5183
5184 return 0;
5185}
5186
5187/*==========================================
5188 * @exp by [Skotlex]
5189 *------------------------------------------*/
5190ACMD_FUNC(exp)
5191{
5192 char output[CHAT_SIZE_MAX];
5193 double nextb, nextj;
5194 nullpo_retr(-1, sd);
5195 memset(output, '\0', sizeof(output));
5196
5197 nextb = pc_nextbaseexp(sd);
5198 if (nextb)
5199 nextb = sd->status.base_exp*100.0/nextb;
5200
5201 nextj = pc_nextjobexp(sd);
5202 if (nextj)
5203 nextj = sd->status.job_exp*100.0/nextj;
5204
5205 sprintf(output, msg_txt(1148), sd->status.base_level, nextb, sd->status.job_level, nextj); // Base Level: %d (%.3f%%) | Job Level: %d (%.3f%%)
5206 clif_displaymessage(fd, output);
5207 return 0;
5208}
5209
5210
5211/*==========================================
5212 * @broadcast by [Valaris]
5213 *------------------------------------------*/
5214ACMD_FUNC(broadcast)
5215{
5216 nullpo_retr(-1, sd);
5217
5218 memset(atcmd_output, '\0', sizeof(atcmd_output));
5219
5220 if (!message || !*message) {
5221 clif_displaymessage(fd, msg_txt(1149)); // Please enter a message (usage: @broadcast <message>).
5222 return -1;
5223 }
5224
5225 sprintf(atcmd_output, "%s: %s", sd->status.name, message);
5226 intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, 0);
5227
5228 return 0;
5229}
5230
5231/*==========================================
5232 * @localbroadcast by [Valaris]
5233 *------------------------------------------*/
5234ACMD_FUNC(localbroadcast)
5235{
5236 nullpo_retr(-1, sd);
5237
5238 memset(atcmd_output, '\0', sizeof(atcmd_output));
5239
5240 if (!message || !*message) {
5241 clif_displaymessage(fd, msg_txt(1150)); // Please enter a message (usage: @localbroadcast <message>).
5242 return -1;
5243 }
5244
5245 sprintf(atcmd_output, "%s: %s", sd->status.name, message);
5246
5247 clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP);
5248
5249 return 0;
5250}
5251
5252/*==========================================
5253 * @email <actual@email> <new@email> by [Yor]
5254 *------------------------------------------*/
5255ACMD_FUNC(email)
5256{
5257 char actual_email[100];
5258 char new_email[100];
5259 nullpo_retr(-1, sd);
5260
5261 memset(actual_email, '\0', sizeof(actual_email));
5262 memset(new_email, '\0', sizeof(new_email));
5263
5264 if (!message || !*message || sscanf(message, "%99s %99s", actual_email, new_email) < 2) {
5265 clif_displaymessage(fd, msg_txt(1151)); // Please enter 2 emails (usage: @email <actual@email> <new@email>).
5266 return -1;
5267 }
5268
5269 if (e_mail_check(actual_email) == 0) {
5270 clif_displaymessage(fd, msg_txt(144)); // Invalid actual email. If you have default e-mail, give a@a.com.
5271 return -1;
5272 } else if (e_mail_check(new_email) == 0) {
5273 clif_displaymessage(fd, msg_txt(145)); // Invalid new email. Please enter a real e-mail.
5274 return -1;
5275 } else if (strcmpi(new_email, "a@a.com") == 0) {
5276 clif_displaymessage(fd, msg_txt(146)); // New email must be a real e-mail.
5277 return -1;
5278 } else if (strcmpi(actual_email, new_email) == 0) {
5279 clif_displaymessage(fd, msg_txt(147)); // New email must be different of the actual e-mail.
5280 return -1;
5281 }
5282
5283 chrif_changeemail(sd->status.account_id, actual_email, new_email);
5284 clif_displaymessage(fd, msg_txt(148)); // Information sended to login-server via char-server.
5285 return 0;
5286}
5287
5288/*==========================================
5289 *@effect
5290 *------------------------------------------*/
5291ACMD_FUNC(effect)
5292{
5293 int type = 0, flag = 0;
5294 nullpo_retr(-1, sd);
5295
5296 if (!message || !*message || sscanf(message, "%d", &type) < 1) {
5297 clif_displaymessage(fd, msg_txt(1152)); // Please enter an effect number (usage: @effect <effect number>).
5298 return -1;
5299 }
5300
5301 clif_specialeffect(&sd->bl, type, (send_target)flag);
5302 clif_displaymessage(fd, msg_txt(229)); // Your effect has changed.
5303 return 0;
5304}
5305
5306/*==========================================
5307 * @killer by MouseJstr
5308 * enable killing players even when not in pvp
5309 *------------------------------------------*/
5310ACMD_FUNC(killer)
5311{
5312 nullpo_retr(-1, sd);
5313 sd->state.killer = !sd->state.killer;
5314
5315 if(sd->state.killer)
5316 clif_displaymessage(fd, msg_txt(241));
5317 else {
5318 clif_displaymessage(fd, msg_txt(287));
5319 pc_stop_attack(sd);
5320 }
5321 return 0;
5322}
5323
5324/*==========================================
5325 * @killable by MouseJstr
5326 * enable other people killing you
5327 *------------------------------------------*/
5328ACMD_FUNC(killab