
* Changed Guild/Party Bound Item Retrieval Methods: - Fixes bugreport:9338 - Now resend the list to map-server from char/inter-server to avoid "weird" item allocation on guild storage. Example, previously you will meet stacked item like GUID does, but it shouldn't! - Also will check the maximum amount that can be store in guild store. If guild storage is full (the slots or item stack limit is reach) the rest value/item will be dropped. - Account of kicked guild member won't be kicked from server any more if the player idle on character select window (just prevents player to login when retrieving items are in progress) - Delete guild bound items from guild master when guild is disbanded! Previously, the bound type just changed to NONE. Also for party bound item. - If kicked guild/party member is trading bound item when be kicked, the trade will be cancelled! - If the guild member is being kicked when open guild storage, storage will be closed first waiting for next item retrieval. - Now when guild storage is opened, storage_status (changed the var to 'opened') will be used to hold char_id who opens it. * Misc: - Cleanup guild storage prefix functions, changed them to "gstorage_*" - Added picklog type 'B' for logging deleted bound item because of kicked from guild/party. - Updated documentation for new used packet 0x3857
10461 lines
312 KiB
C
10461 lines
312 KiB
C
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
|
|
// For more information, see LICENCE in the main folder
|
|
|
|
#include "../common/cbasetypes.h"
|
|
#include "../common/mmo.h"
|
|
#include "../common/timer.h"
|
|
#include "../common/nullpo.h"
|
|
#include "../common/showmsg.h"
|
|
#include "../common/malloc.h"
|
|
#include "../common/random.h"
|
|
#include "../common/socket.h"
|
|
#include "../common/strlib.h"
|
|
#include "../common/utils.h"
|
|
#include "../common/conf.h"
|
|
|
|
#include "map.h"
|
|
#include "atcommand.h"
|
|
#include "battle.h"
|
|
#include "chat.h"
|
|
#include "channel.h"
|
|
#include "chrif.h"
|
|
#include "duel.h"
|
|
#include "instance.h"
|
|
#include "intif.h"
|
|
#include "pet.h"
|
|
#include "homunculus.h"
|
|
#include "mail.h"
|
|
#include "mercenary.h"
|
|
#include "elemental.h"
|
|
#include "party.h"
|
|
#include "storage.h"
|
|
#include "trade.h"
|
|
#include "mapreg.h"
|
|
#include "quest.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
|
|
#define ATCOMMAND_LENGTH 50
|
|
#define ACMD_FUNC(x) static int atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message)
|
|
|
|
typedef struct AtCommandInfo AtCommandInfo;
|
|
typedef struct AliasInfo AliasInfo;
|
|
|
|
int atcmd_binding_count = 0;
|
|
|
|
/// Atcommand restriction usage
|
|
enum e_atcmd_restict {
|
|
ATCMD_NOCONSOLE = 0x1, /// Cannot be used via console (is_atcommand type 2)
|
|
ATCMD_NOSCRIPT = 0x2, /// Cannot be used via script command 'atcommand' or 'useatcmd' (is_atcommand type 0 and 3)
|
|
ATCMD_NOAUTOTRADE = 0x4, /// Like ATCMD_NOSCRIPT, but if the player is autotrader. Example: atcommand "@kick "+strcharinfo(0);
|
|
};
|
|
|
|
struct AtCommandInfo {
|
|
char command[ATCOMMAND_LENGTH];
|
|
AtCommandFunc func;
|
|
char* at_groups; /// Quick @commands "can-use" lookup
|
|
char* char_groups; /// Quick @charcommands "can-use" lookup
|
|
uint8 restriction; /// Restrictions see enum e_restict
|
|
};
|
|
|
|
struct AliasInfo {
|
|
AtCommandInfo *command;
|
|
char alias[ATCOMMAND_LENGTH];
|
|
};
|
|
|
|
|
|
char atcommand_symbol = '@'; // first char of the commands
|
|
char charcommand_symbol = '#';
|
|
|
|
static DBMap* atcommand_db = NULL; //name -> AtCommandInfo
|
|
static DBMap* atcommand_alias_db = NULL; //alias -> AtCommandInfo
|
|
static config_t atcommand_config;
|
|
|
|
static char atcmd_output[CHAT_SIZE_MAX];
|
|
static char atcmd_player_name[NAME_LENGTH];
|
|
const char *parent_cmd;
|
|
|
|
static AtCommandInfo* get_atcommandinfo_byname(const char *name); // @help
|
|
static const char* atcommand_checkalias(const char *aliasname); // @help
|
|
static void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool atcommand); // @help
|
|
static void warp_get_suggestions(struct map_session_data* sd, const char *name); // @rura, @warp, @mapmove
|
|
|
|
// @commands (script-based)
|
|
struct atcmd_binding_data* get_atcommandbind_byname(const char* name) {
|
|
int i = 0;
|
|
|
|
if( *name == atcommand_symbol || *name == charcommand_symbol )
|
|
name++; // for backwards compatibility
|
|
|
|
ARR_FIND( 0, atcmd_binding_count, i, strcmpi(atcmd_binding[i]->command, name) == 0 );
|
|
|
|
return ( i < atcmd_binding_count ) ? atcmd_binding[i] : NULL;
|
|
}
|
|
|
|
/**
|
|
* retrieves the help string associated with a given command.
|
|
*
|
|
* @param name the name of the command to retrieve help information for
|
|
* @return the string associated with the command, or NULL
|
|
*/
|
|
static const char* atcommand_help_string(const char* command)
|
|
{
|
|
const char* str = NULL;
|
|
config_setting_t* info;
|
|
|
|
if( *command == atcommand_symbol || *command == charcommand_symbol )
|
|
{// remove the prefix symbol for the raw name of the command
|
|
command ++;
|
|
}
|
|
|
|
// convert alias to the real command name
|
|
command = atcommand_checkalias(command);
|
|
|
|
// attempt to find the first default help command
|
|
info = config_lookup(&atcommand_config, "help");
|
|
|
|
if( info == NULL )
|
|
{// failed to find the help property in the configuration file
|
|
return NULL;
|
|
}
|
|
|
|
if( !config_setting_lookup_string( info, command, &str ) )
|
|
{// failed to find the matching help string
|
|
return NULL;
|
|
}
|
|
|
|
// push the result from the method
|
|
return str;
|
|
}
|
|
|
|
|
|
/*==========================================
|
|
* @send (used for testing packet sends from the client)
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(send)
|
|
{
|
|
int len=0,type;
|
|
// read message type as hex number (without the 0x)
|
|
if(!message || !*message ||
|
|
!((sscanf(message, "len %x", &type)==1 && (len=1))
|
|
|| sscanf(message, "%x", &type)==1) )
|
|
{
|
|
int i;
|
|
for (i = 900; i <= 903; ++i)
|
|
clif_displaymessage(fd, msg_txt(sd,i));
|
|
return -1;
|
|
}
|
|
|
|
#define PARSE_ERROR(error,p) \
|
|
{\
|
|
clif_displaymessage(fd, (error));\
|
|
sprintf(atcmd_output, ">%s", (p));\
|
|
clif_displaymessage(fd, atcmd_output);\
|
|
}
|
|
//define PARSE_ERROR
|
|
|
|
#define CHECK_EOS(p) \
|
|
if(*(p) == 0){\
|
|
clif_displaymessage(fd, "Unexpected end of string");\
|
|
return -1;\
|
|
}
|
|
//define CHECK_EOS
|
|
|
|
#define SKIP_VALUE(p) \
|
|
{\
|
|
while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\
|
|
while(*(p) && ISSPACE(*(p))) ++(p); /* space */\
|
|
}
|
|
//define SKIP_VALUE
|
|
|
|
#define GET_VALUE(p,num) \
|
|
{\
|
|
if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\
|
|
PARSE_ERROR("Invalid number in:",(p));\
|
|
return -1;\
|
|
}\
|
|
}
|
|
//define GET_VALUE
|
|
if (type > 0 && type < MAX_PACKET_DB) {
|
|
int off,end;
|
|
long num;
|
|
if(len)
|
|
{// show packet length
|
|
sprintf(atcmd_output, msg_txt(sd,904), type, packet_db[sd->packet_ver][type].len); // Packet 0x%x length: %d
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
len=packet_db[sd->packet_ver][type].len;
|
|
off=2;
|
|
if(len == 0)
|
|
{// unknown packet - ERROR
|
|
sprintf(atcmd_output, msg_txt(sd,905), type); // Unknown packet: 0x%x
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
} else if(len == -1)
|
|
{// dynamic packet
|
|
len=SHRT_MAX-4; // maximum length
|
|
off=4;
|
|
}
|
|
WFIFOHEAD(fd, len);
|
|
WFIFOW(fd,0)=TOW(type);
|
|
|
|
// parse packet contents
|
|
SKIP_VALUE(message);
|
|
while(*message != 0 && off < len){
|
|
if(ISDIGIT(*message) || *message == '-' || *message == '+')
|
|
{// default (byte)
|
|
GET_VALUE(message,num);
|
|
WFIFOB(fd,off)=TOB(num);
|
|
++off;
|
|
} else if(TOUPPER(*message) == 'B')
|
|
{// byte
|
|
++message;
|
|
GET_VALUE(message,num);
|
|
WFIFOB(fd,off)=TOB(num);
|
|
++off;
|
|
} else if(TOUPPER(*message) == 'W')
|
|
{// word (2 bytes)
|
|
++message;
|
|
GET_VALUE(message,num);
|
|
WFIFOW(fd,off)=TOW(num);
|
|
off+=2;
|
|
} else if(TOUPPER(*message) == 'L')
|
|
{// long word (4 bytes)
|
|
++message;
|
|
GET_VALUE(message,num);
|
|
WFIFOL(fd,off)=TOL(num);
|
|
off+=4;
|
|
} else if(TOUPPER(*message) == 'S')
|
|
{// string - escapes are valid
|
|
// get string length - num <= 0 means not fixed length (default)
|
|
++message;
|
|
if(*message == '"'){
|
|
num=0;
|
|
} else {
|
|
GET_VALUE(message,num);
|
|
while(*message != '"')
|
|
{// find start of string
|
|
if(*message == 0 || ISSPACE(*message)){
|
|
PARSE_ERROR(msg_txt(sd,906),message); // Not a string:
|
|
return -1;
|
|
}
|
|
++message;
|
|
}
|
|
}
|
|
|
|
// parse string
|
|
++message;
|
|
CHECK_EOS(message);
|
|
end=(num<=0? 0: min(off+((int)num),len));
|
|
for(; *message != '"' && (off < end || end == 0); ++off){
|
|
if(*message == '\\'){
|
|
++message;
|
|
CHECK_EOS(message);
|
|
switch(*message){
|
|
case 'a': num=0x07; break; // Bell
|
|
case 'b': num=0x08; break; // Backspace
|
|
case 't': num=0x09; break; // Horizontal tab
|
|
case 'n': num=0x0A; break; // Line feed
|
|
case 'v': num=0x0B; break; // Vertical tab
|
|
case 'f': num=0x0C; break; // Form feed
|
|
case 'r': num=0x0D; break; // Carriage return
|
|
case 'e': num=0x1B; break; // Escape
|
|
default: num=*message; break;
|
|
case 'x': // Hexadecimal
|
|
{
|
|
++message;
|
|
CHECK_EOS(message);
|
|
if(!ISXDIGIT(*message)){
|
|
PARSE_ERROR(msg_txt(sd,907),message); // Not a hexadecimal digit:
|
|
return -1;
|
|
}
|
|
num=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10);
|
|
if(ISXDIGIT(*message)){
|
|
++message;
|
|
CHECK_EOS(message);
|
|
num<<=8;
|
|
num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10);
|
|
}
|
|
WFIFOB(fd,off)=TOB(num);
|
|
++message;
|
|
CHECK_EOS(message);
|
|
continue;
|
|
}
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7': // Octal
|
|
{
|
|
num=*message-'0'; // 1st octal digit
|
|
++message;
|
|
CHECK_EOS(message);
|
|
if(ISDIGIT(*message) && *message < '8'){
|
|
num<<=3;
|
|
num+=*message-'0'; // 2nd octal digit
|
|
++message;
|
|
CHECK_EOS(message);
|
|
if(ISDIGIT(*message) && *message < '8'){
|
|
num<<=3;
|
|
num+=*message-'0'; // 3rd octal digit
|
|
++message;
|
|
CHECK_EOS(message);
|
|
}
|
|
}
|
|
WFIFOB(fd,off)=TOB(num);
|
|
continue;
|
|
}
|
|
}
|
|
} else
|
|
num=*message;
|
|
WFIFOB(fd,off)=TOB(num);
|
|
++message;
|
|
CHECK_EOS(message);
|
|
}//for
|
|
while(*message != '"')
|
|
{// ignore extra characters
|
|
++message;
|
|
CHECK_EOS(message);
|
|
}
|
|
|
|
// terminate the string
|
|
if(off < end)
|
|
{// fill the rest with 0's
|
|
memset(WFIFOP(fd,off),0,end-off);
|
|
off=end;
|
|
}
|
|
} else
|
|
{// unknown
|
|
PARSE_ERROR(msg_txt(sd,908),message); // Unknown type of value in:
|
|
return -1;
|
|
}
|
|
SKIP_VALUE(message);
|
|
}
|
|
|
|
if(packet_db[sd->packet_ver][type].len == -1)
|
|
{// send dynamic packet
|
|
WFIFOW(fd,2)=TOW(off);
|
|
WFIFOSET(fd,off);
|
|
} else
|
|
{// send static packet
|
|
if(off < len)
|
|
memset(WFIFOP(fd,off),0,len-off);
|
|
WFIFOSET(fd,len);
|
|
}
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,259)); // Invalid packet
|
|
return -1;
|
|
}
|
|
sprintf (atcmd_output, msg_txt(sd,258), type, type); // Sent packet 0x%x (%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
#undef PARSE_ERROR
|
|
#undef CHECK_EOS
|
|
#undef SKIP_VALUE
|
|
#undef GET_VALUE
|
|
}
|
|
|
|
/**
|
|
* Retrieves map name suggestions for a given string.
|
|
* This will first check if any map names contain the given string, and will
|
|
* print out MAX_SUGGESTIONS results if any maps are found.
|
|
* Otherwise, suggestions will be calculated through Levenshtein distance,
|
|
* and up to 5 of the closest matches will be printed.
|
|
*
|
|
* @author Euphy
|
|
*/
|
|
static void warp_get_suggestions(struct map_session_data* sd, const char *name) {
|
|
char buffer[512];
|
|
int i, count = 0;
|
|
|
|
if (strlen(name) < 2)
|
|
return;
|
|
|
|
// build the suggestion string
|
|
strcpy(buffer, msg_txt(sd, 205)); // Maybe you meant:
|
|
strcat(buffer, "\n");
|
|
|
|
// check for maps that contain string
|
|
for (i = 0; i < MAX_MAP_PER_SERVER; i++) {
|
|
if (count < MAX_SUGGESTIONS && strstr(map[i].name, name) != NULL) {
|
|
strcat(buffer, map[i].name);
|
|
strcat(buffer, " ");
|
|
if (++count >= MAX_SUGGESTIONS)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if no maps found, search by edit distance
|
|
if (!count) {
|
|
unsigned int distance[MAX_MAP_PER_SERVER][2];
|
|
int j;
|
|
|
|
// calculate Levenshtein distance for all maps
|
|
for (i = 0; i < MAX_MAP_PER_SERVER; i++) {
|
|
if (strlen(map[i].name) < 4) // invalid map name?
|
|
distance[i][0] = INT_MAX;
|
|
else {
|
|
distance[i][0] = levenshtein(map[i].name, name);
|
|
distance[i][1] = i;
|
|
}
|
|
}
|
|
|
|
// selection sort elements as needed
|
|
count = min(MAX_SUGGESTIONS, 5); // results past 5 aren't worth showing
|
|
for (i = 0; i < count; i++) {
|
|
int min = i;
|
|
for (j = i+1; j < MAX_MAP_PER_SERVER; j++) {
|
|
if (distance[j][0] < distance[min][0])
|
|
min = j;
|
|
}
|
|
|
|
// print map name
|
|
if (distance[min][0] > 4) { // awful results, don't bother
|
|
if (!i) return;
|
|
break;
|
|
}
|
|
strcat(buffer, map[distance[min][1]].name);
|
|
strcat(buffer, " ");
|
|
|
|
// swap elements
|
|
swap(distance[i][0], distance[min][0]);
|
|
swap(distance[i][1], distance[min][1]);
|
|
}
|
|
}
|
|
|
|
clif_displaymessage(sd->fd, buffer);
|
|
}
|
|
|
|
/*==========================================
|
|
* @rura, @warp, @mapmove
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(mapmove)
|
|
{
|
|
char map_name[MAP_NAME_LENGTH_EXT];
|
|
unsigned short mapindex;
|
|
short x = 0, y = 0;
|
|
int16 m = -1;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(map_name, '\0', sizeof(map_name));
|
|
|
|
if (!message || !*message ||
|
|
(sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 &&
|
|
sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) {
|
|
clif_displaymessage(fd, msg_txt(sd,909)); // Please enter a map (usage: @warp/@rura/@mapmove <mapname> <x> <y>).
|
|
return -1;
|
|
}
|
|
|
|
mapindex = mapindex_name2id(map_name);
|
|
if (mapindex)
|
|
m = map_mapindex2mapid(mapindex);
|
|
|
|
if (!mapindex) { // m < 0 means on different server! [Kevin]
|
|
clif_displaymessage(fd, msg_txt(sd,1)); // Map not found.
|
|
|
|
if (battle_config.warp_suggestions_enabled)
|
|
warp_get_suggestions(sd, map_name);
|
|
|
|
return -1;
|
|
}
|
|
|
|
if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS))
|
|
{ //This is to prevent the pc_setpos call from printing an error.
|
|
clif_displaymessage(fd, msg_txt(sd,2));
|
|
if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1))
|
|
x = y = 0; //Invalid cell, use random spot.
|
|
}
|
|
if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,247));
|
|
return -1;
|
|
}
|
|
if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,248));
|
|
return -1;
|
|
}
|
|
if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1)); // Map not found.
|
|
return -1;
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,0)); // Warped.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Displays where a character is. Corrected version by Silent. [Skotlex]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(where)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
|
|
nullpo_retr(-1, sd);
|
|
memset(atcmd_player_name, '\0', sizeof atcmd_player_name);
|
|
|
|
if (!message || !*message || sscanf(message, "%23s[^\n]", atcmd_player_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,910)); // Please enter a player name (usage: @where <char name>).
|
|
return -1;
|
|
}
|
|
|
|
pl_sd = map_nick2sd(atcmd_player_name);
|
|
if (pl_sd == NULL ||
|
|
strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 ||
|
|
(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))
|
|
) {
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
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);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(jumpto)
|
|
{
|
|
struct map_session_data *pl_sd = NULL;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,911)); // Please enter a player name (usage: @jumpto/@warpto/@goto <char name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,247)); // You are not authorized to warp to this map.
|
|
return -1;
|
|
}
|
|
|
|
if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,248)); // You are not authorized to warp from your current map.
|
|
return -1;
|
|
}
|
|
|
|
if( pc_isdead(sd) )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,664));
|
|
return -1;
|
|
}
|
|
|
|
pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
|
|
sprintf(atcmd_output, msg_txt(sd,4), pl_sd->status.name); // Jumped to %s
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(jump)
|
|
{
|
|
short x = 0, y = 0;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
sscanf(message, "%hd %hd", &x, &y);
|
|
|
|
if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,248)); // You are not authorized to warp from your current map.
|
|
return -1;
|
|
}
|
|
|
|
if( pc_isdead(sd) )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,664));
|
|
return -1;
|
|
}
|
|
|
|
if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS))
|
|
{ //This is to prevent the pc_setpos call from printing an error.
|
|
clif_displaymessage(fd, msg_txt(sd,2));
|
|
if (!map_search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1))
|
|
x = y = 0; //Invalid cell, use random spot.
|
|
}
|
|
|
|
pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT);
|
|
sprintf(atcmd_output, msg_txt(sd,5), sd->bl.x, sd->bl.y); // Jumped to %d %d
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Display list of online characters with
|
|
* various info.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(who) {
|
|
struct map_session_data *pl_sd = NULL;
|
|
struct s_mapiterator *iter = NULL;
|
|
char player_name[NAME_LENGTH] = "";
|
|
int count = 0;
|
|
int level = 0;
|
|
StringBuf buf;
|
|
/**
|
|
* 1 = @who : Player name, [Title], [Party name], [Guild name]
|
|
* 2 = @who2 : Player name, [Title], BLvl, JLvl, Job
|
|
* 3 = @who3 : [CID/AID] Player name [Title], Map, X, Y
|
|
*/
|
|
int display_type = 1;
|
|
int map_id = -1;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (strstr(command, "map") != NULL) {
|
|
char map_name[MAP_NAME_LENGTH_EXT] = "";
|
|
if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map_mapname2mapid(map_name)) < 0)
|
|
map_id = sd->bl.m;
|
|
} else {
|
|
sscanf(message, "%23s", player_name);
|
|
}
|
|
|
|
if (strstr(command, "2") != NULL)
|
|
display_type = 2;
|
|
else if (strstr(command, "3") != NULL)
|
|
display_type = 3;
|
|
|
|
level = pc_get_group_level(sd);
|
|
StringBuf_Init(&buf);
|
|
|
|
iter = mapit_getallusers();
|
|
for (pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter)) {
|
|
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
|
|
if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive
|
|
|| (map_id >= 0 && pl_sd->bl.m != map_id))
|
|
continue;
|
|
switch (display_type) {
|
|
case 2: {
|
|
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
|
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
|
StringBuf_Printf(&buf, msg_txt(sd,344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
|
|
StringBuf_Printf(&buf, msg_txt(sd,347), pl_sd->status.base_level, pl_sd->status.job_level,
|
|
job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s"
|
|
break;
|
|
}
|
|
case 3: {
|
|
if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID))
|
|
StringBuf_Printf(&buf, msg_txt(sd,912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) "
|
|
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
|
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
|
StringBuf_Printf(&buf, msg_txt(sd,344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
|
|
StringBuf_Printf(&buf, msg_txt(sd,348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d"
|
|
break;
|
|
}
|
|
default: {
|
|
struct party_data *p = party_search(pl_sd->status.party_id);
|
|
struct guild *g = pl_sd->guild;
|
|
|
|
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
|
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
|
StringBuf_Printf(&buf, msg_txt(sd,344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
|
|
if (p != NULL)
|
|
StringBuf_Printf(&buf, msg_txt(sd,345), p->party.name); // " | Party: '%s'"
|
|
if (g != NULL)
|
|
StringBuf_Printf(&buf, msg_txt(sd,346), g->name); // " | Guild: '%s'"
|
|
break;
|
|
}
|
|
}
|
|
clif_displaymessage(fd, StringBuf_Value(&buf));
|
|
StringBuf_Clear(&buf);
|
|
count++;
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
|
|
if (map_id < 0) {
|
|
if (count == 0)
|
|
StringBuf_Printf(&buf, msg_txt(sd,28)); // No player found.
|
|
else if (count == 1)
|
|
StringBuf_Printf(&buf, msg_txt(sd,29)); // 1 player found.
|
|
else
|
|
StringBuf_Printf(&buf, msg_txt(sd,30), count); // %d players found.
|
|
} else {
|
|
if (count == 0)
|
|
StringBuf_Printf(&buf, msg_txt(sd,54), map[map_id].name); // No player found in map '%s'.
|
|
else if (count == 1)
|
|
StringBuf_Printf(&buf, msg_txt(sd,55), map[map_id].name); // 1 player found in map '%s'.
|
|
else
|
|
StringBuf_Printf(&buf, msg_txt(sd,56), count, map[map_id].name); // %d players found in map '%s'.
|
|
}
|
|
clif_displaymessage(fd, StringBuf_Value(&buf));
|
|
StringBuf_Destroy(&buf);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(whogm)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
int j, count;
|
|
int level;
|
|
char match_text[CHAT_SIZE_MAX];
|
|
char player_name[NAME_LENGTH];
|
|
struct guild *g;
|
|
struct party_data *p;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
memset(match_text, '\0', sizeof(match_text));
|
|
memset(player_name, '\0', sizeof(player_name));
|
|
|
|
if (sscanf(message, "%199[^\n]", match_text) < 1)
|
|
strcpy(match_text, "");
|
|
for (j = 0; match_text[j]; j++)
|
|
match_text[j] = TOLOWER(match_text[j]);
|
|
|
|
count = 0;
|
|
level = pc_get_group_level(sd);
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
{
|
|
int pl_level = pc_get_group_level(pl_sd);
|
|
if (!pl_level)
|
|
continue;
|
|
|
|
if (match_text[0])
|
|
{
|
|
memcpy(player_name, pl_sd->status.name, NAME_LENGTH);
|
|
for (j = 0; player_name[j]; j++)
|
|
player_name[j] = TOLOWER(player_name[j]);
|
|
// search with no case sensitive
|
|
if (strstr(player_name, match_text) == NULL)
|
|
continue;
|
|
}
|
|
if (pl_level > level) {
|
|
if (pl_sd->sc.option & OPTION_INVISIBLE)
|
|
continue;
|
|
sprintf(atcmd_output, msg_txt(sd,913), pl_sd->status.name); // Name: %s (GM)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
count++;
|
|
continue;
|
|
}
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,914), // Name: %s (GM:%d) | Location: %s %d %d
|
|
pl_sd->status.name, pl_level,
|
|
mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,915), // BLvl: %d | Job: %s (Lvl: %d)
|
|
pl_sd->status.base_level,
|
|
job_name(pl_sd->status.class_), pl_sd->status.job_level);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
p = party_search(pl_sd->status.party_id);
|
|
g = pl_sd->guild;
|
|
|
|
sprintf(atcmd_output,msg_txt(sd,916), // Party: '%s' | Guild: '%s'
|
|
p?p->party.name:msg_txt(sd,917), g?g->name:msg_txt(sd,917)); // None.
|
|
|
|
clif_displaymessage(fd, atcmd_output);
|
|
count++;
|
|
}
|
|
mapit_free(iter);
|
|
|
|
if (count == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,150)); // No GM found.
|
|
else if (count == 1)
|
|
clif_displaymessage(fd, msg_txt(sd,151)); // 1 GM found.
|
|
else {
|
|
sprintf(atcmd_output, msg_txt(sd,152), count); // %d GMs found.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(save)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if( map[sd->bl.m].instance_id ) {
|
|
clif_displaymessage(fd, msg_txt(sd,383)); // You cannot create a savepoint in an instance.
|
|
return 1;
|
|
}
|
|
|
|
pc_setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y);
|
|
if (sd->status.pet_id > 0 && sd->pd)
|
|
intif_save_petdata(sd->status.account_id, &sd->pd->pet);
|
|
|
|
chrif_save(sd,0);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,6)); // Your save point has been changed.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(load)
|
|
{
|
|
int16 m;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
m = map_mapindex2mapid(sd->status.save_point.map);
|
|
if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,249)); // You are not authorized to warp to your save map.
|
|
return -1;
|
|
}
|
|
if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,248)); // You are not authorized to warp from your current map.
|
|
return -1;
|
|
}
|
|
|
|
pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT);
|
|
clif_displaymessage(fd, msg_txt(sd,7)); // Warping to save point..
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(speed)
|
|
{
|
|
int speed;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%d", &speed) < 1) {
|
|
sprintf(atcmd_output, msg_txt(sd,918), MIN_WALK_SPEED, MAX_WALK_SPEED); // Please enter a speed value (usage: @speed <%d-%d>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
sd->state.permanent_speed = 0; // Remove lock when set back to default speed.
|
|
|
|
if (speed < 0)
|
|
sd->base_status.speed = DEFAULT_WALK_SPEED;
|
|
else
|
|
sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED);
|
|
|
|
if (sd->base_status.speed != DEFAULT_WALK_SPEED) {
|
|
sd->state.permanent_speed = 1; // Set lock when set to non-default speed.
|
|
clif_displaymessage(fd, msg_txt(sd,8)); // Speed changed.
|
|
} else
|
|
clif_displaymessage(fd, msg_txt(sd,389)); // Speed returned to normal.
|
|
|
|
status_calc_bl(&sd->bl, SCB_SPEED);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(storage)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag)
|
|
return -1;
|
|
|
|
if (storage_storageopen(sd) == 1)
|
|
{ //Already open.
|
|
clif_displaymessage(fd, msg_txt(sd,250));
|
|
return -1;
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,919)); // Storage opened.
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(guildstorage)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!sd->status.guild_id) {
|
|
clif_displaymessage(fd, msg_txt(sd,252));
|
|
return -1;
|
|
}
|
|
|
|
if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading)
|
|
return -1;
|
|
|
|
if (sd->state.storage_flag == 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,250));
|
|
return -1;
|
|
}
|
|
|
|
if (sd->state.storage_flag == 2) {
|
|
clif_displaymessage(fd, msg_txt(sd,251));
|
|
return -1;
|
|
}
|
|
|
|
gstorage_storageopen(sd);
|
|
clif_displaymessage(fd, msg_txt(sd,920)); // Guild storage opened.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(option)
|
|
{
|
|
int param1 = 0, param2 = 0, param3 = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 || param1 < 0 || param2 < 0 || param3 < 0)
|
|
{// failed to match the parameters so inform the user of the options
|
|
const char* text;
|
|
|
|
// attempt to find the setting information for this command
|
|
text = atcommand_help_string( command );
|
|
|
|
// notify the user of the requirement to enter an option
|
|
clif_displaymessage(fd, msg_txt(sd,921)); // Please enter at least one option.
|
|
|
|
if( text )
|
|
{// send the help text associated with this command
|
|
clif_displaymessage( fd, text );
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
sd->sc.opt1 = param1;
|
|
sd->sc.opt2 = param2;
|
|
pc_setoption(sd, param3);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,9)); // Options changed.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(hide)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (sd->sc.option & OPTION_INVISIBLE) {
|
|
sd->sc.option &= ~OPTION_INVISIBLE;
|
|
if (sd->disguise)
|
|
status_set_viewdata(&sd->bl, sd->disguise);
|
|
else
|
|
status_set_viewdata(&sd->bl, sd->status.class_);
|
|
clif_displaymessage(fd, msg_txt(sd,10)); // Invisible: Off
|
|
|
|
// increment the number of pvp players on the map
|
|
map[sd->bl.m].users_pvp++;
|
|
|
|
if( !battle_config.pk_mode && map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank )
|
|
{// register the player for ranking calculations
|
|
sd->pvp_timer = add_timer( gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0 );
|
|
}
|
|
//bugreport:2266
|
|
map_foreachinmovearea(clif_insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl);
|
|
} else {
|
|
sd->sc.option |= OPTION_INVISIBLE;
|
|
sd->vd.class_ = INVISIBLE_CLASS;
|
|
clif_displaymessage(fd, msg_txt(sd,11)); // Invisible: On
|
|
|
|
// decrement the number of pvp players on the map
|
|
map[sd->bl.m].users_pvp--;
|
|
|
|
if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER )
|
|
{// unregister the player for ranking
|
|
delete_timer( sd->pvp_timer, pc_calc_pvprank_timer );
|
|
sd->pvp_timer = INVALID_TIMER;
|
|
}
|
|
}
|
|
clif_changeoption(&sd->bl);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Changes a character's class
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(jobchange)
|
|
{
|
|
int job = 0, upper = 0;
|
|
const char* text;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) {
|
|
int i;
|
|
bool found = false;
|
|
|
|
upper = 0;
|
|
|
|
// Normal Jobs
|
|
for( i = JOB_NOVICE; i < JOB_MAX_BASIC && !found; i++ ) {
|
|
if (strncmpi(message, job_name(i), 16) == 0) {
|
|
job = i;
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
// High Jobs, Babys and Third
|
|
for( i = JOB_NOVICE_HIGH; i < JOB_MAX && !found; i++ ) {
|
|
if (strncmpi(message, job_name(i), 16) == 0) {
|
|
job = i;
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
text = atcommand_help_string(command);
|
|
if (text)
|
|
clif_displaymessage(fd, text);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (job == JOB_KNIGHT2 || job == JOB_CRUSADER2 || job == JOB_WEDDING || job == JOB_XMAS || job == JOB_SUMMER || job == JOB_HANBOK || job == JOB_OKTOBERFEST
|
|
|| job == JOB_LORD_KNIGHT2 || job == JOB_PALADIN2 || job == JOB_BABY_KNIGHT2 || job == JOB_BABY_CRUSADER2 || job == JOB_STAR_GLADIATOR2
|
|
|| (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2))
|
|
{ // Deny direct transformation into dummy jobs
|
|
clif_displaymessage(fd, msg_txt(sd,923)); //"You can not change to this job by command."
|
|
return 0;
|
|
}
|
|
|
|
if (pcdb_checkid(job))
|
|
{
|
|
if (pc_jobchange(sd, job, upper))
|
|
clif_displaymessage(fd, msg_txt(sd,12)); // Your job has been changed.
|
|
else {
|
|
clif_displaymessage(fd, msg_txt(sd,155)); // You are unable to change your job.
|
|
return -1;
|
|
}
|
|
} else {
|
|
text = atcommand_help_string(command);
|
|
if (text)
|
|
clif_displaymessage(fd, text);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(kill)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
status_kill(&sd->bl);
|
|
clif_displaymessage(sd->fd, msg_txt(sd,13)); // A pity! You've died.
|
|
if (fd != sd->fd)
|
|
clif_displaymessage(fd, msg_txt(sd,14)); // Character killed.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(alive)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (!status_revive(&sd->bl, 100, 100))
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,667));
|
|
return -1;
|
|
}
|
|
clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1);
|
|
clif_displaymessage(fd, msg_txt(sd,16)); // You've been revived! It's a miracle!
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* +kamic [LuzZza]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(kami)
|
|
{
|
|
unsigned long color=0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if(*(command + 5) != 'c' && *(command + 5) != 'C') {
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,980)); // Please enter a message (usage: @kami <message>).
|
|
return -1;
|
|
}
|
|
|
|
sscanf(message, "%199[^\n]", atcmd_output);
|
|
if (strstr(command, "l") != NULL)
|
|
clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP);
|
|
else
|
|
intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? BC_BLUE : BC_DEFAULT);
|
|
} else {
|
|
if(!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) {
|
|
clif_displaymessage(fd, msg_txt(sd,981)); // Please enter color and message (usage: @kamic <color> <message>).
|
|
return -1;
|
|
}
|
|
|
|
if(color > 0xFFFFFF) {
|
|
clif_displaymessage(fd, msg_txt(sd,982)); // Invalid color.
|
|
return -1;
|
|
}
|
|
intif_broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(heal)
|
|
{
|
|
int hp = 0, sp = 0; // [Valaris] thanks to fov
|
|
nullpo_retr(-1, sd);
|
|
|
|
sscanf(message, "%d %d", &hp, &sp);
|
|
|
|
// some overflow checks
|
|
if( hp == INT_MIN ) hp++;
|
|
if( sp == INT_MIN ) sp++;
|
|
|
|
if ( hp == 0 && sp == 0 ) {
|
|
if (!status_percent_heal(&sd->bl, 100, 100))
|
|
clif_displaymessage(fd, msg_txt(sd,157)); // HP and SP have already been recovered.
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,17)); // HP, SP recovered.
|
|
return 0;
|
|
}
|
|
|
|
if ( hp > 0 && sp >= 0 ) {
|
|
if(!status_heal(&sd->bl, hp, sp, 0))
|
|
clif_displaymessage(fd, msg_txt(sd,157)); // HP and SP are already with the good value.
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,17)); // HP, SP recovered.
|
|
return 0;
|
|
}
|
|
|
|
if ( hp < 0 && sp <= 0 ) {
|
|
status_damage(NULL, &sd->bl, -hp, -sp, 0, 0);
|
|
clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, DMG_ENDURE, 0);
|
|
clif_displaymessage(fd, msg_txt(sd,156)); // HP or/and SP modified.
|
|
return 0;
|
|
}
|
|
|
|
//Opposing signs.
|
|
if ( hp ) {
|
|
if (hp > 0)
|
|
status_heal(&sd->bl, hp, 0, 0);
|
|
else {
|
|
status_damage(NULL, &sd->bl, -hp, 0, 0, 0);
|
|
clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, DMG_ENDURE, 0);
|
|
}
|
|
}
|
|
|
|
if ( sp ) {
|
|
if (sp > 0)
|
|
status_heal(&sd->bl, 0, sp, 0);
|
|
else
|
|
status_damage(NULL, &sd->bl, 0, -sp, 0, 0);
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,156)); // HP or/and SP modified.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @item command (usage: @item <itemdid1:itemid2:itemname:..> <quantity>) (modified by [Yor] for pet_egg)
|
|
* @itembound command (usage: @itembound <name/id_of_item> <quantity> <bound_type>)
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(item)
|
|
{
|
|
char item_name[100];
|
|
int number = 0, bound = BOUND_NONE;
|
|
char flag = 0;
|
|
struct item item_tmp;
|
|
struct item_data *item_data[10];
|
|
int get_count, i, j=0;
|
|
char *itemlist;
|
|
|
|
nullpo_retr(-1, sd);
|
|
memset(item_name, '\0', sizeof(item_name));
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
if (!strcmpi(parent_cmd,"itembound")) {
|
|
if (!message || !*message || (
|
|
sscanf(message, "\"%99[^\"]\" %d %d", item_name, &number, &bound) < 3 &&
|
|
sscanf(message, "%99s %d %d", item_name, &number, &bound) < 3))
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,295)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity> <bound_type>).
|
|
clif_displaymessage(fd, msg_txt(sd,298)); // Invalid bound type
|
|
return -1;
|
|
}
|
|
if( bound <= BOUND_NONE || bound >= BOUND_MAX ) {
|
|
clif_displaymessage(fd, msg_txt(sd,298)); // Invalid bound type
|
|
return -1;
|
|
}
|
|
} else if (!message || !*message || (
|
|
sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 &&
|
|
sscanf(message, "%99s %d", item_name, &number) < 1
|
|
)) {
|
|
clif_displaymessage(fd, msg_txt(sd,983)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity>).
|
|
return -1;
|
|
}
|
|
itemlist = strtok(item_name, ":");
|
|
while (itemlist != NULL && j<10) {
|
|
if ((item_data[j] = itemdb_searchname(itemlist)) == NULL &&
|
|
(item_data[j] = itemdb_exists(atoi(itemlist))) == NULL){
|
|
clif_displaymessage(fd, msg_txt(sd,19)); // Invalid item ID or name.
|
|
return -1;
|
|
}
|
|
itemlist = strtok(NULL, ":"); //next itemline
|
|
j++;
|
|
}
|
|
|
|
if (number <= 0)
|
|
number = 1;
|
|
get_count = number;
|
|
|
|
for(j--; j>=0; j--){ //produce items in list
|
|
unsigned short item_id = item_data[j]->nameid;
|
|
//Check if it's stackable.
|
|
if (!itemdb_isstackable2(item_data[j]))
|
|
get_count = 1;
|
|
|
|
for (i = 0; i < number; i += get_count) {
|
|
// if not pet egg
|
|
if (!pet_create_egg(sd, item_id)) {
|
|
memset(&item_tmp, 0, sizeof(item_tmp));
|
|
item_tmp.nameid = item_id;
|
|
item_tmp.identify = 1;
|
|
item_tmp.bound = bound;
|
|
if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
|
|
clif_additem(sd, 0, 0, flag);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,18)); // Item created.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(item2)
|
|
{
|
|
struct item item_tmp;
|
|
struct item_data *item_data;
|
|
char item_name[100];
|
|
unsigned short item_id;
|
|
int number = 0, bound = BOUND_NONE;
|
|
int identify = 0, refine = 0, attr = 0;
|
|
int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(item_name, '\0', sizeof(item_name));
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
if (!strcmpi(parent_cmd+1,"itembound2")) {
|
|
if (!message || !*message || (
|
|
sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 &&
|
|
sscanf(message, "%99s %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 ))
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,296)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity>
|
|
clif_displaymessage(fd, msg_txt(sd,297)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4> <bound_type>).
|
|
clif_displaymessage(fd, msg_txt(sd,298)); // Invalid bound type
|
|
return -1;
|
|
}
|
|
if( bound <= BOUND_NONE || bound >= BOUND_MAX ) {
|
|
clif_displaymessage(fd, msg_txt(sd,298)); // Invalid bound type
|
|
return -1;
|
|
}
|
|
} else if ( !message || !*message || (
|
|
sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 &&
|
|
sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9
|
|
)) {
|
|
clif_displaymessage(fd, msg_txt(sd,984)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity>
|
|
clif_displaymessage(fd, msg_txt(sd,985)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4>).
|
|
return -1;
|
|
}
|
|
|
|
if (number <= 0)
|
|
number = 1;
|
|
|
|
item_id = 0;
|
|
if ((item_data = itemdb_searchname(item_name)) != NULL ||
|
|
(item_data = itemdb_exists(atoi(item_name))) != NULL)
|
|
item_id = item_data->nameid;
|
|
|
|
if (item_id > 500) {
|
|
int loop, get_count, i;
|
|
char flag = 0;
|
|
loop = 1;
|
|
get_count = number;
|
|
if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR ||
|
|
item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) {
|
|
loop = number;
|
|
get_count = 1;
|
|
if (item_data->type == IT_PETEGG) {
|
|
identify = 1;
|
|
refine = 0;
|
|
}
|
|
if (item_data->type == IT_PETARMOR)
|
|
refine = 0;
|
|
if (refine > MAX_REFINE)
|
|
refine = MAX_REFINE;
|
|
} else {
|
|
identify = 1;
|
|
refine = attr = 0;
|
|
}
|
|
for (i = 0; i < loop; i++) {
|
|
memset(&item_tmp, 0, sizeof(item_tmp));
|
|
item_tmp.nameid = item_id;
|
|
item_tmp.identify = identify;
|
|
item_tmp.refine = refine;
|
|
item_tmp.attribute = attr;
|
|
item_tmp.card[0] = c1;
|
|
item_tmp.card[1] = c2;
|
|
item_tmp.card[2] = c3;
|
|
item_tmp.card[3] = c4;
|
|
item_tmp.bound = bound;
|
|
if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
|
|
clif_additem(sd, 0, 0, flag);
|
|
}
|
|
|
|
if (flag == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,18)); // Item created.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,19)); // Invalid item ID or name.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(itemreset)
|
|
{
|
|
int i;
|
|
nullpo_retr(-1, sd);
|
|
|
|
for (i = 0; i < MAX_INVENTORY; i++) {
|
|
if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) {
|
|
pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_COMMAND);
|
|
}
|
|
}
|
|
clif_displaymessage(fd, msg_txt(sd,20)); // All of your items have been removed.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Atcommand @lvlup
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(baselevelup)
|
|
{
|
|
int level=0, i=0, status_point=0;
|
|
nullpo_retr(-1, sd);
|
|
level = atoi(message);
|
|
|
|
if (!message || !*message || !level) {
|
|
clif_displaymessage(fd, msg_txt(sd,986)); // Please enter a level adjustment (usage: @lvup/@blevel/@baselvlup <number of levels>).
|
|
return -1;
|
|
}
|
|
|
|
if (level > 0) {
|
|
if (sd->status.base_level >= pc_maxbaselv(sd)) { // check for max level by Valaris
|
|
clif_displaymessage(fd, msg_txt(sd,47)); // Base level can't go any higher.
|
|
return -1;
|
|
} // End Addition
|
|
if ((unsigned int)level > pc_maxbaselv(sd) || (unsigned int)level > pc_maxbaselv(sd) - sd->status.base_level) // fix positive overflow
|
|
level = pc_maxbaselv(sd) - sd->status.base_level;
|
|
for (i = 0; i < level; i++)
|
|
status_point += pc_gets_status_point(sd->status.base_level + i);
|
|
|
|
sd->status.status_point += status_point;
|
|
sd->status.base_level += (unsigned int)level;
|
|
status_calc_pc(sd, SCO_FORCE);
|
|
status_percent_heal(&sd->bl, 100, 100);
|
|
clif_misceffect(&sd->bl, 0);
|
|
clif_displaymessage(fd, msg_txt(sd,21)); // Base level raised.
|
|
} else {
|
|
if (sd->status.base_level == 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,158)); // Base level can't go any lower.
|
|
return -1;
|
|
}
|
|
level*=-1;
|
|
if ((unsigned int)level >= sd->status.base_level)
|
|
level = sd->status.base_level-1;
|
|
for (i = 0; i > -level; i--)
|
|
status_point += pc_gets_status_point(sd->status.base_level + i - 1);
|
|
if (sd->status.status_point < status_point)
|
|
pc_resetstate(sd);
|
|
if (sd->status.status_point < status_point)
|
|
sd->status.status_point = 0;
|
|
else
|
|
sd->status.status_point -= status_point;
|
|
sd->status.base_level -= (unsigned int)level;
|
|
clif_displaymessage(fd, msg_txt(sd,22)); // Base level lowered.
|
|
status_calc_pc(sd, SCO_FORCE);
|
|
}
|
|
sd->status.base_exp = 0;
|
|
clif_updatestatus(sd, SP_STATUSPOINT);
|
|
clif_updatestatus(sd, SP_BASELEVEL);
|
|
clif_updatestatus(sd, SP_BASEEXP);
|
|
clif_updatestatus(sd, SP_NEXTBASEEXP);
|
|
pc_baselevelchanged(sd);
|
|
if(sd->status.party_id)
|
|
party_send_levelup(sd);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(joblevelup)
|
|
{
|
|
int level=0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
level = atoi(message);
|
|
|
|
if (!message || !*message || !level) {
|
|
clif_displaymessage(fd, msg_txt(sd,987)); // Please enter a level adjustment (usage: @joblvup/@jlevel/@joblvlup <number of levels>).
|
|
return -1;
|
|
}
|
|
if (level > 0) {
|
|
if (sd->status.job_level >= pc_maxjoblv(sd)) {
|
|
clif_displaymessage(fd, msg_txt(sd,23)); // Job level can't go any higher.
|
|
return -1;
|
|
}
|
|
if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positive overflow
|
|
level = pc_maxjoblv(sd) - sd->status.job_level;
|
|
sd->status.job_level += (unsigned int)level;
|
|
sd->status.skill_point += level;
|
|
clif_misceffect(&sd->bl, 1);
|
|
clif_displaymessage(fd, msg_txt(sd,24)); // Job level raised.
|
|
} else {
|
|
if (sd->status.job_level == 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,159)); // Job level can't go any lower.
|
|
return -1;
|
|
}
|
|
level *=-1;
|
|
if ((unsigned int)level >= sd->status.job_level) // fix negative overflow
|
|
level = sd->status.job_level-1;
|
|
sd->status.job_level -= (unsigned int)level;
|
|
if (sd->status.skill_point < level)
|
|
pc_resetskill(sd,0); //Reset skills since we need to subtract more points.
|
|
if (sd->status.skill_point < level)
|
|
sd->status.skill_point = 0;
|
|
else
|
|
sd->status.skill_point -= level;
|
|
clif_displaymessage(fd, msg_txt(sd,25)); // Job level lowered.
|
|
}
|
|
sd->status.job_exp = 0;
|
|
clif_updatestatus(sd, SP_JOBLEVEL);
|
|
clif_updatestatus(sd, SP_JOBEXP);
|
|
clif_updatestatus(sd, SP_NEXTJOBEXP);
|
|
clif_updatestatus(sd, SP_SKILLPOINT);
|
|
status_calc_pc(sd, SCO_FORCE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @help
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(help)
|
|
{
|
|
config_setting_t *help;
|
|
const char *text = NULL;
|
|
const char *command_name = NULL;
|
|
char *default_command = "help";
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
help = config_lookup(&atcommand_config, "help");
|
|
if (help == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,27)); // "Commands help is not available."
|
|
return -1;
|
|
}
|
|
|
|
if (!message || !*message) {
|
|
command_name = default_command; // If no command_name specified, display help for @help.
|
|
} else {
|
|
if (*message == atcommand_symbol || *message == charcommand_symbol)
|
|
++message;
|
|
command_name = atcommand_checkalias(message);
|
|
}
|
|
|
|
if (!pc_can_use_command(sd, command_name, COMMAND_ATCOMMAND)) {
|
|
sprintf(atcmd_output, msg_txt(sd,153), message); // "%s is Unknown Command"
|
|
clif_displaymessage(fd, atcmd_output);
|
|
atcommand_get_suggestions(sd, command_name, true);
|
|
return -1;
|
|
}
|
|
|
|
if (!config_setting_lookup_string(help, command_name, &text)) {
|
|
sprintf(atcmd_output, msg_txt(sd,988), atcommand_symbol, command_name); // There is no help for %c%s.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
atcommand_get_suggestions(sd, command_name, true);
|
|
return -1;
|
|
}
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,989), atcommand_symbol, command_name); // Help for command %c%s:
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
{ // Display aliases
|
|
DBIterator* iter;
|
|
AtCommandInfo *command_info;
|
|
AliasInfo *alias_info = NULL;
|
|
StringBuf buf;
|
|
bool has_aliases = false;
|
|
|
|
StringBuf_Init(&buf);
|
|
StringBuf_AppendStr(&buf, msg_txt(sd,990)); // Available aliases:
|
|
command_info = get_atcommandinfo_byname(command_name);
|
|
iter = db_iterator(atcommand_alias_db);
|
|
for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) {
|
|
if (alias_info->command == command_info) {
|
|
StringBuf_Printf(&buf, " %s", alias_info->alias);
|
|
has_aliases = true;
|
|
}
|
|
}
|
|
dbi_destroy(iter);
|
|
if (has_aliases)
|
|
clif_displaymessage(fd, StringBuf_Value(&buf));
|
|
StringBuf_Destroy(&buf);
|
|
}
|
|
|
|
// Display help contents
|
|
clif_displaymessage(fd, text);
|
|
return 0;
|
|
}
|
|
|
|
// helper function, used in foreach calls to stop auto-attack timers
|
|
// parameter: '0' - everyone, 'id' - only those attacking someone with that id
|
|
static int atcommand_stopattack(struct block_list *bl,va_list ap)
|
|
{
|
|
struct unit_data *ud = unit_bl2ud(bl);
|
|
int id = va_arg(ap, int);
|
|
if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target))
|
|
{
|
|
unit_stop_attack(bl);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
static int atcommand_pvpoff_sub(struct block_list *bl,va_list ap)
|
|
{
|
|
TBL_PC* sd = (TBL_PC*)bl;
|
|
clif_pvpset(sd, 0, 0, 2);
|
|
if (sd->pvp_timer != INVALID_TIMER) {
|
|
delete_timer(sd->pvp_timer, pc_calc_pvprank_timer);
|
|
sd->pvp_timer = INVALID_TIMER;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(pvpoff)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!map[sd->bl.m].flag.pvp) {
|
|
clif_displaymessage(fd, msg_txt(sd,160)); // PvP is already Off.
|
|
return -1;
|
|
}
|
|
|
|
map[sd->bl.m].flag.pvp = 0;
|
|
|
|
if (!battle_config.pk_mode){
|
|
clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING);
|
|
clif_maptypeproperty2(&sd->bl,ALL_SAMEMAP);
|
|
}
|
|
map_foreachinmap(atcommand_pvpoff_sub,sd->bl.m, BL_PC);
|
|
map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0);
|
|
clif_displaymessage(fd, msg_txt(sd,31)); // PvP: Off.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
static int atcommand_pvpon_sub(struct block_list *bl,va_list ap)
|
|
{
|
|
TBL_PC* sd = (TBL_PC*)bl;
|
|
if (sd->pvp_timer == INVALID_TIMER) {
|
|
sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0);
|
|
sd->pvp_rank = 0;
|
|
sd->pvp_lastusers = 0;
|
|
sd->pvp_point = 5;
|
|
sd->pvp_won = 0;
|
|
sd->pvp_lost = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(pvpon)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (map[sd->bl.m].flag.pvp) {
|
|
clif_displaymessage(fd, msg_txt(sd,161)); // PvP is already On.
|
|
return -1;
|
|
}
|
|
|
|
map[sd->bl.m].flag.pvp = 1;
|
|
|
|
if (!battle_config.pk_mode) {// display pvp circle and rank
|
|
clif_map_property_mapall(sd->bl.m, MAPPROPERTY_FREEPVPZONE);
|
|
clif_maptypeproperty2(&sd->bl,ALL_SAMEMAP);
|
|
map_foreachinmap(atcommand_pvpon_sub,sd->bl.m, BL_PC);
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,32)); // PvP: On.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(gvgoff)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!map[sd->bl.m].flag.gvg) {
|
|
clif_displaymessage(fd, msg_txt(sd,162)); // GvG is already Off.
|
|
return -1;
|
|
}
|
|
|
|
map[sd->bl.m].flag.gvg = 0;
|
|
clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING);
|
|
clif_maptypeproperty2(&sd->bl,ALL_SAMEMAP);
|
|
map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0);
|
|
clif_displaymessage(fd, msg_txt(sd,33)); // GvG: Off.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(gvgon)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (map[sd->bl.m].flag.gvg) {
|
|
clif_displaymessage(fd, msg_txt(sd,163)); // GvG is already On.
|
|
return -1;
|
|
}
|
|
|
|
map[sd->bl.m].flag.gvg = 1;
|
|
clif_map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE);
|
|
clif_maptypeproperty2(&sd->bl,ALL_SAMEMAP);
|
|
clif_displaymessage(fd, msg_txt(sd,34)); // GvG: On.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(model)
|
|
{
|
|
int hair_style = 0, hair_color = 0, cloth_color = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%d %d %d", &hair_style, &hair_color, &cloth_color) < 1) {
|
|
sprintf(atcmd_output, msg_txt(sd,991), // Please enter at least one value (usage: @model <hair ID: %d-%d> <hair color: %d-%d> <clothes color: %d-%d>).
|
|
MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE &&
|
|
hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR &&
|
|
cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) {
|
|
pc_changelook(sd, LOOK_HAIR, hair_style);
|
|
pc_changelook(sd, LOOK_HAIR_COLOR, hair_color);
|
|
pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color);
|
|
clif_displaymessage(fd, msg_txt(sd,36)); // Appearance changed.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,37)); // An invalid number was specified.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @dye && @ccolor
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(dye)
|
|
{
|
|
int cloth_color = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) {
|
|
sprintf(atcmd_output, msg_txt(sd,992), MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); // Please enter a clothes color (usage: @dye/@ccolor <clothes color: %d-%d>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) {
|
|
pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color);
|
|
clif_displaymessage(fd, msg_txt(sd,36)); // Appearance changed.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,37)); // An invalid number was specified.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @hairstyle && @hstyle
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(hair_style)
|
|
{
|
|
int hair_style = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) {
|
|
sprintf(atcmd_output, msg_txt(sd,993), MIN_HAIR_STYLE, MAX_HAIR_STYLE); // Please enter a hair style (usage: @hairstyle/@hstyle <hair ID: %d-%d>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) {
|
|
pc_changelook(sd, LOOK_HAIR, hair_style);
|
|
clif_displaymessage(fd, msg_txt(sd,36)); // Appearance changed.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,37)); // An invalid number was specified.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @haircolor && @hcolor
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(hair_color)
|
|
{
|
|
int hair_color = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) {
|
|
sprintf(atcmd_output, msg_txt(sd,994), MIN_HAIR_COLOR, MAX_HAIR_COLOR); // Please enter a hair color (usage: @haircolor/@hcolor <hair color: %d-%d>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) {
|
|
pc_changelook(sd, LOOK_HAIR_COLOR, hair_color);
|
|
clif_displaymessage(fd, msg_txt(sd,36)); // Appearance changed.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,37)); // An invalid number was specified.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @go [city_number or city_name] - Updated by Harbin
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(go)
|
|
{
|
|
int i;
|
|
int town;
|
|
char map_name[MAP_NAME_LENGTH];
|
|
int16 m;
|
|
|
|
const struct {
|
|
char map[MAP_NAME_LENGTH];
|
|
int x, y;
|
|
} data[] = {
|
|
{ MAP_PRONTERA, 156, 191 }, // 0=Prontera
|
|
{ MAP_MORROC, 156, 93 }, // 1=Morroc
|
|
{ MAP_GEFFEN, 119, 59 }, // 2=Geffen
|
|
{ MAP_PAYON, 162, 233 }, // 3=Payon
|
|
{ MAP_ALBERTA, 192, 147 }, // 4=Alberta
|
|
#ifdef RENEWAL
|
|
{ MAP_IZLUDE, 128, 146 }, // 5=Izlude (Renewal)
|
|
#else
|
|
{ MAP_IZLUDE, 128, 114 }, // 5=Izlude
|
|
#endif
|
|
{ MAP_ALDEBARAN, 140, 131 }, // 6=Al de Baran
|
|
{ MAP_LUTIE, 147, 134 }, // 7=Lutie
|
|
{ MAP_COMODO, 209, 143 }, // 8=Comodo
|
|
{ MAP_YUNO, 157, 51 }, // 9=Yuno
|
|
{ MAP_AMATSU, 198, 84 }, // 10=Amatsu
|
|
{ MAP_GONRYUN, 160, 120 }, // 11=Gonryun
|
|
{ MAP_UMBALA, 89, 157 }, // 12=Umbala
|
|
{ MAP_NIFLHEIM, 21, 153 }, // 13=Niflheim
|
|
{ MAP_LOUYANG, 217, 40 }, // 14=Louyang
|
|
{ MAP_NOVICE, 53, 111 }, // 15=Training Grounds
|
|
{ MAP_JAIL, 23, 61 }, // 16=Prison
|
|
{ MAP_JAWAII, 249, 127 }, // 17=Jawaii
|
|
{ MAP_AYOTHAYA, 151, 117 }, // 18=Ayothaya
|
|
{ MAP_EINBROCH, 64, 200 }, // 19=Einbroch
|
|
{ MAP_LIGHTHALZEN, 158, 92 }, // 20=Lighthalzen
|
|
{ MAP_EINBECH, 70, 95 }, // 21=Einbech
|
|
{ MAP_HUGEL, 96, 145 }, // 22=Hugel
|
|
{ MAP_RACHEL, 130, 110 }, // 23=Rachel
|
|
{ MAP_VEINS, 216, 123 }, // 24=Veins
|
|
{ MAP_MOSCOVIA, 223, 184 }, // 25=Moscovia
|
|
{ MAP_MIDCAMP, 180, 240 }, // 26=Midgard Camp
|
|
{ MAP_MANUK, 282, 138 }, // 27=Manuk
|
|
{ MAP_SPLENDIDE, 201, 147 }, // 28=Splendide
|
|
{ MAP_BRASILIS, 182, 239 }, // 29=Brasilis
|
|
{ MAP_DICASTES, 198, 187 }, // 30=El Dicastes
|
|
{ MAP_MORA, 44, 151 }, // 31=Mora
|
|
{ MAP_DEWATA, 200, 180 }, // 32=Dewata
|
|
{ MAP_MALANGDO, 140, 114 }, // 33=Malangdo Island
|
|
{ MAP_MALAYA, 242, 211 }, // 34=Malaya Port
|
|
{ MAP_ECLAGE, 110, 39 }, // 35=Eclage
|
|
};
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if( map[sd->bl.m].flag.nogo && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,995)); // You cannot use @go on this map.
|
|
return 0;
|
|
}
|
|
|
|
memset(map_name, '\0', sizeof(map_name));
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
// get the number
|
|
town = atoi(message);
|
|
|
|
if (!message || !*message || sscanf(message, "%11s", map_name) < 1 || town < 0 || town >= ARRAYLENGTH(data))
|
|
{// no value matched so send the list of locations
|
|
const char* text;
|
|
|
|
// attempt to find the text help string
|
|
text = atcommand_help_string( command );
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,38)); // Invalid location number, or name.
|
|
|
|
if( text )
|
|
{// send the text to the client
|
|
clif_displaymessage( fd, text );
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// get possible name of the city
|
|
map_name[MAP_NAME_LENGTH-1] = '\0';
|
|
for (i = 0; map_name[i]; i++)
|
|
map_name[i] = TOLOWER(map_name[i]);
|
|
// try to identify the map name
|
|
if (strncmp(map_name, "prontera", 3) == 0) {
|
|
town = 0;
|
|
} else if (strncmp(map_name, "morocc", 4) == 0 ||
|
|
strncmp(map_name, "morroc", 4) == 0) {
|
|
town = 1;
|
|
} else if (strncmp(map_name, "geffen", 3) == 0) {
|
|
town = 2;
|
|
} else if (strncmp(map_name, "payon", 3) == 0) {
|
|
town = 3;
|
|
} else if (strncmp(map_name, "alberta", 3) == 0) {
|
|
town = 4;
|
|
} else if (strncmp(map_name, "izlude", 3) == 0) {
|
|
town = 5;
|
|
} else if (strncmp(map_name, "aldebaran", 3) == 0) {
|
|
town = 6;
|
|
} else if (strncmp(map_name, "lutie", 3) == 0 ||
|
|
strcmp(map_name, "christmas") == 0 ||
|
|
strncmp(map_name, "xmas", 3) == 0 ||
|
|
strncmp(map_name, "x-mas", 3) == 0) {
|
|
town = 7;
|
|
} else if (strncmp(map_name, "comodo", 3) == 0) {
|
|
town = 8;
|
|
} else if (strncmp(map_name, "juno", 3) == 0 ||
|
|
strncmp(map_name, "yuno", 3) == 0) {
|
|
town = 9;
|
|
} else if (strncmp(map_name, "amatsu", 3) == 0) {
|
|
town = 10;
|
|
} else if (strncmp(map_name, "kunlun", 3) == 0 ||
|
|
strncmp(map_name, "gonryun", 3) == 0) {
|
|
town = 11;
|
|
} else if (strncmp(map_name, "umbala", 3) == 0) {
|
|
town = 12;
|
|
} else if (strncmp(map_name, "niflheim", 3) == 0) {
|
|
town = 13;
|
|
} else if (strncmp(map_name, "louyang", 3) == 0) {
|
|
town = 14;
|
|
} else if (strncmp(map_name, "new_1-1", 3) == 0 ||
|
|
strncmp(map_name, "startpoint", 3) == 0 ||
|
|
strncmp(map_name, "beginning", 3) == 0) {
|
|
town = 15;
|
|
} else if (strncmp(map_name, "sec_pri", 3) == 0 ||
|
|
strncmp(map_name, "prison", 3) == 0 ||
|
|
strncmp(map_name, "jail", 3) == 0) {
|
|
town = 16;
|
|
} else if (strncmp(map_name, "jawaii", 3) == 0) {
|
|
town = 17;
|
|
} else if (strncmp(map_name, "ayothaya", 3) == 0) {
|
|
town = 18;
|
|
} else if (strncmp(map_name, "einbroch", 5) == 0) {
|
|
town = 19;
|
|
} else if (strncmp(map_name, "lighthalzen", 3) == 0) {
|
|
town = 20;
|
|
} else if (strncmp(map_name, "einbech", 5) == 0) {
|
|
town = 21;
|
|
} else if (strncmp(map_name, "hugel", 3) == 0) {
|
|
town = 22;
|
|
} else if (strncmp(map_name, "rachel", 3) == 0) {
|
|
town = 23;
|
|
} else if (strncmp(map_name, "veins", 3) == 0) {
|
|
town = 24;
|
|
} else if (strncmp(map_name, "moscovia", 3) == 0) {
|
|
town = 25;
|
|
} else if (strncmp(map_name, "mid_camp", 3) == 0) {
|
|
town = 26;
|
|
} else if (strncmp(map_name, "manuk", 3) == 0) {
|
|
town = 27;
|
|
} else if (strncmp(map_name, "splendide", 3) == 0) {
|
|
town = 28;
|
|
} else if (strncmp(map_name, "brasilis", 3) == 0) {
|
|
town = 29;
|
|
} else if (strncmp(map_name, "dicastes01", 3) == 0) {
|
|
town = 30;
|
|
} else if (strcmp(map_name, "mora") == 0) {
|
|
town = 31;
|
|
} else if (strncmp(map_name, "dewata", 3) == 0) {
|
|
town = 32;
|
|
} else if (strncmp(map_name, "malangdo", 5) == 0) {
|
|
town = 33;
|
|
} else if (strncmp(map_name, "malaya", 5) == 0) {
|
|
town = 34;
|
|
} else if (strncmp(map_name, "eclage", 3) == 0) {
|
|
town = 35;
|
|
}
|
|
|
|
if (town >= 0 && town < ARRAYLENGTH(data))
|
|
{
|
|
m = map_mapname2mapid(data[town].map);
|
|
if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,247));
|
|
return -1;
|
|
}
|
|
if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,248));
|
|
return -1;
|
|
}
|
|
if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,0)); // Warped.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,1)); // Map not found.
|
|
return -1;
|
|
}
|
|
} else { // if you arrive here, you have an error in town variable when reading of names
|
|
clif_displaymessage(fd, msg_txt(sd,38)); // Invalid location number or name.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(monster)
|
|
{
|
|
char name[NAME_LENGTH];
|
|
char monster[NAME_LENGTH];
|
|
char eventname[EVENT_NAME_LENGTH] = "";
|
|
int mob_id;
|
|
int number = 0;
|
|
int count;
|
|
int i, range;
|
|
short mx, my;
|
|
unsigned int size;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(name, '\0', sizeof(name));
|
|
memset(monster, '\0', sizeof(monster));
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,80)); // Give the display name or monster name/id please.
|
|
return -1;
|
|
}
|
|
if (sscanf(message, "\"%23[^\"]\" %23s %d", name, monster, &number) > 1 ||
|
|
sscanf(message, "%23s \"%23[^\"]\" %d", monster, name, &number) > 1) {
|
|
//All data can be left as it is.
|
|
} else if ((count=sscanf(message, "%23s %d %23s", monster, &number, name)) > 1) {
|
|
//Here, it is possible name was not given and we are using monster for it.
|
|
if (count < 3) //Blank mob's name.
|
|
name[0] = '\0';
|
|
} else if (sscanf(message, "%23s %23s %d", name, monster, &number) > 1) {
|
|
//All data can be left as it is.
|
|
} else if (sscanf(message, "%23s", monster) > 0) {
|
|
//As before, name may be already filled.
|
|
name[0] = '\0';
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,80)); // Give a display name and monster name/id please.
|
|
return -1;
|
|
}
|
|
|
|
if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number)
|
|
mob_id = mobdb_checkid(atoi(monster));
|
|
|
|
if (mob_id == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,40)); // Invalid monster ID or name.
|
|
return -1;
|
|
}
|
|
|
|
if (mob_id == MOBID_EMPERIUM) {
|
|
clif_displaymessage(fd, msg_txt(sd,83)); // Monster 'Emperium' cannot be spawned.
|
|
return -1;
|
|
}
|
|
|
|
if (number <= 0)
|
|
number = 1;
|
|
|
|
if( !name[0] )
|
|
strcpy(name, "--ja--");
|
|
|
|
// 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
|
|
if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit)
|
|
number = battle_config.atc_spawn_quantity_limit;
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
if (strcmp(parent_cmd, "monstersmall") == 0)
|
|
size = SZ_MEDIUM; // This is just gorgeous [mkbu95]
|
|
else if (strcmp(parent_cmd, "monsterbig") == 0)
|
|
size = SZ_BIG;
|
|
else
|
|
size = SZ_SMALL;
|
|
|
|
if (battle_config.etc_log)
|
|
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);
|
|
|
|
count = 0;
|
|
range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around)
|
|
for (i = 0; i < number; i++) {
|
|
int k;
|
|
map_search_freecell(&sd->bl, 0, &mx, &my, range, range, 0);
|
|
k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname, size, AI_NONE);
|
|
if(k) {
|
|
//mapreg_setreg(reference_uid(add_str("$@mobid"), i),k); //retain created mobid in array uncomment if needed
|
|
count ++;
|
|
}
|
|
}
|
|
|
|
if (count != 0)
|
|
if (number == count)
|
|
clif_displaymessage(fd, msg_txt(sd,39)); // All monster summoned!
|
|
else {
|
|
sprintf(atcmd_output, msg_txt(sd,240), count); // %d monster(s) summoned!
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
else {
|
|
clif_displaymessage(fd, msg_txt(sd,40)); // Invalid monster ID or name.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
static int atkillmonster_sub(struct block_list *bl, va_list ap)
|
|
{
|
|
struct mob_data *md;
|
|
int flag;
|
|
|
|
nullpo_ret(md=(struct mob_data *)bl);
|
|
flag = va_arg(ap, int);
|
|
|
|
if (md->guardian_data)
|
|
return 0; //Do not touch WoE mobs!
|
|
|
|
if (flag)
|
|
status_zap(bl,md->status.hp, 0);
|
|
else
|
|
status_kill(bl);
|
|
return 1;
|
|
}
|
|
|
|
ACMD_FUNC(killmonster)
|
|
{
|
|
int map_id, drop_flag;
|
|
char map_name[MAP_NAME_LENGTH_EXT];
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(map_name, '\0', sizeof(map_name));
|
|
|
|
if (!message || !*message || sscanf(message, "%15s", map_name) < 1)
|
|
map_id = sd->bl.m;
|
|
else {
|
|
if ((map_id = map_mapname2mapid(map_name)) < 0)
|
|
map_id = sd->bl.m;
|
|
}
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
drop_flag = strcmp(parent_cmd, "killmonster2");
|
|
|
|
map_foreachinmap(atkillmonster_sub, map_id, BL_MOB, -drop_flag);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,165)); // All monsters killed!
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(refine)
|
|
{
|
|
int j, position = 0, refine = 0, current_position, final_refine;
|
|
int count;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%d %d", &position, &refine) < 2) {
|
|
clif_displaymessage(fd, msg_txt(sd,996)); // Please enter a position and an amount (usage: @refine <equip position> <+/- amount>).
|
|
sprintf(atcmd_output, msg_txt(sd,997), EQP_HEAD_LOW); // %d: Lower Headgear
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,998), EQP_HAND_R); // %d: Right Hand
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,999), EQP_GARMENT); // %d: Garment
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,1000), EQP_ACC_L); // %d: Left Accessory
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,1001), EQP_ARMOR); // %d: Body Armor
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,1002), EQP_HAND_L); // %d: Left Hand
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,1003), EQP_SHOES); // %d: Shoes
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,1004), EQP_ACC_R); // %d: Right Accessory
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,1005), EQP_HEAD_TOP); // %d: Top Headgear
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,1006), EQP_HEAD_MID); // %d: Mid Headgear
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
refine = cap_value(refine, -MAX_REFINE, MAX_REFINE);
|
|
|
|
count = 0;
|
|
for (j = 0; j < EQI_MAX; j++) {
|
|
int i;
|
|
if ((i = sd->equip_index[j]) < 0)
|
|
continue;
|
|
if(j == EQI_AMMO)
|
|
continue;
|
|
if (pc_is_same_equip_index((enum equip_index)j, sd->equip_index, i))
|
|
continue;
|
|
|
|
if(position && !(sd->status.inventory[i].equip & position))
|
|
continue;
|
|
|
|
final_refine = cap_value(sd->status.inventory[i].refine + refine, 0, MAX_REFINE);
|
|
if (sd->status.inventory[i].refine != final_refine) {
|
|
sd->status.inventory[i].refine = final_refine;
|
|
current_position = sd->status.inventory[i].equip;
|
|
pc_unequipitem(sd, i, 3);
|
|
clif_refine(fd, 0, i, sd->status.inventory[i].refine);
|
|
clif_delitem(sd, i, 1, 3);
|
|
clif_additem(sd, i, 1, 0);
|
|
pc_equipitem(sd, i, current_position);
|
|
clif_misceffect(&sd->bl, 3);
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (count == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,166)); // No item has been refined.
|
|
else if (count == 1)
|
|
clif_displaymessage(fd, msg_txt(sd,167)); // 1 item has been refined.
|
|
else {
|
|
sprintf(atcmd_output, msg_txt(sd,168), count); // %d items have been refined.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(produce)
|
|
{
|
|
char item_name[100];
|
|
unsigned short item_id;
|
|
int attribute = 0, star = 0;
|
|
struct item_data *item_data;
|
|
struct item tmp_item;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
memset(item_name, '\0', sizeof(item_name));
|
|
|
|
if (!message || !*message || (
|
|
sscanf(message, "\"%99[^\"]\" %d %d", item_name, &attribute, &star) < 1 &&
|
|
sscanf(message, "%99s %d %d", item_name, &attribute, &star) < 1
|
|
)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1007)); // Please enter at least one item name/ID (usage: @produce <equip name/ID> <element> <# of very's>).
|
|
return -1;
|
|
}
|
|
|
|
if ( (item_data = itemdb_searchname(item_name)) == NULL &&
|
|
(item_data = itemdb_exists(atoi(item_name))) == NULL ) {
|
|
clif_displaymessage(fd, msg_txt(sd,170)); //This item is not an equipment.
|
|
return -1;
|
|
}
|
|
|
|
item_id = item_data->nameid;
|
|
|
|
if (itemdb_isequip2(item_data)) {
|
|
char flag = 0;
|
|
if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE)
|
|
attribute = ATTRIBUTE_NORMAL;
|
|
if (star < MIN_STAR || star > MAX_STAR)
|
|
star = 0;
|
|
memset(&tmp_item, 0, sizeof tmp_item);
|
|
tmp_item.nameid = item_id;
|
|
tmp_item.amount = 1;
|
|
tmp_item.identify = 1;
|
|
tmp_item.card[0] = CARD0_FORGE;
|
|
tmp_item.card[1] = item_data->type==IT_WEAPON?
|
|
((star*5) << 8) + attribute:0;
|
|
tmp_item.card[2] = GetWord(sd->status.char_id, 0);
|
|
tmp_item.card[3] = GetWord(sd->status.char_id, 1);
|
|
clif_produceeffect(sd, 0, item_id);
|
|
clif_misceffect(&sd->bl, 3);
|
|
|
|
if ((flag = pc_additem(sd, &tmp_item, 1, LOG_TYPE_COMMAND)))
|
|
clif_additem(sd, 0, 0, flag);
|
|
} else {
|
|
sprintf(atcmd_output, msg_txt(sd,169), item_id, item_data->name); // The item (%hu: '%s') is not equipable.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(memo)
|
|
{
|
|
int position = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if( !message || !*message || sscanf(message, "%d", &position) < 1 )
|
|
{
|
|
int i;
|
|
clif_displaymessage(sd->fd, msg_txt(sd,668));
|
|
for( i = 0; i < MAX_MEMOPOINTS; i++ )
|
|
{
|
|
if( sd->status.memo_point[i].map )
|
|
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);
|
|
else
|
|
sprintf(atcmd_output, msg_txt(sd,171), i); // %d - void
|
|
clif_displaymessage(sd->fd, atcmd_output);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if( position < 0 || position >= MAX_MEMOPOINTS )
|
|
{
|
|
sprintf(atcmd_output, msg_txt(sd,1008), 0, MAX_MEMOPOINTS-1); // Please enter a valid position (usage: @memo <memo_position:%d-%d>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
return !pc_memo( sd, position );
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(gat)
|
|
{
|
|
int y;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
for (y = 2; y >= -2; y--) {
|
|
sprintf(atcmd_output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X",
|
|
map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y,
|
|
map_getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE),
|
|
map_getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE),
|
|
map_getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE),
|
|
map_getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE),
|
|
map_getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE));
|
|
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(displaystatus)
|
|
{
|
|
int i, type, flag, tick, val1 = 0, val2 = 0, val3 = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || (i = sscanf(message, "%d %d %d %d %d %d", &type, &flag, &tick, &val1, &val2, &val3)) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1009)); // Please enter a status type/flag (usage: @displaystatus <status type> <flag> <tick> {<val1> {<val2> {<val3>}}}).
|
|
return -1;
|
|
}
|
|
if (i < 2) flag = 1;
|
|
if (i < 3) tick = 0;
|
|
|
|
clif_status_change(&sd->bl, type, flag, tick, val1, val2, val3);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @stpoint (Rewritten by [Yor])
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(statuspoint)
|
|
{
|
|
int point;
|
|
unsigned int new_status_point;
|
|
|
|
if (!message || !*message || (point = atoi(message)) == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1010)); // Please enter a number (usage: @stpoint <number of points>).
|
|
return -1;
|
|
}
|
|
|
|
if(point < 0)
|
|
{
|
|
if(sd->status.status_point < (unsigned int)(-point))
|
|
{
|
|
new_status_point = 0;
|
|
}
|
|
else
|
|
{
|
|
new_status_point = sd->status.status_point + point;
|
|
}
|
|
}
|
|
else if(UINT_MAX - sd->status.status_point < (unsigned int)point)
|
|
{
|
|
new_status_point = UINT_MAX;
|
|
}
|
|
else
|
|
{
|
|
new_status_point = sd->status.status_point + point;
|
|
}
|
|
|
|
if (new_status_point != sd->status.status_point) {
|
|
sd->status.status_point = new_status_point;
|
|
clif_updatestatus(sd, SP_STATUSPOINT);
|
|
clif_displaymessage(fd, msg_txt(sd,174)); // Number of status points changed.
|
|
} else {
|
|
if (point < 0)
|
|
clif_displaymessage(fd, msg_txt(sd,41)); // Unable to decrease the number/value.
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,149)); // Unable to increase the number/value.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @skpoint (Rewritten by [Yor])
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(skillpoint)
|
|
{
|
|
int point;
|
|
unsigned int new_skill_point;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || (point = atoi(message)) == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1011)); // Please enter a number (usage: @skpoint <number of points>).
|
|
return -1;
|
|
}
|
|
|
|
if(point < 0)
|
|
{
|
|
if(sd->status.skill_point < (unsigned int)(-point))
|
|
{
|
|
new_skill_point = 0;
|
|
}
|
|
else
|
|
{
|
|
new_skill_point = sd->status.skill_point + point;
|
|
}
|
|
}
|
|
else if(UINT_MAX - sd->status.skill_point < (unsigned int)point)
|
|
{
|
|
new_skill_point = UINT_MAX;
|
|
}
|
|
else
|
|
{
|
|
new_skill_point = sd->status.skill_point + point;
|
|
}
|
|
|
|
if (new_skill_point != sd->status.skill_point) {
|
|
sd->status.skill_point = new_skill_point;
|
|
clif_updatestatus(sd, SP_SKILLPOINT);
|
|
clif_displaymessage(fd, msg_txt(sd,175)); // Number of skill points changed.
|
|
} else {
|
|
if (point < 0)
|
|
clif_displaymessage(fd, msg_txt(sd,41)); // Unable to decrease the number/value.
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,149)); // Unable to increase the number/value.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @zeny
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(zeny)
|
|
{
|
|
int zeny=0, ret=-1;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || (zeny = atoi(message)) == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1012)); // Please enter an amount (usage: @zeny <amount>).
|
|
return -1;
|
|
}
|
|
|
|
if(zeny > 0){
|
|
if((ret=pc_getzeny(sd,zeny,LOG_TYPE_COMMAND,NULL)) == 1)
|
|
clif_displaymessage(fd, msg_txt(sd,149)); // Unable to increase the number/value.
|
|
}
|
|
else {
|
|
if( sd->status.zeny < -zeny ) zeny = -sd->status.zeny;
|
|
if((ret=pc_payzeny(sd,-zeny,LOG_TYPE_COMMAND,NULL)) == 1)
|
|
clif_displaymessage(fd, msg_txt(sd,41)); // Unable to decrease the number/value.
|
|
}
|
|
if(!ret) clif_displaymessage(fd, msg_txt(sd,176)); //ret=0 mean cmd success
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(param)
|
|
{
|
|
uint8 i;
|
|
int value = 0;
|
|
const char* param[] = { "str", "agi", "vit", "int", "dex", "luk" };
|
|
short new_value, *status[6], max_status[6];
|
|
//we don't use direct initialization because it isn't part of the c standard.
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>).
|
|
return -1;
|
|
}
|
|
|
|
ARR_FIND( 0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0 );
|
|
|
|
if( i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible...
|
|
clif_displaymessage(fd, msg_txt(sd,1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>).
|
|
return -1;
|
|
}
|
|
|
|
status[0] = &sd->status.str;
|
|
status[1] = &sd->status.agi;
|
|
status[2] = &sd->status.vit;
|
|
status[3] = &sd->status.int_;
|
|
status[4] = &sd->status.dex;
|
|
status[5] = &sd->status.luk;
|
|
|
|
if( pc_has_permission(sd, PC_PERM_BYPASS_MAX_STAT) )
|
|
max_status[0] = max_status[1] = max_status[2] = max_status[3] = max_status[4] = max_status[5] = SHRT_MAX;
|
|
else {
|
|
max_status[0] = pc_maxparameter(sd,PARAM_STR);
|
|
max_status[1] = pc_maxparameter(sd,PARAM_AGI);
|
|
max_status[2] = pc_maxparameter(sd,PARAM_VIT);
|
|
max_status[3] = pc_maxparameter(sd,PARAM_INT);
|
|
max_status[4] = pc_maxparameter(sd,PARAM_DEX);
|
|
max_status[5] = pc_maxparameter(sd,PARAM_LUK);
|
|
}
|
|
|
|
if(value > 0 && *status[i] + value >= max_status[i])
|
|
new_value = max_status[i];
|
|
else if(value < 0 && *status[i] <= -value)
|
|
new_value = 1;
|
|
else
|
|
new_value = *status[i] + value;
|
|
|
|
if (new_value != *status[i]) {
|
|
*status[i] = new_value;
|
|
clif_updatestatus(sd, SP_STR + i);
|
|
clif_updatestatus(sd, SP_USTR + i);
|
|
status_calc_pc(sd, SCO_FORCE);
|
|
clif_displaymessage(fd, msg_txt(sd,42)); // Stat changed.
|
|
} else {
|
|
if (value < 0)
|
|
clif_displaymessage(fd, msg_txt(sd,41)); // Unable to decrease the number/value.
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,149)); // Unable to increase the number/value.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Stat all by fritz (rewritten by [Yor])
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(stat_all)
|
|
{
|
|
int value = 0;
|
|
uint8 count, i;
|
|
short *status[PARAM_MAX], max_status[PARAM_MAX];
|
|
//we don't use direct initialization because it isn't part of the c standard.
|
|
nullpo_retr(-1, sd);
|
|
|
|
status[0] = &sd->status.str;
|
|
status[1] = &sd->status.agi;
|
|
status[2] = &sd->status.vit;
|
|
status[3] = &sd->status.int_;
|
|
status[4] = &sd->status.dex;
|
|
status[5] = &sd->status.luk;
|
|
|
|
if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) {
|
|
max_status[0] = pc_maxparameter(sd,PARAM_STR);
|
|
max_status[1] = pc_maxparameter(sd,PARAM_AGI);
|
|
max_status[2] = pc_maxparameter(sd,PARAM_VIT);
|
|
max_status[3] = pc_maxparameter(sd,PARAM_INT);
|
|
max_status[4] = pc_maxparameter(sd,PARAM_DEX);
|
|
max_status[5] = pc_maxparameter(sd,PARAM_LUK);
|
|
value = SHRT_MAX;
|
|
} else {
|
|
if( pc_has_permission(sd, PC_PERM_BYPASS_MAX_STAT) )
|
|
max_status[0] = max_status[1] = max_status[2] = max_status[3] = max_status[4] = max_status[5] = SHRT_MAX;
|
|
else {
|
|
max_status[0] = pc_maxparameter(sd,PARAM_STR);
|
|
max_status[1] = pc_maxparameter(sd,PARAM_AGI);
|
|
max_status[2] = pc_maxparameter(sd,PARAM_VIT);
|
|
max_status[3] = pc_maxparameter(sd,PARAM_INT);
|
|
max_status[4] = pc_maxparameter(sd,PARAM_DEX);
|
|
max_status[5] = pc_maxparameter(sd,PARAM_LUK);
|
|
}
|
|
}
|
|
|
|
count = 0;
|
|
for (i = 0; i < ARRAYLENGTH(status); i++) {
|
|
short new_value;
|
|
if (value > 0 && *status[i] + value >= max_status[i])
|
|
new_value = max_status[i];
|
|
else if (value < 0 && *status[i] <= -value)
|
|
new_value = 1;
|
|
else
|
|
new_value = *status[i] + value;
|
|
|
|
if (new_value != *status[i]) {
|
|
*status[i] = new_value;
|
|
clif_updatestatus(sd, SP_STR + i);
|
|
clif_updatestatus(sd, SP_USTR + i);
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (count > 0) { // if at least 1 stat modified
|
|
status_calc_pc(sd, SCO_FORCE);
|
|
clif_displaymessage(fd, msg_txt(sd,84)); // All stats changed!
|
|
} else {
|
|
if (value < 0)
|
|
clif_displaymessage(fd, msg_txt(sd,177)); // You cannot decrease that stat anymore.
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,178)); // You cannot increase that stat anymore.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(guildlevelup) {
|
|
int level = 0;
|
|
short added_level;
|
|
struct guild *guild_info;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1014)); // Please enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>).
|
|
return -1;
|
|
}
|
|
|
|
if (sd->status.guild_id <= 0 || (guild_info = sd->guild) == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,43)); // You're not in a guild.
|
|
return -1;
|
|
}
|
|
//if (strcmp(sd->status.name, guild_info->master) != 0) {
|
|
// clif_displaymessage(fd, msg_txt(sd,44)); // You're not the master of your guild.
|
|
// return -1;
|
|
//}
|
|
|
|
added_level = (short)level;
|
|
if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positive overflow
|
|
added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv;
|
|
else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negative overflow
|
|
added_level = 1 - guild_info->guild_lv;
|
|
|
|
if (added_level != 0) {
|
|
intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level));
|
|
clif_displaymessage(fd, msg_txt(sd,179)); // Guild level changed.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,45)); // Guild level change failed.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(makeegg) {
|
|
struct item_data *item_data;
|
|
int id, pet_id;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1015)); // Please enter a monster/egg name/ID (usage: @makeegg <pet>).
|
|
return -1;
|
|
}
|
|
|
|
if ((item_data = itemdb_searchname(message)) != NULL) // for egg name
|
|
id = item_data->nameid;
|
|
else
|
|
if ((id = mobdb_searchname(message)) != 0) // for monster name
|
|
;
|
|
else
|
|
id = atoi(message);
|
|
|
|
pet_id = search_petDB_index(id, PET_CLASS);
|
|
if (pet_id < 0)
|
|
pet_id = search_petDB_index(id, PET_EGG);
|
|
if (pet_id >= 0) {
|
|
sd->catch_target_class = pet_db[pet_id].class_;
|
|
intif_create_pet(
|
|
sd->status.account_id, sd->status.char_id,
|
|
(short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv,
|
|
(short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate,
|
|
100, 0, 1, pet_db[pet_id].jname);
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,180)); // The monster/egg name/id doesn't exist.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(hatch) {
|
|
nullpo_retr(-1, sd);
|
|
if (sd->status.pet_id <= 0)
|
|
clif_sendegg(sd);
|
|
else {
|
|
clif_displaymessage(fd, msg_txt(sd,181)); // You already have a pet.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(petfriendly) {
|
|
int friendly;
|
|
struct pet_data *pd;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || (friendly = atoi(message)) < 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1016)); // Please enter a valid value (usage: @petfriendly <0-1000>).
|
|
return -1;
|
|
}
|
|
|
|
pd = sd->pd;
|
|
if (!pd) {
|
|
clif_displaymessage(fd, msg_txt(sd,184)); // Sorry, but you have no pet.
|
|
return -1;
|
|
}
|
|
|
|
if (friendly < 0 || friendly > 1000)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,37)); // An invalid number was specified.
|
|
return -1;
|
|
}
|
|
|
|
if (friendly == pd->pet.intimate) {
|
|
clif_displaymessage(fd, msg_txt(sd,183)); // Pet intimacy is already at maximum.
|
|
return -1;
|
|
}
|
|
|
|
pet_set_intimate(pd, friendly);
|
|
clif_send_petstatus(sd);
|
|
clif_displaymessage(fd, msg_txt(sd,182)); // Pet intimacy changed.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(pethungry)
|
|
{
|
|
int hungry;
|
|
struct pet_data *pd;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || (hungry = atoi(message)) < 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1017)); // Please enter a valid number (usage: @pethungry <0-100>).
|
|
return -1;
|
|
}
|
|
|
|
pd = sd->pd;
|
|
if (!sd->status.pet_id || !pd) {
|
|
clif_displaymessage(fd, msg_txt(sd,184)); // Sorry, but you have no pet.
|
|
return -1;
|
|
}
|
|
if (hungry < 0 || hungry > 100) {
|
|
clif_displaymessage(fd, msg_txt(sd,37)); // An invalid number was specified.
|
|
return -1;
|
|
}
|
|
if (hungry == pd->pet.hungry) {
|
|
clif_displaymessage(fd, msg_txt(sd,186)); // Pet hunger is already at maximum.
|
|
return -1;
|
|
}
|
|
|
|
pd->pet.hungry = hungry;
|
|
clif_send_petstatus(sd);
|
|
clif_displaymessage(fd, msg_txt(sd,185)); // Pet hunger changed.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(petrename)
|
|
{
|
|
struct pet_data *pd;
|
|
nullpo_retr(-1, sd);
|
|
if (!sd->status.pet_id || !sd->pd) {
|
|
clif_displaymessage(fd, msg_txt(sd,184)); // Sorry, but you have no pet.
|
|
return -1;
|
|
}
|
|
pd = sd->pd;
|
|
if (!pd->pet.rename_flag) {
|
|
clif_displaymessage(fd, msg_txt(sd,188)); // You can already rename your pet.
|
|
return -1;
|
|
}
|
|
|
|
pd->pet.rename_flag = 0;
|
|
intif_save_petdata(sd->status.account_id, &pd->pet);
|
|
clif_send_petstatus(sd);
|
|
clif_displaymessage(fd, msg_txt(sd,187)); // You can now rename your pet.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(recall) {
|
|
struct map_session_data *pl_sd = NULL;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1018)); // Please enter a player name (usage: @recall <char name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level doesn't authorize you to preform this action on the specified player.
|
|
return -1;
|
|
}
|
|
|
|
if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1019)); // You are not authorized to warp someone to this map.
|
|
return -1;
|
|
}
|
|
if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1020)); // You are not authorized to warp this player from their map.
|
|
return -1;
|
|
}
|
|
if (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y) {
|
|
return -1;
|
|
}
|
|
pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
|
|
sprintf(atcmd_output, msg_txt(sd,46), pl_sd->status.name); // %s recalled!
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* charblock command (usage: charblock <player_name>)
|
|
* This command do a definitiv ban on a player
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(char_block)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
|
|
sprintf(atcmd_output, msg_txt(sd, 1021), command); // Please enter a player name (usage: %s <char name>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
chrif_req_login_operation(sd->status.account_id, atcmd_player_name, CHRIF_OP_LOGIN_BLOCK, 0, 0, 0);
|
|
sprintf(atcmd_output, msg_txt(sd,88), "login"); // Sending request to %s server...
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* accountban command (usage: ban <%time> <player_name>)
|
|
* charban command (usage: charban <%time> <player_name>)
|
|
* %time see common/timer.c::solve_time()
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(char_ban)
|
|
{
|
|
char *modif_p, output[CHAT_SIZE_MAX];
|
|
int32 timediff = 0; //don't set this as uint as we may want to decrease banned time
|
|
int bantype = 0;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
if (strcmpi(parent_cmd,"charban") == 0)
|
|
bantype = CHRIF_OP_BAN;
|
|
else if (strcmpi(parent_cmd,"ban") == 0)
|
|
bantype = CHRIF_OP_LOGIN_BAN;
|
|
else
|
|
return -1;
|
|
|
|
if (!message || !*message || sscanf(message, "%255s %23[^\n]", atcmd_output, atcmd_player_name) < 2) {
|
|
sprintf(output, msg_txt(sd,1022), command); // Please enter ban time and a player name (usage: %s <time> <char name>).
|
|
clif_displaymessage(fd, output);
|
|
return -1;
|
|
}
|
|
|
|
atcmd_output[sizeof(atcmd_output)-1] = '\0';
|
|
|
|
modif_p = atcmd_output;
|
|
timediff = (int32)solve_time(modif_p); //discard seconds
|
|
|
|
if (timediff == 0) { //allow negative ?
|
|
safesnprintf(output, sizeof(output), msg_txt(sd,85), command, timediff); // Invalid time for %s command (time=%d)
|
|
clif_displaymessage(fd, output);
|
|
clif_displaymessage(fd, msg_txt(sd,702)); // Time parameter format is +/-<value> to alter. y/a = Year, m = Month, d/j = Day, h = Hour, n/mn = Minute, s = Second.
|
|
return -1;
|
|
}
|
|
|
|
if( timediff < 0 && (
|
|
(bantype == CHRIF_OP_LOGIN_BAN && !pc_can_use_command(sd, "unban", COMMAND_ATCOMMAND))
|
|
|| (bantype == CHRIF_OP_BAN && !pc_can_use_command(sd, "charunban", COMMAND_ATCOMMAND))
|
|
))
|
|
{
|
|
clif_displaymessage(fd,msg_txt(sd,1023)); // You are not allowed to alter the time of a ban.
|
|
return -1;
|
|
}
|
|
|
|
if (bantype == CHRIF_OP_BAN)
|
|
chrif_req_charban(sd->status.account_id, atcmd_player_name,timediff);
|
|
else
|
|
chrif_req_login_operation(sd->status.account_id, atcmd_player_name, bantype, timediff, 0, 0);
|
|
|
|
safesnprintf(output, sizeof(output), msg_txt(sd,88), bantype == CHRIF_OP_BAN ? "char" : "login"); // Sending request to %s server...
|
|
clif_displaymessage(fd, output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* charunblock command (usage: charunblock <player_name>)
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(char_unblock)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
|
|
sprintf(atcmd_output, msg_txt(sd, 1021), command); // Please enter a player name (usage: %s <char name>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
// send answer to login server via char-server
|
|
chrif_req_login_operation(sd->status.account_id, atcmd_player_name, CHRIF_OP_LOGIN_UNBLOCK, 0, 0, 0);
|
|
sprintf(atcmd_output, msg_txt(sd,88), "login"); // Sending request to %s server...
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* acc unban command (usage: unban <player_name>)
|
|
* char unban command (usage: charunban <player_name>)
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(char_unban){
|
|
int unbantype = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
if (strcmpi(parent_cmd,"charunban") == 0)
|
|
unbantype = CHRIF_OP_UNBAN;
|
|
else if (strcmpi(parent_cmd,"unban") == 0)
|
|
unbantype = CHRIF_OP_LOGIN_UNBAN;
|
|
else
|
|
return -1;
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
|
|
sprintf(atcmd_output, msg_txt(sd,435), command); // Please enter a player name (usage: %s <char name>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
if (unbantype == CHRIF_OP_UNBAN)
|
|
chrif_req_charunban(sd->status.account_id,atcmd_player_name);
|
|
else
|
|
chrif_req_login_operation(sd->status.account_id, atcmd_player_name, unbantype, 0, 0, 0);
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,88), unbantype == CHRIF_OP_UNBAN ? "char":"login"); // Sending request to %s server...
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(night)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (night_flag != 1) {
|
|
map_night_timer(night_timer_tid, 0, 0, 1);
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,89)); // Night mode is already enabled.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(day)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (night_flag != 0) {
|
|
map_day_timer(day_timer_tid, 0, 0, 1);
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,90)); // Day mode is already enabled.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(doom)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
{
|
|
if (pl_sd->fd != fd && pc_get_group_level(sd) >= pc_get_group_level(pl_sd))
|
|
{
|
|
status_kill(&pl_sd->bl);
|
|
clif_specialeffect(&pl_sd->bl,450,AREA);
|
|
clif_displaymessage(pl_sd->fd, msg_txt(sd,61)); // The holy messenger has given judgement.
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,62)); // Judgement was made.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(doommap)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
{
|
|
if (pl_sd->fd != fd && sd->bl.m == pl_sd->bl.m && pc_get_group_level(sd) >= pc_get_group_level(pl_sd))
|
|
{
|
|
status_kill(&pl_sd->bl);
|
|
clif_specialeffect(&pl_sd->bl,450,AREA);
|
|
clif_displaymessage(pl_sd->fd, msg_txt(sd,61)); // The holy messenger has given judgement.
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,62)); // Judgement was made.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
static void atcommand_raise_sub(struct map_session_data* sd) {
|
|
|
|
status_revive(&sd->bl, 100, 100);
|
|
|
|
clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1);
|
|
clif_displaymessage(sd->fd, msg_txt(sd,63)); // Mercy has been shown.
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(raise)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
if( pc_isdead(pl_sd) )
|
|
atcommand_raise_sub(pl_sd);
|
|
mapit_free(iter);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,64)); // Mercy has been granted.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(raisemap)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
if (sd->bl.m == pl_sd->bl.m && pc_isdead(pl_sd) )
|
|
atcommand_raise_sub(pl_sd);
|
|
mapit_free(iter);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,64)); // Mercy has been granted.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(kick)
|
|
{
|
|
struct map_session_data *pl_sd;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1026)); // Please enter a player name (usage: @kick <char name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
|
|
return -1;
|
|
}
|
|
|
|
clif_GM_kick(sd, pl_sd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(kickall)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
nullpo_retr(-1, sd);
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
{
|
|
if (pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { // you can kick only lower or same gm level
|
|
if (sd->status.account_id != pl_sd->status.account_id)
|
|
clif_GM_kick(NULL, pl_sd);
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,195)); // All players have been kicked!
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(allskill)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
pc_allskillup(sd); // all skills
|
|
sd->status.skill_point = 0; // 0 skill points
|
|
clif_updatestatus(sd, SP_SKILLPOINT); // update
|
|
clif_displaymessage(fd, msg_txt(sd,76)); // All skills have been added to your skill tree.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(questskill)
|
|
{
|
|
uint16 skill_id;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || (skill_id = atoi(message)) <= 0)
|
|
{// also send a list of skills applicable to this command
|
|
const char* text;
|
|
|
|
// attempt to find the text corresponding to this command
|
|
text = atcommand_help_string( command );
|
|
|
|
// send the error message as always
|
|
clif_displaymessage(fd, msg_txt(sd,1027)); // Please enter a quest skill number.
|
|
|
|
if( text )
|
|
{// send the skill ID list associated with this command
|
|
clif_displaymessage( fd, text );
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
if (skill_id >= MAX_SKILL_DB) {
|
|
clif_displaymessage(fd, msg_txt(sd,198)); // This skill number doesn't exist.
|
|
return -1;
|
|
}
|
|
if (!(skill_get_inf2(skill_id) & INF2_QUEST_SKILL)) {
|
|
clif_displaymessage(fd, msg_txt(sd,197)); // This skill number doesn't exist or isn't a quest skill.
|
|
return -1;
|
|
}
|
|
if (pc_checkskill(sd, skill_id) > 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,196)); // You already have this quest skill.
|
|
return -1;
|
|
}
|
|
|
|
pc_skill(sd, skill_id, 1, 0);
|
|
clif_displaymessage(fd, msg_txt(sd,70)); // You have learned the skill.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(lostskill)
|
|
{
|
|
uint16 skill_id;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || (skill_id = atoi(message)) <= 0)
|
|
{// also send a list of skills applicable to this command
|
|
const char* text;
|
|
|
|
// attempt to find the text corresponding to this command
|
|
text = atcommand_help_string( command );
|
|
|
|
// send the error message as always
|
|
clif_displaymessage(fd, msg_txt(sd,1027)); // Please enter a quest skill number.
|
|
|
|
if( text )
|
|
{// send the skill ID list associated with this command
|
|
clif_displaymessage( fd, text );
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
if (skill_id >= MAX_SKILL) {
|
|
clif_displaymessage(fd, msg_txt(sd,198)); // This skill number doesn't exist.
|
|
return -1;
|
|
}
|
|
if (!(skill_get_inf2(skill_id) & INF2_QUEST_SKILL)) {
|
|
clif_displaymessage(fd, msg_txt(sd,197)); // This skill number doesn't exist or isn't a quest skill.
|
|
return -1;
|
|
}
|
|
if (pc_checkskill(sd, skill_id) == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,201)); // You don't have this quest skill.
|
|
return -1;
|
|
}
|
|
|
|
sd->status.skill[skill_id].lv = 0;
|
|
sd->status.skill[skill_id].flag = SKILL_FLAG_PERMANENT;
|
|
clif_deleteskill(sd,skill_id);
|
|
clif_displaymessage(fd, msg_txt(sd,71)); // You have forgotten the skill.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(spiritball)
|
|
{
|
|
int max_spiritballs;
|
|
int number;
|
|
nullpo_retr(-1, sd);
|
|
|
|
max_spiritballs = min(ARRAYLENGTH(sd->spirit_timer), 0x7FFF);
|
|
|
|
if( !message || !*message || (number = atoi(message)) < 0 || number > max_spiritballs )
|
|
{
|
|
char msg[CHAT_SIZE_MAX];
|
|
safesnprintf(msg, sizeof(msg), msg_txt(sd,1028), max_spiritballs); // Please enter a party name (usage: @party <party_name>).
|
|
clif_displaymessage(fd, msg);
|
|
return -1;
|
|
}
|
|
|
|
if( sd->spiritball > 0 )
|
|
pc_delspiritball(sd, sd->spiritball, 1);
|
|
sd->spiritball = number;
|
|
clif_spiritball(&sd->bl);
|
|
// no message, player can look the difference
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(party)
|
|
{
|
|
char party[NAME_LENGTH];
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(party, '\0', sizeof(party));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", party) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1029)); // Please enter a party name (usage: @party <party_name>).
|
|
return -1;
|
|
}
|
|
|
|
party_create(sd, party, 0, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(guild)
|
|
{
|
|
char guild[NAME_LENGTH];
|
|
int prev;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(guild, '\0', sizeof(guild));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", guild) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1030)); // Please enter a guild name (usage: @guild <guild_name>).
|
|
return -1;
|
|
}
|
|
|
|
prev = battle_config.guild_emperium_check;
|
|
battle_config.guild_emperium_check = 0;
|
|
guild_create(sd, guild);
|
|
battle_config.guild_emperium_check = prev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(breakguild)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (sd->status.guild_id) { // Check if the player has a guild
|
|
struct guild *g;
|
|
g = sd->guild; // Search the guild
|
|
if (g) { // Check if guild was found
|
|
if (sd->state.gmaster_flag) { // Check if player is guild master
|
|
int ret = 0;
|
|
ret = guild_break(sd, g->name); // Break guild
|
|
if (ret) { // Check if anything went wrong
|
|
return 0; // Guild was broken
|
|
} else {
|
|
return -1; // Something went wrong
|
|
}
|
|
} else { // Not guild master
|
|
clif_displaymessage(fd, msg_txt(sd,1181)); // You need to be a Guild Master to use this command.
|
|
return -1;
|
|
}
|
|
} else { // Guild was not found. HOW?
|
|
clif_displaymessage(fd, msg_txt(sd,252)); // You are not in a guild.
|
|
return -1;
|
|
}
|
|
} else { // Player does not have a guild
|
|
clif_displaymessage(fd, msg_txt(sd,252)); // You are not in a guild.
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(agitstart)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (agit_flag == 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,73)); // War of Emperium is currently in progress.
|
|
return -1;
|
|
}
|
|
|
|
agit_flag = 1;
|
|
guild_agit_start();
|
|
clif_displaymessage(fd, msg_txt(sd,72)); // War of Emperium has been initiated.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(agitstart2)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (agit2_flag == 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,404)); // "War of Emperium SE is currently in progress."
|
|
return -1;
|
|
}
|
|
|
|
agit2_flag = 1;
|
|
guild_agit2_start();
|
|
clif_displaymessage(fd, msg_txt(sd,403)); // "War of Emperium SE has been initiated."
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(agitend)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (agit_flag == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,75)); // War of Emperium is currently not in progress.
|
|
return -1;
|
|
}
|
|
|
|
agit_flag = 0;
|
|
guild_agit_end();
|
|
clif_displaymessage(fd, msg_txt(sd,74)); // War of Emperium has been ended.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(agitend2)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (agit2_flag == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,406)); // "War of Emperium SE is currently not in progress."
|
|
return -1;
|
|
}
|
|
|
|
agit2_flag = 0;
|
|
guild_agit2_end();
|
|
clif_displaymessage(fd, msg_txt(sd,405)); // "War of Emperium SE has been ended."
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @mapexit - shuts down the map server
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(mapexit)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
do_shutdown();
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* idsearch <part_of_name>: revrited by [Yor]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(idsearch)
|
|
{
|
|
char item_name[100];
|
|
unsigned int i, match;
|
|
struct item_data *item_array[MAX_SEARCH];
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(item_name, '\0', sizeof(item_name));
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%99s", item_name) < 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1031)); // Please enter part of an item name (usage: @idsearch <part_of_item_name>).
|
|
return -1;
|
|
}
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,77), item_name); // The reference result of '%s' (name: id):
|
|
clif_displaymessage(fd, atcmd_output);
|
|
match = itemdb_searchname_array(item_array, MAX_SEARCH, item_name);
|
|
if (match > MAX_SEARCH) {
|
|
sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH, match);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
match = MAX_SEARCH;
|
|
}
|
|
for(i = 0; i < match; i++) {
|
|
sprintf(atcmd_output, msg_txt(sd,78), item_array[i]->jname, item_array[i]->nameid); // %s: %d
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
sprintf(atcmd_output, msg_txt(sd,79), match); // It is %d affair above.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Recall All Characters Online To Your Location
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(recallall)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
int count;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1032)); // You are not authorized to warp someone to your current map.
|
|
return -1;
|
|
}
|
|
|
|
count = 0;
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
{
|
|
if (sd->status.account_id != pl_sd->status.account_id && pc_get_group_level(sd) >= pc_get_group_level(pl_sd))
|
|
{
|
|
if (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y)
|
|
continue; // Don't waste time warping the character to the same place.
|
|
if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
|
|
count++;
|
|
else {
|
|
if (pc_isdead(pl_sd)) { //Wake them up
|
|
pc_setstand(pl_sd, true);
|
|
pc_setrestartvalue(pl_sd,1);
|
|
}
|
|
pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
|
|
}
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,92)); // All characters recalled!
|
|
if (count) {
|
|
sprintf(atcmd_output, msg_txt(sd,1033), count); // Because you are not authorized to warp from some maps, %d player(s) have not been recalled.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Recall online characters of a guild to your location
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(guildrecall)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
int count;
|
|
char guild_name[NAME_LENGTH];
|
|
struct guild *g;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(guild_name, '\0', sizeof(guild_name));
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", guild_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1034)); // Please enter a guild name/ID (usage: @guildrecall <guild_name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1032)); // You are not authorized to warp someone to your current map.
|
|
return -1;
|
|
}
|
|
|
|
if ((g = guild_searchname(guild_name)) == NULL && // name first to avoid error when name begin with a number
|
|
(g = guild_search(atoi(message))) == NULL)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,94)); // Incorrect name/ID, or no one from the guild is online.
|
|
return -1;
|
|
}
|
|
|
|
count = 0;
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
{
|
|
if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.guild_id == g->guild_id)
|
|
{
|
|
if (pc_get_group_level(pl_sd) > pc_get_group_level(sd) || (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y))
|
|
continue; // Skip GMs greater than you... or chars already on the cell
|
|
if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
|
|
count++;
|
|
else
|
|
pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,93), g->name); // All online characters of the %s guild have been recalled to your position.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
if (count) {
|
|
sprintf(atcmd_output, msg_txt(sd,1033), count); // Because you are not authorized to warp from some maps, %d player(s) have not been recalled.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Recall online characters of a party to your location
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(partyrecall)
|
|
{
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
char party_name[NAME_LENGTH];
|
|
struct party_data *p;
|
|
int count;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(party_name, '\0', sizeof(party_name));
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", party_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1035)); // Please enter a party name/ID (usage: @partyrecall <party_name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1032)); // You are not authorized to warp someone to your current map.
|
|
return -1;
|
|
}
|
|
|
|
if ((p = party_searchname(party_name)) == NULL && // name first to avoid error when name begin with a number
|
|
(p = party_search(atoi(message))) == NULL)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,96)); // Incorrect name or ID, or no one from the party is online.
|
|
return -1;
|
|
}
|
|
|
|
count = 0;
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
{
|
|
if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.party_id == p->party.party_id)
|
|
{
|
|
if (pc_get_group_level(pl_sd) > pc_get_group_level(sd) || (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y))
|
|
continue; // Skip GMs greater than you... or chars already on the cell
|
|
if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE))
|
|
count++;
|
|
else
|
|
pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,95), p->party.name); // All online characters of the %s party have been recalled to your position.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
if (count) {
|
|
sprintf(atcmd_output, msg_txt(sd,1033), count); // Because you are not authorized to warp from some maps, %d player(s) have not been recalled.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
void atcommand_doload();
|
|
ACMD_FUNC(reload) {
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ((strlen(command) < 8 ) && (!message || !*message)) {
|
|
const char* text;
|
|
|
|
text = atcommand_help_string( command );
|
|
if(text)
|
|
clif_displaymessage( fd, text );
|
|
return -1;
|
|
}
|
|
|
|
if (strstr(command, "itemdb") || strncmp(message, "itemdb", 4) == 0) {
|
|
itemdb_reload();
|
|
clif_displaymessage(fd, msg_txt(sd,97)); // Item database has been reloaded.
|
|
} else if (strstr(command, "mobdb") || strncmp(message, "mobdb", 3) == 0) {
|
|
mob_reload();
|
|
read_petdb();
|
|
hom_reload();
|
|
mercenary_readdb();
|
|
mercenary_read_skilldb();
|
|
reload_elementaldb();
|
|
clif_displaymessage(fd, msg_txt(sd,98)); // Monster database has been reloaded.
|
|
} else if (strstr(command, "skilldb") || strncmp(message, "skilldb", 4) == 0) {
|
|
skill_reload();
|
|
hom_reload_skill();
|
|
reload_elemental_skilldb();
|
|
mercenary_read_skilldb();
|
|
clif_displaymessage(fd, msg_txt(sd,99)); // Skill database has been reloaded.
|
|
} else if (strstr(command, "atcommand") || strncmp(message, "atcommand", 4) == 0) {
|
|
config_t run_test;
|
|
|
|
if (conf_read_file(&run_test, "conf/groups.conf")) {
|
|
clif_displaymessage(fd, msg_txt(sd,1036)); // Error reading groups.conf, reload failed.
|
|
return -1;
|
|
}
|
|
|
|
config_destroy(&run_test);
|
|
|
|
if (conf_read_file(&run_test, ATCOMMAND_CONF_FILENAME)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1037)); // Error reading atcommand_athena.conf, reload failed.
|
|
return -1;
|
|
}
|
|
|
|
config_destroy(&run_test);
|
|
|
|
atcommand_doload();
|
|
pc_groups_reload();
|
|
clif_displaymessage(fd, msg_txt(sd,254));
|
|
} else if (strstr(command, "battleconf") || strncmp(message, "battleconf", 3) == 0) {
|
|
struct Battle_Config prev_config;
|
|
memcpy(&prev_config, &battle_config, sizeof(prev_config));
|
|
|
|
battle_config_read(BATTLE_CONF_FILENAME);
|
|
|
|
if( prev_config.item_rate_mvp != battle_config.item_rate_mvp
|
|
|| prev_config.item_rate_common != battle_config.item_rate_common
|
|
|| prev_config.item_rate_common_boss != battle_config.item_rate_common_boss
|
|
|| prev_config.item_rate_card != battle_config.item_rate_card
|
|
|| prev_config.item_rate_card_boss != battle_config.item_rate_card_boss
|
|
|| prev_config.item_rate_equip != battle_config.item_rate_equip
|
|
|| prev_config.item_rate_equip_boss != battle_config.item_rate_equip_boss
|
|
|| prev_config.item_rate_heal != battle_config.item_rate_heal
|
|
|| prev_config.item_rate_heal_boss != battle_config.item_rate_heal_boss
|
|
|| prev_config.item_rate_use != battle_config.item_rate_use
|
|
|| prev_config.item_rate_use_boss != battle_config.item_rate_use_boss
|
|
|| prev_config.item_rate_treasure != battle_config.item_rate_treasure
|
|
|| prev_config.item_rate_adddrop != battle_config.item_rate_adddrop
|
|
|| prev_config.logarithmic_drops != battle_config.logarithmic_drops
|
|
|| prev_config.item_drop_common_min != battle_config.item_drop_common_min
|
|
|| prev_config.item_drop_common_max != battle_config.item_drop_common_max
|
|
|| prev_config.item_drop_card_min != battle_config.item_drop_card_min
|
|
|| prev_config.item_drop_card_max != battle_config.item_drop_card_max
|
|
|| prev_config.item_drop_equip_min != battle_config.item_drop_equip_min
|
|
|| prev_config.item_drop_equip_max != battle_config.item_drop_equip_max
|
|
|| prev_config.item_drop_mvp_min != battle_config.item_drop_mvp_min
|
|
|| prev_config.item_drop_mvp_max != battle_config.item_drop_mvp_max
|
|
|| prev_config.item_drop_heal_min != battle_config.item_drop_heal_min
|
|
|| prev_config.item_drop_heal_max != battle_config.item_drop_heal_max
|
|
|| prev_config.item_drop_use_min != battle_config.item_drop_use_min
|
|
|| prev_config.item_drop_use_max != battle_config.item_drop_use_max
|
|
|| prev_config.item_drop_treasure_min != battle_config.item_drop_treasure_min
|
|
|| prev_config.item_drop_treasure_max != battle_config.item_drop_treasure_max
|
|
|| prev_config.base_exp_rate != battle_config.base_exp_rate
|
|
|| prev_config.job_exp_rate != battle_config.job_exp_rate
|
|
)
|
|
{ // Exp or Drop rates changed.
|
|
mob_reload(); //Needed as well so rate changes take effect.
|
|
chrif_ragsrvinfo(battle_config.base_exp_rate, battle_config.job_exp_rate, battle_config.item_rate_common);
|
|
}
|
|
clif_displaymessage(fd, msg_txt(sd,255));
|
|
} else if (strstr(command, "statusdb") || strncmp(message, "statusdb", 3) == 0) {
|
|
status_readdb();
|
|
clif_displaymessage(fd, msg_txt(sd,256));
|
|
} else if (strstr(command, "pcdb") || strncmp(message, "pcdb", 2) == 0) {
|
|
pc_readdb();
|
|
clif_displaymessage(fd, msg_txt(sd,257));
|
|
} else if (strstr(command, "motd") || strncmp(message, "motd", 4) == 0) {
|
|
pc_read_motd();
|
|
clif_displaymessage(fd, msg_txt(sd,268));
|
|
} else if (strstr(command, "script") || strncmp(message, "script", 3) == 0) {
|
|
struct s_mapiterator* iter;
|
|
struct map_session_data* pl_sd;
|
|
//atcommand_broadcast( fd, sd, "@broadcast", "Server is reloading scripts..." );
|
|
//atcommand_broadcast( fd, sd, "@broadcast", "You will feel a bit of lag at this point !" );
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
pc_close_npc(pl_sd,2);
|
|
mapit_free(iter);
|
|
|
|
flush_fifos();
|
|
map_reloadnpc(true); // reload config files seeking for npcs
|
|
script_reload();
|
|
npc_reload();
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,100)); // Scripts have been reloaded.
|
|
} else if (strstr(command, "msgconf") || strncmp(message, "msgconf", 3) == 0) {
|
|
map_msg_reload();
|
|
clif_displaymessage(fd, msg_txt(sd,463)); // Message configuration has been reloaded.
|
|
} else if (strstr(command, "questdb") || strncmp(message, "questdb", 3) == 0) {
|
|
do_reload_quest();
|
|
clif_displaymessage(fd, msg_txt(sd,1377)); // Quest database has been reloaded.
|
|
} else if (strstr(command, "packetdb") || strncmp(message, "packetdb", 4) == 0) {
|
|
packetdb_readdb();
|
|
clif_displaymessage(fd, msg_txt(sd,1477)); // Packet database has been reloaded.
|
|
} else if (strstr(command, "instancedb") || strncmp(message, "instancedb", 4) == 0) {
|
|
instance_readdb();
|
|
clif_displaymessage(fd, msg_txt(sd,516)); // Instance database has been reloaded.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/*==========================================
|
|
* @partysharelvl <share_range> [Akinari]
|
|
* Updates char server party share level range in runtime
|
|
* Temporary - Permanent update in inter_athena.conf
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(partysharelvl) {
|
|
unsigned int share_lvl;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if(!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1322)); // Please enter an amount.
|
|
return -1;
|
|
} else
|
|
share_lvl = min(abs(atoi(message)),MAX_LEVEL);
|
|
|
|
if(intif_party_sharelvlupdate(share_lvl)) //Successfully updated
|
|
clif_displaymessage(fd, msg_txt(sd,1478)); // Party share level range has been changed successfully.
|
|
else //Char server offline
|
|
clif_displaymessage(fd, msg_txt(sd,1479)); // Failed to update configuration. Character server is offline.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @mapinfo [0-3] <map name> by MC_Cameri
|
|
* => Shows information about the map [map name]
|
|
* 0 = no additional information
|
|
* 1 = Show users in that map and their location
|
|
* 2 = Shows NPCs in that map
|
|
* 3 = Shows the chats in that map
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(mapinfo) {
|
|
struct map_session_data* pl_sd;
|
|
struct s_mapiterator* iter;
|
|
struct chat_data *cd = NULL;
|
|
char direction[12];
|
|
int i, m_id, chat_num = 0, list = 0, vend_num = 0;
|
|
unsigned short m_index;
|
|
char mapname[24];
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
memset(mapname, '\0', sizeof(mapname));
|
|
memset(direction, '\0', sizeof(direction));
|
|
|
|
sscanf(message, "%d %23[^\n]", &list, mapname);
|
|
|
|
if (list < 0 || list > 3) {
|
|
clif_displaymessage(fd, msg_txt(sd,1038)); // Please enter at least one valid list number (usage: @mapinfo <0-3> <map>).
|
|
return -1;
|
|
}
|
|
|
|
if (mapname[0] == '\0') {
|
|
safestrncpy(mapname, mapindex_id2name(sd->mapindex), MAP_NAME_LENGTH);
|
|
m_id = map_mapindex2mapid(sd->mapindex);
|
|
} else {
|
|
m_id = map_mapname2mapid(mapname);
|
|
}
|
|
|
|
if (m_id < 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1)); // Map not found.
|
|
return -1;
|
|
}
|
|
m_index = mapindex_name2id(mapname); //This one shouldn't fail since the previous seek did not.
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1039)); // ------ Map Info ------
|
|
|
|
// count chats (for initial message)
|
|
chat_num = 0;
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) ) {
|
|
if( pl_sd->mapindex == m_index ) {
|
|
if( pl_sd->state.vending )
|
|
vend_num++;
|
|
else if( (cd = (struct chat_data*)map_id2bl(pl_sd->chatID)) != NULL && cd->usersd[0] == pl_sd )
|
|
chat_num++;
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,1040), mapname, map[m_id].users, map[m_id].npc_num, chat_num, vend_num); // Map: %s | Players: %d | NPCs: %d | Chats: %d | Vendings: %d
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1041)); // ------ Map Flags ------
|
|
if (map[m_id].flag.town)
|
|
clif_displaymessage(fd, msg_txt(sd,1042)); // Town Map
|
|
if (map[m_id].flag.restricted){
|
|
sprintf(atcmd_output, " Restricted (zone %d)",map[m_id].zone);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
if (battle_config.autotrade_mapflag == map[m_id].flag.autotrade)
|
|
clif_displaymessage(fd, msg_txt(sd,1043)); // Autotrade Enabled
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,1044)); // Autotrade Disabled
|
|
|
|
if (map[m_id].flag.battleground){
|
|
sprintf(atcmd_output, msg_txt(sd,1045),map[m_id].flag.battleground); // Battlegrounds ON (type %d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
/* Skill damage adjustment info [Cydh] */
|
|
#ifdef ADJUST_SKILL_DAMAGE
|
|
if (map[m_id].flag.skill_damage) {
|
|
clif_displaymessage(fd,msg_txt(sd,1052)); // Skill Damage Adjustments:
|
|
sprintf(atcmd_output," > [Map] %d%%, %d%%, %d%%, %d%% | Caster:%d"
|
|
,map[m_id].adjust.damage.pc
|
|
,map[m_id].adjust.damage.mob
|
|
,map[m_id].adjust.damage.boss
|
|
,map[m_id].adjust.damage.other
|
|
,map[m_id].adjust.damage.caster);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
if (map[m_id].skill_damage.count) {
|
|
uint8 j;
|
|
clif_displaymessage(fd," > [Map Skill] Name : Player, Monster, Boss Monster, Other | Caster");
|
|
for (j = 0; j < map[m_id].skill_damage.count; j++) {
|
|
sprintf(atcmd_output," %d. %s : %d%%, %d%%, %d%%, %d%% | %d"
|
|
,j+1
|
|
,skill_get_name(map[m_id].skill_damage.entries[j]->skill_id)
|
|
,map[m_id].skill_damage.entries[j]->pc
|
|
,map[m_id].skill_damage.entries[j]->mob
|
|
,map[m_id].skill_damage.entries[j]->boss
|
|
,map[m_id].skill_damage.entries[j]->other
|
|
,map[m_id].skill_damage.entries[j]->caster);
|
|
clif_displaymessage(fd,atcmd_output);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
strcpy(atcmd_output,msg_txt(sd,1046)); // PvP Flags:
|
|
if (map[m_id].flag.pvp)
|
|
strcat(atcmd_output, " Pvp ON |");
|
|
if (map[m_id].flag.pvp_noguild)
|
|
strcat(atcmd_output, " NoGuild |");
|
|
if (map[m_id].flag.pvp_noparty)
|
|
strcat(atcmd_output, " NoParty |");
|
|
if (map[m_id].flag.pvp_nightmaredrop)
|
|
strcat(atcmd_output, " NightmareDrop |");
|
|
if (map[m_id].flag.pvp_nocalcrank)
|
|
strcat(atcmd_output, " NoCalcRank |");
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
strcpy(atcmd_output,msg_txt(sd,1047)); // GvG Flags:
|
|
if (map[m_id].flag.gvg)
|
|
strcat(atcmd_output, " GvG ON |");
|
|
if (map[m_id].flag.gvg_dungeon)
|
|
strcat(atcmd_output, " GvG Dungeon |");
|
|
if (map[m_id].flag.gvg_castle)
|
|
strcat(atcmd_output, " GvG Castle |");
|
|
if (map[m_id].flag.gvg_noparty)
|
|
strcat(atcmd_output, " NoParty |");
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
strcpy(atcmd_output,msg_txt(sd,1048)); // Teleport Flags:
|
|
if (map[m_id].flag.noteleport)
|
|
strcat(atcmd_output, " NoTeleport |");
|
|
if (map[m_id].flag.monster_noteleport)
|
|
strcat(atcmd_output, " Monster NoTeleport |");
|
|
if (map[m_id].flag.nowarp)
|
|
strcat(atcmd_output, " NoWarp |");
|
|
if (map[m_id].flag.nowarpto)
|
|
strcat(atcmd_output, " NoWarpTo |");
|
|
if (map[m_id].flag.noreturn)
|
|
strcat(atcmd_output, " NoReturn |");
|
|
if (map[m_id].flag.nogo)
|
|
strcat(atcmd_output, " NoGo |"); //
|
|
if (map[m_id].flag.nomemo)
|
|
strcat(atcmd_output, " NoMemo |");
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,1065), // No Exp Penalty: %s | No Zeny Penalty: %s
|
|
(map[m_id].flag.noexppenalty) ? msg_txt(sd,1066) : msg_txt(sd,1067), (map[m_id].flag.nozenypenalty) ? msg_txt(sd,1066) : msg_txt(sd,1067)); // On / Off
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
if (map[m_id].flag.nosave) {
|
|
if (!map[m_id].save.map)
|
|
clif_displaymessage(fd, msg_txt(sd,1068)); // No Save (Return to last Save Point)
|
|
else if (map[m_id].save.x == -1 || map[m_id].save.y == -1 ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1069), mapindex_id2name(map[m_id].save.map)); // No Save, Save Point: %s,Random
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
else {
|
|
sprintf(atcmd_output, msg_txt(sd,1070), // No Save, Save Point: %s,%d,%d
|
|
mapindex_id2name(map[m_id].save.map),map[m_id].save.x,map[m_id].save.y);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
}
|
|
|
|
strcpy(atcmd_output,msg_txt(sd,1049)); // Weather Flags:
|
|
if (map[m_id].flag.snow)
|
|
strcat(atcmd_output, " Snow |");
|
|
if (map[m_id].flag.fog)
|
|
strcat(atcmd_output, " Fog |");
|
|
if (map[m_id].flag.sakura)
|
|
strcat(atcmd_output, " Sakura |");
|
|
if (map[m_id].flag.clouds)
|
|
strcat(atcmd_output, " Clouds |");
|
|
if (map[m_id].flag.clouds2)
|
|
strcat(atcmd_output, " Clouds2 |");
|
|
if (map[m_id].flag.fireworks)
|
|
strcat(atcmd_output, " Fireworks |");
|
|
if (map[m_id].flag.leaves)
|
|
strcat(atcmd_output, " Leaves |");
|
|
if (map[m_id].flag.nightenabled)
|
|
strcat(atcmd_output, " Displays Night |");
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
strcpy(atcmd_output,msg_txt(sd,1050)); // Other Flags:
|
|
if (map[m_id].flag.nobranch)
|
|
strcat(atcmd_output, " NoBranch |");
|
|
if (map[m_id].flag.notrade)
|
|
strcat(atcmd_output, " NoTrade |");
|
|
if (map[m_id].flag.novending)
|
|
strcat(atcmd_output, " NoVending |");
|
|
if (map[m_id].flag.nodrop)
|
|
strcat(atcmd_output, " NoDrop |");
|
|
if (map[m_id].flag.noskill)
|
|
strcat(atcmd_output, " NoSkill |");
|
|
if (map[m_id].flag.noicewall)
|
|
strcat(atcmd_output, " NoIcewall |");
|
|
if (map[m_id].flag.allowks)
|
|
strcat(atcmd_output, " AllowKS |");
|
|
if (map[m_id].flag.reset)
|
|
strcat(atcmd_output, " Reset |");
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
strcpy(atcmd_output,msg_txt(sd,1051)); // Other Flags2:
|
|
if (map[m_id].nocommand)
|
|
strcat(atcmd_output, " NoCommand |");
|
|
if (map[m_id].flag.nobaseexp)
|
|
strcat(atcmd_output, " NoBaseEXP |");
|
|
if (map[m_id].flag.nojobexp)
|
|
strcat(atcmd_output, " NoJobEXP |");
|
|
if (map[m_id].flag.nomobloot)
|
|
strcat(atcmd_output, " NoMobLoot |");
|
|
if (map[m_id].flag.nomvploot)
|
|
strcat(atcmd_output, " NoMVPLoot |");
|
|
if (map[m_id].flag.partylock)
|
|
strcat(atcmd_output, " PartyLock |");
|
|
if (map[m_id].flag.guildlock)
|
|
strcat(atcmd_output, " GuildLock |");
|
|
if (map[m_id].flag.loadevent)
|
|
strcat(atcmd_output, " Loadevent |");
|
|
if (map[m_id].flag.chmautojoin)
|
|
strcat(atcmd_output, " Chmautojoin |");
|
|
if (map[m_id].flag.nousecart)
|
|
strcat(atcmd_output, " NoUsecart |");
|
|
if (map[m_id].flag.noitemconsumption)
|
|
strcat(atcmd_output, " NoItemConsumption |");
|
|
if (map[m_id].flag.nosumstarmiracle)
|
|
strcat(atcmd_output, " NoSumStarMiracle |");
|
|
if (map[m_id].flag.nomineeffect)
|
|
strcat(atcmd_output, " NoMineEffect |");
|
|
if (map[m_id].flag.nolockon)
|
|
strcat(atcmd_output, " NoLockOn |");
|
|
if (map[m_id].flag.notomb)
|
|
strcat(atcmd_output, " NoTomb |");
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
switch (list) {
|
|
case 0:
|
|
// Do nothing. It's list 0, no additional display.
|
|
break;
|
|
case 1:
|
|
clif_displaymessage(fd, msg_txt(sd,480)); // ----- Players in Map -----
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
{
|
|
if (pl_sd->mapindex == m_index) {
|
|
sprintf(atcmd_output, msg_txt(sd,481), // Player '%s' (session #%d) | Location: %d,%d
|
|
pl_sd->status.name, pl_sd->fd, pl_sd->bl.x, pl_sd->bl.y);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
break;
|
|
case 2:
|
|
clif_displaymessage(fd, msg_txt(sd,482)); // ----- NPCs in Map -----
|
|
for (i = 0; i < map[m_id].npc_num;)
|
|
{
|
|
struct npc_data *nd = map[m_id].npc[i];
|
|
switch(nd->ud.dir) {
|
|
case 0: strcpy(direction, msg_txt(sd,491)); break; // North
|
|
case 1: strcpy(direction, msg_txt(sd,492)); break; // North West
|
|
case 2: strcpy(direction, msg_txt(sd,493)); break; // West
|
|
case 3: strcpy(direction, msg_txt(sd,494)); break; // South West
|
|
case 4: strcpy(direction, msg_txt(sd,495)); break; // South
|
|
case 5: strcpy(direction, msg_txt(sd,496)); break; // South East
|
|
case 6: strcpy(direction, msg_txt(sd,497)); break; // East
|
|
case 7: strcpy(direction, msg_txt(sd,498)); break; // North East
|
|
case 9: strcpy(direction, msg_txt(sd,491)); break; // North
|
|
default: strcpy(direction, msg_txt(sd,499)); break; // Unknown
|
|
}
|
|
if(strcmp(nd->name,nd->exname) == 0)
|
|
sprintf(atcmd_output, msg_txt(sd,490), // NPC %d: %s | Direction: %s | Sprite: %d | Location: %d %d
|
|
++i, nd->name, direction, nd->class_, nd->bl.x, nd->bl.y);
|
|
else
|
|
sprintf(atcmd_output, msg_txt(sd,489), // NPC %d: %s::%s | Direction: %s | Sprite: %d | Location: %d %d
|
|
++i, nd->name, nd->exname, direction, nd->class_, nd->bl.x, nd->bl.y);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
break;
|
|
case 3:
|
|
clif_displaymessage(fd, msg_txt(sd,483)); // ----- Chats in Map -----
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
{
|
|
if ((cd = (struct chat_data*)map_id2bl(pl_sd->chatID)) != NULL &&
|
|
pl_sd->mapindex == m_index &&
|
|
cd->usersd[0] == pl_sd)
|
|
{
|
|
sprintf(atcmd_output, msg_txt(sd,484), // Chat: %s | Player: %s | Location: %d %d
|
|
cd->title, pl_sd->status.name, cd->bl.x, cd->bl.y);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,485), // Users: %d/%d | Password: %s | Public: %s
|
|
cd->users, cd->limit, cd->pass, (cd->pub) ? msg_txt(sd,486) : msg_txt(sd,487)); // Yes / No
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
break;
|
|
default: // normally impossible to arrive here
|
|
clif_displaymessage(fd, msg_txt(sd,488)); // Please enter at least one valid list number (usage: @mapinfo <0-3> <map>).
|
|
return -1;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(mount_peco)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (sd->disguise) {
|
|
clif_displaymessage(fd, msg_txt(sd,212)); // Cannot mount while in disguise.
|
|
return -1;
|
|
}
|
|
|
|
if( (sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT && pc_checkskill(sd,RK_DRAGONTRAINING) > 0 ) {
|
|
if( !(sd->sc.option&OPTION_DRAGON) ) {
|
|
unsigned int option = OPTION_DRAGON1;
|
|
if( message[0] ) {
|
|
int color = atoi(message);
|
|
option = ( color == 2 ? OPTION_DRAGON2 :
|
|
color == 3 ? OPTION_DRAGON3 :
|
|
color == 4 ? OPTION_DRAGON4 :
|
|
color == 5 ? OPTION_DRAGON5 :
|
|
OPTION_DRAGON1 );
|
|
}
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1119)); // You have mounted your Dragon.
|
|
pc_setoption(sd, sd->sc.option|option);
|
|
} else {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1120)); // You have released your Dragon.
|
|
pc_setoption(sd, sd->sc.option&~OPTION_DRAGON);
|
|
}
|
|
return 0;
|
|
}
|
|
if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER && pc_checkskill(sd,RA_WUGRIDER) > 0 && (!pc_isfalcon(sd) || battle_config.warg_can_falcon) ) {
|
|
if( !pc_isridingwug(sd) ) {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1121)); // You have mounted your Warg.
|
|
pc_setoption(sd, sd->sc.option|OPTION_WUGRIDER);
|
|
} else {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1122)); // You have released your Warg.
|
|
pc_setoption(sd, sd->sc.option&~OPTION_WUGRIDER);
|
|
}
|
|
return 0;
|
|
}
|
|
if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) {
|
|
if( !pc_ismadogear(sd) ) {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1123)); // You have mounted your Mado Gear.
|
|
pc_setoption(sd, sd->sc.option|OPTION_MADOGEAR);
|
|
} else {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1124)); // You have released your Mado Gear.
|
|
pc_setoption(sd, sd->sc.option&~OPTION_MADOGEAR);
|
|
}
|
|
return 0;
|
|
}
|
|
if (!pc_isriding(sd)) { // if actually no peco
|
|
|
|
if (!pc_checkskill(sd, KN_RIDING)) {
|
|
clif_displaymessage(fd, msg_txt(sd,213)); // You can not mount a Peco Peco with your current job.
|
|
return -1;
|
|
}
|
|
|
|
pc_setoption(sd, sd->sc.option | OPTION_RIDING);
|
|
clif_displaymessage(fd, msg_txt(sd,102)); // You have mounted a Peco Peco.
|
|
} else {//Dismount
|
|
pc_setoption(sd, sd->sc.option & ~OPTION_RIDING);
|
|
clif_displaymessage(fd, msg_txt(sd,214)); // You have released your Peco Peco.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*Spy Commands by Syrus22
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(guildspy)
|
|
{
|
|
char guild_name[NAME_LENGTH];
|
|
struct guild *g;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(guild_name, '\0', sizeof(guild_name));
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!enable_spy)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1125)); // The mapserver has spy command support disabled.
|
|
return -1;
|
|
}
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", guild_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1126)); // Please enter a guild name/ID (usage: @guildspy <guild_name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if ((g = guild_searchname(guild_name)) != NULL || // name first to avoid error when name begin with a number
|
|
(g = guild_search(atoi(message))) != NULL) {
|
|
if (sd->guildspy == g->guild_id) {
|
|
sd->guildspy = 0;
|
|
sprintf(atcmd_output, msg_txt(sd,103), g->name); // No longer spying on the %s guild.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
} else {
|
|
sd->guildspy = g->guild_id;
|
|
sprintf(atcmd_output, msg_txt(sd,104), g->name); // Spying on the %s guild.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,94)); // Incorrect name/ID, or no one from the specified guild is online.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(partyspy)
|
|
{
|
|
char party_name[NAME_LENGTH];
|
|
struct party_data *p;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(party_name, '\0', sizeof(party_name));
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!enable_spy)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1125)); // The mapserver has spy command support disabled.
|
|
return -1;
|
|
}
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", party_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1127)); // Please enter a party name/ID (usage: @partyspy <party_name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if ((p = party_searchname(party_name)) != NULL || // name first to avoid error when name begin with a number
|
|
(p = party_search(atoi(message))) != NULL) {
|
|
if (sd->partyspy == p->party.party_id) {
|
|
sd->partyspy = 0;
|
|
sprintf(atcmd_output, msg_txt(sd,105), p->party.name); // No longer spying on the %s party.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
} else {
|
|
sd->partyspy = p->party.party_id;
|
|
sprintf(atcmd_output, msg_txt(sd,106), p->party.name); // Spying on the %s party.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,96)); // Incorrect name/ID, or no one from the specified party is online.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @repairall [Valaris]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(repairall)
|
|
{
|
|
int count, i;
|
|
nullpo_retr(-1, sd);
|
|
|
|
count = 0;
|
|
for (i = 0; i < MAX_INVENTORY; i++) {
|
|
if (sd->status.inventory[i].nameid && sd->status.inventory[i].attribute == 1) {
|
|
sd->status.inventory[i].attribute = 0;
|
|
clif_produceeffect(sd, 0, sd->status.inventory[i].nameid);
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (count > 0) {
|
|
clif_misceffect(&sd->bl, 3);
|
|
clif_equiplist(sd);
|
|
clif_displaymessage(fd, msg_txt(sd,107)); // All items have been repaired.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,108)); // No item need to be repaired.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @nuke [Valaris]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(nuke)
|
|
{
|
|
struct map_session_data *pl_sd;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1128)); // Please enter a player name (usage: @nuke <char name>).
|
|
return -1;
|
|
}
|
|
|
|
if ((pl_sd = map_nick2sd(atcmd_player_name)) != NULL) {
|
|
if (pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { // you can kill only lower or same GM level
|
|
skill_castend_nodamage_id(&pl_sd->bl, &pl_sd->bl, NPC_SELFDESTRUCTION, 99, gettick(), 0);
|
|
clif_displaymessage(fd, msg_txt(sd,109)); // Player has been nuked!
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
|
|
return -1;
|
|
}
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @tonpc
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(tonpc)
|
|
{
|
|
char npcname[NAME_LENGTH+1];
|
|
struct npc_data *nd;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(npcname, 0, sizeof(npcname));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", npcname) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1129)); // Please enter a NPC name (usage: @tonpc <NPC_name>).
|
|
return -1;
|
|
}
|
|
|
|
if ((nd = npc_name2id(npcname)) != NULL) {
|
|
if (pc_setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, CLR_TELEPORT) == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,0)); // Warped.
|
|
else
|
|
return -1;
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,111)); // This NPC doesn't exist.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(shownpc)
|
|
{
|
|
char NPCname[NAME_LENGTH+1];
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(NPCname, '\0', sizeof(NPCname));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", NPCname) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1130)); // Please enter a NPC name (usage: @enablenpc <NPC_name>).
|
|
return -1;
|
|
}
|
|
|
|
if (npc_name2id(NPCname) != NULL) {
|
|
npc_enable(NPCname, 1);
|
|
clif_displaymessage(fd, msg_txt(sd,110)); // Npc Enabled.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,111)); // This NPC doesn't exist.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(hidenpc)
|
|
{
|
|
char NPCname[NAME_LENGTH+1];
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(NPCname, '\0', sizeof(NPCname));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", NPCname) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1131)); // Please enter a NPC name (usage: @hidenpc <NPC_name>).
|
|
return -1;
|
|
}
|
|
|
|
if (npc_name2id(NPCname) == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,111)); // This NPC doesn't exist.
|
|
return -1;
|
|
}
|
|
|
|
npc_enable(NPCname, 0);
|
|
clif_displaymessage(fd, msg_txt(sd,112)); // Npc Disabled.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(loadnpc)
|
|
{
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1132)); // Please enter a script file name (usage: @loadnpc <file name>).
|
|
return -1;
|
|
}
|
|
|
|
// add to list of script sources and run it
|
|
if( !npc_addsrcfile(message) //try to read file
|
|
|| !npc_parsesrcfile(message,true)
|
|
){
|
|
clif_displaymessage(fd, msg_txt(sd,261));
|
|
return -1;
|
|
}
|
|
|
|
npc_read_event_script();
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,262));
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(unloadnpc)
|
|
{
|
|
struct npc_data *nd;
|
|
char NPCname[NAME_LENGTH];
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(NPCname, '\0', sizeof(NPCname));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", NPCname) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1133)); // Please enter a NPC name (usage: @unloadnpc <NPC_name>).
|
|
return -1;
|
|
}
|
|
|
|
if ((nd = npc_name2id(NPCname)) == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,111)); // This NPC doesn't exist.
|
|
return -1;
|
|
}
|
|
|
|
npc_unload_duplicates(nd);
|
|
npc_unload(nd,true);
|
|
npc_read_event_script();
|
|
clif_displaymessage(fd, msg_txt(sd,112)); // Npc Disabled.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* time in txt for time command (by [Yor])
|
|
*------------------------------------------*/
|
|
char* txt_time(unsigned int duration)
|
|
{
|
|
int days, hours, minutes, seconds;
|
|
char temp[CHAT_SIZE_MAX];
|
|
static char temp1[CHAT_SIZE_MAX];
|
|
|
|
memset(temp, '\0', sizeof(temp));
|
|
memset(temp1, '\0', sizeof(temp1));
|
|
|
|
days = duration / (60 * 60 * 24);
|
|
duration = duration - (60 * 60 * 24 * days);
|
|
hours = duration / (60 * 60);
|
|
duration = duration - (60 * 60 * hours);
|
|
minutes = duration / 60;
|
|
seconds = duration - (60 * minutes);
|
|
|
|
if (days == 1)
|
|
sprintf(temp, msg_txt(NULL,219), days); // %d day
|
|
else if (days > 1)
|
|
sprintf(temp, msg_txt(NULL,220), days); // %d days
|
|
if (hours == 1)
|
|
sprintf(temp1, msg_txt(NULL,221), temp, hours); // %s %d hour
|
|
else if (hours > 1)
|
|
sprintf(temp1, msg_txt(NULL,222), temp, hours); // %s %d hours
|
|
if (minutes < 2)
|
|
sprintf(temp, msg_txt(NULL,223), temp1, minutes); // %s %d minute
|
|
else
|
|
sprintf(temp, msg_txt(NULL,224), temp1, minutes); // %s %d minutes
|
|
if (seconds == 1)
|
|
sprintf(temp1, msg_txt(NULL,225), temp, seconds); // %s and %d second
|
|
else if (seconds > 1)
|
|
sprintf(temp1, msg_txt(NULL,226), temp, seconds); // %s and %d seconds
|
|
|
|
return temp1;
|
|
}
|
|
|
|
/*==========================================
|
|
* @time/@date/@serverdate/@servertime: Display the date/time of the server (by [Yor]
|
|
* Calculation management of GM modification (@day/@night GM commands) is done
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(servertime)
|
|
{
|
|
const struct TimerData * timer_data;
|
|
time_t time_server; // variable for number of seconds (used with time() function)
|
|
struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ...
|
|
char temp[CHAT_SIZE_MAX];
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(temp, '\0', sizeof(temp));
|
|
|
|
time(&time_server); // get time in seconds since 1/1/1970
|
|
datetime = localtime(&time_server); // convert seconds in structure
|
|
// like sprintf, but only for date/time (Sunday, November 02 2003 15:12:52)
|
|
strftime(temp, sizeof(temp)-1, msg_txt(sd,230), datetime); // Server time (normal time): %A, %B %d %Y %X.
|
|
clif_displaymessage(fd, temp);
|
|
|
|
if (battle_config.night_duration == 0 && battle_config.day_duration == 0) {
|
|
if (night_flag == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,231)); // Game time: The game is in permanent daylight.
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,232)); // Game time: The game is in permanent night.
|
|
} else if (battle_config.night_duration == 0)
|
|
if (night_flag == 1) { // we start with night
|
|
timer_data = get_timer(day_timer_tid);
|
|
sprintf(temp, msg_txt(sd,233), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is in night for %s.
|
|
clif_displaymessage(fd, temp);
|
|
clif_displaymessage(fd, msg_txt(sd,234)); // Game time: After, the game will be in permanent daylight.
|
|
} else
|
|
clif_displaymessage(fd, msg_txt(sd,231)); // Game time: The game is in permanent daylight.
|
|
else if (battle_config.day_duration == 0)
|
|
if (night_flag == 0) { // we start with day
|
|
timer_data = get_timer(night_timer_tid);
|
|
sprintf(temp, msg_txt(sd,235), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is in daylight for %s.
|
|
clif_displaymessage(fd, temp);
|
|
clif_displaymessage(fd, msg_txt(sd,236)); // Game time: After, the game will be in permanent night.
|
|
} else
|
|
clif_displaymessage(fd, msg_txt(sd,232)); // Game time: The game is in permanent night.
|
|
else {
|
|
const struct TimerData * timer_data2;
|
|
if (night_flag == 0) {
|
|
timer_data = get_timer(night_timer_tid);
|
|
timer_data2 = get_timer(day_timer_tid);
|
|
sprintf(temp, msg_txt(sd,235), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is in daylight for %s.
|
|
clif_displaymessage(fd, temp);
|
|
if (DIFF_TICK(timer_data->tick, timer_data2->tick) > 0)
|
|
sprintf(temp, msg_txt(sd,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.
|
|
else
|
|
sprintf(temp, msg_txt(sd,237), txt_time(DIFF_TICK(timer_data2->tick,timer_data->tick)/1000)); // Game time: After, the game will be in night for %s.
|
|
clif_displaymessage(fd, temp);
|
|
sprintf(temp, msg_txt(sd,238), txt_time(timer_data->interval / 1000)); // Game time: A day cycle has a normal duration of %s.
|
|
clif_displaymessage(fd, temp);
|
|
} else {
|
|
timer_data = get_timer(day_timer_tid);
|
|
timer_data2 = get_timer(night_timer_tid);
|
|
sprintf(temp, msg_txt(sd,233), txt_time(DIFF_TICK(timer_data->tick,gettick()) / 1000)); // Game time: The game is in night for %s.
|
|
clif_displaymessage(fd, temp);
|
|
if (DIFF_TICK(timer_data->tick,timer_data2->tick) > 0)
|
|
sprintf(temp, msg_txt(sd,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.
|
|
else
|
|
sprintf(temp, msg_txt(sd,239), txt_time(DIFF_TICK(timer_data2->tick, timer_data->tick) / 1000)); // Game time: After, the game will be in daylight for %s.
|
|
clif_displaymessage(fd, temp);
|
|
sprintf(temp, msg_txt(sd,238), txt_time(timer_data->interval / 1000)); // Game time: A day cycle has a normal duration of %s.
|
|
clif_displaymessage(fd, temp);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @jail <char_name> by [Yor]
|
|
* Special warp! No check with nowarp and nowarpto flag
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(jail)
|
|
{
|
|
struct map_session_data *pl_sd;
|
|
int x, y;
|
|
unsigned short m_index;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1134)); // Please enter a player name (usage: @jail <char_name>).
|
|
return -1;
|
|
}
|
|
|
|
if ((pl_sd = map_nick2sd(atcmd_player_name)) == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) { // you can jail only lower or same GM
|
|
clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
|
|
return -1;
|
|
}
|
|
|
|
if (pl_sd->sc.data[SC_JAILED]) {
|
|
clif_displaymessage(fd, msg_txt(sd,118)); // Player warped in jails.
|
|
return -1;
|
|
}
|
|
|
|
switch(rnd() % 2) { //Jail Locations
|
|
case 0:
|
|
m_index = mapindex_name2id(MAP_JAIL);
|
|
x = 24;
|
|
y = 75;
|
|
break;
|
|
default:
|
|
m_index = mapindex_name2id(MAP_JAIL);
|
|
x = 49;
|
|
y = 75;
|
|
break;
|
|
}
|
|
|
|
//Duration of INT_MAX to specify infinity.
|
|
sc_start4(NULL,&pl_sd->bl,SC_JAILED,100,INT_MAX,m_index,x,y,1000);
|
|
clif_displaymessage(pl_sd->fd, msg_txt(sd,117)); // GM has send you in jails.
|
|
clif_displaymessage(fd, msg_txt(sd,118)); // Player warped in jails.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @unjail/@discharge <char_name> by [Yor]
|
|
* Special warp! No check with nowarp and nowarpto flag
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(unjail)
|
|
{
|
|
struct map_session_data *pl_sd;
|
|
|
|
memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
|
|
|
|
if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1135)); // Please enter a player name (usage: @unjail/@discharge <char_name>).
|
|
return -1;
|
|
}
|
|
|
|
if ((pl_sd = map_nick2sd(atcmd_player_name)) == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) { // you can jail only lower or same GM
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
|
|
return -1;
|
|
}
|
|
|
|
if (!pl_sd->sc.data[SC_JAILED]) {
|
|
clif_displaymessage(fd, msg_txt(sd,119)); // This player is not in jails.
|
|
return -1;
|
|
}
|
|
|
|
//Reset jail time to 1 sec.
|
|
sc_start(NULL,&pl_sd->bl,SC_JAILED,100,1,1000);
|
|
clif_displaymessage(pl_sd->fd, msg_txt(sd,120)); // A GM has discharged you from jail.
|
|
clif_displaymessage(fd, msg_txt(sd,121)); // Player unjailed.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(jailfor) {
|
|
struct map_session_data *pl_sd = NULL;
|
|
char * modif_p;
|
|
int jailtime = 0,x,y;
|
|
short m_index = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%255s %23[^\n]",atcmd_output,atcmd_player_name) < 2) {
|
|
clif_displaymessage(fd, msg_txt(sd,400)); //Usage: @jailfor <time> <character name>
|
|
return -1;
|
|
}
|
|
|
|
atcmd_output[sizeof(atcmd_output)-1] = '\0';
|
|
|
|
modif_p = atcmd_output;
|
|
jailtime = (int)solve_time(modif_p)/60; // Change to minutes
|
|
|
|
if (jailtime == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1136)); // Invalid time for jail command.
|
|
clif_displaymessage(fd, msg_txt(sd,702)); // Time parameter format is +/-<value> to alter. y/a = Year, m = Month, d/j = Day, h = Hour, n/mn = Minute, s = Second.
|
|
return -1;
|
|
}
|
|
|
|
if ((pl_sd = map_nick2sd(atcmd_player_name)) == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if (pc_get_group_level(pl_sd) > pc_get_group_level(sd)) {
|
|
clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
|
|
return -1;
|
|
}
|
|
|
|
// Added by Coltaro
|
|
if(pl_sd->sc.data[SC_JAILED] && pl_sd->sc.data[SC_JAILED]->val1 != INT_MAX) { // Update the player's jail time
|
|
jailtime += pl_sd->sc.data[SC_JAILED]->val1;
|
|
if (jailtime <= 0) {
|
|
jailtime = 0;
|
|
clif_displaymessage(pl_sd->fd, msg_txt(sd,120)); // GM has discharge you.
|
|
clif_displaymessage(fd, msg_txt(sd,121)); // Player unjailed
|
|
} else {
|
|
int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
|
|
char timestr[21];
|
|
time_t now=time(NULL);
|
|
split_time(jailtime*60,&year,&month,&day,&hour,&minute,&second);
|
|
sprintf(atcmd_output,msg_txt(sd,402),msg_txt(sd,1137),year,month,day,hour,minute); // %s in jail for %d years, %d months, %d days, %d hours and %d minutes
|
|
clif_displaymessage(pl_sd->fd, atcmd_output);
|
|
sprintf(atcmd_output,msg_txt(sd,402),msg_txt(sd,1138),year,month,day,hour,minute); // This player is now in jail for %d years, %d months, %d days, %d hours and %d minutes
|
|
clif_displaymessage(fd, atcmd_output);
|
|
timestamp2string(timestr,20,now+jailtime*60,"%Y-%m-%d %H:%M");
|
|
sprintf(atcmd_output,"Release date is: %s",timestr);
|
|
clif_displaymessage(pl_sd->fd, atcmd_output);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
} else if (jailtime < 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1136));
|
|
return -1;
|
|
}
|
|
|
|
// Jail locations, add more as you wish.
|
|
switch(rnd()%2) {
|
|
case 1: // Jail #1
|
|
m_index = mapindex_name2id(MAP_JAIL);
|
|
x = 49; y = 75;
|
|
break;
|
|
default: // Default Jail
|
|
m_index = mapindex_name2id(MAP_JAIL);
|
|
x = 24; y = 75;
|
|
break;
|
|
}
|
|
|
|
sc_start4(NULL,&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).
|
|
return 0;
|
|
}
|
|
|
|
//By Coltaro
|
|
ACMD_FUNC(jailtime){
|
|
int year, month, day, hour, minute, second;
|
|
char timestr[21];
|
|
time_t now = time(NULL);
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!sd->sc.data[SC_JAILED]) {
|
|
clif_displaymessage(fd, msg_txt(sd,1139)); // You are not in jail.
|
|
return -1;
|
|
}
|
|
|
|
if (sd->sc.data[SC_JAILED]->val1 == INT_MAX) {
|
|
clif_displaymessage(fd, msg_txt(sd,1140)); // You have been jailed indefinitely.
|
|
return 0;
|
|
}
|
|
|
|
if (sd->sc.data[SC_JAILED]->val1 <= 0) { // Was not jailed with @jailfor (maybe @jail? or warped there? or got recalled?)
|
|
clif_displaymessage(fd, msg_txt(sd,1141)); // You have been jailed for an unknown amount of time.
|
|
return -1;
|
|
}
|
|
|
|
// Get remaining jail time
|
|
split_time(sd->sc.data[SC_JAILED]->val1*60,&year,&month,&day,&hour,&minute,&second);
|
|
sprintf(atcmd_output,msg_txt(sd,402),msg_txt(sd,1142),year,month,day,hour,minute); // You will remain in jail for %d years, %d months, %d days, %d hours and %d minutes
|
|
clif_displaymessage(fd, atcmd_output);
|
|
timestamp2string(timestr,20,now+sd->sc.data[SC_JAILED]->val1*60,"%Y-%m-%d %H:%M");
|
|
sprintf(atcmd_output,"Release date is: %s",timestr);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @disguise <mob_id> by [Valaris] (simplified by [Yor])
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(disguise)
|
|
{
|
|
int id = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1143)); // Please enter a Monster/NPC name/ID (usage: @disguise <name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if ((id = atoi(message)) > 0)
|
|
{ //Acquired an ID
|
|
if (!mobdb_checkid(id) && !npcdb_checkid(id))
|
|
id = 0; //Invalid id for either mobs or npcs.
|
|
} else { //Acquired a Name
|
|
if ((id = mobdb_searchname(message)) == 0)
|
|
{
|
|
struct npc_data* nd = npc_name2id(message);
|
|
if (nd != NULL)
|
|
id = nd->class_;
|
|
}
|
|
}
|
|
|
|
if (id == 0)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,123)); // Invalid Monster/NPC name/ID specified.
|
|
return -1;
|
|
}
|
|
|
|
if(pc_isriding(sd))
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1144)); // Character cannot be disguised while mounted.
|
|
return -1;
|
|
}
|
|
|
|
if (sd->sc.data[SC_MONSTER_TRANSFORM]) {
|
|
clif_displaymessage(fd, msg_txt(sd,730)); // Character cannot be disguised while in monster transform.
|
|
return -1;
|
|
}
|
|
|
|
pc_disguise(sd, id);
|
|
clif_displaymessage(fd, msg_txt(sd,122)); // Disguise applied.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* DisguiseAll
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(disguiseall)
|
|
{
|
|
int mob_id=0;
|
|
struct map_session_data *pl_sd;
|
|
struct s_mapiterator* iter;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1145)); // Please enter a Monster/NPC name/ID (usage: @disguiseall <name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if ((mob_id = mobdb_searchname(message)) == 0) // check name first (to avoid possible name beginning by a number)
|
|
mob_id = atoi(message);
|
|
|
|
if (!mobdb_checkid(mob_id) && !npcdb_checkid(mob_id)) { //if mob or npc...
|
|
clif_displaymessage(fd, msg_txt(sd,123)); // Monster/NPC name/id not found.
|
|
return -1;
|
|
}
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
pc_disguise(pl_sd, mob_id);
|
|
mapit_free(iter);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,122)); // Disguise applied.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* DisguiseGuild
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(disguiseguild)
|
|
{
|
|
int id = 0, i;
|
|
char monster[NAME_LENGTH], guild[NAME_LENGTH];
|
|
|
|
struct guild *g;
|
|
|
|
memset(monster, '\0', sizeof(monster));
|
|
memset(guild, '\0', sizeof(guild));
|
|
|
|
if( !message || !*message || sscanf(message, "%23[^,], %23[^\r\n]", monster, guild) < 2 ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1146)); // Please enter a mob name/ID and guild name/ID (usage: @disguiseguild <mob name/ID>, <guild name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if( (id = atoi(monster)) > 0 ) {
|
|
if( !mobdb_checkid(id) && !npcdb_checkid(id) )
|
|
id = 0;
|
|
} else {
|
|
if( (id = mobdb_searchname(monster)) == 0 ) {
|
|
struct npc_data* nd = npc_name2id(monster);
|
|
if( nd != NULL )
|
|
id = nd->class_;
|
|
}
|
|
}
|
|
|
|
if( id == 0 ) {
|
|
clif_displaymessage(fd, msg_txt(sd,123)); // Monster/NPC name/id hasn't been found.
|
|
return -1;
|
|
}
|
|
|
|
if( (g = guild_searchname(guild)) == NULL && (g = guild_search(atoi(guild))) == NULL ) {
|
|
clif_displaymessage(fd, msg_txt(sd,94)); // Incorrect name/ID, or no one from the guild is online.
|
|
return -1;
|
|
}
|
|
|
|
for( i = 0; i < g->max_member; i++ ){
|
|
struct map_session_data *pl_sd;
|
|
if( (pl_sd = g->member[i].sd) && !pc_isriding(pl_sd) )
|
|
pc_disguise(pl_sd, id);
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,122)); // Disguise applied.
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*==========================================
|
|
* @undisguise by [Yor]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(undisguise)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (sd->disguise) {
|
|
pc_disguise(sd, 0);
|
|
clif_displaymessage(fd, msg_txt(sd,124)); // Undisguise applied.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,125)); // You're not disguised.
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* UndisguiseAll
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(undisguiseall)
|
|
{
|
|
struct map_session_data *pl_sd;
|
|
struct s_mapiterator* iter;
|
|
nullpo_retr(-1, sd);
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
|
|
if( pl_sd->disguise )
|
|
pc_disguise(pl_sd, 0);
|
|
mapit_free(iter);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,124)); // Undisguise applied.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* UndisguiseGuild
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(undisguiseguild)
|
|
{
|
|
char guild_name[NAME_LENGTH];
|
|
struct guild *g;
|
|
int i;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(guild_name, '\0', sizeof(guild_name));
|
|
|
|
if(!message || !*message || sscanf(message, "%23[^\n]", guild_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1147)); // Please enter guild name/ID (usage: @undisguiseguild <guild name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if( (g = guild_searchname(guild_name)) == NULL && (g = guild_search(atoi(message))) == NULL ) {
|
|
clif_displaymessage(fd, msg_txt(sd,94)); // Incorrect name/ID, or no one from the guild is online.
|
|
return -1;
|
|
}
|
|
|
|
for(i = 0; i < g->max_member; i++){
|
|
struct map_session_data *pl_sd;
|
|
if( (pl_sd = g->member[i].sd) && pl_sd->disguise )
|
|
pc_disguise(pl_sd, 0);
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,124)); // Undisguise applied.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @exp by [Skotlex]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(exp)
|
|
{
|
|
char output[CHAT_SIZE_MAX];
|
|
double nextb, nextj;
|
|
nullpo_retr(-1, sd);
|
|
memset(output, '\0', sizeof(output));
|
|
|
|
nextb = pc_nextbaseexp(sd);
|
|
if (nextb)
|
|
nextb = sd->status.base_exp*100.0/nextb;
|
|
|
|
nextj = pc_nextjobexp(sd);
|
|
if (nextj)
|
|
nextj = sd->status.job_exp*100.0/nextj;
|
|
|
|
sprintf(output, msg_txt(sd,1148), sd->status.base_level, nextb, sd->status.job_level, nextj); // Base Level: %d (%.3f%%) | Job Level: %d (%.3f%%)
|
|
clif_displaymessage(fd, output);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*==========================================
|
|
* @broadcast by [Valaris]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(broadcast)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1149)); // Please enter a message (usage: @broadcast <message>).
|
|
return -1;
|
|
}
|
|
|
|
sprintf(atcmd_output, "%s: %s", sd->status.name, message);
|
|
intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @localbroadcast by [Valaris]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(localbroadcast)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1150)); // Please enter a message (usage: @localbroadcast <message>).
|
|
return -1;
|
|
}
|
|
|
|
sprintf(atcmd_output, "%s: %s", sd->status.name, message);
|
|
|
|
clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @email <actual@email> <new@email> by [Yor]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(email)
|
|
{
|
|
char actual_email[100];
|
|
char new_email[100];
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(actual_email, '\0', sizeof(actual_email));
|
|
memset(new_email, '\0', sizeof(new_email));
|
|
|
|
if (!message || !*message || sscanf(message, "%99s %99s", actual_email, new_email) < 2) {
|
|
clif_displaymessage(fd, msg_txt(sd,1151)); // Please enter 2 emails (usage: @email <actual@email> <new@email>).
|
|
return -1;
|
|
}
|
|
|
|
if (e_mail_check(actual_email) == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,144)); // Invalid actual email. If you have default e-mail, give a@a.com.
|
|
return -1;
|
|
} else if (e_mail_check(new_email) == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,145)); // Invalid new email. Please enter a real e-mail.
|
|
return -1;
|
|
} else if (strcmpi(new_email, "a@a.com") == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,146)); // New email must be a real e-mail.
|
|
return -1;
|
|
} else if (strcmpi(actual_email, new_email) == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,147)); // New email must be different of the actual e-mail.
|
|
return -1;
|
|
}
|
|
|
|
chrif_changeemail(sd->status.account_id, actual_email, new_email);
|
|
clif_displaymessage(fd, msg_txt(sd,148)); // Information sent to login-server via char-server.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*@effect
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(effect)
|
|
{
|
|
int type = 0, flag = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%d", &type) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1152)); // Please enter an effect number (usage: @effect <effect number>).
|
|
return -1;
|
|
}
|
|
|
|
clif_specialeffect(&sd->bl, type, (send_target)flag);
|
|
clif_displaymessage(fd, msg_txt(sd,229)); // Your effect has changed.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @killer by MouseJstr
|
|
* enable killing players even when not in pvp
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(killer)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
sd->state.killer = !sd->state.killer;
|
|
|
|
if(sd->state.killer)
|
|
clif_displaymessage(fd, msg_txt(sd,241));
|
|
else {
|
|
clif_displaymessage(fd, msg_txt(sd,292));
|
|
pc_stop_attack(sd);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @killable by MouseJstr
|
|
* enable other people killing you
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(killable)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
sd->state.killable = !sd->state.killable;
|
|
|
|
if(sd->state.killable)
|
|
clif_displaymessage(fd, msg_txt(sd,242));
|
|
else {
|
|
clif_displaymessage(fd, msg_txt(sd,288));
|
|
map_foreachinrange(atcommand_stopattack,&sd->bl, AREA_SIZE, BL_CHAR, sd->bl.id);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @skillon by MouseJstr
|
|
* turn skills on for the map
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(skillon)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
map[sd->bl.m].flag.noskill = 0;
|
|
clif_displaymessage(fd, msg_txt(sd,244));
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @skilloff by MouseJstr
|
|
* Turn skills off on the map
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(skilloff)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
map[sd->bl.m].flag.noskill = 1;
|
|
clif_displaymessage(fd, msg_txt(sd,243));
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @npcmove by MouseJstr
|
|
* move a npc
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(npcmove)
|
|
{
|
|
int x = 0, y = 0, m;
|
|
struct npc_data *nd = 0;
|
|
nullpo_retr(-1, sd);
|
|
memset(atcmd_player_name, '\0', sizeof atcmd_player_name);
|
|
|
|
if (!message || !*message || sscanf(message, "%d %d %23[^\n]", &x, &y, atcmd_player_name) < 3) {
|
|
clif_displaymessage(fd, msg_txt(sd,1153)); // Usage: @npcmove <X> <Y> <npc_name>
|
|
return -1;
|
|
}
|
|
|
|
if ((nd = npc_name2id(atcmd_player_name)) == NULL)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,111)); // This NPC doesn't exist.
|
|
return -1;
|
|
}
|
|
|
|
if ((m=nd->bl.m) < 0 || nd->bl.prev == NULL)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1154)); // NPC is not on this map.
|
|
return -1; //Not on a map.
|
|
}
|
|
|
|
x = cap_value(x, 0, map[m].xs-1);
|
|
y = cap_value(y, 0, map[m].ys-1);
|
|
map_foreachinrange(clif_outsight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
|
|
map_moveblock(&nd->bl, x, y, gettick());
|
|
map_foreachinrange(clif_insight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
|
|
clif_displaymessage(fd, msg_txt(sd,1155)); // NPC moved.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @addwarp by MouseJstr
|
|
* Create a new static warp point.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(addwarp)
|
|
{
|
|
char mapname[32], warpname[NAME_LENGTH+1];
|
|
int x,y;
|
|
unsigned short m;
|
|
struct npc_data* nd;
|
|
|
|
nullpo_retr(-1, sd);
|
|
memset(warpname, '\0', sizeof(warpname));
|
|
|
|
if (!message || !*message || sscanf(message, "%31s %d %d %23[^\n]", mapname, &x, &y, warpname) < 4) {
|
|
clif_displaymessage(fd, msg_txt(sd,1156)); // Usage: @addwarp <mapname> <X> <Y> <npc name>
|
|
return -1;
|
|
}
|
|
|
|
m = mapindex_name2id(mapname);
|
|
if( m == 0 )
|
|
{
|
|
sprintf(atcmd_output, msg_txt(sd,1157), mapname); // Unknown map '%s'.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
nd = npc_add_warp(warpname, sd->bl.m, sd->bl.x, sd->bl.y, 2, 2, m, x, y);
|
|
if( nd == NULL )
|
|
return -1;
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,1158), nd->exname); // New warp NPC '%s' created.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @follow by [MouseJstr]
|
|
* Follow a player .. staying no more then 5 spaces away
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(follow)
|
|
{
|
|
struct map_session_data *pl_sd = NULL;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message) {
|
|
if (sd->followtarget == -1)
|
|
return -1;
|
|
|
|
pc_stop_following (sd);
|
|
clif_displaymessage(fd, msg_txt(sd,1159)); // Follow mode OFF.
|
|
return 0;
|
|
}
|
|
|
|
if ( (pl_sd = map_nick2sd((char *)message)) == NULL )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if (sd->followtarget == pl_sd->bl.id) {
|
|
pc_stop_following (sd);
|
|
clif_displaymessage(fd, msg_txt(sd,1159)); // Follow mode OFF.
|
|
} else {
|
|
pc_follow(sd, pl_sd->bl.id);
|
|
clif_displaymessage(fd, msg_txt(sd,1160)); // Follow mode ON.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*==========================================
|
|
* @dropall by [MouseJstr] and [Xantara]
|
|
* Drops all your possession on the ground based on item type
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(dropall)
|
|
{
|
|
int8 type = -1;
|
|
uint16 i, count = 0, count2 = 0;
|
|
struct item_data *item_data = NULL;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if( message[0] ) {
|
|
type = atoi(message);
|
|
if( type != -1 && type != IT_HEALING && type != IT_USABLE && type != IT_ETC && type != IT_WEAPON &&
|
|
type != IT_ARMOR && type != IT_CARD && type != IT_PETEGG && type != IT_PETARMOR && type != IT_AMMO )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1492));
|
|
clif_displaymessage(fd, msg_txt(sd,1493));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for( i = 0; i < MAX_INVENTORY; i++ ) {
|
|
if( sd->status.inventory[i].amount ) {
|
|
if( (item_data = itemdb_exists(sd->status.inventory[i].nameid)) == NULL ) {
|
|
ShowDebug("Non-existant item %d on dropall list (account_id: %d, char_id: %d)\n", sd->status.inventory[i].nameid, sd->status.account_id, sd->status.char_id);
|
|
continue;
|
|
}
|
|
if( !pc_candrop(sd,&sd->status.inventory[i]) )
|
|
continue;
|
|
|
|
if( type == -1 || type == (uint8)item_data->type ) {
|
|
if( sd->status.inventory[i].equip != 0 )
|
|
pc_unequipitem(sd, i, 3);
|
|
if(pc_dropitem(sd, i, sd->status.inventory[i].amount))
|
|
count += sd->status.inventory[i].amount;
|
|
else count2 += sd->status.inventory[i].amount;
|
|
}
|
|
}
|
|
}
|
|
sprintf(atcmd_output, msg_txt(sd,1494), count,count2); // %d items are dropped (%d skipped)!
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @storeall by [MouseJstr]
|
|
* Put everything into storage
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(storeall)
|
|
{
|
|
int i;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (sd->state.storage_flag != 1)
|
|
{ //Open storage.
|
|
if( storage_storageopen(sd) == 1 ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1161)); // You currently cannot open your storage.
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_INVENTORY; i++) {
|
|
if (sd->status.inventory[i].amount) {
|
|
if(sd->status.inventory[i].equip != 0)
|
|
pc_unequipitem(sd, i, 3);
|
|
storage_storageadd(sd, i, sd->status.inventory[i].amount);
|
|
}
|
|
}
|
|
storage_storageclose(sd);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1162)); // All items stored.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(clearstorage)
|
|
{
|
|
int i, j;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (sd->state.storage_flag == 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,250));
|
|
return -1;
|
|
}
|
|
|
|
j = sd->status.storage.storage_amount;
|
|
for (i = 0; i < j; ++i) {
|
|
storage_delitem(sd, i, sd->status.storage.items[i].amount);
|
|
}
|
|
storage_storageclose(sd);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1394)); // Your storage was cleaned.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(cleargstorage)
|
|
{
|
|
int i, j;
|
|
struct guild *g;
|
|
struct guild_storage *gstorage;
|
|
nullpo_retr(-1, sd);
|
|
|
|
g = sd->guild;
|
|
|
|
if (g == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,43));
|
|
return -1;
|
|
}
|
|
|
|
if (sd->state.storage_flag == 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,250));
|
|
return -1;
|
|
}
|
|
|
|
if (sd->state.storage_flag == 2) {
|
|
clif_displaymessage(fd, msg_txt(sd,251));
|
|
return -1;
|
|
}
|
|
|
|
gstorage = gstorage_get_storage(sd->status.guild_id);
|
|
if (gstorage == NULL) {// Doesn't have opened @gstorage yet, so we skip the deletion since *shouldn't* have any item there.
|
|
return -1;
|
|
}
|
|
|
|
if (gstorage->opened) {
|
|
struct map_session_data *tsd = map_charid2sd(gstorage->opened);
|
|
if (tsd)
|
|
gstorage_storageclose(tsd);
|
|
}
|
|
|
|
j = gstorage->storage_amount;
|
|
gstorage->locked = true; // Lock @gstorage: do not allow any item to be retrieved or stored from any guild member
|
|
for (i = 0; i < j; ++i) {
|
|
gstorage_delitem(sd, gstorage, i, gstorage->items[i].amount);
|
|
}
|
|
gstorage_storageclose(sd);
|
|
gstorage->locked = false; // Cleaning done, release lock
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1395)); // Your guild storage was cleaned.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(clearcart)
|
|
{
|
|
int i;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (pc_iscarton(sd) == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1396)); // You do not have a cart to be cleaned.
|
|
return -1;
|
|
}
|
|
|
|
if (sd->state.vending == 1) { //Somehow...
|
|
return -1;
|
|
}
|
|
|
|
for( i = 0; i < MAX_CART; i++ )
|
|
if(sd->status.cart[i].nameid > 0)
|
|
pc_cart_delitem(sd, i, sd->status.cart[i].amount, 1, LOG_TYPE_OTHER);
|
|
|
|
clif_clearcart(fd);
|
|
clif_updatestatus(sd,SP_CARTINFO);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1397)); // Your cart was cleaned.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @skillid by [MouseJstr]
|
|
* lookup a skill by name
|
|
*------------------------------------------*/
|
|
#define MAX_SKILLID_PARTIAL_RESULTS 5
|
|
#define MAX_SKILLID_PARTIAL_RESULTS_LEN 74 // "skill " (6) + "%d:" (up to 5) + "%s" (up to 30) + " (%s)" (up to 33)
|
|
ACMD_FUNC(skillid) {
|
|
int skillen, i, found = 0;
|
|
DBIterator* iter;
|
|
DBKey key;
|
|
DBData *data;
|
|
char partials[MAX_SKILLID_PARTIAL_RESULTS][MAX_SKILLID_PARTIAL_RESULTS_LEN];
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1163)); // Please enter a skill name to look up (usage: @skillid <skill name>).
|
|
return -1;
|
|
}
|
|
|
|
skillen = strlen(message);
|
|
|
|
iter = db_iterator(skilldb_name2id);
|
|
|
|
for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) {
|
|
int idx = skill_get_index(db_data2i(data));
|
|
if (strnicmp(key.str, message, skillen) == 0 || strnicmp(skill_db[idx].desc, message, skillen) == 0) {
|
|
sprintf(atcmd_output, msg_txt(sd,1164), db_data2i(data), skill_db[idx].desc, key.str); // skill %d: %s (%s)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
} else if ( found < MAX_SKILLID_PARTIAL_RESULTS && ( stristr(key.str,message) || stristr(skill_db[idx].desc,message) ) ) {
|
|
snprintf(partials[found++], MAX_SKILLID_PARTIAL_RESULTS_LEN, msg_txt(sd,1164), db_data2i(data), skill_db[idx].desc, key.str);
|
|
}
|
|
}
|
|
|
|
dbi_destroy(iter);
|
|
|
|
if( found ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1398), found); // -- Displaying first %d partial matches
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
for(i = 0; i < found; i++) { /* partials */
|
|
clif_displaymessage(fd, partials[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @useskill by [MouseJstr]
|
|
* A way of using skills without having to find them in the skills menu
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(useskill)
|
|
{
|
|
struct map_session_data *pl_sd = NULL;
|
|
struct block_list *bl;
|
|
uint16 skill_id;
|
|
uint16 skill_lv;
|
|
char target[100];
|
|
nullpo_retr(-1, sd);
|
|
|
|
if(!message || !*message || sscanf(message, "%hu %hu %23[^\n]", &skill_id, &skill_lv, target) != 3) {
|
|
clif_displaymessage(fd, msg_txt(sd,1165)); // Usage: @useskill <skill ID> <skill level> <target>
|
|
return -1;
|
|
}
|
|
|
|
if(!strcmp(target,"self")) pl_sd = sd; //quick keyword
|
|
else if ( (pl_sd = map_nick2sd(target)) == NULL ){
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
|
|
return -1;
|
|
}
|
|
|
|
if (skill_id >= HM_SKILLBASE && skill_id < HM_SKILLBASE+MAX_HOMUNSKILL
|
|
&& sd->hd && hom_is_active(sd->hd)) // (If used with @useskill, put the homunc as dest)
|
|
bl = &sd->hd->bl;
|
|
else
|
|
bl = &sd->bl;
|
|
|
|
if (skill_get_inf(skill_id)&INF_GROUND_SKILL)
|
|
unit_skilluse_pos(bl, pl_sd->bl.x, pl_sd->bl.y, skill_id, skill_lv);
|
|
else
|
|
unit_skilluse_id(bl, pl_sd->bl.id, skill_id, skill_lv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @displayskill by [Skotlex]
|
|
* Debug command to locate new skill IDs. It sends the
|
|
* three possible skill-effect packets to the area.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(displayskill)
|
|
{
|
|
struct status_data * status;
|
|
unsigned int tick;
|
|
uint16 skill_id;
|
|
uint16 skill_lv = 1;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%hu %hu", &skill_id, &skill_lv) < 1)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1166)); // Usage: @displayskill <skill ID> {<skill level>}
|
|
return -1;
|
|
}
|
|
status = status_get_status_data(&sd->bl);
|
|
tick = gettick();
|
|
clif_skill_damage(&sd->bl,&sd->bl, tick, status->amotion, status->dmotion, 1, 1, skill_id, skill_lv, 5);
|
|
clif_skill_nodamage(&sd->bl, &sd->bl, skill_id, skill_lv, 1);
|
|
clif_skill_poseffect(&sd->bl, skill_id, skill_lv, sd->bl.x, sd->bl.y, tick);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @skilltree by [MouseJstr]
|
|
* prints the skill tree for a player required to get to a skill
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(skilltree)
|
|
{
|
|
struct map_session_data *pl_sd = NULL;
|
|
uint16 skill_id;
|
|
int meets, j, c=0;
|
|
char target[NAME_LENGTH];
|
|
struct skill_tree_entry *ent;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if(!message || !*message || sscanf(message, "%hu %23[^\r\n]", &skill_id, target) != 2) {
|
|
clif_displaymessage(fd, msg_txt(sd,1167)); // Usage: @skilltree <skill ID> <target>
|
|
return -1;
|
|
}
|
|
|
|
if ( (pl_sd = map_nick2sd(target)) == NULL )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
c = pc_calc_skilltree_normalize_job(pl_sd);
|
|
c = pc_mapid2jobid(c, pl_sd->status.sex);
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,1168), job_name(c), pc_checkskill(pl_sd, NV_BASIC)); // Player is using %s skill tree (%d basic points).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
ARR_FIND( 0, MAX_SKILL_TREE, j, skill_tree[c][j].id == 0 || skill_tree[c][j].id == skill_id );
|
|
if( j == MAX_SKILL_TREE || skill_tree[c][j].id == 0 )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1169)); // The player cannot use that skill.
|
|
return 0;
|
|
}
|
|
|
|
ent = &skill_tree[c][j];
|
|
|
|
meets = 1;
|
|
for(j=0;j<MAX_PC_SKILL_REQUIRE;j++)
|
|
{
|
|
if( ent->need[j].id && pc_checkskill(sd,ent->need[j].id) < ent->need[j].lv)
|
|
{
|
|
sprintf(atcmd_output, msg_txt(sd,1170), ent->need[j].lv, skill_db[ent->need[j].id].desc); // Player requires level %d of skill %s.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
meets = 0;
|
|
}
|
|
}
|
|
if (meets == 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1171)); // The player meets all the requirements for that skill.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Hand a ring with partners name on it to this char
|
|
void getring (struct map_session_data* sd)
|
|
{
|
|
char flag = 0;
|
|
unsigned short item_id;
|
|
struct item item_tmp;
|
|
item_id = (sd->status.sex) ? WEDDING_RING_M : WEDDING_RING_F;
|
|
|
|
memset(&item_tmp, 0, sizeof(item_tmp));
|
|
item_tmp.nameid = item_id;
|
|
item_tmp.identify = 1;
|
|
item_tmp.card[0] = 255;
|
|
item_tmp.card[2] = sd->status.partner_id;
|
|
item_tmp.card[3] = sd->status.partner_id >> 16;
|
|
|
|
if((flag = pc_additem(sd,&item_tmp,1,LOG_TYPE_COMMAND))) {
|
|
clif_additem(sd,0,0,flag);
|
|
map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,4);
|
|
}
|
|
}
|
|
|
|
/*==========================================
|
|
* @marry by [MouseJstr], fixed by Lupus
|
|
* Marry two players
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(marry)
|
|
{
|
|
struct map_session_data *pl_sd = NULL;
|
|
char player_name[NAME_LENGTH] = "";
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%23s", player_name) != 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1172)); // Usage: @marry <char name>
|
|
return -1;
|
|
}
|
|
|
|
if ((pl_sd = map_nick2sd(player_name)) == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,3));
|
|
return -1;
|
|
}
|
|
|
|
if (pc_marriage(sd, pl_sd)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1173)); // They are married... wish them well.
|
|
clif_wedding_effect(&pl_sd->bl); //wedding effect and music [Lupus]
|
|
getring(sd); // Auto-give named rings (Aru)
|
|
getring(pl_sd);
|
|
return 0;
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1174)); // The two cannot wed because one is either a baby or already married.
|
|
return -1;
|
|
}
|
|
|
|
/*==========================================
|
|
* @divorce by [MouseJstr], fixed by [Lupus]
|
|
* divorce two players
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(divorce)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!pc_divorce(sd)) {
|
|
sprintf(atcmd_output, msg_txt(sd,1175), sd->status.name); // '%s' is not married.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,1176), sd->status.name); // '%s' and his/her partner are now divorced.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @changelook by [Celest]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(changelook)
|
|
{
|
|
int i, j = 0, k = 0;
|
|
int pos[7] = { LOOK_HEAD_TOP,LOOK_HEAD_MID,LOOK_HEAD_BOTTOM,LOOK_WEAPON,LOOK_SHIELD,LOOK_SHOES,LOOK_ROBE };
|
|
|
|
if((i = sscanf(message, "%d %d", &j, &k)) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1177)); // Usage: @changelook {<position>} <view id>
|
|
clif_displaymessage(fd, msg_txt(sd,1178)); // Position: 1-Top 2-Middle 3-Bottom 4-Weapon 5-Shield 6-Shoes 7-Robe
|
|
return -1;
|
|
} else if ( i == 2 ) {
|
|
if (j < 1 || j > 7)
|
|
j = 1;
|
|
j = pos[j - 1];
|
|
} else if( i == 1 ) { // position not defined, use HEAD_TOP as default
|
|
k = j; // swap
|
|
j = LOOK_HEAD_TOP;
|
|
}
|
|
|
|
clif_changelook(&sd->bl,j,k);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @autotrade by durf [Lupus] [Paradox924X]
|
|
* Turns on/off Autotrade for a specific player
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(autotrade) {
|
|
nullpo_retr(-1, sd);
|
|
|
|
if( map[sd->bl.m].flag.autotrade != battle_config.autotrade_mapflag ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1179)); // Autotrade is not allowed on this map.
|
|
return -1;
|
|
}
|
|
|
|
if( pc_isdead(sd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1180)); // You cannot autotrade when dead.
|
|
return -1;
|
|
}
|
|
|
|
if( !sd->state.vending && !sd->state.buyingstore ) { //check if player is vending or buying
|
|
clif_displaymessage(fd, msg_txt(sd,549)); // "You should have a shop open to use @autotrade."
|
|
return -1;
|
|
}
|
|
|
|
sd->state.autotrade = 1;
|
|
if (battle_config.autotrade_monsterignore)
|
|
sd->state.monster_ignore = 1;
|
|
|
|
if( sd->state.vending ){
|
|
if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", vendings_db, sd->vender_id ) != SQL_SUCCESS ){
|
|
Sql_ShowDebug( mmysql_handle );
|
|
}
|
|
}else if( sd->state.buyingstore ){
|
|
if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", buyingstores_db, sd->buyer_id ) != SQL_SUCCESS ){
|
|
Sql_ShowDebug( mmysql_handle );
|
|
}
|
|
}
|
|
|
|
if( battle_config.at_timeout ) {
|
|
int timeout = atoi(message);
|
|
status_change_start(NULL,&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, SCSTART_NONE);
|
|
}
|
|
|
|
channel_pcquit(sd,0xF); //leave all chan
|
|
clif_authfail_fd(sd->fd, 15);
|
|
|
|
chrif_save(sd,3);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @changegm by durf (changed by Lupus)
|
|
* Changes Master of your Guild to a specified guild member
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(changegm)
|
|
{
|
|
struct guild *g;
|
|
struct map_session_data *pl_sd;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (sd->status.guild_id == 0 || (g = sd->guild) == NULL || strcmp(g->master,sd->status.name)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1181)); // You need to be a Guild Master to use this command.
|
|
return -1;
|
|
}
|
|
|
|
if( map[sd->bl.m].flag.guildlock || map[sd->bl.m].flag.gvg_castle ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1182)); // You cannot change guild leaders on this map.
|
|
return -1;
|
|
}
|
|
|
|
if( !message[0] ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1183)); // Usage: @changegm <guild_member_name>
|
|
return -1;
|
|
}
|
|
|
|
if((pl_sd=map_nick2sd((char *) message)) == NULL || pl_sd->status.guild_id != sd->status.guild_id) {
|
|
clif_displaymessage(fd, msg_txt(sd,1184)); // Target character must be online and be a guild member.
|
|
return -1;
|
|
}
|
|
|
|
guild_gm_change(sd->status.guild_id, pl_sd);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @changeleader by Skotlex
|
|
* Changes the leader of a party.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(changeleader)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if( !message[0] )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1185)); // Usage: @changeleader <party_member_name>
|
|
return -1;
|
|
}
|
|
|
|
if (party_changeleader(sd, map_nick2sd((char *) message),NULL))
|
|
return 0;
|
|
return -1;
|
|
}
|
|
|
|
/*==========================================
|
|
* @partyoption by Skotlex
|
|
* Used to change the item share setting of a party.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(partyoption)
|
|
{
|
|
struct party_data *p;
|
|
int mi, option;
|
|
char w1[16], w2[16];
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (sd->status.party_id == 0 || (p = party_search(sd->status.party_id)) == NULL)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,282));
|
|
return -1;
|
|
}
|
|
|
|
ARR_FIND( 0, MAX_PARTY, mi, p->data[mi].sd == sd );
|
|
if (mi == MAX_PARTY)
|
|
return -1; //Shouldn't happen
|
|
|
|
if (!p->party.member[mi].leader)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,282));
|
|
return -1;
|
|
}
|
|
|
|
if(!message || !*message || sscanf(message, "%15s %15s", w1, w2) < 2)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1186)); // Usage: @partyoption <pickup share: yes/no> <item distribution: yes/no>
|
|
return -1;
|
|
}
|
|
|
|
option = (config_switch(w1)?1:0)|(config_switch(w2)?2:0);
|
|
|
|
//Change item share type.
|
|
if (option != p->party.item)
|
|
party_changeoption(sd, p->party.exp, option);
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,286));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @autoloot by Upa-Kun
|
|
* Turns on/off AutoLoot for a specific player
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(autoloot)
|
|
{
|
|
int rate;
|
|
nullpo_retr(-1, sd);
|
|
// autoloot command without value
|
|
if(!message || !*message)
|
|
{
|
|
if (sd->state.autoloot)
|
|
rate = 0;
|
|
else
|
|
rate = 10000;
|
|
} else {
|
|
double drate;
|
|
drate = atof(message);
|
|
rate = (int)(drate*100);
|
|
}
|
|
if (rate < 0) rate = 0;
|
|
if (rate > 10000) rate = 10000;
|
|
|
|
sd->state.autoloot = rate;
|
|
if (sd->state.autoloot) {
|
|
snprintf(atcmd_output, sizeof atcmd_output, msg_txt(sd,1187),((double)sd->state.autoloot)/100.); // Autolooting items with drop rates of %0.02f%% and below.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}else
|
|
clif_displaymessage(fd, msg_txt(sd,1188)); // Autoloot is now off.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @alootid
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(autolootitem)
|
|
{
|
|
struct item_data *item_data = NULL;
|
|
int i;
|
|
int action = 3; // 1=add, 2=remove, 3=help+list (default), 4=reset
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (message && *message) {
|
|
if (message[0] == '+') {
|
|
message++;
|
|
action = 1;
|
|
}
|
|
else if (message[0] == '-') {
|
|
message++;
|
|
action = 2;
|
|
}
|
|
else if (!strcmp(message,"reset"))
|
|
action = 4;
|
|
}
|
|
|
|
if (action < 3) // add or remove
|
|
{
|
|
if ((item_data = itemdb_exists(atoi(message))) == NULL)
|
|
item_data = itemdb_searchname(message);
|
|
if (!item_data) {
|
|
// No items founds in the DB with Id or Name
|
|
clif_displaymessage(fd, msg_txt(sd,1189)); // Item not found.
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
switch(action) {
|
|
case 1:
|
|
ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] == item_data->nameid);
|
|
if (i != AUTOLOOTITEM_SIZE) {
|
|
clif_displaymessage(fd, msg_txt(sd,1190)); // You're already autolooting this item.
|
|
return -1;
|
|
}
|
|
ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] == 0);
|
|
if (i == AUTOLOOTITEM_SIZE) {
|
|
clif_displaymessage(fd, msg_txt(sd,1191)); // Your autolootitem list is full. Remove some items first with @autolootid -<item name or ID>.
|
|
return -1;
|
|
}
|
|
sd->state.autolootid[i] = item_data->nameid; // Autoloot Activated
|
|
sprintf(atcmd_output, msg_txt(sd,1192), item_data->name, item_data->jname, item_data->nameid); // Autolooting item: '%s'/'%s' {%d}
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sd->state.autolooting = 1;
|
|
break;
|
|
case 2:
|
|
ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] == item_data->nameid);
|
|
if (i == AUTOLOOTITEM_SIZE) {
|
|
clif_displaymessage(fd, msg_txt(sd,1193)); // You're currently not autolooting this item.
|
|
return -1;
|
|
}
|
|
sd->state.autolootid[i] = 0;
|
|
sprintf(atcmd_output, msg_txt(sd,1194), item_data->name, item_data->jname, item_data->nameid); // Removed item: '%s'/'%s' {%d} from your autolootitem list.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] != 0);
|
|
if (i == AUTOLOOTITEM_SIZE) {
|
|
sd->state.autolooting = 0;
|
|
}
|
|
break;
|
|
case 3:
|
|
sprintf(atcmd_output, msg_txt(sd,1195), AUTOLOOTITEM_SIZE); // You can have %d items on your autolootitem list.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1196)); // To add an item to the list, use "@alootid +<item name or ID>". To remove an item, use "@alootid -<item name or ID>".
|
|
clif_displaymessage(fd, msg_txt(sd,1197)); // "@alootid reset" will clear your autolootitem list.
|
|
ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] != 0);
|
|
if (i == AUTOLOOTITEM_SIZE) {
|
|
clif_displaymessage(fd, msg_txt(sd,1198)); // Your autolootitem list is empty.
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,1199)); // Items on your autolootitem list:
|
|
for(i = 0; i < AUTOLOOTITEM_SIZE; i++)
|
|
{
|
|
if (sd->state.autolootid[i] == 0)
|
|
continue;
|
|
if (!(item_data = itemdb_exists(sd->state.autolootid[i]))) {
|
|
ShowDebug("Non-existant item %d on autolootitem list (account_id: %d, char_id: %d)", sd->state.autolootid[i], sd->status.account_id, sd->status.char_id);
|
|
continue;
|
|
}
|
|
sprintf(atcmd_output, "'%s'/'%s' {%hu}", item_data->name, item_data->jname, item_data->nameid);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
}
|
|
break;
|
|
case 4:
|
|
memset(sd->state.autolootid, 0, sizeof(sd->state.autolootid));
|
|
clif_displaymessage(fd, msg_txt(sd,1200)); // Your autolootitem list has been reset.
|
|
sd->state.autolooting = 0;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @autoloottype
|
|
* Flags:
|
|
* 1: IT_HEALING, 2: IT_UNKNOWN, 4: IT_USABLE, 8: IT_ETC,
|
|
* 16: IT_ARMOR, 32: IT_WEAPON, 64: IT_CARD, 128: IT_PETEGG,
|
|
* 256: IT_PETARMOR, 512: IT_UNKNOWN2, 1024: IT_AMMO, 2048: IT_DELAYCONSUME
|
|
* 262144: IT_CASH
|
|
*------------------------------------------
|
|
* Credits:
|
|
* chriser
|
|
* Aleos
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(autoloottype)
|
|
{
|
|
uint8 i = 0, action = 3; // 1=add, 2=remove, 3=help+list (default), 4=reset
|
|
enum item_types type = -1;
|
|
int ITEM_MAX = 1533;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (message && *message) {
|
|
if (message[0] == '+') {
|
|
message++;
|
|
action = 1;
|
|
}
|
|
else if (message[0] == '-') {
|
|
message++;
|
|
action = 2;
|
|
}
|
|
else if (!strcmp(message,"reset"))
|
|
action = 4;
|
|
}
|
|
|
|
if (action < 3) { // add or remove
|
|
if ((strncmp(message, "healing", 3) == 0) || (atoi(message) == 0))
|
|
type = IT_HEALING;
|
|
else if ((strncmp(message, "usable", 3) == 0) || (atoi(message) == 2))
|
|
type = IT_USABLE;
|
|
else if ((strncmp(message, "etc", 3) == 0) || (atoi(message) == 3))
|
|
type = IT_ETC;
|
|
else if ((strncmp(message, "armor", 3) == 0) || (atoi(message) == 4))
|
|
type = IT_ARMOR;
|
|
else if ((strncmp(message, "weapon", 3) == 0) || (atoi(message) == 5))
|
|
type = IT_WEAPON;
|
|
else if ((strncmp(message, "card", 3) == 0) || (atoi(message) == 6))
|
|
type = IT_CARD;
|
|
else if ((strncmp(message, "petegg", 4) == 0) || (atoi(message) == 7))
|
|
type = IT_PETEGG;
|
|
else if ((strncmp(message, "petarmor", 4) == 0) || (atoi(message) == 8))
|
|
type = IT_PETARMOR;
|
|
else if ((strncmp(message, "ammo", 3) == 0) || (atoi(message) == 10))
|
|
type = IT_AMMO;
|
|
else {
|
|
clif_displaymessage(fd, msg_txt(sd,1480)); // Item type not found.
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
switch (action) {
|
|
case 1:
|
|
if (sd->state.autoloottype&(1<<type)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1481)); // You're already autolooting this item type.
|
|
return -1;
|
|
}
|
|
if (sd->state.autoloottype == ITEM_MAX) {
|
|
clif_displaymessage(fd, msg_txt(sd,1482)); // Your autoloottype list has all item types. You can remove some items with @autoloottype -<type name or ID>.
|
|
return -1;
|
|
}
|
|
sd->state.autoloottype |= (1<<type); // Stores the type
|
|
sprintf(atcmd_output, msg_txt(sd,1483), itemdb_typename(type), type); // Autolooting item type: '%s' {%d}
|
|
clif_displaymessage(fd, atcmd_output);
|
|
break;
|
|
case 2:
|
|
if (!(sd->state.autoloottype&(1<<type))) {
|
|
clif_displaymessage(fd, msg_txt(sd,1484)); // You're currently not autolooting this item type.
|
|
return -1;
|
|
}
|
|
sd->state.autoloottype &= ~(1<<type);
|
|
sprintf(atcmd_output, msg_txt(sd,1485), itemdb_typename(type), type); // Removed item type: '%s' {%d} from your autoloottype list.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
break;
|
|
case 3:
|
|
clif_displaymessage(fd, msg_txt(sd,1486)); // To add an item type to the list, use "@aloottype +<type name or ID>". To remove an item type, use "@aloottype -<type name or ID>".
|
|
clif_displaymessage(fd, msg_txt(sd,1487)); // Type List: healing = 0, usable = 2, etc = 3, armor = 4, weapon = 5, card = 6, petegg = 7, petarmor = 8, ammo = 10
|
|
clif_displaymessage(fd, msg_txt(sd,1488)); // "@aloottype reset" will clear your autoloottype list.
|
|
if (sd->state.autoloottype == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,1489)); // Your autoloottype list is empty.
|
|
else {
|
|
clif_displaymessage(fd, msg_txt(sd,1490)); // Item types on your autoloottype list:
|
|
while (i < IT_MAX) {
|
|
if (sd->state.autoloottype&(1<<i)) {
|
|
sprintf(atcmd_output, " '%s' {%d}", itemdb_typename(i), i);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
break;
|
|
case 4:
|
|
sd->state.autoloottype = 0;
|
|
clif_displaymessage(fd, msg_txt(sd,1491)); // Your autoloottype list has been reset.
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* No longer available, keeping here just in case it's back someday. [Ind]
|
|
**/
|
|
/*==========================================
|
|
* It is made to rain.
|
|
*------------------------------------------*/
|
|
//ACMD_FUNC(rain)
|
|
//{
|
|
// nullpo_retr(-1, sd);
|
|
// if (map[sd->bl.m].flag.rain) {
|
|
// map[sd->bl.m].flag.rain=0;
|
|
// clif_weather(sd->bl.m);
|
|
// clif_displaymessage(fd, msg_txt(sd,1201)); // The rain has stopped.
|
|
// } else {
|
|
// map[sd->bl.m].flag.rain=1;
|
|
// clif_weather(sd->bl.m);
|
|
// clif_displaymessage(fd, msg_txt(sd,1202)); // It has started to rain.
|
|
// }
|
|
// return 0;
|
|
//}
|
|
|
|
/*==========================================
|
|
* It is made to snow.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(snow)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (map[sd->bl.m].flag.snow) {
|
|
map[sd->bl.m].flag.snow=0;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1203)); // Snow has stopped falling.
|
|
} else {
|
|
map[sd->bl.m].flag.snow=1;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1204)); // It has started to snow.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Cherry tree snowstorm is made to fall. (Sakura)
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(sakura)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (map[sd->bl.m].flag.sakura) {
|
|
map[sd->bl.m].flag.sakura=0;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1205)); // Cherry tree leaves no longer fall.
|
|
} else {
|
|
map[sd->bl.m].flag.sakura=1;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1206)); // Cherry tree leaves have begun to fall.
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Clouds appear.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(clouds)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (map[sd->bl.m].flag.clouds) {
|
|
map[sd->bl.m].flag.clouds=0;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1207)); // The clouds has disappear.
|
|
} else {
|
|
map[sd->bl.m].flag.clouds=1;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1208)); // Clouds appear.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Different type of clouds using effect 516
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(clouds2)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (map[sd->bl.m].flag.clouds2) {
|
|
map[sd->bl.m].flag.clouds2=0;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1209)); // The alternative clouds disappear.
|
|
} else {
|
|
map[sd->bl.m].flag.clouds2=1;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1210)); // Alternative clouds appear.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Fog hangs over.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(fog)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (map[sd->bl.m].flag.fog) {
|
|
map[sd->bl.m].flag.fog=0;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1211)); // The fog has gone.
|
|
} else {
|
|
map[sd->bl.m].flag.fog=1;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1212)); // Fog hangs over.
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Fallen leaves fall.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(leaves)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (map[sd->bl.m].flag.leaves) {
|
|
map[sd->bl.m].flag.leaves=0;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1213)); // Leaves no longer fall.
|
|
} else {
|
|
map[sd->bl.m].flag.leaves=1;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1214)); // Fallen leaves fall.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Fireworks appear.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(fireworks)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
if (map[sd->bl.m].flag.fireworks) {
|
|
map[sd->bl.m].flag.fireworks=0;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1215)); // Fireworks have ended.
|
|
} else {
|
|
map[sd->bl.m].flag.fireworks=1;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,1216)); // Fireworks have launched.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Clearing Weather Effects by Dexity
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(clearweather)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
/**
|
|
* No longer available, keeping here just in case it's back someday. [Ind]
|
|
**/
|
|
//map[sd->bl.m].flag.rain=0;
|
|
map[sd->bl.m].flag.snow=0;
|
|
map[sd->bl.m].flag.sakura=0;
|
|
map[sd->bl.m].flag.clouds=0;
|
|
map[sd->bl.m].flag.clouds2=0;
|
|
map[sd->bl.m].flag.fog=0;
|
|
map[sd->bl.m].flag.fireworks=0;
|
|
map[sd->bl.m].flag.leaves=0;
|
|
clif_weather(sd->bl.m);
|
|
clif_displaymessage(fd, msg_txt(sd,291));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*===============================================================
|
|
* Sound Command - plays a sound for everyone around! [Codemaster]
|
|
*---------------------------------------------------------------*/
|
|
ACMD_FUNC(sound)
|
|
{
|
|
char sound_file[100];
|
|
|
|
memset(sound_file, '\0', sizeof(sound_file));
|
|
|
|
if(!message || !*message || sscanf(message, "%99[^\n]", sound_file) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1217)); // Please enter a sound filename (usage: @sound <filename>).
|
|
return -1;
|
|
}
|
|
|
|
if(strstr(sound_file, ".wav") == NULL)
|
|
strcat(sound_file, ".wav");
|
|
|
|
clif_soundeffectall(&sd->bl, sound_file, 0, AREA);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* MOB Search
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(mobsearch)
|
|
{
|
|
char mob_name[100];
|
|
int mob_id;
|
|
int number = 0;
|
|
struct s_mapiterator* it;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%99[^\n]", mob_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1218)); // Please enter a monster name (usage: @mobsearch <monster name>).
|
|
return -1;
|
|
}
|
|
|
|
if ((mob_id = atoi(mob_name)) == 0)
|
|
mob_id = mobdb_searchname(mob_name);
|
|
if(mob_id > 0 && mobdb_checkid(mob_id) == 0){
|
|
snprintf(atcmd_output, sizeof atcmd_output, msg_txt(sd,1219),mob_name); // Invalid mob ID %s!
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
if(mob_id == atoi(mob_name) && mob_db(mob_id)->jname)
|
|
strcpy(mob_name,mob_db(mob_id)->jname); // --ja--
|
|
// strcpy(mob_name,mob_db(mob_id)->name); // --en--
|
|
|
|
snprintf(atcmd_output, sizeof atcmd_output, msg_txt(sd,1220), mob_name, mapindex_id2name(sd->mapindex)); // Mob Search... %s %s
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
it = mapit_geteachmob();
|
|
for(;;)
|
|
{
|
|
TBL_MOB* md = (TBL_MOB*)mapit_next(it);
|
|
if( md == NULL )
|
|
break;// no more mobs
|
|
|
|
if( md->bl.m != sd->bl.m )
|
|
continue;
|
|
if( mob_id != -1 && md->mob_id != mob_id )
|
|
continue;
|
|
|
|
++number;
|
|
if( md->spawn_timer == INVALID_TIMER )
|
|
snprintf(atcmd_output, sizeof(atcmd_output), "%2d[%3d:%3d] %s", number, md->bl.x, md->bl.y, md->name);
|
|
else
|
|
snprintf(atcmd_output, sizeof(atcmd_output), "%2d[%s] %s", number, "dead", md->name);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
mapit_free(it);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @cleanmap - cleans items on the ground
|
|
* @cleanarea - cleans items on the ground within an specified area
|
|
*------------------------------------------*/
|
|
static int atcommand_cleanfloor_sub(struct block_list *bl, va_list ap)
|
|
{
|
|
nullpo_ret(bl);
|
|
map_clearflooritem(bl);
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(cleanmap)
|
|
{
|
|
map_foreachinmap(atcommand_cleanfloor_sub, sd->bl.m, BL_ITEM);
|
|
clif_displaymessage(fd, msg_txt(sd,1221)); // All dropped items have been cleaned up.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(cleanarea)
|
|
{
|
|
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
|
|
|
|
if (!message || !*message || sscanf(message, "%d %d %d %d", &x0, &y0, &x1, &y1) < 1) {
|
|
map_foreachinarea(atcommand_cleanfloor_sub, sd->bl.m, sd->bl.x - (AREA_SIZE * 2), sd->bl.y - (AREA_SIZE * 2), sd->bl.x + (AREA_SIZE * 2), sd->bl.y + (AREA_SIZE * 2), BL_ITEM);
|
|
}
|
|
else if (sscanf(message, "%d %d %d %d", &x0, &y0, &x1, &y1) == 1) {
|
|
map_foreachinarea(atcommand_cleanfloor_sub, sd->bl.m, sd->bl.x - x0, sd->bl.y - x0, sd->bl.x + x0, sd->bl.y + x0, BL_ITEM);
|
|
}
|
|
else if (sscanf(message, "%d %d %d %d", &x0, &y0, &x1, &y1) == 4) {
|
|
map_foreachinarea(atcommand_cleanfloor_sub, sd->bl.m, x0, y0, x1, y1, BL_ITEM);
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1221)); // All dropped items have been cleaned up.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* make a NPC/PET talk
|
|
* @npctalkc [SnakeDrak]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(npctalk)
|
|
{
|
|
char name[NAME_LENGTH],mes[100],temp[100];
|
|
struct npc_data *nd;
|
|
bool ifcolor=(*(command + 8) != 'c' && *(command + 8) != 'C')?0:1;
|
|
unsigned long color=0;
|
|
|
|
if (sd->sc.cant.chat)
|
|
return -1; //no "chatting" while muted.
|
|
|
|
if(!ifcolor) {
|
|
if (!message || !*message || sscanf(message, "%23[^,], %99[^\n]", name, mes) < 2) {
|
|
clif_displaymessage(fd, msg_txt(sd,1222)); // Please enter the correct parameters (usage: @npctalk <npc name>, <message>).
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
if (!message || !*message || sscanf(message, "%lx %23[^,], %99[^\n]", &color, name, mes) < 3) {
|
|
clif_displaymessage(fd, msg_txt(sd,1223)); // Please enter the correct parameters (usage: @npctalkc <color> <npc name>, <message>).
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (!(nd = npc_name2id(name))) {
|
|
clif_displaymessage(fd, msg_txt(sd,111)); // This NPC doesn't exist
|
|
return -1;
|
|
}
|
|
|
|
strtok(name, "#"); // discard extra name identifier if present
|
|
snprintf(temp, sizeof(temp), "%s : %s", name, mes);
|
|
|
|
if(ifcolor) clif_messagecolor(&nd->bl,color,temp);
|
|
else clif_disp_overhead(&nd->bl, temp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(pettalk)
|
|
{
|
|
char mes[100],temp[100];
|
|
struct pet_data *pd;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ( battle_config.min_chat_delay ) {
|
|
if( DIFF_TICK(sd->cantalk_tick, gettick()) > 0 )
|
|
return 0;
|
|
sd->cantalk_tick = gettick() + battle_config.min_chat_delay;
|
|
}
|
|
|
|
if(!sd->status.pet_id || !(pd=sd->pd))
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,184));
|
|
return -1;
|
|
}
|
|
|
|
if (sd->sc.cant.chat)
|
|
return -1; //no "chatting" while muted.
|
|
|
|
if (!message || !*message || sscanf(message, "%99[^\n]", mes) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1224)); // Please enter a message (usage: @pettalk <message>).
|
|
return -1;
|
|
}
|
|
|
|
if (message[0] == '/')
|
|
{// pet emotion processing
|
|
const char* emo[] = {
|
|
"/!", "/?", "/ho", "/lv", "/swt", "/ic", "/an", "/ag", "/$", "/...",
|
|
"/scissors", "/rock", "/paper", "/korea", "/lv2", "/thx", "/wah", "/sry", "/heh", "/swt2",
|
|
"/hmm", "/no1", "/??", "/omg", "/O", "/X", "/hlp", "/go", "/sob", "/gg",
|
|
"/kis", "/kis2", "/pif", "/ok", "-?-", "/indonesia", "/bzz", "/rice", "/awsm", "/meh",
|
|
"/shy", "/pat", "/mp", "/slur", "/com", "/yawn", "/grat", "/hp", "/philippines", "/malaysia",
|
|
"/singapore", "/brazil", "/fsh", "/spin", "/sigh", "/dum", "/crwd", "/desp", "/dice", "-dice2",
|
|
"-dice3", "-dice4", "-dice5", "-dice6", "/india", "/love", "/russia", "-?-", "/mobile", "/mail",
|
|
"/chinese", "/antenna1", "/antenna2", "/antenna3", "/hum", "/abs", "/oops", "/spit", "/ene", "/panic",
|
|
"/whisp"
|
|
};
|
|
int i;
|
|
ARR_FIND( 0, ARRAYLENGTH(emo), i, stricmp(message, emo[i]) == 0 );
|
|
if( i == E_DICE1 ) i = rnd()%6 + E_DICE1; // randomize /dice
|
|
if( i < ARRAYLENGTH(emo) )
|
|
{
|
|
if (sd->emotionlasttime + 1 >= time(NULL)) { // not more than 1 per second
|
|
sd->emotionlasttime = time(NULL);
|
|
return 0;
|
|
}
|
|
sd->emotionlasttime = time(NULL);
|
|
|
|
clif_emotion(&pd->bl, i);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
snprintf(temp, sizeof temp ,"%s : %s", pd->pet.name, mes);
|
|
clif_disp_overhead(&pd->bl, temp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// @users - displays the number of players present on each map (and percentage)
|
|
/// #users displays on the target user instead of self
|
|
ACMD_FUNC(users)
|
|
{
|
|
char buf[CHAT_SIZE_MAX];
|
|
int i;
|
|
int users[MAX_MAPINDEX];
|
|
int users_all;
|
|
struct s_mapiterator* iter;
|
|
|
|
memset(users, 0, sizeof(users));
|
|
users_all = 0;
|
|
|
|
// count users on each map
|
|
iter = mapit_getallusers();
|
|
for(;;)
|
|
{
|
|
struct map_session_data* sd2 = (struct map_session_data*)mapit_next(iter);
|
|
if( sd2 == NULL )
|
|
break;// no more users
|
|
|
|
if( sd2->mapindex >= MAX_MAPINDEX )
|
|
continue;// invalid mapindex
|
|
|
|
if( users[sd2->mapindex] < INT_MAX ) ++users[sd2->mapindex];
|
|
if( users_all < INT_MAX ) ++users_all;
|
|
}
|
|
mapit_free(iter);
|
|
|
|
// display results for each map
|
|
for( i = 0; i < MAX_MAPINDEX; ++i )
|
|
{
|
|
if( users[i] == 0 )
|
|
continue;// empty
|
|
|
|
safesnprintf(buf, sizeof(buf), "%s: %d (%.2f%%)", mapindex_id2name(i), users[i], (float)(100.0f*users[i]/users_all));
|
|
clif_displaymessage(sd->fd, buf);
|
|
}
|
|
|
|
// display overall count
|
|
safesnprintf(buf, sizeof(buf), "all: %d", users_all);
|
|
clif_displaymessage(sd->fd, buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(reset)
|
|
{
|
|
pc_resetstate(sd);
|
|
pc_resetskill(sd,1);
|
|
sprintf(atcmd_output, msg_txt(sd,208), sd->status.name); // '%s' skill and stats points reseted!
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(summon)
|
|
{
|
|
char name[NAME_LENGTH];
|
|
int mob_id = 0;
|
|
int duration = 0;
|
|
struct mob_data *md;
|
|
unsigned int tick=gettick();
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%23s %d", name, &duration) < 1)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1225)); // Please enter a monster name (usage: @summon <monster name> {duration}).
|
|
return -1;
|
|
}
|
|
|
|
if (duration < 1)
|
|
duration =1;
|
|
else if (duration > 60)
|
|
duration =60;
|
|
|
|
if ((mob_id = atoi(name)) == 0)
|
|
mob_id = mobdb_searchname(name);
|
|
if(mob_id == 0 || mobdb_checkid(mob_id) == 0)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,40)); // Invalid monster ID or name.
|
|
return -1;
|
|
}
|
|
|
|
md = mob_once_spawn_sub(&sd->bl, sd->bl.m, -1, -1, "--ja--", mob_id, "", SZ_SMALL, AI_NONE);
|
|
|
|
if(!md)
|
|
return -1;
|
|
|
|
md->master_id=sd->bl.id;
|
|
md->special_state.ai=AI_ATTACK;
|
|
md->deletetimer=add_timer(tick+(duration*60000),mob_timer_delete,md->bl.id,0);
|
|
clif_specialeffect(&md->bl,344,AREA);
|
|
mob_spawn(md);
|
|
sc_start4(NULL,&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
|
|
clif_skill_poseffect(&sd->bl,AM_CALLHOMUN,1,md->bl.x,md->bl.y,tick);
|
|
clif_displaymessage(fd, msg_txt(sd,39)); // All monster summoned!
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @adjgroup
|
|
* Temporarily move player to another group
|
|
* Useful during beta testing to allow players to use GM commands for short periods of time
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(adjgroup)
|
|
{
|
|
int new_group = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%d", &new_group) != 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1226)); // Usage: @adjgroup <group_id>
|
|
return -1;
|
|
}
|
|
|
|
if (!pc_group_exists(new_group)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1227)); // Specified group does not exist.
|
|
return -1;
|
|
}
|
|
|
|
sd->group_id = new_group;
|
|
pc_group_pc_load(sd);/* update cache */
|
|
clif_displaymessage(fd, msg_txt(sd,1228)); // Group changed successfully.
|
|
clif_displaymessage(sd->fd, msg_txt(sd,1229)); // Your group has changed.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @trade by [MouseJstr]
|
|
* Open a trade window with a remote player
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(trade)
|
|
{
|
|
struct map_session_data *pl_sd = NULL;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1230)); // Please enter a player name (usage: @trade <char name>).
|
|
return -1;
|
|
}
|
|
|
|
if ( (pl_sd = map_nick2sd((char *)message)) == NULL )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
trade_traderequest(sd, pl_sd);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @setbattleflag by [MouseJstr]
|
|
* set a battle_config flag without having to reboot
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(setbattleflag)
|
|
{
|
|
char flag[128], value[128];
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%127s %127s", flag, value) != 2) {
|
|
clif_displaymessage(fd, msg_txt(sd,1231)); // Usage: @setbattleflag <flag> <value>
|
|
return -1;
|
|
}
|
|
|
|
if (battle_set_value(flag, value) == 0)
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1232)); // Unknown battle_config flag.
|
|
return -1;
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1233)); // Set battle_config as requested.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @unmute [Valaris]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(unmute)
|
|
{
|
|
struct map_session_data *pl_sd = NULL;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1234)); // Please enter a player name (usage: @unmute <char name>).
|
|
return -1;
|
|
}
|
|
|
|
if ( (pl_sd = map_nick2sd((char *)message)) == NULL )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if(!pl_sd->sc.data[SC_NOCHAT]) {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1235)); // Player is not muted.
|
|
return -1;
|
|
}
|
|
|
|
pl_sd->status.manner = 0;
|
|
status_change_end(&pl_sd->bl, SC_NOCHAT, INVALID_TIMER);
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1236)); // Player unmuted.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @uptime by MC Cameri
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(uptime)
|
|
{
|
|
unsigned long seconds = 0, day = 24*60*60, hour = 60*60,
|
|
minute = 60, days = 0, hours = 0, minutes = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
seconds = get_uptime();
|
|
days = seconds/day;
|
|
seconds -= (seconds/day>0)?(seconds/day)*day:0;
|
|
hours = seconds/hour;
|
|
seconds -= (seconds/hour>0)?(seconds/hour)*hour:0;
|
|
minutes = seconds/minute;
|
|
seconds -= (seconds/minute>0)?(seconds/minute)*minute:0;
|
|
|
|
snprintf(atcmd_output, sizeof(atcmd_output), msg_txt(sd,245), days, hours, minutes, seconds);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @changesex <sex>
|
|
* => Changes one's sex. Argument sex can be 0 or 1, m or f, male or female.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(changesex)
|
|
{
|
|
int i;
|
|
nullpo_retr(-1, sd);
|
|
pc_resetskill(sd,4);
|
|
// to avoid any problem with equipment and invalid sex, equipment is unequiped.
|
|
for( i=0; i<EQI_MAX; i++ )
|
|
if( sd->equip_index[i] >= 0 ) pc_unequipitem(sd, sd->equip_index[i], 3);
|
|
chrif_changesex(sd);
|
|
return 0;
|
|
}
|
|
|
|
/*================================================
|
|
* @mute - Mutes a player for a set amount of time
|
|
*------------------------------------------------*/
|
|
ACMD_FUNC(mute)
|
|
{
|
|
struct map_session_data *pl_sd = NULL;
|
|
int manner;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!message || !*message || sscanf(message, "%d %23[^\n]", &manner, atcmd_player_name) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1237)); // Usage: @mute <time> <char name>
|
|
return -1;
|
|
}
|
|
|
|
if ( (pl_sd = map_nick2sd(atcmd_player_name)) == NULL )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
|
|
return -1;
|
|
}
|
|
|
|
clif_manner_message(sd, 0);
|
|
clif_manner_message(pl_sd, 5);
|
|
|
|
if( pl_sd->status.manner < manner ) {
|
|
pl_sd->status.manner -= manner;
|
|
sc_start(NULL,&pl_sd->bl,SC_NOCHAT,100,0,0);
|
|
} else {
|
|
pl_sd->status.manner = 0;
|
|
status_change_end(&pl_sd->bl, SC_NOCHAT, INVALID_TIMER);
|
|
}
|
|
|
|
clif_GM_silence(sd, pl_sd, (manner > 0 ? 1 : 0));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @refresh (like @jumpto <<yourself>>)
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(refresh)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
clif_refresh(sd);
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(refreshall)
|
|
{
|
|
struct map_session_data* iter_sd;
|
|
struct s_mapiterator* iter;
|
|
nullpo_retr(-1, sd);
|
|
|
|
iter = mapit_getallusers();
|
|
for (iter_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); iter_sd = (TBL_PC*)mapit_next(iter))
|
|
clif_refresh(iter_sd);
|
|
mapit_free(iter);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @identify
|
|
* => GM's magnifier.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(identify)
|
|
{
|
|
int i,num;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
for(i=num=0;i<MAX_INVENTORY;i++){
|
|
if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify!=1){
|
|
num++;
|
|
}
|
|
}
|
|
if (num > 0) {
|
|
clif_item_identify_list(sd);
|
|
} else {
|
|
clif_displaymessage(fd,msg_txt(sd,1238)); // There are no items to appraise.
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*===============================================
|
|
* @identifyall
|
|
* => Indentify all items in inventory - Akinari
|
|
*-----------------------------------------------*/
|
|
ACMD_FUNC(identifyall)
|
|
{
|
|
int i;
|
|
nullpo_retr(-1, sd);
|
|
for(i=0; i<MAX_INVENTORY; i++) {
|
|
if (sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify!=1) {
|
|
sd->status.inventory[i].identify=1;
|
|
clif_item_identified(sd,i,0);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @gmotd (Global MOTD)
|
|
* by davidsiaw :P
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(gmotd)
|
|
{
|
|
FILE* fp;
|
|
|
|
if( ( fp = fopen(motd_txt, "r") ) != NULL )
|
|
{
|
|
char buf[CHAT_SIZE_MAX];
|
|
size_t len;
|
|
|
|
while( fgets(buf, sizeof(buf), fp) )
|
|
{
|
|
if( buf[0] == '/' && buf[1] == '/' )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
len = strlen(buf);
|
|
|
|
while( len && ( buf[len-1] == '\r' || buf[len-1] == '\n' ) )
|
|
{// strip trailing EOL characters
|
|
len--;
|
|
}
|
|
|
|
if( len )
|
|
{
|
|
buf[len] = 0;
|
|
|
|
intif_broadcast(buf, len+1, 0);
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(misceffect)
|
|
{
|
|
int effect = 0;
|
|
nullpo_retr(-1, sd);
|
|
if (!message || !*message)
|
|
return -1;
|
|
if (sscanf(message, "%d", &effect) < 1)
|
|
return -1;
|
|
clif_misceffect(&sd->bl,effect);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* MAIL SYSTEM
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(mail)
|
|
{
|
|
nullpo_ret(sd);
|
|
mail_openmail(sd);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Show Monster DB Info v 1.0
|
|
* originally by [Lupus]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(mobinfo)
|
|
{
|
|
unsigned char msize[SZ_ALL][7] = { "Small", "Medium", "Large" };
|
|
unsigned char mrace[RC_ALL][11] = { "Formless", "Undead", "Beast", "Plant", "Insect", "Fish", "Demon", "Demi-Human", "Angel", "Dragon", "Player" };
|
|
unsigned char melement[ELE_ALL][8] = { "Neutral", "Water", "Earth", "Fire", "Wind", "Poison", "Holy", "Dark", "Ghost", "Undead" };
|
|
char atcmd_output2[CHAT_SIZE_MAX];
|
|
struct item_data *item_data;
|
|
struct mob_db *mob, *mob_array[MAX_SEARCH];
|
|
int count;
|
|
int i, k;
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
memset(atcmd_output2, '\0', sizeof(atcmd_output2));
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1239)); // Please enter a monster name/ID (usage: @mobinfo <monster_name_or_monster_ID>).
|
|
return -1;
|
|
}
|
|
|
|
// If monster identifier/name argument is a name
|
|
if ((i = mobdb_checkid(atoi(message))))
|
|
{
|
|
mob_array[0] = mob_db(i);
|
|
count = 1;
|
|
} else
|
|
count = mobdb_searchname_array(mob_array, MAX_SEARCH, message);
|
|
|
|
if (!count) {
|
|
clif_displaymessage(fd, msg_txt(sd,40)); // Invalid monster ID or name.
|
|
return -1;
|
|
}
|
|
|
|
if (count > MAX_SEARCH) {
|
|
sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH, count);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
count = MAX_SEARCH;
|
|
}
|
|
for (k = 0; k < count; k++) {
|
|
unsigned int j,base_exp,job_exp;
|
|
mob = mob_array[k];
|
|
base_exp = mob->base_exp;
|
|
job_exp = mob->job_exp;
|
|
|
|
#ifdef RENEWAL_EXP
|
|
if( battle_config.atcommand_mobinfo_type ) {
|
|
base_exp = base_exp * pc_level_penalty_mod(sd, mob->lv, mob->status.class_, 1) / 100;
|
|
job_exp = job_exp * pc_level_penalty_mod(sd, mob->lv, mob->status.class_, 1) / 100;
|
|
}
|
|
#endif
|
|
#ifdef VIP_ENABLE
|
|
// Display EXP rate increase for VIP.
|
|
if (pc_isvip(sd) && (battle_config.vip_base_exp_increase || battle_config.vip_job_exp_increase)) {
|
|
base_exp += battle_config.vip_base_exp_increase;
|
|
job_exp += battle_config.vip_job_exp_increase;
|
|
}
|
|
#endif
|
|
// stats
|
|
if (mob->mexp)
|
|
sprintf(atcmd_output, msg_txt(sd,1240), mob->name, mob->jname, mob->sprite, mob->vd.class_); // MVP Monster: '%s'/'%s'/'%s' (%d)
|
|
else
|
|
sprintf(atcmd_output, msg_txt(sd,1241), mob->name, mob->jname, mob->sprite, mob->vd.class_); // Monster: '%s'/'%s'/'%s' (%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,1242), mob->lv, mob->status.max_hp, base_exp, job_exp, MOB_HIT(mob), MOB_FLEE(mob)); // Lv:%d HP:%d Base EXP:%u Job EXP:%u HIT:%d FLEE:%d
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output, msg_txt(sd,1243), // DEF:%d MDEF:%d STR:%d AGI:%d VIT:%d INT:%d DEX:%d LUK:%d
|
|
mob->status.def, mob->status.mdef,mob->status.str, mob->status.agi,
|
|
mob->status.vit, mob->status.int_, mob->status.dex, mob->status.luk);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,1244), // ATK:%d~%d Range:%d~%d~%d Size:%s Race: %s Element: %s (Lv:%d)
|
|
mob->status.rhw.atk, mob->status.rhw.atk2, mob->status.rhw.range,
|
|
mob->range2 , mob->range3, msize[mob->status.size],
|
|
mrace[mob->status.race], melement[mob->status.def_ele], mob->status.ele_lv);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
// drops
|
|
clif_displaymessage(fd, msg_txt(sd,1245)); // Drops:
|
|
strcpy(atcmd_output, " ");
|
|
j = 0;
|
|
for (i = 0; i < MAX_MOB_DROP; i++) {
|
|
int droprate;
|
|
if (mob->dropitem[i].nameid <= 0 || mob->dropitem[i].p < 1 || (item_data = itemdb_exists(mob->dropitem[i].nameid)) == NULL)
|
|
continue;
|
|
droprate = mob->dropitem[i].p;
|
|
|
|
#ifdef RENEWAL_DROP
|
|
if( battle_config.atcommand_mobinfo_type ) {
|
|
droprate = droprate * pc_level_penalty_mod(sd, mob->lv, mob->status.class_, 2) / 100;
|
|
if (droprate <= 0 && !battle_config.drop_rate0item)
|
|
droprate = 1;
|
|
}
|
|
#endif
|
|
#ifdef VIP_ENABLE
|
|
// Display item rate increase for VIP.
|
|
if (pc_isvip(sd) && battle_config.vip_drop_increase)
|
|
droprate += battle_config.vip_drop_increase;
|
|
#endif
|
|
if (item_data->slot)
|
|
sprintf(atcmd_output2, " - %s[%d] %02.02f%%", item_data->jname, item_data->slot, (float)droprate / 100);
|
|
else
|
|
sprintf(atcmd_output2, " - %s %02.02f%%", item_data->jname, (float)droprate / 100);
|
|
strcat(atcmd_output, atcmd_output2);
|
|
if (++j % 3 == 0) {
|
|
clif_displaymessage(fd, atcmd_output);
|
|
strcpy(atcmd_output, " ");
|
|
}
|
|
}
|
|
if (j == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,1246)); // This monster has no drops.
|
|
else if (j % 3 != 0)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
// mvp
|
|
if (mob->mexp) {
|
|
float mvppercent, mvpremain;
|
|
sprintf(atcmd_output, msg_txt(sd,1247), mob->mexp); // MVP Bonus EXP:%u
|
|
clif_displaymessage(fd, atcmd_output);
|
|
strcpy(atcmd_output, msg_txt(sd,1248)); // MVP Items:
|
|
mvpremain = 100.0; //Remaining drop chance for official mvp drop mode
|
|
j = 0;
|
|
for (i = 0; i < MAX_MVP_DROP; i++) {
|
|
if (mob->mvpitem[i].nameid <= 0 || (item_data = itemdb_exists(mob->mvpitem[i].nameid)) == NULL)
|
|
continue;
|
|
//Because if there are 3 MVP drops at 50%, the first has a chance of 50%, the second 25% and the third 12.5%
|
|
mvppercent = (float)mob->mvpitem[i].p * mvpremain / 10000.0f;
|
|
if(battle_config.item_drop_mvp_mode == 0) {
|
|
mvpremain -= mvppercent;
|
|
}
|
|
if (mvppercent > 0) {
|
|
j++;
|
|
if (j == 1) {
|
|
if (item_data->slot)
|
|
sprintf(atcmd_output2, " %s[%d] %02.02f%%", item_data->jname, item_data->slot, mvppercent);
|
|
else
|
|
sprintf(atcmd_output2, " %s %02.02f%%", item_data->jname, mvppercent);
|
|
} else {
|
|
if (item_data->slot)
|
|
sprintf(atcmd_output2, " - %s[%d] %02.02f%%", item_data->jname, item_data->slot, mvppercent);
|
|
else
|
|
sprintf(atcmd_output2, " - %s %02.02f%%", item_data->jname, mvppercent);
|
|
}
|
|
strcat(atcmd_output, atcmd_output2);
|
|
}
|
|
}
|
|
if (j == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,1249)); // This monster has no MVP prizes.
|
|
else
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*=========================================
|
|
* @showmobs by KarLaeda
|
|
* => For 15 sec displays the mobs on minimap
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(showmobs)
|
|
{
|
|
char mob_name[100];
|
|
int mob_id;
|
|
int number = 0;
|
|
struct s_mapiterator* it;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if(sscanf(message, "%99[^\n]", mob_name) < 0)
|
|
return -1;
|
|
|
|
if((mob_id = atoi(mob_name)) == 0)
|
|
mob_id = mobdb_searchname(mob_name);
|
|
if(mob_id > 0 && mobdb_checkid(mob_id) == 0){
|
|
snprintf(atcmd_output, sizeof atcmd_output, msg_txt(sd,1250),mob_name); // Invalid mob id %s!
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
if(mob_db(mob_id)->status.mode&MD_BOSS && !pc_has_permission(sd, PC_PERM_SHOW_BOSS)){ // If player group does not have access to boss mobs.
|
|
clif_displaymessage(fd, msg_txt(sd,1251)); // Can't show boss mobs!
|
|
return 0;
|
|
}
|
|
|
|
if(mob_id == atoi(mob_name) && mob_db(mob_id)->jname)
|
|
strcpy(mob_name,mob_db(mob_id)->jname); // --ja--
|
|
//strcpy(mob_name,mob_db(mob_id)->name); // --en--
|
|
|
|
snprintf(atcmd_output, sizeof atcmd_output, msg_txt(sd,1252), // Mob Search... %s %s
|
|
mob_name, mapindex_id2name(sd->mapindex));
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
it = mapit_geteachmob();
|
|
for(;;)
|
|
{
|
|
TBL_MOB* md = (TBL_MOB*)mapit_next(it);
|
|
if( md == NULL )
|
|
break;// no more mobs
|
|
|
|
if( md->bl.m != sd->bl.m )
|
|
continue;
|
|
if( mob_id != -1 && md->mob_id != mob_id )
|
|
continue;
|
|
if( md->special_state.ai || md->master_id )
|
|
continue; // hide slaves and player summoned mobs
|
|
if( md->spawn_timer != INVALID_TIMER )
|
|
continue; // hide mobs waiting for respawn
|
|
|
|
++number;
|
|
clif_viewpoint(sd, 1, 0, md->bl.x, md->bl.y, number, 0xFFFFFF);
|
|
}
|
|
mapit_free(it);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* homunculus level up [orn]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(homlevel)
|
|
{
|
|
TBL_HOM * hd;
|
|
int level = 0, i = 0;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ( !message || !*message || ( level = atoi(message) ) < 1 ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1253)); // Please enter a level adjustment (usage: @homlevel <number of levels>).
|
|
return -1;
|
|
}
|
|
|
|
if ( !hom_is_active(sd->hd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1254)); // You do not have a homunculus.
|
|
return -1;
|
|
}
|
|
|
|
hd = sd->hd;
|
|
|
|
for (i = 1; i <= level && hd->exp_next; i++){
|
|
hd->homunculus.exp += hd->exp_next;
|
|
if( !hom_levelup(hd) )
|
|
break;
|
|
}
|
|
|
|
status_calc_homunculus(hd, SCO_NONE);
|
|
status_percent_heal(&hd->bl, 100, 100);
|
|
clif_specialeffect(&hd->bl,568,AREA);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* homunculus evolution H [orn]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(homevolution)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ( !hom_is_active(sd->hd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1254)); // You do not have a homunculus.
|
|
return -1;
|
|
}
|
|
|
|
if ( !hom_evolution(sd->hd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1255)); // Your homunculus doesn't evolve.
|
|
return -1;
|
|
}
|
|
clif_homskillinfoblock(sd);
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(hommutate)
|
|
{
|
|
int homun_id, m_class = 0, m_id;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!hom_is_active(sd->hd)) {
|
|
clif_displaymessage(fd, msg_txt(sd,1254)); // You do not have a homunculus.
|
|
return -1;
|
|
}
|
|
|
|
if (!message || !*message) {
|
|
homun_id = 6048 + (rnd() % 4);
|
|
} else {
|
|
homun_id = atoi(message);
|
|
}
|
|
|
|
m_class = hom_class2mapid(sd->hd->homunculus.class_);
|
|
m_id = hom_class2mapid(homun_id);
|
|
|
|
if (m_class != -1 && m_id != -1 && m_class&HOM_EVO && m_id&HOM_S && sd->hd->homunculus.level >= 99) {
|
|
hom_mutate(sd->hd, homun_id);
|
|
} else {
|
|
clif_emotion(&sd->hd->bl, E_SWT);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* call choosen homunculus [orn]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(makehomun)
|
|
{
|
|
int homunid;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ( sd->status.hom_id ) {
|
|
clif_displaymessage(fd, msg_txt(sd,450));
|
|
return -1;
|
|
}
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1256)); // Please enter a homunculus ID (usage: @makehomun <homunculus id>).
|
|
return -1;
|
|
}
|
|
|
|
homunid = atoi(message);
|
|
if( homunid < HM_CLASS_BASE || homunid > HM_CLASS_BASE + MAX_HOMUNCULUS_CLASS - 1 )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1257)); // Invalid Homunculus ID.
|
|
return -1;
|
|
}
|
|
|
|
hom_create_request(sd,homunid);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* modify homunculus intimacy [orn]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(homfriendly)
|
|
{
|
|
int friendly = 0;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ( !hom_is_active(sd->hd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1254)); // You do not have a homunculus.
|
|
return -1;
|
|
}
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1258)); // Please enter a friendly value (usage: @homfriendly <friendly value [0-1000]>).
|
|
return -1;
|
|
}
|
|
|
|
friendly = atoi(message);
|
|
friendly = cap_value(friendly, 0, 1000);
|
|
|
|
sd->hd->homunculus.intimacy = friendly * 100 ;
|
|
clif_send_homdata(sd,SP_INTIMATE,friendly);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* modify homunculus hunger [orn]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(homhungry)
|
|
{
|
|
int hungry = 0;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ( !hom_is_active(sd->hd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1254)); // You do not have a homunculus.
|
|
return -1;
|
|
}
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1259)); // Please enter a hunger value (usage: @homhungry <hunger value [0-100]>).
|
|
return -1;
|
|
}
|
|
|
|
hungry = atoi(message);
|
|
hungry = cap_value(hungry, 0, 100);
|
|
|
|
sd->hd->homunculus.hunger = hungry;
|
|
clif_send_homdata(sd,SP_HUNGRY,hungry);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* make the homunculus speak [orn]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(homtalk)
|
|
{
|
|
char mes[100],temp[100];
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ( battle_config.min_chat_delay ) {
|
|
if( DIFF_TICK(sd->cantalk_tick, gettick()) > 0 )
|
|
return 0;
|
|
sd->cantalk_tick = gettick() + battle_config.min_chat_delay;
|
|
}
|
|
|
|
if (sd->sc.cant.chat)
|
|
return -1; //no "chatting" while muted.
|
|
|
|
if ( !hom_is_active(sd->hd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1254)); // You do not have a homunculus.
|
|
return -1;
|
|
}
|
|
|
|
if (!message || !*message || sscanf(message, "%99[^\n]", mes) < 1) {
|
|
clif_displaymessage(fd, msg_txt(sd,1260)); // Please enter a message (usage: @homtalk <message>).
|
|
return -1;
|
|
}
|
|
|
|
snprintf(temp, sizeof temp ,"%s : %s", sd->hd->homunculus.name, mes);
|
|
clif_disp_overhead(&sd->hd->bl, temp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Show homunculus stats
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(hominfo)
|
|
{
|
|
struct homun_data *hd;
|
|
struct status_data *status;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ( !hom_is_active(sd->hd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1254)); // You do not have a homunculus.
|
|
return -1;
|
|
}
|
|
|
|
hd = sd->hd;
|
|
status = status_get_status_data(&hd->bl);
|
|
clif_displaymessage(fd, msg_txt(sd,1261)); // Homunculus stats:
|
|
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1262), // HP: %d/%d - SP: %d/%d
|
|
status->hp, status->max_hp, status->sp, status->max_sp);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1263), // ATK: %d - MATK: %d~%d
|
|
status->rhw.atk2 +status->batk, status->matk_min, status->matk_max);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1264), // Hungry: %d - Intimacy: %u
|
|
hd->homunculus.hunger, hd->homunculus.intimacy/100);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,
|
|
msg_txt(sd,1265), // Stats: Str %d / Agi %d / Vit %d / Int %d / Dex %d / Luk %d
|
|
status->str, status->agi, status->vit,
|
|
status->int_, status->dex, status->luk);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(homstats)
|
|
{
|
|
struct homun_data *hd;
|
|
struct s_homunculus_db *db;
|
|
struct s_homunculus *hom;
|
|
int lv, min, max, evo;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if ( !hom_is_active(sd->hd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1254)); // You do not have a homunculus.
|
|
return -1;
|
|
}
|
|
|
|
hd = sd->hd;
|
|
|
|
hom = &hd->homunculus;
|
|
db = hd->homunculusDB;
|
|
lv = hom->level;
|
|
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,
|
|
msg_txt(sd,1266), lv, db->name); // Homunculus growth stats (Lv %d %s):
|
|
clif_displaymessage(fd, atcmd_output);
|
|
lv--; //Since the first increase is at level 2.
|
|
|
|
evo = (hom->class_ == db->evo_class);
|
|
min = db->base.HP +lv*db->gmin.HP +(evo?db->emin.HP:0);
|
|
max = db->base.HP +lv*db->gmax.HP +(evo?db->emax.HP:0);;
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1267), hom->max_hp, min, max); // Max HP: %d (%d~%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
min = db->base.SP +lv*db->gmin.SP +(evo?db->emin.SP:0);
|
|
max = db->base.SP +lv*db->gmax.SP +(evo?db->emax.SP:0);;
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1268), hom->max_sp, min, max); // Max SP: %d (%d~%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
min = db->base.str +lv*(db->gmin.str/10) +(evo?db->emin.str:0);
|
|
max = db->base.str +lv*(db->gmax.str/10) +(evo?db->emax.str:0);;
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1269), hom->str/10, min, max); // Str: %d (%d~%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
min = db->base.agi +lv*(db->gmin.agi/10) +(evo?db->emin.agi:0);
|
|
max = db->base.agi +lv*(db->gmax.agi/10) +(evo?db->emax.agi:0);;
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1270), hom->agi/10, min, max); // Agi: %d (%d~%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
min = db->base.vit +lv*(db->gmin.vit/10) +(evo?db->emin.vit:0);
|
|
max = db->base.vit +lv*(db->gmax.vit/10) +(evo?db->emax.vit:0);;
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1271), hom->vit/10, min, max); // Vit: %d (%d~%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
min = db->base.int_ +lv*(db->gmin.int_/10) +(evo?db->emin.int_:0);
|
|
max = db->base.int_ +lv*(db->gmax.int_/10) +(evo?db->emax.int_:0);;
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1272), hom->int_/10, min, max); // Int: %d (%d~%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
min = db->base.dex +lv*(db->gmin.dex/10) +(evo?db->emin.dex:0);
|
|
max = db->base.dex +lv*(db->gmax.dex/10) +(evo?db->emax.dex:0);;
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1273), hom->dex/10, min, max); // Dex: %d (%d~%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
min = db->base.luk +lv*(db->gmin.luk/10) +(evo?db->emin.luk:0);
|
|
max = db->base.luk +lv*(db->gmax.luk/10) +(evo?db->emax.luk:0);;
|
|
snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(sd,1274), hom->luk/10, min, max); // Luk: %d (%d~%d)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(homshuffle)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if(!sd->hd)
|
|
return -1; // nothing to do
|
|
|
|
if(!hom_shuffle(sd->hd))
|
|
return -1;
|
|
|
|
clif_displaymessage(sd->fd, msg_txt(sd,1275)); // Homunculus stats altered.
|
|
atcommand_homstats(fd, sd, command, message); //Print out the new stats
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Show Items DB Info v 1.0
|
|
* originally by [Lupus]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(iteminfo)
|
|
{
|
|
struct item_data *item_array[MAX_SEARCH];
|
|
int i, count = 1;
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1276)); // Please enter an item name/ID (usage: @ii/@iteminfo <item name/ID>).
|
|
return -1;
|
|
}
|
|
if ((item_array[0] = itemdb_exists(atoi(message))) == NULL)
|
|
count = itemdb_searchname_array(item_array, MAX_SEARCH, message);
|
|
|
|
if (!count) {
|
|
clif_displaymessage(fd, msg_txt(sd,19)); // Invalid item ID or name.
|
|
return -1;
|
|
}
|
|
|
|
if (count > MAX_SEARCH) {
|
|
sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH, count); // Displaying first %d out of %d matches
|
|
clif_displaymessage(fd, atcmd_output);
|
|
count = MAX_SEARCH;
|
|
}
|
|
for (i = 0; i < count; i++) {
|
|
struct item_data * item_data = item_array[i];
|
|
sprintf(atcmd_output, msg_txt(sd,1277), // Item: '%s'/'%s'[%d] (%hu) Type: %s | Extra Effect: %s
|
|
item_data->name,item_data->jname,item_data->slot,item_data->nameid,
|
|
(item_data->type != IT_AMMO) ? itemdb_typename((enum item_types)item_data->type) : itemdb_typename_ammo((enum e_item_ammo)item_data->look),
|
|
(item_data->script==NULL)? msg_txt(sd,1278) : msg_txt(sd,1279) // None / With script
|
|
);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,1280), item_data->value_buy, item_data->value_sell, item_data->weight/10. ); // NPC Buy:%dz, Sell:%dz | Weight: %.1f
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
if (item_data->maxchance == -1)
|
|
strcpy(atcmd_output, msg_txt(sd,1281)); // - Available in the shops only.
|
|
else if (!battle_config.atcommand_mobinfo_type && item_data->maxchance)
|
|
sprintf(atcmd_output, msg_txt(sd,1282), (float)item_data->maxchance / 100 ); // - Maximal monsters drop chance: %02.02f%%
|
|
else
|
|
strcpy(atcmd_output, msg_txt(sd,1283)); // - Monsters don't drop this item.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Show who drops the item.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(whodrops)
|
|
{
|
|
struct item_data *item_data, *item_array[MAX_SEARCH];
|
|
int i,j, count = 1;
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1284)); // Please enter item name/ID (usage: @whodrops <item name/ID>).
|
|
return -1;
|
|
}
|
|
if ((item_array[0] = itemdb_exists(atoi(message))) == NULL)
|
|
count = itemdb_searchname_array(item_array, MAX_SEARCH, message);
|
|
|
|
if (!count) {
|
|
clif_displaymessage(fd, msg_txt(sd,19)); // Invalid item ID or name.
|
|
return -1;
|
|
}
|
|
|
|
if (count > MAX_SEARCH) {
|
|
sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH, count); // Displaying first %d out of %d matches
|
|
clif_displaymessage(fd, atcmd_output);
|
|
count = MAX_SEARCH;
|
|
}
|
|
for (i = 0; i < count; i++) {
|
|
item_data = item_array[i];
|
|
sprintf(atcmd_output, msg_txt(sd,1285), item_data->jname, item_data->slot, item_data->nameid); // Item: '%s'[%d] (ID:%hu)
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
if (item_data->mob[0].chance == 0) {
|
|
strcpy(atcmd_output, msg_txt(sd,1286)); // - Item is not dropped by mobs.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
} else {
|
|
sprintf(atcmd_output, msg_txt(sd,1287), MAX_SEARCH); // - Common mobs with highest drop chance (only max %d are listed):
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
for (j=0; j < MAX_SEARCH && item_data->mob[j].chance > 0; j++)
|
|
{
|
|
int dropchance = item_data->mob[j].chance;
|
|
|
|
#ifdef RENEWAL_DROP
|
|
if( battle_config.atcommand_mobinfo_type )
|
|
dropchance = dropchance * pc_level_penalty_mod(sd, mob_db(item_data->mob[j].id)->lv, mob_db(item_data->mob[j].id)->status.class_, 2) / 100;
|
|
#endif
|
|
#ifdef VIP_ENABLE
|
|
// Display item rate increase for VIP.
|
|
if (pc_isvip(sd) && battle_config.vip_drop_increase)
|
|
dropchance += battle_config.vip_drop_increase;
|
|
#endif
|
|
sprintf(atcmd_output, "- %s (%d): %02.02f%%", mob_db(item_data->mob[j].id)->jname, item_data->mob[j].id, dropchance/100.);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(whereis)
|
|
{
|
|
struct mob_db *mob_array[MAX_SEARCH];
|
|
int count;
|
|
int i, j, k;
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1288)); // Please enter a monster name/ID (usage: @whereis <monster_name_or_monster_ID>).
|
|
return -1;
|
|
}
|
|
|
|
// If monster identifier/name argument is a name
|
|
if ((i = mobdb_checkid(atoi(message))))
|
|
{
|
|
mob_array[0] = mob_db(i);
|
|
count = 1;
|
|
} else
|
|
count = mobdb_searchname_array(mob_array, MAX_SEARCH, message);
|
|
|
|
if (!count) {
|
|
clif_displaymessage(fd, msg_txt(sd,40)); // Invalid monster ID or name.
|
|
return -1;
|
|
}
|
|
|
|
if (count > MAX_SEARCH) {
|
|
sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH, count);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
count = MAX_SEARCH;
|
|
}
|
|
for (k = 0; k < count; k++) {
|
|
struct mob_db *mob = mob_array[k];
|
|
snprintf(atcmd_output, sizeof atcmd_output, msg_txt(sd,1289), mob->jname); // %s spawns in:
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
for (i = 0; i < ARRAYLENGTH(mob->spawn) && mob->spawn[i].qty; i++)
|
|
{
|
|
j = map_mapindex2mapid(mob->spawn[i].mapindex);
|
|
if (j < 0) continue;
|
|
snprintf(atcmd_output, sizeof atcmd_output, "%s (%d)", map[j].name, mob->spawn[i].qty);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
if (i == 0)
|
|
clif_displaymessage(fd, msg_txt(sd,1290)); // This monster does not spawn normally.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(version)
|
|
{
|
|
pc_show_version(sd);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @mutearea by MouseJstr
|
|
*------------------------------------------*/
|
|
static int atcommand_mutearea_sub(struct block_list *bl,va_list ap)
|
|
{
|
|
|
|
int time, id;
|
|
struct map_session_data *pl_sd = (struct map_session_data *)bl;
|
|
if (pl_sd == NULL)
|
|
return 0;
|
|
|
|
id = va_arg(ap, int);
|
|
time = va_arg(ap, int);
|
|
|
|
if (id != bl->id && !pc_get_group_level(pl_sd)) {
|
|
pl_sd->status.manner -= time;
|
|
if (pl_sd->status.manner < 0)
|
|
sc_start(NULL,&pl_sd->bl,SC_NOCHAT,100,0,0);
|
|
else
|
|
status_change_end(&pl_sd->bl, SC_NOCHAT, INVALID_TIMER);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(mutearea)
|
|
{
|
|
int time;
|
|
nullpo_ret(sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,1297)); // Please enter a time in minutes (usage: @mutearea/@stfu <time in minutes>).
|
|
return -1;
|
|
}
|
|
|
|
time = atoi(message);
|
|
|
|
map_foreachinarea(atcommand_mutearea_sub,sd->bl.m,
|
|
sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE,
|
|
sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_PC, sd->bl.id, time);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
ACMD_FUNC(rates)
|
|
{
|
|
char buf[CHAT_SIZE_MAX];
|
|
int base_exp_rate = 0, job_exp_rate = 0, item_rate = 0;
|
|
|
|
nullpo_ret(sd);
|
|
memset(buf, '\0', sizeof(buf));
|
|
|
|
#ifdef VIP_ENABLE
|
|
// Display EXP and item rate increase for VIP.
|
|
if (pc_isvip(sd) && (battle_config.vip_base_exp_increase || battle_config.vip_job_exp_increase || battle_config.vip_drop_increase)) {
|
|
base_exp_rate += battle_config.vip_base_exp_increase;
|
|
job_exp_rate += battle_config.vip_job_exp_increase;
|
|
item_rate += battle_config.vip_drop_increase;
|
|
}
|
|
#endif
|
|
snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1298), // Experience rates: Base %.2fx / Job %.2fx
|
|
(battle_config.base_exp_rate+base_exp_rate)/100., (battle_config.job_exp_rate+job_exp_rate)/100.);
|
|
clif_displaymessage(fd, buf);
|
|
snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1299), // Normal Drop Rates: Common %.2fx / Healing %.2fx / Usable %.2fx / Equipment %.2fx / Card %.2fx
|
|
(battle_config.item_rate_common+item_rate)/100., (battle_config.item_rate_heal+item_rate)/100., (battle_config.item_rate_use+item_rate)/100., (battle_config.item_rate_equip+item_rate)/100., (battle_config.item_rate_card+item_rate)/100.);
|
|
clif_displaymessage(fd, buf);
|
|
snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1300), // Boss Drop Rates: Common %.2fx / Healing %.2fx / Usable %.2fx / Equipment %.2fx / Card %.2fx
|
|
(battle_config.item_rate_common_boss+item_rate)/100., (battle_config.item_rate_heal_boss+item_rate)/100., (battle_config.item_rate_use_boss+item_rate)/100., (battle_config.item_rate_equip_boss+item_rate)/100., (battle_config.item_rate_card_boss+item_rate)/100.);
|
|
clif_displaymessage(fd, buf);
|
|
snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1301), // Other Drop Rates: MvP %.2fx / Card-Based %.2fx / Treasure %.2fx
|
|
(battle_config.item_rate_mvp+item_rate)/100., (battle_config.item_rate_adddrop+item_rate)/100., (battle_config.item_rate_treasure+item_rate)/100.);
|
|
clif_displaymessage(fd, buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @me by lordalfa
|
|
* => Displays the OUTPUT string on top of the Visible players Heads.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(me)
|
|
{
|
|
char tempmes[CHAT_SIZE_MAX];
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(tempmes, '\0', sizeof(tempmes));
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (sd->sc.cant.chat)
|
|
return -1; //no "chatting" while muted.
|
|
|
|
if (!message || !*message || sscanf(message, "%199[^\n]", tempmes) < 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,1302)); // Please enter a message (usage: @me <message>).
|
|
return -1;
|
|
}
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,270), sd->status.name, tempmes); // *%s %s*
|
|
clif_disp_overhead(&sd->bl, atcmd_output);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*==========================================
|
|
* @size
|
|
* => Resize your character sprite. [Valaris]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(size)
|
|
{
|
|
int size = 0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
size = cap_value(atoi(message),SZ_SMALL,SZ_BIG);
|
|
|
|
if(sd->state.size) {
|
|
sd->state.size = SZ_SMALL;
|
|
pc_setpos(sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_TELEPORT);
|
|
}
|
|
|
|
sd->state.size = size;
|
|
if( size == SZ_MEDIUM )
|
|
clif_specialeffect(&sd->bl,420,AREA);
|
|
else if( size == SZ_BIG )
|
|
clif_specialeffect(&sd->bl,422,AREA);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1303)); // Size change applied.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(sizeall)
|
|
{
|
|
int size;
|
|
struct map_session_data *pl_sd;
|
|
struct s_mapiterator* iter;
|
|
|
|
size = atoi(message);
|
|
size = cap_value(size,0,2);
|
|
|
|
iter = mapit_getallusers();
|
|
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) ) {
|
|
if( pl_sd->state.size != size ) {
|
|
if( pl_sd->state.size ) {
|
|
pl_sd->state.size = SZ_SMALL;
|
|
pc_setpos(pl_sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
|
|
}
|
|
|
|
pl_sd->state.size = size;
|
|
if( size == SZ_MEDIUM )
|
|
clif_specialeffect(&pl_sd->bl,420,AREA);
|
|
else if( size == SZ_BIG )
|
|
clif_specialeffect(&pl_sd->bl,422,AREA);
|
|
}
|
|
}
|
|
mapit_free(iter);
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1303)); // Size change applied.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(sizeguild)
|
|
{
|
|
int size = 0, i;
|
|
char guild[NAME_LENGTH];
|
|
struct map_session_data *pl_sd;
|
|
struct guild *g;
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(guild, '\0', sizeof(guild));
|
|
|
|
if( !message || !*message || sscanf(message, "%d %23[^\n]", &size, guild) < 2 ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1304)); // Please enter guild name/ID (usage: @sizeguild <size> <guild name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if( (g = guild_searchname(guild)) == NULL && (g = guild_search(atoi(guild))) == NULL ) {
|
|
clif_displaymessage(fd, msg_txt(sd,94)); // Incorrect name/ID, or no one from the guild is online.
|
|
return -1;
|
|
}
|
|
|
|
size = cap_value(size,SZ_SMALL,SZ_BIG);
|
|
|
|
for( i = 0; i < g->max_member; i++ ) {
|
|
if( (pl_sd = g->member[i].sd) && pl_sd->state.size != size ) {
|
|
if( pl_sd->state.size ) {
|
|
pl_sd->state.size = SZ_SMALL;
|
|
pc_setpos(pl_sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
|
|
}
|
|
|
|
pl_sd->state.size = size;
|
|
if( size == SZ_MEDIUM )
|
|
clif_specialeffect(&pl_sd->bl,420,AREA);
|
|
else if( size == SZ_BIG )
|
|
clif_specialeffect(&pl_sd->bl,422,AREA);
|
|
}
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1303)); // Size change applied.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @monsterignore
|
|
* => Makes monsters ignore you. [Valaris]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(monsterignore)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if (!sd->state.monster_ignore) {
|
|
sd->state.monster_ignore = 1;
|
|
clif_displaymessage(sd->fd, msg_txt(sd,1305)); // You are now immune to attacks.
|
|
} else {
|
|
sd->state.monster_ignore = 0;
|
|
clif_displaymessage(sd->fd, msg_txt(sd,1306)); // Returned to normal state.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/*==========================================
|
|
* @fakename
|
|
* => Gives your character a fake name. [Valaris]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(fakename)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
if( !message || !*message )
|
|
{
|
|
if( sd->fakename[0] )
|
|
{
|
|
sd->fakename[0] = '\0';
|
|
clif_charnameack(0, &sd->bl);
|
|
if (sd->disguise)
|
|
clif_charnameack(sd->fd, &sd->bl);
|
|
clif_displaymessage(sd->fd, msg_txt(sd,1307)); // Returned to real name.
|
|
return 0;
|
|
}
|
|
|
|
clif_displaymessage(sd->fd, msg_txt(sd,1308)); // You must enter a name.
|
|
return -1;
|
|
}
|
|
|
|
if( strlen(message) < 2 )
|
|
{
|
|
clif_displaymessage(sd->fd, msg_txt(sd,1309)); // Fake name must be at least two characters.
|
|
return -1;
|
|
}
|
|
|
|
safestrncpy(sd->fakename, message, sizeof(sd->fakename));
|
|
clif_charnameack(0, &sd->bl);
|
|
if (sd->disguise) // Another packet should be sent so the client updates the name for sd
|
|
clif_charnameack(sd->fd, &sd->bl);
|
|
clif_displaymessage(sd->fd, msg_txt(sd,1310)); // Fake name enabled.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Ragnarok Resources
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(mapflag) {
|
|
#define checkflag( cmd ) if ( map[ sd->bl.m ].flag.cmd ) clif_displaymessage(sd->fd,#cmd)
|
|
#define setflag( cmd ) \
|
|
if ( strcmp( flag_name , #cmd ) == 0 ){\
|
|
map[ sd->bl.m ].flag.cmd = flag;\
|
|
sprintf(atcmd_output,"[ @mapflag ] %s flag has been set to %s value = %hd",#cmd,flag?"On":"Off",flag);\
|
|
clif_displaymessage(sd->fd,atcmd_output);\
|
|
return 0;\
|
|
}
|
|
char flag_name[100];
|
|
short flag=0,i;
|
|
nullpo_retr(-1, sd);
|
|
memset(flag_name, '\0', sizeof(flag_name));
|
|
|
|
if (!message || !*message || (sscanf(message, "%99s %hd", flag_name, &flag) < 1)) {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1311)); // Enabled Mapflags in this map:
|
|
clif_displaymessage(sd->fd,"----------------------------------");
|
|
checkflag(town); checkflag(autotrade); checkflag(allowks); checkflag(nomemo);
|
|
checkflag(noteleport); checkflag(noreturn); checkflag(monster_noteleport); checkflag(nosave);
|
|
checkflag(nobranch); checkflag(noexppenalty); checkflag(pvp); checkflag(pvp_noparty);
|
|
checkflag(pvp_noguild); checkflag(pvp_nightmaredrop); checkflag(pvp_nocalcrank); checkflag(gvg_castle);
|
|
checkflag(gvg); checkflag(gvg_dungeon); checkflag(gvg_noparty); checkflag(battleground);
|
|
checkflag(nozenypenalty); checkflag(notrade); checkflag(noskill); checkflag(nowarp);
|
|
checkflag(nowarpto); checkflag(noicewall); checkflag(snow); checkflag(clouds);
|
|
checkflag(clouds2); checkflag(fog); checkflag(fireworks); checkflag(sakura);
|
|
checkflag(leaves); checkflag(nogo); checkflag(nobaseexp); checkflag(nojobexp);
|
|
checkflag(nomobloot); checkflag(nomvploot); checkflag(nightenabled); checkflag(restricted);
|
|
checkflag(nodrop); checkflag(novending); checkflag(loadevent); checkflag(nochat);
|
|
checkflag(partylock); checkflag(guildlock); checkflag(reset); checkflag(chmautojoin);
|
|
checkflag(nousecart); checkflag(noitemconsumption); checkflag(nosumstarmiracle); checkflag(nomineeffect);
|
|
checkflag(nolockon); checkflag(notomb);
|
|
#ifdef ADJUST_SKILL_DAMAGE
|
|
checkflag(skill_damage);
|
|
#endif
|
|
clif_displaymessage(sd->fd," ");
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1312)); // Usage: "@mapflag monster_noteleport 1" (0=Off | 1=On)
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1313)); // Type "@mapflag available" to list the available mapflags.
|
|
return 1;
|
|
}
|
|
for (i = 0; flag_name[i]; i++) flag_name[i] = (char)tolower(flag_name[i]); //lowercase
|
|
|
|
setflag(town); setflag(autotrade); setflag(allowks); setflag(nomemo);
|
|
setflag(noteleport); setflag(noreturn); setflag(monster_noteleport); setflag(nosave);
|
|
setflag(nobranch); setflag(noexppenalty); setflag(pvp); setflag(pvp_noparty);
|
|
setflag(pvp_noguild); setflag(pvp_nightmaredrop); setflag(pvp_nocalcrank); setflag(gvg_castle);
|
|
setflag(gvg); setflag(gvg_dungeon); setflag(gvg_noparty); setflag(battleground);
|
|
setflag(nozenypenalty); setflag(notrade); setflag(noskill); setflag(nowarp);
|
|
setflag(nowarpto); setflag(noicewall); setflag(snow); setflag(clouds);
|
|
setflag(clouds2); setflag(fog); setflag(fireworks); setflag(sakura);
|
|
setflag(leaves); setflag(nogo); setflag(nobaseexp); setflag(nojobexp);
|
|
setflag(nomobloot); setflag(nomvploot); setflag(nightenabled); setflag(restricted);
|
|
setflag(nodrop); setflag(novending); setflag(loadevent); setflag(nochat);
|
|
setflag(partylock); setflag(guildlock); setflag(reset); setflag(chmautojoin);
|
|
setflag(nousecart); setflag(noitemconsumption); setflag(nosumstarmiracle); setflag(nomineeffect);
|
|
setflag(nolockon); setflag(notomb);
|
|
#ifdef ADJUST_SKILL_DAMAGE
|
|
setflag(skill_damage);
|
|
#endif
|
|
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1314)); // Invalid flag name or flag.
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1312)); // Usage: "@mapflag monster_noteleport 1" (0=Off | 1=On)
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1315)); // Available Flags:
|
|
clif_displaymessage(sd->fd,"----------------------------------");
|
|
clif_displaymessage(sd->fd,"town, autotrade, allowks, nomemo, noteleport, noreturn, monster_noteleport, nosave,");
|
|
clif_displaymessage(sd->fd,"nobranch, noexppenalty, pvp, pvp_noparty, pvp_noguild, pvp_nightmaredrop,");
|
|
clif_displaymessage(sd->fd,"pvp_nocalcrank, gvg_castle, gvg, gvg_dungeon, gvg_noparty, battleground,");
|
|
clif_displaymessage(sd->fd,"nozenypenalty, notrade, noskill, nowarp, nowarpto, noicewall, snow, clouds, clouds2,");
|
|
clif_displaymessage(sd->fd,"fog, fireworks, sakura, leaves, nogo, nobaseexp, nojobexp, nomobloot, nomvploot,");
|
|
clif_displaymessage(sd->fd,"nightenabled, restricted, nodrop, novending, loadevent, nochat, partylock, guildlock,");
|
|
clif_displaymessage(sd->fd,"reset, chmautojoin, nousecart, noitemconsumption, nosumstarmiracle, nolockon, notomb");
|
|
#ifdef ADJUST_SKILL_DAMAGE
|
|
clif_displaymessage(sd->fd,"skill_damage");
|
|
#endif
|
|
|
|
#undef checkflag
|
|
#undef setflag
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*===================================
|
|
* Remove some messages
|
|
*-----------------------------------*/
|
|
ACMD_FUNC(showexp)
|
|
{
|
|
if (sd->state.showexp) {
|
|
sd->state.showexp = 0;
|
|
clif_displaymessage(fd, msg_txt(sd,1316)); // Gained exp will not be shown.
|
|
return 0;
|
|
}
|
|
|
|
sd->state.showexp = 1;
|
|
clif_displaymessage(fd, msg_txt(sd,1317)); // Gained exp is now shown.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(showzeny)
|
|
{
|
|
if (sd->state.showzeny) {
|
|
sd->state.showzeny = 0;
|
|
clif_displaymessage(fd, msg_txt(sd,1318)); // Gained zeny will not be shown.
|
|
return 0;
|
|
}
|
|
|
|
sd->state.showzeny = 1;
|
|
clif_displaymessage(fd, msg_txt(sd,1319)); // Gained zeny is now shown.
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(showdelay)
|
|
{
|
|
if (sd->state.showdelay) {
|
|
sd->state.showdelay = 0;
|
|
clif_displaymessage(fd, msg_txt(sd,1320)); // Skill delay failures will not be shown.
|
|
return 0;
|
|
}
|
|
|
|
sd->state.showdelay = 1;
|
|
clif_displaymessage(fd, msg_txt(sd,1321)); // Skill delay failures are now shown.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Duel organizing functions [LuzZza]
|
|
*
|
|
* @duel [limit|nick] - create a duel
|
|
* @invite <nick> - invite player
|
|
* @accept - accept invitation
|
|
* @reject - reject invitation
|
|
* @leave - leave duel
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(invite)
|
|
{
|
|
unsigned int did = sd->duel_group;
|
|
struct map_session_data *target_sd = map_nick2sd((char *)message);
|
|
|
|
if(did == 0) {
|
|
// "Duel: @invite without @duel."
|
|
clif_displaymessage(fd, msg_txt(sd,350));
|
|
return 0;
|
|
}
|
|
|
|
if(duel_list[did].max_players_limit > 0 &&
|
|
duel_list[did].members_count >= duel_list[did].max_players_limit) {
|
|
|
|
// "Duel: Limit of players is reached."
|
|
clif_displaymessage(fd, msg_txt(sd,351));
|
|
return 0;
|
|
}
|
|
|
|
if(target_sd == NULL) {
|
|
// "Duel: Player not found."
|
|
clif_displaymessage(fd, msg_txt(sd,352));
|
|
return 0;
|
|
}
|
|
|
|
if(target_sd->duel_group > 0 || target_sd->duel_invite > 0) {
|
|
// "Duel: Player already in duel."
|
|
clif_displaymessage(fd, msg_txt(sd,353));
|
|
return 0;
|
|
}
|
|
|
|
if(battle_config.duel_only_on_same_map && target_sd->bl.m != sd->bl.m)
|
|
{
|
|
sprintf(atcmd_output, msg_txt(sd,364), message);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
duel_invite(did, sd, target_sd);
|
|
// "Duel: Invitation has been sent."
|
|
clif_displaymessage(fd, msg_txt(sd,354));
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(duel)
|
|
{
|
|
unsigned int maxpl = 0;
|
|
|
|
if(sd->duel_group > 0) {
|
|
duel_showinfo(sd->duel_group, sd);
|
|
return 0;
|
|
}
|
|
|
|
if(sd->duel_invite > 0) {
|
|
// "Duel: @duel without @reject."
|
|
clif_displaymessage(fd, msg_txt(sd,355));
|
|
return 0;
|
|
}
|
|
|
|
if(!duel_checktime(sd)) {
|
|
char output[CHAT_SIZE_MAX];
|
|
// "Duel: You can take part in duel only one time per %d minutes."
|
|
sprintf(output, msg_txt(sd,356), battle_config.duel_time_interval);
|
|
clif_displaymessage(fd, output);
|
|
return 0;
|
|
}
|
|
|
|
if( message[0] ) {
|
|
if(sscanf(message, "%u", &maxpl) >= 1) {
|
|
if(maxpl < 2 || maxpl > 65535) {
|
|
clif_displaymessage(fd, msg_txt(sd,357)); // "Duel: Invalid value."
|
|
return 0;
|
|
}
|
|
duel_create(sd, maxpl);
|
|
} else {
|
|
struct map_session_data *target_sd;
|
|
target_sd = map_nick2sd((char *)message);
|
|
if(target_sd != NULL) {
|
|
unsigned int newduel;
|
|
if((newduel = duel_create(sd, 2)) != -1) {
|
|
if(target_sd->duel_group > 0 || target_sd->duel_invite > 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,353)); // "Duel: Player already in duel."
|
|
return 0;
|
|
}
|
|
duel_invite(newduel, sd, target_sd);
|
|
clif_displaymessage(fd, msg_txt(sd,354)); // "Duel: Invitation has been sent."
|
|
}
|
|
} else {
|
|
// "Duel: Player not found."
|
|
clif_displaymessage(fd, msg_txt(sd,352));
|
|
return 0;
|
|
}
|
|
}
|
|
} else
|
|
duel_create(sd, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
ACMD_FUNC(leave)
|
|
{
|
|
if(sd->duel_group <= 0) {
|
|
// "Duel: @leave without @duel."
|
|
clif_displaymessage(fd, msg_txt(sd,358));
|
|
return 0;
|
|
}
|
|
|
|
duel_leave(sd->duel_group, sd);
|
|
clif_displaymessage(fd, msg_txt(sd,359)); // "Duel: You left the duel."
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(accept)
|
|
{
|
|
if(!duel_checktime(sd)) {
|
|
char output[CHAT_SIZE_MAX];
|
|
// "Duel: You can take part in duel only one time per %d minutes."
|
|
sprintf(output, msg_txt(sd,356), battle_config.duel_time_interval);
|
|
clif_displaymessage(fd, output);
|
|
return 0;
|
|
}
|
|
|
|
if(sd->duel_invite <= 0) {
|
|
// "Duel: @accept without invititation."
|
|
clif_displaymessage(fd, msg_txt(sd,360));
|
|
return 0;
|
|
}
|
|
|
|
if( duel_list[sd->duel_invite].max_players_limit > 0 && duel_list[sd->duel_invite].members_count >= duel_list[sd->duel_invite].max_players_limit )
|
|
{
|
|
// "Duel: Limit of players is reached."
|
|
clif_displaymessage(fd, msg_txt(sd,351));
|
|
return 0;
|
|
}
|
|
|
|
duel_accept(sd->duel_invite, sd);
|
|
// "Duel: Invitation has been accepted."
|
|
clif_displaymessage(fd, msg_txt(sd,361));
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(reject)
|
|
{
|
|
if(sd->duel_invite <= 0) {
|
|
// "Duel: @reject without invititation."
|
|
clif_displaymessage(fd, msg_txt(sd,362));
|
|
return 0;
|
|
}
|
|
|
|
duel_reject(sd->duel_invite, sd);
|
|
// "Duel: Invitation has been rejected."
|
|
clif_displaymessage(fd, msg_txt(sd,363));
|
|
return 0;
|
|
}
|
|
|
|
/*===================================
|
|
* Cash Points
|
|
*-----------------------------------*/
|
|
ACMD_FUNC(cash)
|
|
{
|
|
char output[128];
|
|
int value;
|
|
int ret=0;
|
|
nullpo_retr(-1, sd);
|
|
|
|
if( !message || !*message || (value = atoi(message)) == 0 ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1322)); // Please enter an amount.
|
|
return -1;
|
|
}
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
if( !strcmpi(parent_cmd,"cash") )
|
|
{
|
|
if( value > 0 ) {
|
|
if( (ret=pc_getcash(sd, value, 0, LOG_TYPE_COMMAND)) >= 0){
|
|
// If this option is set, the message is already sent by pc function
|
|
if( !battle_config.cashshop_show_points ){
|
|
sprintf(output, msg_txt(sd,505), ret, sd->cashPoints);
|
|
clif_disp_onlyself(sd, output, strlen(output));
|
|
}
|
|
}
|
|
else clif_displaymessage(fd, msg_txt(sd,149)); // Unable to decrease the number/value.
|
|
} else {
|
|
if (-value > sd->cashPoints) //By command, if cash < value, force it to remove all
|
|
value = -sd->cashPoints;
|
|
if( (ret=pc_paycash(sd, -value, 0, LOG_TYPE_COMMAND)) >= 0){
|
|
// If this option is set, the message is already sent by pc function
|
|
if( !battle_config.cashshop_show_points ){
|
|
sprintf(output, msg_txt(sd,410), ret, sd->cashPoints);
|
|
clif_disp_onlyself(sd, output, strlen(output));
|
|
}
|
|
}
|
|
else clif_displaymessage(fd, msg_txt(sd,41)); // Unable to decrease the number/value.
|
|
}
|
|
}
|
|
else
|
|
{ // @points
|
|
if( value > 0 ) {
|
|
if( (ret=pc_getcash(sd, 0, value, LOG_TYPE_COMMAND)) >= 0){
|
|
sprintf(output, msg_txt(sd,506), ret, sd->kafraPoints);
|
|
clif_disp_onlyself(sd, output, strlen(output));
|
|
}
|
|
else clif_displaymessage(fd, msg_txt(sd,149)); // Unable to decrease the number/value.
|
|
} else {
|
|
if( (ret=pc_paycash(sd, -value, -value, LOG_TYPE_COMMAND)) >= 0){
|
|
sprintf(output, msg_txt(sd,411), ret, sd->kafraPoints);
|
|
clif_disp_onlyself(sd, output, strlen(output));
|
|
}
|
|
else clif_displaymessage(fd, msg_txt(sd,41)); // Unable to decrease the number/value.
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// @clone/@slaveclone/@evilclone <playername> [Valaris]
|
|
ACMD_FUNC(clone)
|
|
{
|
|
int x=0,y=0,flag=0,master=0,i=0;
|
|
struct map_session_data *pl_sd=NULL;
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1323)); // You must enter a player name or ID.
|
|
return 0;
|
|
}
|
|
|
|
if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return 0;
|
|
}
|
|
|
|
if(pc_get_group_level(pl_sd) > pc_get_group_level(sd)) {
|
|
clif_displaymessage(fd, msg_txt(sd,126)); // Cannot clone a player of higher GM level than yourself.
|
|
return 0;
|
|
}
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
if (strcmpi(parent_cmd, "clone") == 0)
|
|
flag = 1;
|
|
else if (strcmpi(parent_cmd, "slaveclone") == 0) {
|
|
flag = 2;
|
|
if(pc_isdead(sd)){
|
|
clif_displaymessage(fd, msg_txt(sd,129+flag*2));
|
|
return 0;
|
|
}
|
|
master = sd->bl.id;
|
|
if (battle_config.atc_slave_clone_limit
|
|
&& mob_countslave(&sd->bl) >= battle_config.atc_slave_clone_limit) {
|
|
clif_displaymessage(fd, msg_txt(sd,127)); // You've reached your slave clones limit.
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
do {
|
|
x = sd->bl.x + (rnd() % 10 - 5);
|
|
y = sd->bl.y + (rnd() % 10 - 5);
|
|
} while (map_getcell(sd->bl.m,x,y,CELL_CHKNOPASS) && i++ < 10);
|
|
|
|
if (i >= 10) {
|
|
x = sd->bl.x;
|
|
y = sd->bl.y;
|
|
}
|
|
|
|
if((x = mob_clone_spawn(pl_sd, sd->bl.m, x, y, "", master, 0, flag?1:0, 0)) > 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,128+flag*2)); // Evil Clone spawned. Clone spawned. Slave clone spawned.
|
|
return 0;
|
|
}
|
|
clif_displaymessage(fd, msg_txt(sd,129+flag*2)); // Unable to spawn evil clone. Unable to spawn clone. Unable to spawn slave clone.
|
|
return 0;
|
|
}
|
|
|
|
/*=====================================
|
|
* Autorejecting Invites/Deals [LuzZza]
|
|
* Usage: @noask
|
|
*-------------------------------------*/
|
|
ACMD_FUNC(noask)
|
|
{
|
|
if(sd->state.noask) {
|
|
clif_displaymessage(fd, msg_txt(sd,391)); // Autorejecting is deactivated.
|
|
sd->state.noask = 0;
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,390)); // Autorejecting is activated.
|
|
sd->state.noask = 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*=====================================
|
|
* Send a @request message to all GMs of lowest_gm_level.
|
|
* Usage: @request <petition>
|
|
*-------------------------------------*/
|
|
ACMD_FUNC(request)
|
|
{
|
|
if (!message || !*message) {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,277)); // Usage: @request <petition/message to online GMs>.
|
|
return -1;
|
|
}
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,278), message); // (@request): %s
|
|
intif_wis_message_to_gm(sd->status.name, PC_PERM_RECEIVE_REQUESTS, atcmd_output);
|
|
clif_disp_onlyself(sd, atcmd_output, strlen(atcmd_output));
|
|
clif_displaymessage(sd->fd,msg_txt(sd,279)); // @request sent.
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Feel (SG save map) Reset [HiddenDragon]
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(feelreset)
|
|
{
|
|
pc_resetfeel(sd);
|
|
clif_displaymessage(fd, msg_txt(sd,1324)); // Reset 'Feeling' maps.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* AUCTION SYSTEM
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(auction)
|
|
{
|
|
nullpo_ret(sd);
|
|
|
|
if (!battle_config.feature_auction) {
|
|
clif_colormes(sd, color_table[COLOR_RED], msg_txt(sd, 517));
|
|
return 0;
|
|
}
|
|
|
|
clif_Auction_openwindow(sd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Kill Steal Protection
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(ksprotection)
|
|
{
|
|
nullpo_retr(-1,sd);
|
|
|
|
if( sd->state.noks ) {
|
|
sd->state.noks = 0;
|
|
clif_displaymessage(fd, msg_txt(sd,1325)); // [ K.S Protection Inactive ]
|
|
}
|
|
else
|
|
{
|
|
if( !message || !*message || !strcmpi(message, "party") )
|
|
{ // Default is Party
|
|
sd->state.noks = 2;
|
|
clif_displaymessage(fd, msg_txt(sd,1326)); // [ K.S Protection Active - Option: Party ]
|
|
}
|
|
else if( !strcmpi(message, "self") )
|
|
{
|
|
sd->state.noks = 1;
|
|
clif_displaymessage(fd, msg_txt(sd,1327)); // [ K.S Protection Active - Option: Self ]
|
|
}
|
|
else if( !strcmpi(message, "guild") )
|
|
{
|
|
sd->state.noks = 3;
|
|
clif_displaymessage(fd, msg_txt(sd,1328)); // [ K.S Protection Active - Option: Guild ]
|
|
}
|
|
else
|
|
clif_displaymessage(fd, msg_txt(sd,1329)); // Usage: @noks <self|party|guild>
|
|
}
|
|
return 0;
|
|
}
|
|
/*==========================================
|
|
* Map Kill Steal Protection Setting
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(allowks)
|
|
{
|
|
nullpo_retr(-1,sd);
|
|
|
|
if( map[sd->bl.m].flag.allowks ) {
|
|
map[sd->bl.m].flag.allowks = 0;
|
|
clif_displaymessage(fd, msg_txt(sd,1330)); // [ Map K.S Protection Active ]
|
|
} else {
|
|
map[sd->bl.m].flag.allowks = 1;
|
|
clif_displaymessage(fd, msg_txt(sd,1331)); // [ Map K.S Protection Inactive ]
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(resetstat)
|
|
{
|
|
nullpo_retr(-1, sd);
|
|
|
|
pc_resetstate(sd);
|
|
sprintf(atcmd_output, msg_txt(sd,207), sd->status.name);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(resetskill)
|
|
{
|
|
nullpo_retr(-1,sd);
|
|
|
|
pc_resetskill(sd,1);
|
|
sprintf(atcmd_output, msg_txt(sd,206), sd->status.name);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* #storagelist: Displays the items list of a player's storage.
|
|
* #cartlist: Displays contents of target's cart.
|
|
* #itemlist: Displays contents of target's inventory.
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(itemlist)
|
|
{
|
|
int i, j, count, counter;
|
|
const char* location;
|
|
const struct item* items;
|
|
int size;
|
|
StringBuf buf;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
if( strcmp(parent_cmd, "storagelist") == 0 ) {
|
|
location = "storage";
|
|
items = sd->status.storage.items;
|
|
size = sd->storage_size;
|
|
} else if( strcmp(parent_cmd, "cartlist") == 0 ) {
|
|
location = "cart";
|
|
items = sd->status.cart;
|
|
size = MAX_CART;
|
|
} else if( strcmp(parent_cmd, "itemlist") == 0 ) {
|
|
location = "inventory";
|
|
items = sd->status.inventory;
|
|
size = MAX_INVENTORY;
|
|
} else
|
|
return 1;
|
|
|
|
StringBuf_Init(&buf);
|
|
|
|
count = 0; // total slots occupied
|
|
counter = 0; // total items found
|
|
for( i = 0; i < size; ++i ) {
|
|
const struct item* it = &items[i];
|
|
struct item_data* itd;
|
|
|
|
if( it->nameid == 0 || (itd = itemdb_exists(it->nameid)) == NULL )
|
|
continue;
|
|
|
|
counter += it->amount;
|
|
count++;
|
|
|
|
if( count == 1 ) {
|
|
StringBuf_Printf(&buf, msg_txt(sd,1332), location, sd->status.name); // ------ %s items list of '%s' ------
|
|
clif_displaymessage(fd, StringBuf_Value(&buf));
|
|
StringBuf_Clear(&buf);
|
|
}
|
|
|
|
if( it->refine )
|
|
StringBuf_Printf(&buf, "%d %s %+d (%s, id: %d)", it->amount, itd->jname, it->refine, itd->name, it->nameid);
|
|
else
|
|
StringBuf_Printf(&buf, "%d %s (%s, id: %d)", it->amount, itd->jname, itd->name, it->nameid);
|
|
|
|
if( it->equip ) {
|
|
char equipstr[CHAT_SIZE_MAX];
|
|
|
|
strcpy(equipstr, msg_txt(sd,1333)); // | Equipped:
|
|
if( it->equip&EQP_GARMENT )
|
|
strcat(equipstr, msg_txt(sd,1334)); // Robe,
|
|
if( it->equip&EQP_ACC_L )
|
|
strcat(equipstr, msg_txt(sd,1335)); // Left Accessory,
|
|
if( it->equip&EQP_ARMOR )
|
|
strcat(equipstr, msg_txt(sd,1336)); // Body/Armor,
|
|
if( (it->equip&EQP_ARMS) == EQP_HAND_R )
|
|
strcat(equipstr, msg_txt(sd,1337)); // Right Hand,
|
|
if( (it->equip&EQP_ARMS) == EQP_HAND_L )
|
|
strcat(equipstr, msg_txt(sd,1338)); // Left Hand,
|
|
if( (it->equip&EQP_ARMS) == EQP_ARMS )
|
|
strcat(equipstr, msg_txt(sd,1339)); // Both Hands,
|
|
if( it->equip&EQP_SHOES )
|
|
strcat(equipstr, msg_txt(sd,1340)); // Shoes,
|
|
if( it->equip&EQP_ACC_R )
|
|
strcat(equipstr, msg_txt(sd,1341)); // Right Accessory,
|
|
if( (it->equip&EQP_HELM) == EQP_HEAD_LOW )
|
|
strcat(equipstr, msg_txt(sd,1342)); // Lower Head,
|
|
if( (it->equip&EQP_HELM) == EQP_HEAD_TOP )
|
|
strcat(equipstr, msg_txt(sd,1343)); // Top Head,
|
|
if( (it->equip&EQP_HELM) == (EQP_HEAD_LOW|EQP_HEAD_TOP) )
|
|
strcat(equipstr, msg_txt(sd,1344)); // Top/Lower Head,
|
|
if( (it->equip&EQP_HELM) == EQP_HEAD_MID )
|
|
strcat(equipstr, msg_txt(sd,1345)); // Mid Head,
|
|
if( (it->equip&EQP_HELM) == (EQP_HEAD_LOW|EQP_HEAD_MID) )
|
|
strcat(equipstr, msg_txt(sd,1346)); // Mid/Lower Head,
|
|
if( (it->equip&EQP_HELM) == EQP_HELM )
|
|
strcat(equipstr, msg_txt(sd,1347)); // Top/Mid/Lower Head,
|
|
if( (it->equip&EQP_COSTUME_HELM) == EQP_COSTUME_HEAD_LOW )
|
|
strcat(equipstr, msg_txt(sd,518));
|
|
if( (it->equip&EQP_COSTUME_HELM) == EQP_COSTUME_HEAD_TOP )
|
|
strcat(equipstr, msg_txt(sd,519));
|
|
if( (it->equip&EQP_COSTUME_HELM) == (EQP_COSTUME_HEAD_LOW|EQP_COSTUME_HEAD_TOP) )
|
|
strcat(equipstr, msg_txt(sd,520));
|
|
if( (it->equip&EQP_COSTUME_HELM) == EQP_COSTUME_HEAD_MID )
|
|
strcat(equipstr, msg_txt(sd,521));
|
|
if( (it->equip&EQP_COSTUME_HELM) == (EQP_COSTUME_HEAD_LOW|EQP_COSTUME_HEAD_MID) )
|
|
strcat(equipstr, msg_txt(sd,522));
|
|
if( (it->equip&EQP_COSTUME_HELM) == EQP_COSTUME_HELM )
|
|
strcat(equipstr, msg_txt(sd,523));
|
|
if( it->equip&EQP_COSTUME_GARMENT )
|
|
strcat(equipstr, msg_txt(sd,524));
|
|
//if( it->equip&EQP_COSTUME_FLOOR )
|
|
//strcat(equipstr, msg_txt(sd,525));
|
|
if( it->equip&EQP_AMMO )
|
|
strcat(equipstr, msg_txt(sd,526));
|
|
if( it->equip&EQP_SHADOW_ARMOR )
|
|
strcat(equipstr, msg_txt(sd,527));
|
|
if( (it->equip&EQP_SHADOW_ARMS) == EQP_SHADOW_WEAPON )
|
|
strcat(equipstr, msg_txt(sd,528));
|
|
if( (it->equip&EQP_SHADOW_ARMS) == EQP_SHADOW_SHIELD )
|
|
strcat(equipstr, msg_txt(sd,529));
|
|
if( (it->equip&EQP_SHADOW_ARMS) == EQP_SHADOW_ARMS )
|
|
strcat(equipstr, msg_txt(sd,530));
|
|
if( it->equip&EQP_SHADOW_SHOES )
|
|
strcat(equipstr, msg_txt(sd,531));
|
|
if( it->equip&EQP_SHADOW_ACC_R )
|
|
strcat(equipstr, msg_txt(sd,532));
|
|
if( it->equip&EQP_SHADOW_ACC_L )
|
|
strcat(equipstr, msg_txt(sd,533));
|
|
// remove final ', '
|
|
equipstr[strlen(equipstr) - 2] = '\0';
|
|
StringBuf_AppendStr(&buf, equipstr);
|
|
}
|
|
|
|
clif_displaymessage(fd, StringBuf_Value(&buf));
|
|
StringBuf_Clear(&buf);
|
|
|
|
if( it->card[0] == CARD0_PET ) { // pet egg
|
|
if (it->card[3])
|
|
StringBuf_Printf(&buf, msg_txt(sd,1348), (unsigned int)MakeDWord(it->card[1], it->card[2])); // -> (pet egg, pet id: %u, named)
|
|
else
|
|
StringBuf_Printf(&buf, msg_txt(sd,1349), (unsigned int)MakeDWord(it->card[1], it->card[2])); // -> (pet egg, pet id: %u, unnamed)
|
|
} else if(it->card[0] == CARD0_FORGE) { // forged item
|
|
StringBuf_Printf(&buf, msg_txt(sd,1350), (unsigned int)MakeDWord(it->card[2], it->card[3]), it->card[1]>>8, it->card[1]&0x0f); // -> (crafted item, creator id: %u, star crumbs %d, element %d)
|
|
} else if(it->card[0] == CARD0_CREATE) { // created item
|
|
StringBuf_Printf(&buf, msg_txt(sd,1351), (unsigned int)MakeDWord(it->card[2], it->card[3])); // -> (produced item, creator id: %u)
|
|
} else { // normal item
|
|
int counter2 = 0;
|
|
|
|
for( j = 0; j < itd->slot; ++j ) {
|
|
struct item_data* card;
|
|
|
|
if( it->card[j] == 0 || (card = itemdb_exists(it->card[j])) == NULL )
|
|
continue;
|
|
|
|
counter2++;
|
|
|
|
if( counter2 == 1 )
|
|
StringBuf_AppendStr(&buf, msg_txt(sd,1352)); // -> (card(s):
|
|
|
|
if( counter2 != 1 )
|
|
StringBuf_AppendStr(&buf, ", ");
|
|
|
|
StringBuf_Printf(&buf, "#%d %s (id: %d)", counter2, card->jname, card->nameid);
|
|
}
|
|
|
|
if( counter2 > 0 )
|
|
StringBuf_AppendStr(&buf, ")");
|
|
}
|
|
|
|
if( StringBuf_Length(&buf) > 0 )
|
|
clif_displaymessage(fd, StringBuf_Value(&buf));
|
|
|
|
StringBuf_Clear(&buf);
|
|
}
|
|
|
|
if( count == 0 )
|
|
StringBuf_Printf(&buf, msg_txt(sd,1353), location); // No item found in this player's %s.
|
|
else
|
|
StringBuf_Printf(&buf, msg_txt(sd,1354), counter, count, location); // %d item(s) found in %d %s slots.
|
|
|
|
clif_displaymessage(fd, StringBuf_Value(&buf));
|
|
|
|
StringBuf_Destroy(&buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(stats)
|
|
{
|
|
char job_jobname[100];
|
|
char output[CHAT_SIZE_MAX];
|
|
int i;
|
|
struct {
|
|
const char* format;
|
|
int value;
|
|
} output_table[] = {
|
|
{ "Base Level - %d", 0 },
|
|
{ NULL, 0 },
|
|
{ "Hp - %d", 0 },
|
|
{ "MaxHp - %d", 0 },
|
|
{ "Sp - %d", 0 },
|
|
{ "MaxSp - %d", 0 },
|
|
{ "Str - %3d", 0 },
|
|
{ "Agi - %3d", 0 },
|
|
{ "Vit - %3d", 0 },
|
|
{ "Int - %3d", 0 },
|
|
{ "Dex - %3d", 0 },
|
|
{ "Luk - %3d", 0 },
|
|
{ "Zeny - %d", 0 },
|
|
{ "Free SK Points - %d", 0 },
|
|
{ "JobChangeLvl (2nd) - %d", 0 },
|
|
{ "JobChangeLvl (3rd) - %d", 0 },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
memset(job_jobname, '\0', sizeof(job_jobname));
|
|
memset(output, '\0', sizeof(output));
|
|
|
|
//direct array initialization with variables is not standard C compliant.
|
|
output_table[0].value = sd->status.base_level;
|
|
output_table[1].format = job_jobname;
|
|
output_table[1].value = sd->status.job_level;
|
|
output_table[2].value = sd->status.hp;
|
|
output_table[3].value = sd->status.max_hp;
|
|
output_table[4].value = sd->status.sp;
|
|
output_table[5].value = sd->status.max_sp;
|
|
output_table[6].value = sd->status.str;
|
|
output_table[7].value = sd->status.agi;
|
|
output_table[8].value = sd->status.vit;
|
|
output_table[9].value = sd->status.int_;
|
|
output_table[10].value = sd->status.dex;
|
|
output_table[11].value = sd->status.luk;
|
|
output_table[12].value = sd->status.zeny;
|
|
output_table[13].value = sd->status.skill_point;
|
|
output_table[14].value = sd->change_level_2nd;
|
|
output_table[15].value = sd->change_level_3rd;
|
|
|
|
sprintf(job_jobname, "Job - %s %s", job_name(sd->status.class_), "(level %d)");
|
|
sprintf(output, msg_txt(sd,53), sd->status.name); // '%s' stats:
|
|
|
|
clif_displaymessage(fd, output);
|
|
|
|
for (i = 0; output_table[i].format != NULL; i++) {
|
|
sprintf(output, output_table[i].format, output_table[i].value);
|
|
clif_displaymessage(fd, output);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(delitem)
|
|
{
|
|
char item_name[100];
|
|
unsigned short nameid;
|
|
int amount = 0, total, idx;
|
|
struct item_data* id;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
if( !message || !*message || ( sscanf(message, "\"%99[^\"]\" %d", item_name, &amount) < 2 && sscanf(message, "%99s %d", item_name, &amount) < 2 ) || amount < 1 )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1355)); // Please enter an item name/ID, a quantity, and a player name (usage: #delitem <player> <item_name_or_ID> <quantity>).
|
|
return -1;
|
|
}
|
|
|
|
if( ( id = itemdb_searchname(item_name) ) != NULL || ( id = itemdb_exists(atoi(item_name)) ) != NULL )
|
|
{
|
|
nameid = id->nameid;
|
|
}
|
|
else
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,19)); // Invalid item ID or name.
|
|
return -1;
|
|
}
|
|
|
|
total = amount;
|
|
|
|
// delete items
|
|
while( amount && ( idx = pc_search_inventory(sd, nameid) ) != -1 )
|
|
{
|
|
int delamount = ( amount < sd->status.inventory[idx].amount ) ? amount : sd->status.inventory[idx].amount;
|
|
|
|
if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET )
|
|
{// delete pet
|
|
intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
|
|
}
|
|
pc_delitem(sd, idx, delamount, 0, 0, LOG_TYPE_COMMAND);
|
|
|
|
amount-= delamount;
|
|
}
|
|
|
|
// notify target
|
|
sprintf(atcmd_output, msg_txt(sd,113), total-amount); // %d item(s) removed by a GM.
|
|
clif_displaymessage(sd->fd, atcmd_output);
|
|
|
|
// notify source
|
|
if( amount == total )
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,116)); // Character does not have the item.
|
|
}
|
|
else if( amount )
|
|
{
|
|
sprintf(atcmd_output, msg_txt(sd,115), total-amount, total-amount, total); // %d item(s) removed. Player had only %d on %d items.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
else
|
|
{
|
|
sprintf(atcmd_output, msg_txt(sd,114), total); // %d item(s) removed from the player.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* Custom Fonts
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(font)
|
|
{
|
|
int font_id;
|
|
nullpo_retr(-1,sd);
|
|
|
|
font_id = atoi(message);
|
|
if( font_id == 0 ) {
|
|
if( sd->status.font ) {
|
|
sd->status.font = 0;
|
|
clif_displaymessage(fd, msg_txt(sd,1356)); // Returning to normal font.
|
|
clif_font(sd);
|
|
} else {
|
|
clif_displaymessage(fd, msg_txt(sd,1357)); // Use @font <1-9> to change your message font.
|
|
clif_displaymessage(fd, msg_txt(sd,1358)); // Use 0 or no parameter to return to normal font.
|
|
}
|
|
} else if( font_id < 0 || font_id > 9 )
|
|
clif_displaymessage(fd, msg_txt(sd,1359)); // Invalid font. Use a value from 0 to 9.
|
|
else if( font_id != sd->status.font ) {
|
|
sd->status.font = font_id;
|
|
clif_font(sd);
|
|
clif_displaymessage(fd, msg_txt(sd,1360)); // Font changed.
|
|
} else
|
|
clif_displaymessage(fd, msg_txt(sd,1361)); // Already using this font.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* type: 1 = commands (@), 2 = charcommands (#)
|
|
*------------------------------------------*/
|
|
static void atcommand_commands_sub(struct map_session_data* sd, const int fd, AtCommandType type)
|
|
{
|
|
char line_buff[CHATBOX_SIZE];
|
|
char* cur = line_buff;
|
|
AtCommandInfo* cmd;
|
|
DBIterator *iter = db_iterator(atcommand_db);
|
|
int count = 0;
|
|
|
|
memset(line_buff,' ',CHATBOX_SIZE);
|
|
line_buff[CHATBOX_SIZE-1] = 0;
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,273)); // "Commands available:"
|
|
|
|
for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) {
|
|
unsigned int slen = 0;
|
|
|
|
switch( type ) {
|
|
case COMMAND_CHARCOMMAND:
|
|
if( cmd->char_groups[sd->group_pos] == 0 )
|
|
continue;
|
|
break;
|
|
case COMMAND_ATCOMMAND:
|
|
if( cmd->at_groups[sd->group_pos] == 0 )
|
|
continue;
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
|
|
slen = strlen(cmd->command);
|
|
|
|
// flush the text buffer if this command won't fit into it
|
|
if (slen + cur - line_buff >= CHATBOX_SIZE) {
|
|
clif_displaymessage(fd,line_buff);
|
|
cur = line_buff;
|
|
memset(line_buff,' ',CHATBOX_SIZE);
|
|
line_buff[CHATBOX_SIZE-1] = 0;
|
|
}
|
|
|
|
memcpy(cur,cmd->command,slen);
|
|
cur += slen+(10-slen%10);
|
|
|
|
count++;
|
|
}
|
|
dbi_destroy(iter);
|
|
clif_displaymessage(fd,line_buff);
|
|
|
|
if ( atcmd_binding_count ) {
|
|
int i, count_bind, gm_lvl = pc_get_group_level(sd);
|
|
for( i = count_bind = 0; i < atcmd_binding_count; i++ ) {
|
|
if ( gm_lvl >= ( (type - 1) ? atcmd_binding[i]->level2 : atcmd_binding[i]->level ) ) {
|
|
unsigned int slen = strlen(atcmd_binding[i]->command);
|
|
if ( count_bind == 0 ) {
|
|
cur = line_buff;
|
|
memset(line_buff,' ',CHATBOX_SIZE);
|
|
line_buff[CHATBOX_SIZE-1] = 0;
|
|
clif_displaymessage(fd, "-----------------");
|
|
clif_displaymessage(fd, msg_txt(sd,509)); // Script-bound commands:
|
|
}
|
|
if (slen + cur - line_buff >= CHATBOX_SIZE) {
|
|
clif_displaymessage(fd,line_buff);
|
|
cur = line_buff;
|
|
memset(line_buff,' ',CHATBOX_SIZE);
|
|
line_buff[CHATBOX_SIZE-1] = 0;
|
|
}
|
|
memcpy(cur,atcmd_binding[i]->command,slen);
|
|
cur += slen+(10-slen%10);
|
|
count_bind++;
|
|
}
|
|
}
|
|
if ( count_bind )
|
|
clif_displaymessage(fd,line_buff);// last one
|
|
count += count_bind;
|
|
|
|
}
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,274), count); // "%d commands found."
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return;
|
|
}
|
|
|
|
/*==========================================
|
|
* @commands Lists available @ commands to you
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(commands)
|
|
{
|
|
atcommand_commands_sub(sd, fd, COMMAND_ATCOMMAND);
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================
|
|
* @charcommands Lists available # commands to you
|
|
*------------------------------------------*/
|
|
ACMD_FUNC(charcommands) {
|
|
atcommand_commands_sub(sd, fd, COMMAND_CHARCOMMAND);
|
|
return 0;
|
|
}
|
|
/* for new mounts */
|
|
ACMD_FUNC(mount2) {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1362)); // NOTICE: If you crash with mount your LUA is outdated.
|
|
if (!&sd->sc || !(sd->sc.data[SC_ALL_RIDING])) {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1363)); // You have mounted.
|
|
sc_start(NULL, &sd->bl, SC_ALL_RIDING, 10000, 1, INVALID_TIMER);
|
|
} else {
|
|
clif_displaymessage(sd->fd,msg_txt(sd,1364)); // You have released your mount.
|
|
if (&sd->sc)
|
|
status_change_end(&sd->bl, SC_ALL_RIDING, INVALID_TIMER);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(accinfo) {
|
|
char query[NAME_LENGTH];
|
|
char type = 0; // type = 1, get only account name
|
|
|
|
if (!message || !*message || strlen(message) > NAME_LENGTH
|
|
|| ( sscanf(message, "%31s %c", query, &type) < 1))
|
|
{
|
|
clif_displaymessage(fd, msg_txt(sd,1365)); // Usage: @accinfo/@accountinfo <account_id/char name>
|
|
clif_displaymessage(fd, msg_txt(sd,1366)); // You may search partial name by making use of '%' in the search, ex. "@accinfo %Mario%" lists all characters whose name contains "Mario".
|
|
return -1;
|
|
} else if (type != 0) {
|
|
type = type-'0'; //make it int
|
|
if (type != 1) {
|
|
clif_displaymessage(fd, "accinfo : Unknow type specified\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
intif_request_accinfo( sd->fd, sd->bl.id, pc_get_group_level(sd), query, type);
|
|
return 0;
|
|
}
|
|
|
|
/* [Ind] */
|
|
ACMD_FUNC(set) {
|
|
char reg[32], val[128];
|
|
struct script_data* data;
|
|
int toset = 0, len;
|
|
bool is_str = false;
|
|
|
|
if( !message || !*message || (toset = sscanf(message, "%31s %128[^\n]s", reg, val)) < 1 ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1367)); // Usage: @set <variable name> <value>
|
|
clif_displaymessage(fd, msg_txt(sd,1368)); // Usage: ex. "@set PoringCharVar 50"
|
|
clif_displaymessage(fd, msg_txt(sd,1369)); // Usage: ex. "@set PoringCharVarSTR$ Super Duper String"
|
|
clif_displaymessage(fd, msg_txt(sd,1370)); // Usage: ex. "@set PoringCharVarSTR$" outputs its value, Super Duper String.
|
|
return -1;
|
|
}
|
|
|
|
/* disabled variable types (they require a proper script state to function, so allowing them would crash the server) */
|
|
if( reg[0] == '.' ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1371)); // NPC variables may not be used with @set.
|
|
return -1;
|
|
} else if( reg[0] == '\'' ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1372)); // Instance variables may not be used with @set.
|
|
return -1;
|
|
}
|
|
|
|
is_str = ( reg[strlen(reg) - 1] == '$' );
|
|
|
|
if( ( len = strlen(val) ) > 1 ) {
|
|
if( val[0] == '"' && val[len-1] == '"') {
|
|
val[len-1] = '\0'; //Strip quotes.
|
|
memmove(val, val+1, len-1);
|
|
}
|
|
}
|
|
|
|
if( toset >= 2 ) {/* we only set the var if there is an val, otherwise we only output the value */
|
|
if( is_str )
|
|
set_var(sd, reg, (void*) val);
|
|
else
|
|
set_var(sd, reg, (void*)__64BPRTSIZE((atoi(val))));
|
|
|
|
}
|
|
|
|
CREATE(data, struct script_data,1);
|
|
|
|
|
|
if( is_str ) {// string variable
|
|
|
|
switch( reg[0] ) {
|
|
case '@':
|
|
data->u.str = pc_readregstr(sd, add_str(reg));
|
|
break;
|
|
case '$':
|
|
data->u.str = mapreg_readregstr(add_str(reg));
|
|
break;
|
|
case '#':
|
|
if( reg[1] == '#' )
|
|
data->u.str = pc_readaccountreg2str(sd, reg);// global
|
|
else
|
|
data->u.str = pc_readaccountregstr(sd, reg);// local
|
|
break;
|
|
default:
|
|
data->u.str = pc_readglobalreg_str(sd, reg);
|
|
break;
|
|
}
|
|
|
|
if( data->u.str == NULL || data->u.str[0] == '\0' ) {// empty string
|
|
data->type = C_CONSTSTR;
|
|
data->u.str = "";
|
|
} else {// duplicate string
|
|
data->type = C_STR;
|
|
data->u.str = aStrdup(data->u.str);
|
|
}
|
|
|
|
} else {// integer variable
|
|
|
|
data->type = C_INT;
|
|
switch( reg[0] ) {
|
|
case '@':
|
|
data->u.num = pc_readreg(sd, add_str(reg));
|
|
break;
|
|
case '$':
|
|
data->u.num = mapreg_readreg(add_str(reg));
|
|
break;
|
|
case '#':
|
|
if( reg[1] == '#' )
|
|
data->u.num = pc_readaccountreg2(sd, reg);// global
|
|
else
|
|
data->u.num = pc_readaccountreg(sd, reg);// local
|
|
break;
|
|
default:
|
|
data->u.num = pc_readglobalreg(sd, reg);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
switch( data->type ) {
|
|
case C_INT:
|
|
sprintf(atcmd_output,msg_txt(sd,1373),reg,data->u.num); // %s value is now :%d
|
|
break;
|
|
case C_STR:
|
|
sprintf(atcmd_output,msg_txt(sd,1374),reg,data->u.str); // %s value is now :%s
|
|
break;
|
|
case C_CONSTSTR:
|
|
sprintf(atcmd_output,msg_txt(sd,1375),reg); // %s is empty
|
|
break;
|
|
default:
|
|
sprintf(atcmd_output,msg_txt(sd,1376),reg,data->type); // %s data type is not supported :%u
|
|
break;
|
|
}
|
|
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
aFree(data);
|
|
|
|
return 0;
|
|
}
|
|
ACMD_FUNC(addperm) {
|
|
int perm_size = ARRAYLENGTH(pc_g_permission_name);
|
|
bool add;
|
|
int i;
|
|
|
|
parent_cmd = atcommand_checkalias(command+1);
|
|
|
|
add = (strcmpi(parent_cmd, "addperm") == 0);
|
|
|
|
if( !message || !*message ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1378),command); // Usage: %s <permission_name>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1379)); // -- Permission List
|
|
for( i = 0; i < perm_size; i++ ) {
|
|
sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
ARR_FIND(0, perm_size, i, strcmpi(pc_g_permission_name[i].name, message) == 0);
|
|
|
|
if( i == perm_size ) {
|
|
sprintf(atcmd_output,msg_txt(sd,1380),message); // '%s' is not a known permission.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1379)); // -- Permission List
|
|
for( i = 0; i < perm_size; i++ ) {
|
|
sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
if( add && (sd->permissions&pc_g_permission_name[i].permission) ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1381),sd->status.name,pc_g_permission_name[i].name); // User '%s' already possesses the '%s' permission.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
} else if ( !add && !(sd->permissions&pc_g_permission_name[i].permission) ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1382),sd->status.name,pc_g_permission_name[i].name); // User '%s' doesn't possess the '%s' permission.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
sprintf(atcmd_output,msg_txt(sd,1383),sd->status.name); // -- User '%s' Permissions
|
|
clif_displaymessage(fd, atcmd_output);
|
|
for( i = 0; i < perm_size; i++ ) {
|
|
if( sd->permissions&pc_g_permission_name[i].permission ) {
|
|
sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name);
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
if( add )
|
|
sd->permissions |= pc_g_permission_name[i].permission;
|
|
else
|
|
sd->permissions &=~ pc_g_permission_name[i].permission;
|
|
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,1384),sd->status.name); // User '%s' permissions updated successfully. The changes are temporary.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
ACMD_FUNC(unloadnpcfile) {
|
|
|
|
if( !message || !*message ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1385)); // Usage: @unloadnpcfile <file name>
|
|
return -1;
|
|
}
|
|
|
|
if( npc_unloadfile(message) )
|
|
clif_displaymessage(fd, msg_txt(sd,1386)); // File unloaded. Be aware that mapflags and monsters spawned directly are not removed.
|
|
else {
|
|
clif_displaymessage(fd, msg_txt(sd,1387)); // File not found.
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
ACMD_FUNC(cart) {
|
|
#define MC_CART_MDFY(x) \
|
|
sd->status.skill[MC_PUSHCART].id = x?MC_PUSHCART:0; \
|
|
sd->status.skill[MC_PUSHCART].lv = x?1:0; \
|
|
sd->status.skill[MC_PUSHCART].flag = x?SKILL_FLAG_TEMPORARY:SKILL_FLAG_PERMANENT;
|
|
|
|
int val = atoi(message);
|
|
bool need_skill = (pc_checkskill(sd, MC_PUSHCART) == 0);
|
|
|
|
if( !message || !*message || val < 0 || val > MAX_CARTS ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1390),command,MAX_CARTS); // Unknown Cart (usage: %s <0-%d>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
if( val == 0 && !pc_iscarton(sd) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1391)); // You do not possess a cart to be removed
|
|
return -1;
|
|
}
|
|
|
|
if( need_skill ) {
|
|
MC_CART_MDFY(1);
|
|
}
|
|
|
|
if( !pc_setcart(sd, val) ) {
|
|
if( need_skill ) {
|
|
MC_CART_MDFY(0);
|
|
}
|
|
return -1;/* @cart failed */
|
|
}
|
|
|
|
if( need_skill ) {
|
|
MC_CART_MDFY(0);
|
|
}
|
|
|
|
clif_displaymessage(fd, msg_txt(sd,1392)); // Cart Added
|
|
|
|
return 0;
|
|
#undef MC_CART_MDFY
|
|
}
|
|
|
|
/* Channel System [Ind] */
|
|
ACMD_FUNC(join){
|
|
char chname[CHAN_NAME_LENGTH], pass[CHAN_NAME_LENGTH];
|
|
|
|
if( !message || !*message || sscanf(message, "%19s %19s", chname, pass) < 1 ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1399),command); // Unknown channel (usage: %s <#channel_name>).
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
return channel_pcjoin(sd, chname, pass);
|
|
}
|
|
/*
|
|
* Display available option for @channel command
|
|
* @command : the name of used command (for alias case)
|
|
*/
|
|
static inline void atcmd_channel_help(struct map_session_data *sd, const char *command)
|
|
{
|
|
int fd = sd->fd;
|
|
bool can_delete = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN);
|
|
bool can_create = (can_delete || channel_config.user_chenable);
|
|
clif_displaymessage(fd, msg_txt(sd,1414));// ---- Available options:
|
|
|
|
//option create
|
|
if( can_create ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1415),command);// * %s create <#channel_name> <channel_password>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1416));// -- Creates a new channel.
|
|
}
|
|
|
|
//option delete
|
|
if(can_delete){
|
|
sprintf(atcmd_output, msg_txt(sd,1469),command);// * %s delete <#channel_name>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1470)); // -- Destroys the specified channel.
|
|
}
|
|
|
|
//option list
|
|
sprintf(atcmd_output, msg_txt(sd,1417),command);// * %s list
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1418));// -- Lists all public channels.
|
|
sprintf(atcmd_output, msg_txt(sd,1471),command);// * %s list mine
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1472));// -- Lists all channels you have joined.
|
|
if( can_create ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1419),command);// * %s list colors
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1420));// -- Lists all available colors for custom channels.
|
|
}
|
|
|
|
//option setcolor
|
|
if(can_create){
|
|
sprintf(atcmd_output, msg_txt(sd,1421),command);// * %s setcolor <#channel_name> <color_name>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1422));// -- Changes channel text to the specified color (channel owners only).
|
|
}
|
|
|
|
//option join
|
|
sprintf(atcmd_output, msg_txt(sd,1473),command);// * %s join <#channel_name> <channel_password>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1474));// -- Joins the specified channel.
|
|
|
|
//option leave
|
|
sprintf(atcmd_output, msg_txt(sd,1423),command);// * %s leave <#channel_name>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1424));// -- Leaves the specified channel.
|
|
|
|
//option bindto
|
|
sprintf(atcmd_output, msg_txt(sd,1427),command);// * %s bindto <#channel_name>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1428));// -- Binds your global chat to the specified channel, sending all global messages to that channel.
|
|
|
|
//option unbind
|
|
sprintf(atcmd_output, msg_txt(sd,1429),command);// * %s unbind
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1430));// -- Unbinds your global chat from the attached channel, if any.
|
|
|
|
//option ban/unban/banlist
|
|
if( can_create ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1456),command);// * %s ban <#channel_name> <player>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1457));// -- Bans the specified player from the channel.
|
|
sprintf(atcmd_output, msg_txt(sd,1458),command);// * %s banlist <#channel_name>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1459));// -- Lists all players banned from the specified channel.
|
|
sprintf(atcmd_output, msg_txt(sd,1460),command);// * %s unban <#channel_name> <player>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1461));// -- Unbans the specified player from the channel.
|
|
sprintf(atcmd_output, msg_txt(sd,1467),command);// * %s unbanall <#channel_name>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1468));// -- Clears all bans from the specified channel.
|
|
}
|
|
|
|
//option setopt
|
|
if(can_create){
|
|
sprintf(atcmd_output, msg_txt(sd,1462),command);// * %s setopt <#channel_name> <option> <value>
|
|
clif_displaymessage(fd, atcmd_output);
|
|
clif_displaymessage(fd, msg_txt(sd,1463));// -- Sets an option and value for the specified channel.
|
|
}
|
|
|
|
sprintf(atcmd_output, msg_txt(sd,1404),command); // %s failed.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
}
|
|
|
|
ACMD_FUNC(channel) {
|
|
char key[NAME_LENGTH], sub1[CHAN_NAME_LENGTH], sub2[64];
|
|
sub1[0] = sub2[0] = '\0';
|
|
|
|
if( !message || !*message || sscanf(message, "%23s %19s %63[^\n]", key, sub1, sub2) < 1 ) {
|
|
atcmd_channel_help(sd,command);
|
|
return 0;
|
|
}
|
|
|
|
if( strcmpi(key,"delete") == 0 && pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) {
|
|
return channel_pcdelete(sd,sub1);
|
|
} else if ( strcmpi(key,"list") == 0 ) {
|
|
return channel_display_list(sd,sub1);
|
|
} else if ( strcmpi(key,"setcolor") == 0 ) {
|
|
return channel_pccolor(sd, sub1, sub2);
|
|
} else if ( strcmpi(key,"join") == 0 ) {
|
|
return channel_pcjoin(sd, sub1, sub2);
|
|
}else if ( strcmpi(key,"leave") == 0 ) {
|
|
return channel_pcleave(sd, sub1);
|
|
} else if ( strcmpi(key,"bindto") == 0 ) {
|
|
return channel_pcbind(sd, sub1);
|
|
} else if ( strcmpi(key,"unbind") == 0 ) {
|
|
return channel_pcunbind(sd);
|
|
} else if ( strcmpi(key,"ban") == 0 ) {
|
|
return channel_pcban(sd,sub1,sub2,0);
|
|
} else if ( strcmpi(key,"banlist") == 0 ) {
|
|
return channel_pcban(sd,sub1,NULL,3);
|
|
} else if ( strcmpi(key,"unban") == 0 ) {
|
|
return channel_pcban(sd,sub1,sub2,1);
|
|
} else if ( strcmpi(key,"unbanall") == 0 ) {
|
|
return channel_pcban(sd,sub1,NULL,2);
|
|
} else {
|
|
char sub3[CHAN_NAME_LENGTH], sub4[CHAN_NAME_LENGTH];
|
|
sub3[0] = sub4[0] = '\0';
|
|
sscanf(sub2, "%19s %19s", sub3, sub4);
|
|
if( strcmpi(key,"create") == 0 && ( channel_config.user_chenable || pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) ) {
|
|
if (sub4[0] != '\0') {
|
|
clif_displaymessage(fd, msg_txt(sd, 1408)); // Channel password may not contain spaces.
|
|
return -1;
|
|
}
|
|
return channel_pccreate(sd,sub1,sub3);
|
|
} else if ( strcmpi(key,"setopt") == 0 ) {
|
|
return channel_pcsetopt(sd,sub1,sub3,sub4);
|
|
}
|
|
atcmd_channel_help(sd,command);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(fontcolor)
|
|
{
|
|
if( !message || !*message ) {
|
|
channel_display_list(sd,"colors");
|
|
return -1;
|
|
}
|
|
|
|
if( strcmpi(message,"Normal") == 0 ) {
|
|
sd->fontcolor = 0;
|
|
} else {
|
|
unsigned char k;
|
|
ARR_FIND(0,channel_config.colors_count,k,( strcmpi(message,channel_config.colors_name[k]) == 0 ));
|
|
if( k == channel_config.colors_count ) {
|
|
sprintf(atcmd_output, msg_txt(sd,1411), message);// Unknown color '%s'.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
sd->fontcolor = k;
|
|
}
|
|
sprintf(atcmd_output, msg_txt(sd,1454), message);// Color set to '%s'.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(langtype)
|
|
{
|
|
char langstr[8];
|
|
int i=0, fail=0;
|
|
|
|
memset(langstr, '\0', sizeof(langstr));
|
|
|
|
if(sscanf(message, "%3s", langstr) >= 1){
|
|
int lang=0;
|
|
lang = msg_langstr2langtype(langstr); //Switch langstr to associated langtype
|
|
if( msg_checklangtype(lang,false) == 1 ){ //Verify it's enabled and set it
|
|
char output[100];
|
|
pc_setaccountreg(sd, "#langtype", lang); //For login/char
|
|
sd->langtype = lang;
|
|
sprintf(output,msg_txt(sd,461),msg_langtype2langstr(lang)); // Language is now set to %s.
|
|
clif_displaymessage(fd,output);
|
|
return 0;
|
|
} else if (lang != -1) { //defined langage but failed check
|
|
clif_displaymessage(fd,msg_txt(sd,462)); // This langage is currently disabled.
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
//wrong or no entry
|
|
clif_displaymessage(fd,msg_txt(sd,460)); // Please enter a valid language (usage: @langtype <language>).
|
|
clif_displaymessage(fd,msg_txt(sd,464)); // ---- Available languages:
|
|
while(fail != -1){ //out of range
|
|
fail = msg_checklangtype(i,false);
|
|
if(fail == 1)
|
|
clif_displaymessage(fd,msg_langtype2langstr(i));
|
|
i++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#ifdef VIP_ENABLE
|
|
ACMD_FUNC(vip) {
|
|
struct map_session_data *pl_sd = NULL;
|
|
char * modif_p;
|
|
int32 vipdifftime = 0;
|
|
time_t now=time(NULL);
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
|
|
if (!message || !*message || sscanf(message, "%255s %23[^\n]",atcmd_output,atcmd_player_name) < 2) {
|
|
clif_displaymessage(fd, msg_txt(sd,700)); //Usage: @vip <timef> <character name>
|
|
return -1;
|
|
}
|
|
|
|
atcmd_output[sizeof(atcmd_output)-1] = '\0';
|
|
|
|
modif_p = atcmd_output;
|
|
vipdifftime = (int32)solve_time(modif_p);
|
|
if (vipdifftime == 0) {
|
|
clif_displaymessage(fd, msg_txt(sd,701)); // Invalid time for vip command.
|
|
clif_displaymessage(fd, msg_txt(sd,702)); // Time parameter format is +/-<value> to alter. y/a = Year, m = Month, d/j = Day, h = Hour, n/mn = Minute, s = Second.
|
|
return -1;
|
|
}
|
|
|
|
if ((pl_sd = map_nick2sd(atcmd_player_name)) == NULL) {
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
if (pc_get_group_level(pl_sd) > pc_get_group_level(sd)) {
|
|
clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
|
|
return -1;
|
|
}
|
|
if(pl_sd->vip.time==0) pl_sd->vip.time=now;
|
|
pl_sd->vip.time += vipdifftime; //increase or reduce VIP duration
|
|
|
|
if (pl_sd->vip.time <= now) {
|
|
pl_sd->vip.time = 0;
|
|
pl_sd->vip.enabled = 0;
|
|
clif_displaymessage(pl_sd->fd, msg_txt(pl_sd,703)); // GM has removed your VIP time.
|
|
clif_displaymessage(fd, msg_txt(sd,704)); // Player is no longer VIP.
|
|
} else {
|
|
int year,month,day,hour,minute,second;
|
|
char timestr[21];
|
|
|
|
split_time((int)(pl_sd->vip.time-now),&year,&month,&day,&hour,&minute,&second);
|
|
sprintf(atcmd_output,msg_txt(pl_sd,705),year,month,day,hour,minute); // Your VIP status is valid for %d years, %d months, %d days, %d hours and %d minutes.
|
|
clif_displaymessage(pl_sd->fd,atcmd_output);
|
|
timestamp2string(timestr,20,pl_sd->vip.time,"%Y-%m-%d %H:%M");
|
|
sprintf(atcmd_output,msg_txt(pl_sd,707),timestr); // You are VIP until : %s
|
|
clif_displaymessage(pl_sd->fd,atcmd_output);
|
|
|
|
if (pl_sd != sd) {
|
|
sprintf(atcmd_output,msg_txt(sd,706),pl_sd->status.name,year,month,day,hour,minute); // Player '%s' is now VIP for %d years, %d months, %d days, %d hours and %d minutes.
|
|
clif_displaymessage(fd,atcmd_output);
|
|
sprintf(atcmd_output,msg_txt(sd,708),timestr); // The player is now VIP until : %s
|
|
clif_displaymessage(fd,atcmd_output);
|
|
}
|
|
}
|
|
chrif_req_login_operation(pl_sd->status.account_id, pl_sd->status.name, CHRIF_OP_LOGIN_VIP, vipdifftime, 7, 0);
|
|
return 0;
|
|
}
|
|
|
|
/** Enable/disable rate info */
|
|
ACMD_FUNC(showrate) {
|
|
nullpo_retr(-1,sd);
|
|
if (!sd->disableshowrate) {
|
|
sprintf(atcmd_output,msg_txt(sd,718)); //Personal rate information is not displayed now.
|
|
sd->disableshowrate = 1;
|
|
}
|
|
else {
|
|
sprintf(atcmd_output,msg_txt(sd,719)); //Personal rate information will be shown.
|
|
sd->disableshowrate = 0;
|
|
}
|
|
clif_displaymessage(fd,atcmd_output);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
ACMD_FUNC(fullstrip) {
|
|
int i;
|
|
TBL_PC *tsd;
|
|
|
|
nullpo_retr(-1,sd);
|
|
|
|
if (!message || !*message) {
|
|
clif_displaymessage(fd, msg_txt(sd,349)); // Please enter a player name (usage: @fullstrip/@warpto/@goto <char name/ID>).
|
|
return -1;
|
|
}
|
|
|
|
if((tsd=map_nick2sd((char *)message)) == NULL && (tsd=map_id2sd(atoi(message))) == NULL){
|
|
clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
|
|
return -1;
|
|
}
|
|
|
|
for( i = 0; i < EQI_MAX; i++ ) {
|
|
if( tsd->equip_index[ i ] >= 0 )
|
|
pc_unequipitem( tsd , tsd->equip_index[ i ] , 2 );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ACMD_FUNC(costume) {
|
|
const char* names[] = {
|
|
"Wedding",
|
|
"Xmas",
|
|
"Summer",
|
|
"Hanbok",
|
|
"Oktoberfest",
|
|
};
|
|
const int name2id[] = {
|
|
SC_WEDDING,
|
|
SC_XMAS,
|
|
SC_SUMMER,
|
|
SC_HANBOK,
|
|
SC_OKTOBERFEST
|
|
};
|
|
unsigned short k = 0, len = ARRAYLENGTH(names);
|
|
|
|
if( !message || !*message ) {
|
|
for( k = 0; k < len; k++ ) {
|
|
if( sd->sc.data[name2id[k]] ) {
|
|
sprintf(atcmd_output, msg_txt(sd, 727), names[k]); // '%s' Costume removed.
|
|
clif_displaymessage(sd->fd, atcmd_output);
|
|
status_change_end(&sd->bl, (sc_type)name2id[k], INVALID_TIMER);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
clif_displaymessage(sd->fd, msg_txt(sd, 726)); // Available Costumes
|
|
for( k = 0; k < len; k++ ) {
|
|
sprintf(atcmd_output, msg_txt(sd, 725), names[k]); // -- %s
|
|
clif_displaymessage(sd->fd, atcmd_output);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
for( k = 0; k < len; k++ ) {
|
|
if( sd->sc.data[name2id[k]] ) {
|
|
sprintf(atcmd_output, msg_txt(sd, 724), names[k]); // You're already wearing a(n) '%s' costume, type '@costume' to remove it.
|
|
clif_displaymessage(sd->fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for( k = 0; k < len; k++ )
|
|
if( strcmpi(message, names[k]) == 0 )
|
|
break;
|
|
|
|
if( k == len ) {
|
|
sprintf(atcmd_output, msg_txt(sd, 723), message); // '%s' is an unknown costume
|
|
clif_displaymessage(sd->fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
sc_start(&sd->bl, &sd->bl, (sc_type)name2id[k], 100, 0, -1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Clone other player's equipments
|
|
* Usage: @cloneequip <char_id or "char name">
|
|
* http://rathena.org/board/topic/95076-new-atcommands-suggestion/
|
|
* @author [Cydh], [Antares]
|
|
*/
|
|
ACMD_FUNC(cloneequip) {
|
|
struct map_session_data *pl_sd;
|
|
uint32 char_id = 0;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
if( !message || !*message || (sscanf(message, "%d", &char_id) < 1 && sscanf(message, "\"%23[^\"]\"", atcmd_output) < 1) ) {
|
|
clif_displaymessage(fd, msg_txt(sd, 735)); // Please enter char_id or \"char name\".
|
|
return -1;
|
|
}
|
|
|
|
if (char_id)
|
|
pl_sd = map_charid2sd(char_id);
|
|
else
|
|
pl_sd = map_nick2sd(atcmd_output);
|
|
|
|
if (!pl_sd) {
|
|
clif_displaymessage(fd, msg_txt(sd, 3));
|
|
return -1;
|
|
}
|
|
|
|
if (sd == pl_sd) {
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
sprintf(atcmd_output, msg_txt(sd, 734), "equip"); // Cannot clone your own %.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) {
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
sprintf(atcmd_output, msg_txt(sd, 736), "equip"); // Cannot clone %s from this player.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
else {
|
|
int8 i;
|
|
for (i = 0; i < EQI_MAX; i++) {
|
|
short idx;
|
|
char flag = 0;
|
|
struct item tmp_item;
|
|
if ((idx = pl_sd->equip_index[i]) < 0)
|
|
continue;
|
|
if (i == EQI_AMMO)
|
|
continue;
|
|
if (pc_is_same_equip_index((enum equip_index) i, pl_sd->equip_index, idx))
|
|
continue;
|
|
|
|
tmp_item = pl_sd->status.inventory[idx];
|
|
if (itemdb_isspecial(tmp_item.card[0]))
|
|
memset(tmp_item.card, 0, sizeof(tmp_item.card));
|
|
tmp_item.bound = 0;
|
|
tmp_item.expire_time = 0;
|
|
tmp_item.unique_id = 0;
|
|
tmp_item.favorite = 0;
|
|
tmp_item.amount = 1;
|
|
|
|
if ((flag = pc_additem(sd, &tmp_item, 1, LOG_TYPE_COMMAND)))
|
|
clif_additem(sd, 0, 0, flag);
|
|
else
|
|
pc_equipitem(sd, sd->last_addeditem_index, itemdb_equip(tmp_item.nameid));
|
|
}
|
|
}
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
sprintf(atcmd_output, msg_txt(sd, 738), "equip");
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Clone other player's statuses/parameters using method same like ACMD_FUNC(param), doesn't use stat point
|
|
* Usage: @clonestat <char_id or "char name">
|
|
* http://rathena.org/board/topic/95076-new-atcommands-suggestion/
|
|
* @author [Cydh], [Antares]
|
|
*/
|
|
ACMD_FUNC(clonestat) {
|
|
struct map_session_data *pl_sd;
|
|
uint32 char_id = 0;
|
|
|
|
nullpo_retr(-1, sd);
|
|
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
if( !message || !*message || (sscanf(message, "%d", &char_id) < 1 && sscanf(message, "\"%23[^\"]\"", atcmd_output) < 1) ) {
|
|
clif_displaymessage(fd, msg_txt(sd, 735)); // Please enter char_id or \"char name\".
|
|
return -1;
|
|
}
|
|
|
|
if (char_id)
|
|
pl_sd = map_charid2sd(char_id);
|
|
else
|
|
pl_sd = map_nick2sd(atcmd_output);
|
|
|
|
if (!pl_sd) {
|
|
clif_displaymessage(fd, msg_txt(sd, 3));
|
|
return -1;
|
|
}
|
|
|
|
if (sd == pl_sd) {
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
sprintf(atcmd_output, msg_txt(sd, 734), "status"); // Cannot clone your own %.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
|
|
if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) {
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
sprintf(atcmd_output, msg_txt(sd, 736), "status"); // Cannot clone %s from this player.
|
|
clif_displaymessage(fd, atcmd_output);
|
|
return -1;
|
|
}
|
|
else {
|
|
uint8 i;
|
|
short max_status[6];
|
|
|
|
pc_resetstate(sd);
|
|
if (pc_has_permission(sd, PC_PERM_BYPASS_STAT_ONCLONE))
|
|
max_status[0] = max_status[1] = max_status[2] = max_status[3] = max_status[4] = max_status[5] = SHRT_MAX;
|
|
else {
|
|
max_status[0] = pc_maxparameter(sd, PARAM_STR);
|
|
max_status[1] = pc_maxparameter(sd, PARAM_AGI);
|
|
max_status[2] = pc_maxparameter(sd, PARAM_VIT);
|
|
max_status[3] = pc_maxparameter(sd, PARAM_INT);
|
|
max_status[4] = pc_maxparameter(sd, PARAM_DEX);
|
|
max_status[5] = pc_maxparameter(sd, PARAM_LUK);
|
|
}
|
|
|
|
#define clonestat_check(cmd,stat)\
|
|
{\
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));\
|
|
if (pl_sd->status.cmd > max_status[(stat)]) {\
|
|
sprintf(atcmd_output, msg_txt(sd, 737), #cmd, pl_sd->status.cmd, max_status[(stat)]);\
|
|
clif_displaymessage(fd, atcmd_output);\
|
|
sd->status.cmd = max_status[(stat)];\
|
|
}\
|
|
else\
|
|
sd->status.cmd = pl_sd->status.cmd;\
|
|
}
|
|
|
|
clonestat_check(str, PARAM_STR);
|
|
clonestat_check(agi, PARAM_AGI);
|
|
clonestat_check(vit, PARAM_VIT);
|
|
clonestat_check(int_, PARAM_INT);
|
|
clonestat_check(dex, PARAM_DEX);
|
|
clonestat_check(luk, PARAM_LUK);
|
|
|
|
for (i = 0; i < PARAM_MAX; i++) {
|
|
clif_updatestatus(sd, SP_STR + i);
|
|
clif_updatestatus(sd, SP_USTR + i);
|
|
}
|
|
status_calc_pc(sd, SCO_FORCE);
|
|
}
|
|
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
|
sprintf(atcmd_output, msg_txt(sd, 738), "status");
|
|
clif_displaymessage(fd, atcmd_output);
|
|
|
|
#undef clonestat_check
|
|
return 0;
|
|
}
|
|
|
|
#include "../custom/atcommand.inc"
|
|
|
|
/**
|
|
* Fills the reference of available commands in atcommand DBMap
|
|
**/
|
|
#define ACMD_DEF(x) { #x, atcommand_ ## x, NULL, NULL, 0 }
|
|
#define ACMD_DEF2(x2, x) { x2, atcommand_ ## x, NULL, NULL, 0 }
|
|
// Define with restriction
|
|
#define ACMD_DEFR(x, r) { #x, atcommand_ ## x, NULL, NULL, r }
|
|
#define ACMD_DEF2R(x2, x, r) { x2, atcommand_ ## x, NULL, NULL, r }
|
|
void atcommand_basecommands(void) {
|
|
/**
|
|
* Command reference list, place the base of your commands here
|
|
* TODO: List all commands that causing crash
|
|
**/
|
|
AtCommandInfo atcommand_base[] = {
|
|
#include "../custom/atcommand_def.inc"
|
|
ACMD_DEF2R("warp", mapmove, ATCMD_NOCONSOLE),
|
|
ACMD_DEF(where),
|
|
ACMD_DEF(jumpto),
|
|
ACMD_DEF(jump),
|
|
ACMD_DEF(who),
|
|
ACMD_DEF2("who2", who),
|
|
ACMD_DEF2("who3", who),
|
|
ACMD_DEF2("whomap", who),
|
|
ACMD_DEF2("whomap2", who),
|
|
ACMD_DEF2("whomap3", who),
|
|
ACMD_DEF(whogm),
|
|
ACMD_DEF(save),
|
|
ACMD_DEF(load),
|
|
ACMD_DEF(speed),
|
|
ACMD_DEF(storage),
|
|
ACMD_DEF(guildstorage),
|
|
ACMD_DEF(option),
|
|
ACMD_DEF(hide), // + /hide
|
|
ACMD_DEFR(jobchange, ATCMD_NOCONSOLE),
|
|
ACMD_DEF(kill),
|
|
ACMD_DEF(alive),
|
|
ACMD_DEF(kami),
|
|
ACMD_DEF2("kamib", kami),
|
|
ACMD_DEF2("kamic", kami),
|
|
ACMD_DEF2("lkami", kami),
|
|
ACMD_DEF(heal),
|
|
ACMD_DEF(item),
|
|
ACMD_DEF(item2),
|
|
ACMD_DEF2("itembound",item),
|
|
ACMD_DEF2("itembound2",item2),
|
|
ACMD_DEF(itemreset),
|
|
ACMD_DEF(clearstorage),
|
|
ACMD_DEF(cleargstorage),
|
|
ACMD_DEF(clearcart),
|
|
ACMD_DEF2R("blvl", baselevelup, ATCMD_NOCONSOLE),
|
|
ACMD_DEF2("jlvl", joblevelup),
|
|
ACMD_DEF(help),
|
|
ACMD_DEF(pvpoff),
|
|
ACMD_DEF(pvpon),
|
|
ACMD_DEF(gvgoff),
|
|
ACMD_DEF(gvgon),
|
|
ACMD_DEF(model),
|
|
ACMD_DEFR(go, ATCMD_NOCONSOLE),
|
|
ACMD_DEF(monster),
|
|
ACMD_DEF2("monstersmall", monster),
|
|
ACMD_DEF2("monsterbig", monster),
|
|
ACMD_DEF(killmonster),
|
|
ACMD_DEF2("killmonster2", killmonster),
|
|
ACMD_DEF(refine),
|
|
ACMD_DEF(produce),
|
|
ACMD_DEF(memo),
|
|
ACMD_DEF(gat),
|
|
ACMD_DEF(displaystatus),
|
|
ACMD_DEF2("stpoint", statuspoint),
|
|
ACMD_DEF2("skpoint", skillpoint),
|
|
ACMD_DEF(zeny),
|
|
ACMD_DEF2("str", param),
|
|
ACMD_DEF2("agi", param),
|
|
ACMD_DEF2("vit", param),
|
|
ACMD_DEF2("int", param),
|
|
ACMD_DEF2("dex", param),
|
|
ACMD_DEF2("luk", param),
|
|
ACMD_DEF2("glvl", guildlevelup),
|
|
ACMD_DEF(makeegg),
|
|
ACMD_DEF(hatch),
|
|
ACMD_DEF(petfriendly),
|
|
ACMD_DEF(pethungry),
|
|
ACMD_DEF(petrename),
|
|
ACMD_DEF(recall), // + /recall
|
|
ACMD_DEF(night),
|
|
ACMD_DEF(day),
|
|
ACMD_DEF(doom),
|
|
ACMD_DEF(doommap),
|
|
ACMD_DEF(raise),
|
|
ACMD_DEF(raisemap),
|
|
ACMD_DEFR(kick,ATCMD_NOAUTOTRADE), // + right click menu for GM "(name) force to quit"
|
|
ACMD_DEF(kickall),
|
|
ACMD_DEF(allskill),
|
|
ACMD_DEF(questskill),
|
|
ACMD_DEF(lostskill),
|
|
ACMD_DEF(spiritball),
|
|
ACMD_DEF(party),
|
|
ACMD_DEF(guild),
|
|
ACMD_DEF(breakguild),
|
|
ACMD_DEF(agitstart),
|
|
ACMD_DEF(agitend),
|
|
ACMD_DEF(mapexit),
|
|
ACMD_DEF(idsearch),
|
|
ACMD_DEF(broadcast), // + /b and /nb
|
|
ACMD_DEF(localbroadcast), // + /lb and /nlb
|
|
ACMD_DEF(recallall),
|
|
ACMD_DEFR(reload,ATCMD_NOSCRIPT),
|
|
ACMD_DEF2("reloaditemdb", reload),
|
|
ACMD_DEF2("reloadmobdb", reload),
|
|
ACMD_DEF2("reloadskilldb", reload),
|
|
ACMD_DEF2R("reloadscript", reload, ATCMD_NOSCRIPT),
|
|
ACMD_DEF2("reloadatcommand", reload),
|
|
ACMD_DEF2("reloadbattleconf", reload),
|
|
ACMD_DEF2("reloadstatusdb", reload),
|
|
ACMD_DEF2("reloadpcdb", reload),
|
|
ACMD_DEF2("reloadmotd", reload),
|
|
ACMD_DEF2("reloadquestdb", reload),
|
|
ACMD_DEF2("reloadmsgconf", reload),
|
|
ACMD_DEF2("reloadpacketdb", reload),
|
|
ACMD_DEF2("reloadinstancedb", reload),
|
|
ACMD_DEF(partysharelvl),
|
|
ACMD_DEF(mapinfo),
|
|
ACMD_DEF(dye),
|
|
ACMD_DEF2("hairstyle", hair_style),
|
|
ACMD_DEF2("haircolor", hair_color),
|
|
ACMD_DEF2("allstats", stat_all),
|
|
ACMD_DEF2("block", char_block),
|
|
ACMD_DEF2("ban", char_ban),
|
|
ACMD_DEF2("unblock", char_unblock),
|
|
ACMD_DEF2("unban", char_unban),
|
|
ACMD_DEF2("charban", char_ban),
|
|
ACMD_DEF2("charunban", char_unban),
|
|
ACMD_DEF2("mount", mount_peco),
|
|
ACMD_DEF(guildspy),
|
|
ACMD_DEF(partyspy),
|
|
ACMD_DEF(repairall),
|
|
ACMD_DEF(guildrecall),
|
|
ACMD_DEF(partyrecall),
|
|
ACMD_DEF(nuke),
|
|
ACMD_DEF(shownpc),
|
|
ACMD_DEF(hidenpc),
|
|
ACMD_DEF(loadnpc),
|
|
ACMD_DEF(unloadnpc),
|
|
ACMD_DEF2("time", servertime),
|
|
ACMD_DEF(jail),
|
|
ACMD_DEF(unjail),
|
|
ACMD_DEF(jailfor),
|
|
ACMD_DEF(jailtime),
|
|
ACMD_DEF(disguise),
|
|
ACMD_DEF(undisguise),
|
|
ACMD_DEF(email),
|
|
ACMD_DEF(effect),
|
|
ACMD_DEF(follow),
|
|
ACMD_DEF(addwarp),
|
|
ACMD_DEF(skillon),
|
|
ACMD_DEF(skilloff),
|
|
ACMD_DEF(killer),
|
|
ACMD_DEF(npcmove),
|
|
ACMD_DEF(killable),
|
|
ACMD_DEF(dropall),
|
|
ACMD_DEF(storeall),
|
|
ACMD_DEF(skillid),
|
|
ACMD_DEF(useskill),
|
|
ACMD_DEF(displayskill),
|
|
ACMD_DEF(snow),
|
|
ACMD_DEF(sakura),
|
|
ACMD_DEF(clouds),
|
|
ACMD_DEF(clouds2),
|
|
ACMD_DEF(fog),
|
|
ACMD_DEF(fireworks),
|
|
ACMD_DEF(leaves),
|
|
ACMD_DEF(summon),
|
|
ACMD_DEF(adjgroup),
|
|
ACMD_DEF(trade),
|
|
ACMD_DEF(send),
|
|
ACMD_DEF(setbattleflag),
|
|
ACMD_DEF(unmute),
|
|
ACMD_DEF(clearweather),
|
|
ACMD_DEF(uptime),
|
|
ACMD_DEF(changesex),
|
|
ACMD_DEF(mute),
|
|
ACMD_DEF(refresh),
|
|
ACMD_DEF(refreshall),
|
|
ACMD_DEF(identify),
|
|
ACMD_DEF(identifyall),
|
|
ACMD_DEF(gmotd),
|
|
ACMD_DEF(misceffect),
|
|
ACMD_DEF(mobsearch),
|
|
ACMD_DEF(cleanmap),
|
|
ACMD_DEF(cleanarea),
|
|
ACMD_DEF(npctalk),
|
|
ACMD_DEF(pettalk),
|
|
ACMD_DEF(users),
|
|
ACMD_DEF(reset),
|
|
ACMD_DEF(skilltree),
|
|
ACMD_DEF(marry),
|
|
ACMD_DEF(divorce),
|
|
ACMD_DEF(sound),
|
|
ACMD_DEF(undisguiseall),
|
|
ACMD_DEF(disguiseall),
|
|
ACMD_DEF(changelook),
|
|
ACMD_DEF(autoloot),
|
|
ACMD_DEF2("alootid", autolootitem),
|
|
ACMD_DEF(autoloottype),
|
|
ACMD_DEF(mobinfo),
|
|
ACMD_DEF(exp),
|
|
ACMD_DEF(version),
|
|
ACMD_DEF(mutearea),
|
|
ACMD_DEF(rates),
|
|
ACMD_DEF(iteminfo),
|
|
ACMD_DEF(whodrops),
|
|
ACMD_DEF(whereis),
|
|
ACMD_DEF(mapflag),
|
|
ACMD_DEF(me),
|
|
ACMD_DEF(monsterignore),
|
|
ACMD_DEF(fakename),
|
|
ACMD_DEF(size),
|
|
ACMD_DEF(showexp),
|
|
ACMD_DEF(showzeny),
|
|
ACMD_DEF(showdelay),
|
|
ACMD_DEF(autotrade),
|
|
ACMD_DEF(changegm),
|
|
ACMD_DEF(changeleader),
|
|
ACMD_DEF(partyoption),
|
|
ACMD_DEF(invite),
|
|
ACMD_DEF(duel),
|
|
ACMD_DEF(leave),
|
|
ACMD_DEF(accept),
|
|
ACMD_DEF(reject),
|
|
ACMD_DEF(clone),
|
|
ACMD_DEF2("slaveclone", clone),
|
|
ACMD_DEF2("evilclone", clone),
|
|
ACMD_DEF(tonpc),
|
|
ACMD_DEF(commands),
|
|
ACMD_DEF(noask),
|
|
ACMD_DEF(request),
|
|
ACMD_DEF(homlevel),
|
|
ACMD_DEF(homevolution),
|
|
ACMD_DEF(hommutate),
|
|
ACMD_DEF(makehomun),
|
|
ACMD_DEF(homfriendly),
|
|
ACMD_DEF(homhungry),
|
|
ACMD_DEF(homtalk),
|
|
ACMD_DEF(hominfo),
|
|
ACMD_DEF(homstats),
|
|
ACMD_DEF(homshuffle),
|
|
ACMD_DEF(showmobs),
|
|
ACMD_DEF(feelreset),
|
|
ACMD_DEF(auction),
|
|
ACMD_DEF(mail),
|
|
ACMD_DEF2("noks", ksprotection),
|
|
ACMD_DEF(allowks),
|
|
ACMD_DEF(cash),
|
|
ACMD_DEF2("points", cash),
|
|
ACMD_DEF(agitstart2),
|
|
ACMD_DEF(agitend2),
|
|
ACMD_DEF(resetskill),
|
|
ACMD_DEF(resetstat),
|
|
ACMD_DEF2("storagelist", itemlist),
|
|
ACMD_DEF2("cartlist", itemlist),
|
|
ACMD_DEF2("itemlist", itemlist),
|
|
ACMD_DEF(stats),
|
|
ACMD_DEF(delitem),
|
|
ACMD_DEF(charcommands),
|
|
ACMD_DEF(font),
|
|
ACMD_DEF(accinfo),
|
|
ACMD_DEF(set),
|
|
ACMD_DEF(undisguiseguild),
|
|
ACMD_DEF(disguiseguild),
|
|
ACMD_DEF(sizeall),
|
|
ACMD_DEF(sizeguild),
|
|
ACMD_DEF(addperm),
|
|
ACMD_DEF2("rmvperm", addperm),
|
|
ACMD_DEF(unloadnpcfile),
|
|
ACMD_DEF(cart),
|
|
ACMD_DEF(mount2),
|
|
ACMD_DEF(join),
|
|
ACMD_DEF(channel),
|
|
ACMD_DEF(fontcolor),
|
|
ACMD_DEF(langtype),
|
|
#ifdef VIP_ENABLE
|
|
ACMD_DEF(vip),
|
|
ACMD_DEF(showrate),
|
|
#endif
|
|
ACMD_DEF(fullstrip),
|
|
ACMD_DEF(costume),
|
|
ACMD_DEF(cloneequip),
|
|
ACMD_DEF(clonestat),
|
|
};
|
|
AtCommandInfo* atcommand;
|
|
int i;
|
|
|
|
for( i = 0; i < ARRAYLENGTH(atcommand_base); i++ ) {
|
|
if(atcommand_exists(atcommand_base[i].command)) { // Should not happen if atcommand_base[] array is OK
|
|
ShowDebug("atcommand_basecommands: duplicate ACMD_DEF for '%s'.\n", atcommand_base[i].command);
|
|
continue;
|
|
}
|
|
CREATE(atcommand, AtCommandInfo, 1);
|
|
safestrncpy(atcommand->command, atcommand_base[i].command, sizeof(atcommand->command));
|
|
atcommand->func = atcommand_base[i].func;
|
|
atcommand->restriction = atcommand_base[i].restriction;
|
|
strdb_put(atcommand_db, atcommand->command, atcommand);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*==========================================
|
|
* Command lookup functions
|
|
*------------------------------------------*/
|
|
bool atcommand_exists(const char* name)
|
|
{
|
|
return strdb_exists(atcommand_db, name);
|
|
}
|
|
|
|
static AtCommandInfo* get_atcommandinfo_byname(const char *name)
|
|
{
|
|
if (strdb_exists(atcommand_db, name))
|
|
return (AtCommandInfo*)strdb_get(atcommand_db, name);
|
|
return NULL;
|
|
}
|
|
|
|
static const char* atcommand_checkalias(const char *aliasname)
|
|
{
|
|
AliasInfo *alias_info = NULL;
|
|
if ((alias_info = (AliasInfo*)strdb_get(atcommand_alias_db, aliasname)) != NULL)
|
|
return alias_info->command->command;
|
|
return aliasname;
|
|
}
|
|
|
|
/// AtCommand suggestion
|
|
static void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool atcommand) {
|
|
DBIterator* atcommand_iter;
|
|
DBIterator* alias_iter;
|
|
AtCommandInfo* command_info = NULL;
|
|
AliasInfo* alias_info = NULL;
|
|
AtCommandType type = atcommand ? COMMAND_ATCOMMAND : COMMAND_CHARCOMMAND;
|
|
char* full_match[MAX_SUGGESTIONS];
|
|
char* suggestions[MAX_SUGGESTIONS];
|
|
char* match;
|
|
int prefix_count = 0, full_count = 0;
|
|
bool can_use;
|
|
|
|
if (!battle_config.atcommand_suggestions_enabled)
|
|
return;
|
|
|
|
atcommand_iter = db_iterator(atcommand_db);
|
|
alias_iter = db_iterator(atcommand_alias_db);
|
|
|
|
// Build the matches
|
|
for (command_info = dbi_first(atcommand_iter); dbi_exists(atcommand_iter); command_info = dbi_next(atcommand_iter)) {
|
|
match = strstr(command_info->command, name);
|
|
can_use = pc_can_use_command(sd, command_info->command, type);
|
|
if ( prefix_count < MAX_SUGGESTIONS && match == command_info->command && can_use ) {
|
|
suggestions[prefix_count] = command_info->command;
|
|
++prefix_count;
|
|
}
|
|
if ( full_count < MAX_SUGGESTIONS && match != NULL && match != command_info->command && can_use ) {
|
|
full_match[full_count] = command_info->command;
|
|
++full_count;
|
|
}
|
|
}
|
|
|
|
for (alias_info = dbi_first(alias_iter); dbi_exists(alias_iter); alias_info = dbi_next(alias_iter)) {
|
|
match = strstr(alias_info->alias, name);
|
|
can_use = pc_can_use_command(sd, alias_info->command->command, type);
|
|
if ( prefix_count < MAX_SUGGESTIONS && match == alias_info->alias && can_use) {
|
|
suggestions[prefix_count] = alias_info->alias;
|
|
++prefix_count;
|
|
}
|
|
if ( full_count < MAX_SUGGESTIONS && match != NULL && match != alias_info->alias && can_use ) {
|
|
full_match[full_count] = alias_info->alias;
|
|
++full_count;
|
|
}
|
|
}
|
|
|
|
if ((full_count+prefix_count) > 0) {
|
|
char buffer[512];
|
|
int i;
|
|
|
|
// Merge full match and prefix match results
|
|
if (prefix_count < MAX_SUGGESTIONS) {
|
|
memmove(&suggestions[prefix_count], full_match, sizeof(char*) * (MAX_SUGGESTIONS-prefix_count));
|
|
prefix_count = min(prefix_count+full_count, MAX_SUGGESTIONS);
|
|
}
|
|
|
|
// Build the suggestion string
|
|
strcpy(buffer, msg_txt(sd,205));
|
|
strcat(buffer,"\n");
|
|
|
|
for(i=0; i < prefix_count; ++i) {
|
|
strcat(buffer,suggestions[i]);
|
|
strcat(buffer," ");
|
|
}
|
|
|
|
clif_displaymessage(sd->fd, buffer);
|
|
}
|
|
|
|
dbi_destroy(atcommand_iter);
|
|
dbi_destroy(alias_iter);
|
|
}
|
|
|
|
/**
|
|
* Executes an at-command
|
|
* @param fd
|
|
* @param sd
|
|
* @param message
|
|
* @param type
|
|
* 0 : script call (atcommand)
|
|
* 1 : normal player @atcommand
|
|
* 2 : console (admin:@atcommand)
|
|
* 3 : script call (useatcmd)
|
|
*/
|
|
bool is_atcommand(const int fd, struct map_session_data* sd, const char* message, int type)
|
|
{
|
|
char charname[NAME_LENGTH], params[100];
|
|
char charname2[NAME_LENGTH];
|
|
char command[100];
|
|
char output[CHAT_SIZE_MAX];
|
|
|
|
//Reconstructed message
|
|
char atcmd_msg[CHAT_SIZE_MAX];
|
|
|
|
TBL_PC * ssd = NULL; //sd for target
|
|
AtCommandInfo * info;
|
|
|
|
nullpo_retr(false, sd);
|
|
|
|
//Shouldn't happen
|
|
if ( !message || !*message )
|
|
return false;
|
|
|
|
//If cannot use atcomamnd while talking with NPC [Kichi]
|
|
if (type == 1 && sd->npc_id && sd->state.disable_atcommand_on_npc)
|
|
return false;
|
|
|
|
//Block NOCHAT but do not display it as a normal message
|
|
if ( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCOMMAND )
|
|
return true;
|
|
|
|
// skip 10/11-langtype's codepage indicator, if detected
|
|
if ( message[0] == '|' && strlen(message) >= 4 && (message[3] == atcommand_symbol || message[3] == charcommand_symbol) )
|
|
message += 3;
|
|
|
|
//Should display as a normal message
|
|
if ( *message != atcommand_symbol && *message != charcommand_symbol )
|
|
return false;
|
|
|
|
// type value 0|2 = script|console invoked: bypass restrictions
|
|
if ( type == 1 || type == 3) {
|
|
//Commands are disabled on maps flagged as 'nocommand'
|
|
if ( map[sd->bl.m].nocommand && pc_get_group_level(sd) < map[sd->bl.m].nocommand ) {
|
|
clif_displaymessage(fd, msg_txt(sd,143));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (*message == charcommand_symbol) {
|
|
do {
|
|
int x, y, z;
|
|
char params2[100];
|
|
|
|
//Checks to see if #command has a name or a name + parameters.
|
|
x = sscanf(message, "%99s \"%23[^\"]\" %99[^\n]", command, charname, params);
|
|
y = sscanf(message, "%99s %23s %99[^\n]", command, charname2, params2);
|
|
|
|
//z always has the value of the scan that was successful
|
|
z = ( x > 1 ) ? x : y;
|
|
|
|
//#command + name means the sufficient target was used and anything else after
|
|
//can be looked at by the actual command function since most scan to see if the
|
|
//right parameters are used.
|
|
if ( x > 2 ) {
|
|
sprintf(atcmd_msg, "%s %s", command, params);
|
|
break;
|
|
}
|
|
else if ( y > 2 ) {
|
|
sprintf(atcmd_msg, "%s %s", command, params2);
|
|
break;
|
|
}
|
|
//Regardless of what style the #command is used, if it's correct, it will always have
|
|
//this value if there is no parameter. Send it as just the #command
|
|
else if ( z == 2 ) {
|
|
sprintf(atcmd_msg, "%s", command);
|
|
break;
|
|
}
|
|
|
|
if( !pc_get_group_level(sd) ) {
|
|
if( x >= 1 || y >= 1 ) { /* we have command */
|
|
info = get_atcommandinfo_byname(atcommand_checkalias(command + 1));
|
|
if( !info || info->char_groups[sd->group_pos] == 0 ) /* if we can't use or doesn't exist: don't even display the command failed message */
|
|
return false;
|
|
} else
|
|
return false;/* display as normal message */
|
|
}
|
|
|
|
sprintf(output, msg_txt(sd,1388), charcommand_symbol); // Charcommand failed (usage: %c<command> <char name> <parameters>).
|
|
clif_displaymessage(fd, output);
|
|
return true;
|
|
} while(0);
|
|
}
|
|
else if (*message == atcommand_symbol) {
|
|
//atcmd_msg is constructed above differently for charcommands
|
|
//it's copied from message if not a charcommand so it can
|
|
//pass through the rest of the code compatible with both symbols
|
|
sprintf(atcmd_msg, "%s", message);
|
|
}
|
|
|
|
if (battle_config.idletime_option&IDLE_ATCOMMAND)
|
|
sd->idletime = last_tick;
|
|
|
|
//Clearing these to be used once more.
|
|
memset(command, '\0', sizeof(command));
|
|
memset(params, '\0', sizeof(params));
|
|
|
|
//check to see if any params exist within this command
|
|
if( sscanf(atcmd_msg, "%99s %99[^\n]", command, params) < 2 )
|
|
params[0] = '\0';
|
|
|
|
// @commands (script based)
|
|
if((type == 1 || type == 3) && atcmd_binding_count > 0) {
|
|
struct atcmd_binding_data * binding;
|
|
|
|
// Check if the command initiated is a character command
|
|
if (*message == charcommand_symbol &&
|
|
(ssd = map_nick2sd(charname)) == NULL && (ssd = map_nick2sd(charname2)) == NULL ) {
|
|
sprintf(output, msg_txt(sd,1389), command); // %s failed. Player not found.
|
|
clif_displaymessage(fd, output);
|
|
return true;
|
|
}
|
|
|
|
// Get atcommand binding
|
|
binding = get_atcommandbind_byname(command);
|
|
|
|
// Check if the binding isn't NULL and there is a NPC event, level of usage met, et cetera
|
|
if( binding != NULL && binding->npc_event[0] &&
|
|
((*atcmd_msg == atcommand_symbol && pc_get_group_level(sd) >= binding->level) ||
|
|
(*atcmd_msg == charcommand_symbol && pc_get_group_level(sd) >= binding->level2)))
|
|
{
|
|
// Check if self or character invoking; if self == character invoked, then self invoke.
|
|
bool invokeFlag = ((*atcmd_msg == atcommand_symbol) ? 1 : 0);
|
|
npc_do_atcmd_event((invokeFlag ? sd : ssd), command, params, binding->npc_event);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//Grab the command information and check for the proper GM level required to use it or if the command exists
|
|
info = get_atcommandinfo_byname(atcommand_checkalias(command + 1));
|
|
if (info == NULL) {
|
|
if( pc_get_group_level(sd) ) { // TODO: remove or replace with proper permission
|
|
sprintf(output, msg_txt(sd,153), command); // "%s is Unknown Command."
|
|
clif_displaymessage(fd, output);
|
|
atcommand_get_suggestions(sd, command + 1, *message == atcommand_symbol);
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
//check restriction
|
|
if (info->restriction) {
|
|
if (info->restriction&ATCMD_NOCONSOLE && type == 2) //console prevent
|
|
return true;
|
|
if (info->restriction&ATCMD_NOSCRIPT && (type == 0 || type == 3)) //scripts prevent
|
|
return true;
|
|
if (info->restriction&ATCMD_NOAUTOTRADE && (type == 0 || type == 3)
|
|
&& ((*atcmd_msg == atcommand_symbol && sd && sd->state.autotrade) || (ssd && ssd->state.autotrade)))
|
|
return true;
|
|
}
|
|
|
|
// type == 1 : player invoked
|
|
if (type == 1) {
|
|
if ((*command == atcommand_symbol && info->at_groups[sd->group_pos] == 0) ||
|
|
(*command == charcommand_symbol && info->char_groups[sd->group_pos] == 0) ) {
|
|
return false;
|
|
}
|
|
if( pc_isdead(sd) && pc_has_permission(sd,PC_PERM_DISABLE_CMD_DEAD) ) {
|
|
clif_displaymessage(fd, msg_txt(sd,1393)); // You can't use commands while dead
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Check if target is valid only if confirmed that player can use command.
|
|
if (*message == charcommand_symbol &&
|
|
(ssd = map_nick2sd(charname)) == NULL && (ssd = map_nick2sd(charname2)) == NULL ) {
|
|
sprintf(output, msg_txt(sd,1389), command); // %s failed. Player not found.
|
|
clif_displaymessage(fd, output);
|
|
return true;
|
|
}
|
|
|
|
//Attempt to use the command
|
|
if ( (info->func(fd, (*atcmd_msg == atcommand_symbol) ? sd : ssd, command, params) != 0) )
|
|
{
|
|
sprintf(output,msg_txt(sd,154), command); // %s failed.
|
|
clif_displaymessage(fd, output);
|
|
return true;
|
|
}
|
|
|
|
//Log only if successful.
|
|
if ( *atcmd_msg == atcommand_symbol )
|
|
log_atcommand(sd, atcmd_msg);
|
|
else if ( *atcmd_msg == charcommand_symbol )
|
|
log_atcommand(sd, message);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*==========================================
|
|
*
|
|
*------------------------------------------*/
|
|
static void atcommand_config_read(const char* config_filename)
|
|
{
|
|
config_setting_t *aliases = NULL, *help = NULL;
|
|
const char *symbol = NULL;
|
|
int num_aliases = 0;
|
|
|
|
if (conf_read_file(&atcommand_config, config_filename))
|
|
return;
|
|
|
|
// Command symbols
|
|
if (config_lookup_string(&atcommand_config, "atcommand_symbol", &symbol)) {
|
|
if (ISPRINT(*symbol) && // no control characters
|
|
*symbol != '/' && // symbol of client commands
|
|
*symbol != '%' && // symbol of party chat
|
|
*symbol != '$' && // symbol of guild chat
|
|
*symbol != charcommand_symbol)
|
|
atcommand_symbol = *symbol;
|
|
}
|
|
|
|
if (config_lookup_string(&atcommand_config, "charcommand_symbol", &symbol)) {
|
|
if (ISPRINT(*symbol) && // no control characters
|
|
*symbol != '/' && // symbol of client commands
|
|
*symbol != '%' && // symbol of party chat
|
|
*symbol != '$' && // symbol of guild chat
|
|
*symbol != atcommand_symbol)
|
|
charcommand_symbol = *symbol;
|
|
}
|
|
|
|
// Command aliases
|
|
aliases = config_lookup(&atcommand_config, "aliases");
|
|
if (aliases != NULL) {
|
|
int i = 0;
|
|
int count = config_setting_length(aliases);
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
config_setting_t *command;
|
|
const char *commandname = NULL;
|
|
int j = 0, alias_count = 0;
|
|
AtCommandInfo *commandinfo = NULL;
|
|
|
|
command = config_setting_get_elem(aliases, i);
|
|
if (config_setting_type(command) != CONFIG_TYPE_ARRAY)
|
|
continue;
|
|
commandname = config_setting_name(command);
|
|
if (!atcommand_exists(commandname)) {
|
|
ShowConfigWarning(command, "atcommand_config_read: can not set alias for non-existent command %s", commandname);
|
|
continue;
|
|
}
|
|
commandinfo = get_atcommandinfo_byname(commandname);
|
|
alias_count = config_setting_length(command);
|
|
for (j = 0; j < alias_count; ++j) {
|
|
const char *alias = config_setting_get_string_elem(command, j);
|
|
if (alias != NULL) {
|
|
AliasInfo *alias_info;
|
|
if (strdb_exists(atcommand_alias_db, alias)) {
|
|
ShowConfigWarning(command, "atcommand_config_read: alias %s already exists", alias);
|
|
continue;
|
|
}
|
|
CREATE(alias_info, AliasInfo, 1);
|
|
alias_info->command = commandinfo;
|
|
safestrncpy(alias_info->alias, alias, sizeof(alias_info->alias));
|
|
strdb_put(atcommand_alias_db, alias, alias_info);
|
|
++num_aliases;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Commands help
|
|
// We only check if all commands exist
|
|
help = config_lookup(&atcommand_config, "help");
|
|
if (help != NULL) {
|
|
int count = config_setting_length(help);
|
|
int i;
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
config_setting_t *command;
|
|
const char *commandname;
|
|
|
|
command = config_setting_get_elem(help, i);
|
|
commandname = config_setting_name(command);
|
|
if (!atcommand_exists(commandname))
|
|
ShowConfigWarning(command, "atcommand_config_read: command %s does not exist", commandname);
|
|
}
|
|
}
|
|
|
|
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' command aliases in '"CL_WHITE"%s"CL_RESET"'.\n", num_aliases, config_filename);
|
|
return;
|
|
}
|
|
void atcommand_db_load_groups(int* group_ids) {
|
|
DBIterator *iter = db_iterator(atcommand_db);
|
|
AtCommandInfo* cmd;
|
|
int i;
|
|
|
|
for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) {
|
|
cmd->at_groups = aMalloc( pc_group_max * sizeof(char) );
|
|
cmd->char_groups = aMalloc( pc_group_max * sizeof(char) );
|
|
for(i = 0; i < pc_group_max; i++) {
|
|
if( pc_group_can_use_command(group_ids[i], cmd->command, COMMAND_ATCOMMAND ) )
|
|
cmd->at_groups[i] = 1;
|
|
else
|
|
cmd->at_groups[i] = 0;
|
|
if( pc_group_can_use_command(group_ids[i], cmd->command, COMMAND_CHARCOMMAND ) )
|
|
cmd->char_groups[i] = 1;
|
|
else
|
|
cmd->char_groups[i] = 0;
|
|
}
|
|
}
|
|
|
|
dbi_destroy(iter);
|
|
|
|
return;
|
|
}
|
|
void atcommand_db_clear(void) {
|
|
|
|
if (atcommand_db != NULL) {
|
|
DBIterator *iter = db_iterator(atcommand_db);
|
|
AtCommandInfo* cmd;
|
|
|
|
for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) {
|
|
aFree(cmd->at_groups);
|
|
aFree(cmd->char_groups);
|
|
}
|
|
|
|
dbi_destroy(iter);
|
|
|
|
db_destroy(atcommand_db);
|
|
}
|
|
if (atcommand_alias_db != NULL)
|
|
db_destroy(atcommand_alias_db);
|
|
|
|
config_destroy(&atcommand_config);
|
|
}
|
|
|
|
void atcommand_doload(void) {
|
|
atcommand_db_clear();
|
|
atcommand_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, ATCOMMAND_LENGTH);
|
|
atcommand_alias_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, ATCOMMAND_LENGTH);
|
|
atcommand_basecommands(); //fills initial atcommand_db with known commands
|
|
atcommand_config_read(ATCOMMAND_CONF_FILENAME);
|
|
}
|
|
|
|
void do_init_atcommand(void) {
|
|
atcommand_doload();
|
|
}
|
|
|
|
void do_final_atcommand(void) {
|
|
atcommand_db_clear();
|
|
}
|