server-1.12/server/c_misc.c

2612 lines
84 KiB
C

/*
* static char *rcsid_c_misc_c =
* "$Id: c_misc.c 11869 2009-06-14 14:32:45Z akirschbaum $";
*/
/*
CrossFire, A Multiplayer game for X-windows
Copyright (C) 2002 Mark Wedel & Crossfire Development Team
Copyright (C) 1992 Frank Tore Johansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The authors can be reached via e-mail at crossfire-devel@real-time.com
*/
/**
* @file
* Various functions. Handles misc. input request - things like hash table, malloc, maps,
* who, etc.
*/
#include <global.h>
#include <loader.h>
#undef SS_STATISTICS
#include <shstr.h>
#ifndef __CEXTRACT__
#include <sproto.h>
#endif
#include <assert.h>
#include <sounds.h>
/**
* This is the 'maps' command.
*
* @param op
* player requesting the information.
* @param search
* optional substring to search for.
*/
void map_info(object *op, char *search) {
mapstruct *m;
char map_path[MAX_BUF];
long sec = seconds();
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MAPS,
i18n_translate(get_language(op), I18N_MSG_CMISC_000),
i18n_translate(get_language(op), I18N_MSG_CMISC_000),
(sec%86400)/3600, (sec%3600)/60, sec%60);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MAPS,
i18n_translate(get_language(op), I18N_MSG_CMISC_001),
i18n_translate(get_language(op), I18N_MSG_CMISC_002));
for (m = first_map; m != NULL; m = m->next) {
if (search && strstr(m->path, search) == NULL)
continue; /* Skip unwanted maps */
/* Print out the last 18 characters of the map name... */
if (strlen(m->path) <= 18)
strcpy(map_path, m->path);
else
strcpy(map_path, m->path+strlen(m->path)-18);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MAPS,
i18n_translate(get_language(op), I18N_MSG_CMISC_003),
i18n_translate(get_language(op), I18N_MSG_CMISC_004),
map_path, m->players, players_on_map(m, FALSE),
m->in_memory, m->timeout, m->difficulty,
(MAP_WHEN_RESET(m)%86400)/3600, (MAP_WHEN_RESET(m)%3600)/60,
MAP_WHEN_RESET(m)%60);
}
}
/**
* This is the 'language' command.
*
* @param op
* player requesting the information.
* @param params
* optional language code ("en", "fr", etc.)
*/
int command_language(object *op, char *params) {
const char *language_str;
int language;
int i;
if (!op->contr)
return 0;
language_str = language_names[get_language(op)];
if (!params || (!strcmp(params, ""))) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_005),
i18n_translate(get_language(op), I18N_MSG_CMISC_005),
language_str);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_051),
i18n_translate(get_language(op), I18N_MSG_CMISC_051),
language_str);
for (i = 0; i < NUM_LANGUAGES; i++) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
"[fixed]%s: %s",
"%s: %s",
language_codes[i],
language_names[i]);
}
return 0;
} else {
for (i = 0; i < NUM_LANGUAGES; i++) {
if (!strcmp(language_codes[i], params)) {
language = i;
i = NUM_LANGUAGES;
}
}
op->contr->language = language;
language_str = language_names[language];
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(language, I18N_MSG_CMISC_006),
i18n_translate(language, I18N_MSG_CMISC_006),
language_str);
return 0;
}
}
/**
* This command dumps the body information for object *op.
* it doesn't care what the params are.
*
* This is mostly meant as a debug command.
*
* This is the 'body' command.
*
* @param op
* player to display body info for.
* @param params
* unused
* @retval
* 1.
*/
int command_body(object *op, char *params) {
int i;
/* Too hard to try and make a header that lines everything up, so just
* give a description.
*/
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_BODY,
i18n_translate(get_language(op), I18N_MSG_CMISC_007), NULL);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_BODY,
i18n_translate(get_language(op), I18N_MSG_CMISC_008), NULL);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_BODY,
i18n_translate(get_language(op), I18N_MSG_CMISC_009), NULL);
for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
/* really debugging - normally body_used should not be set to anything
* if body_info isn't also set.
*/
if (op->body_info[i] || op->body_used[i]) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_BODY,
i18n_translate(get_language(op), I18N_MSG_CMISC_010),
i18n_translate(get_language(op), I18N_MSG_CMISC_011),
body_locations[i].use_name, op->body_info[i], op->body_used[i]);
}
}
if (!QUERY_FLAG(op, FLAG_USE_ARMOUR))
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_BODY,
i18n_translate(get_language(op), I18N_MSG_CMISC_012), NULL);
if (!QUERY_FLAG(op, FLAG_USE_WEAPON))
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_BODY,
i18n_translate(get_language(op), I18N_MSG_CMISC_013), NULL);
return 1;
}
/**
* Display the message of the day.
*
* @param op
* player requesting the motd.
* @param params
* unused.
* @retval
* 1.
*/
int command_motd(object *op, char *params) {
display_motd(op);
return 1;
}
/**
* Display the server rules.
*
* @param op
* player requesting the rules.
* @param params
* unused.
* @retval
* 1.
*/
int command_rules(object *op, char *params) {
send_rules(op);
return 1;
}
/**
* Display the server news.
*
* @param op
* player requesting the news.
* @param params
* unused.
* @retval
* 1.
*/
int command_news(object *op, char *params) {
send_news(op);
return 1;
}
/**
* Sends various memory-related statistics.
*
* @param op
* player requesting the information.
*/
void malloc_info(object *op) {
int ob_used = count_used(), ob_free = count_free(), players, nrofmaps;
int nrm = 0, mapmem = 0, anr, anims, sum_alloc = 0, sum_used = 0, i, tlnr, alnr;
treasurelist *tl;
player *pl;
mapstruct *m;
archetype *at;
artifactlist *al;
for (tl = first_treasurelist, tlnr = 0; tl != NULL; tl = tl->next, tlnr++)
;
for (al = first_artifactlist, alnr = 0; al != NULL; al = al->next, alnr++)
;
for (at = first_archetype, anr = 0, anims = 0; at != NULL; at = at->more == NULL ? at->next : at->more, anr++)
;
for (i = 1; i < num_animations; i++)
anims += animations[i].num_animations;
for (pl = first_player, players = 0; pl != NULL; pl = pl->next, players++)
;
for (m = first_map, nrofmaps = 0; m != NULL; m = m->next, nrofmaps++)
if (m->in_memory == MAP_IN_MEMORY) {
mapmem += MAP_WIDTH(m)*MAP_HEIGHT(m)*(sizeof(object *)+sizeof(MapSpace));
nrm++;
}
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_014),
i18n_translate(get_language(op), I18N_MSG_CMISC_014),
sizeof(object), sizeof(player), sizeof(mapstruct));
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_015),
i18n_translate(get_language(op), I18N_MSG_CMISC_016),
ob_used, i = (ob_used*sizeof(object)));
sum_used += i;
sum_alloc += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_017),
i18n_translate(get_language(op), I18N_MSG_CMISC_018),
ob_free, i = (ob_free*sizeof(object)));
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_019),
i18n_translate(get_language(op), I18N_MSG_CMISC_020),
count_active(), 0);
sum_alloc += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_021),
i18n_translate(get_language(op), I18N_MSG_CMISC_022),
players, i = (players*sizeof(player)));
sum_alloc += i;
sum_used += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_023),
i18n_translate(get_language(op), I18N_MSG_CMISC_024),
nrofmaps, i = (nrofmaps*sizeof(mapstruct)));
sum_alloc += i;
sum_used += nrm*sizeof(mapstruct);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_025),
i18n_translate(get_language(op), I18N_MSG_CMISC_026),
nrm, mapmem);
sum_alloc += mapmem;
sum_used += mapmem;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_027),
i18n_translate(get_language(op), I18N_MSG_CMISC_028),
anr, i = (anr*sizeof(archetype)));
sum_alloc += i;
sum_used += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_029),
i18n_translate(get_language(op), I18N_MSG_CMISC_030),
anims, i = (anims*sizeof(Fontindex)));
sum_alloc += i;
sum_used += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_031),
i18n_translate(get_language(op), I18N_MSG_CMISC_032),
tlnr, i = (tlnr*sizeof(treasurelist)));
sum_alloc += i;
sum_used += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_033),
i18n_translate(get_language(op), I18N_MSG_CMISC_034),
nroftreasures, i = (nroftreasures*sizeof(treasure)));
sum_alloc += i;
sum_used += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_035),
i18n_translate(get_language(op), I18N_MSG_CMISC_036),
nrofartifacts, i = (nrofartifacts*sizeof(artifact)));
sum_alloc += i;
sum_used += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_037),
i18n_translate(get_language(op), I18N_MSG_CMISC_038),
nrofallowedstr, i = (nrofallowedstr*sizeof(linked_char)));
sum_alloc += i;
sum_used += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_039),
i18n_translate(get_language(op), I18N_MSG_CMISC_040),
alnr, i = (alnr*sizeof(artifactlist)));
sum_alloc += i;
sum_used += i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_041),
i18n_translate(get_language(op), I18N_MSG_CMISC_042),
sum_alloc);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
i18n_translate(get_language(op), I18N_MSG_CMISC_043),
i18n_translate(get_language(op), I18N_MSG_CMISC_044),
sum_used);
}
/**
* 'whereami' command.
*
* Pretty much identical to current map_info(), but on a bigger scale
*
* This function returns the name of the players current region, and
* a description of it. It is there merely for flavour text.
*
* @param op
* player wanting information.
*/
void current_region_info(object *op) {
/*
* Ok I /suppose/ I should write a seperate function for this, but it isn't
* going to be /that/ slow, and won't get called much
*/
region *r = get_region_by_name(get_name_of_region_for_map(op->map));
/* This should only be possible if regions are not operating on this server. */
if (!r)
return;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_045),
i18n_translate(get_language(op), I18N_MSG_CMISC_045),
get_region_longname(r), get_region_msg(r));
}
/**
* 'mapinfo' command.
*
* @param op
* player requesting the information.
*/
void current_map_info(object *op) {
mapstruct *m = op->map;
if (!m)
return;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
"%s (%s) in %s",
"%s (%s) in %s",
m->name, m->path, get_region_longname(get_region_by_map(m)));
if (QUERY_FLAG(op, FLAG_WIZ)) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_046),
i18n_translate(get_language(op), I18N_MSG_CMISC_046),
m->players, m->difficulty,
MAP_WIDTH(m), MAP_HEIGHT(m),
MAP_ENTER_X(m), MAP_ENTER_Y(m),
MAP_TIMEOUT(m));
}
if (m->msg)
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE, m->msg, NULL);
}
#ifdef DEBUG_MALLOC_LEVEL
/**
* Checks the server heap.
*
* @param op
* player checking.
* @param parms
* ignored.
* @retval 1
*/
int command_malloc_verify(object *op, char *parms) {
extern int malloc_verify(void);
if (!malloc_verify())
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_047), NULL);
else
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_048), NULL);
return 1;
}
#endif
/**
* 'whereabouts' command.
*
* Displays how many players are in which regions.
*
* @param op
* player requesting information.
* @param params
* unused.
* @return
* 1.
*/
int command_whereabouts(object *op, char *params) {
region *reg;
player *pl;
/*
* reset the counter on the region, then use it to store the number of
* players there.
* I don't know how thread-safe this would be, I suspect not very....
*/
for (reg = first_region; reg != NULL; reg = reg->next) {
reg->counter = 0;
}
for (pl = first_player; pl != NULL; pl = pl->next)
if (pl->ob->map != NULL)
get_region_by_map(pl->ob->map)->counter++;
/* we only want to print out by places with a 'longname' field...*/
for (reg = first_region; reg != NULL; reg = reg->next) {
if (reg->longname == NULL && reg->counter > 0) {
if (reg->parent != NULL) {
reg->parent->counter += reg->counter;
reg->counter = 0;
} else /*uh oh, we shouldn't be here. */
LOG(llevError, "command_whereabouts() Region %s with no longname has no parent\n", reg->name);
}
}
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_049), NULL);
for (reg = first_region; reg != NULL; reg = reg->next)
if (reg->counter > 0) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_050),
i18n_translate(get_language(op), I18N_MSG_CMISC_050),
reg->counter, get_region_longname(reg));
}
return 1;
}
/** Utility structure for the 'who' command. */
typedef struct {
char namebuf[MAX_BUF];
int login_order;
} chars_names;
/**
* Local function for qsort comparison.
*
* @param c1
* @param c2
* players to compare.
* @return
* -1, 0 or 1 depending on c1 and c2's order.
*/
static int name_cmp(const chars_names *c1, const chars_names *c2) {
return strcasecmp(c1->namebuf, c2->namebuf);
}
/**
* Displays the players in a region or party. If both are NULL, all players are listed.
*
* @param op
* who is asking for player list.
* @param reg
* region to display players of.
* @param party
* party to list.
*/
void list_players(object *op, region *reg, partylist *party) {
player *pl;
uint16 i;
char *format;
int num_players = 0, num_wiz = 0, num_afk = 0, num_bot = 0;
chars_names *chars = NULL;
if (op == NULL || QUERY_FLAG(op, FLAG_WIZ))
format = settings.who_wiz_format;
else
format = settings.who_format;
for (pl = first_player; pl != NULL; pl = pl->next) {
if (pl->ob->map == NULL)
continue;
if (pl->hidden && !QUERY_FLAG(op, FLAG_WIZ))
continue;
if (reg && !region_is_child_of_region(get_region_by_map(pl->ob->map), reg))
continue;
if (party && pl->party != party)
continue;
if (pl->state == ST_PLAYING || pl->state == ST_GET_PARTY_PASSWORD) {
num_players++;
chars = (chars_names *)realloc(chars, num_players*sizeof(chars_names));
if (chars == NULL) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_WHO,
i18n_translate(get_language(op), I18N_MSG_CMISC_052), NULL);
return;
}
sprintf(chars[num_players-1].namebuf, "%s", pl->ob->name);
chars[num_players-1].login_order = num_players;
/* Check for WIZ's & AFK's*/
if (QUERY_FLAG(pl->ob, FLAG_WIZ))
num_wiz++;
if (QUERY_FLAG(pl->ob, FLAG_AFK))
num_afk++;
if (pl->socket.is_bot)
num_bot++;
}
}
if (first_player != (player *)NULL) {
if (reg == NULL && party == NULL)
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_WHO,
i18n_translate(get_language(op), I18N_MSG_CMISC_053),
i18n_translate(get_language(op), I18N_MSG_CMISC_053),
num_players, num_wiz, num_afk, num_bot);
else if (party == NULL)
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_WHO,
i18n_translate(get_language(op), I18N_MSG_CMISC_054),
i18n_translate(get_language(op), I18N_MSG_CMISC_054),
reg->longname ? reg->longname : reg->name, num_players, num_wiz, num_afk, num_bot);
else
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_WHO,
i18n_translate(get_language(op), I18N_MSG_CMISC_055),
i18n_translate(get_language(op), I18N_MSG_CMISC_055),
party->partyname, num_players, num_wiz, num_afk, num_bot);
}
qsort(chars, num_players, sizeof(chars_names), (int (*)(const void *, const void *))name_cmp);
for (i = 0; i < num_players; i++)
display_who_entry(op, find_player(chars[i].namebuf), format);
free(chars);
}
/**
* 'who' command.
*
* @param op
* player requesting the information.
* @param params
* optional region to limit the information to.
* @return
* 1.
*/
int command_who(object *op, char *params) {
region *reg;
reg = get_region_from_string(params);
list_players(op, reg, NULL);
return 1;
}
/**
* Display a line of 'who' to op, about pl, using the formatting specified by format.
*
* @param op
* player getting the information.
* @param pl
* player to display information for.
* @param format
* format to display.
*/
void display_who_entry(object *op, player *pl, const char *format) {
char tmpbuf[MAX_BUF];
char outbuf[MAX_BUF], outbuf1[MAX_BUF];
size_t i;
strcpy(outbuf, "[fixed]");
outbuf1[0] = '\0';
if (pl == NULL) {
LOG(llevError, "display_who_entry(): I was passed a null player\n");
return;
}
for (i = 0; i <= strlen(format); i++) {
if (format[i] == '%') {
i++;
get_who_escape_code_value(tmpbuf, sizeof(tmpbuf), format[i], pl);
strcat(outbuf, tmpbuf);
strcat(outbuf1, tmpbuf);
} else if (format[i] == '_') {
strcat(outbuf, " "); /* allow '_' to be used in place of spaces */
strcat(outbuf1, " "); /* allow '_' to be used in place of spaces */
} else {
snprintf(tmpbuf, sizeof(tmpbuf), "%c", format[i]);
strcat(outbuf, tmpbuf);
strcat(outbuf1, tmpbuf);
}
}
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_WHO, outbuf, outbuf1);
}
/**
* Returns the value of the escape code used in the who format specifier.
*
* Specifier values are:
* - N Name of character
* - t title of character
* - T the optional "the " sequence value (depend if player has own_title or not)
* - c count
* - n newline
* - h \<Hostile\> if character is hostile, nothing otherwise
* - d \<WIZ\> if character is a dm, nothing otherwise
* - a \<AFK\> if character is afk, nothing otherwise
* - b \<BOT\> if character is a bot, nothing otherwise
* - l the level of the character
* - m the map path the character is currently on
* - M the map name of the map the character is currently on
* - p the party the player belongs to @@@
* - A the race of the player @@@
* - r the region name (eg scorn, wolfsburg)
* - R the regional title (eg The Kingdom of Scorn, The Port of Wolfsburg)
* - i player's ip address
* - % a literal %
* - _ a literal underscore
*
* @param[out] return_val
* buffer that will contain the information.
* @param size
* length of return_val.
* @param letter
* format specifier.
* @param pl
* player to get information for.
*/
void get_who_escape_code_value(char *return_val, int size, const char letter, player *pl) {
switch (letter) {
case 'N':
snprintf(return_val, size, "%s", pl->ob->name);
break;
case 't':
snprintf(return_val, size, "%s", (pl->own_title[0] == '\0' ? pl->title : pl->own_title));
break;
case 'T':
if (pl->own_title[0] == '\0')
snprintf(return_val, size, "the ");
else
*return_val = '\0';
break;
case 'c':
snprintf(return_val, size, "%u", pl->ob->count);
break;
case 'p':
if (pl->party)
snprintf(return_val, size, "%s", pl->party->partyname);
else
*return_val = '\0';
break;
case 'P':
if (pl->party)
snprintf(return_val, size, "of ");
else
*return_val = '\0';
break;
case 'A':
snprintf(return_val, size, "%s", pl->ob->race);
break;
case 'n':
snprintf(return_val, size, "\n");
break;
case 'h':
snprintf(return_val, size, "%s", pl->peaceful ? "" : " <Hostile>");
break;
case 'l':
snprintf(return_val, size, "%d", pl->ob->level);
break;
case 'd':
snprintf(return_val, size, "%s", (QUERY_FLAG(pl->ob, FLAG_WIZ) ? " <WIZ>" : ""));
break;
case 'a':
snprintf(return_val, size, "%s", (QUERY_FLAG(pl->ob, FLAG_AFK) ? " <AFK>" : ""));
break;
case 'b':
snprintf(return_val, size, "%s", (pl->socket.is_bot == 1) ? " <BOT>" : "");
break;
case 'm':
snprintf(return_val, size, "%s", pl->ob->map->path);
break;
case 'M':
snprintf(return_val, size, "%s", pl->ob->map->name ? pl->ob->map->name : "Untitled");
break;
case 'r':
snprintf(return_val, size, "%s", get_name_of_region_for_map(pl->ob->map));
break;
case 'R':
snprintf(return_val, size, "%s", get_region_longname(get_region_by_map(pl->ob->map)));
break;
case 'i':
snprintf(return_val, size, "%s", pl->socket.host);
break;
case '%':
snprintf(return_val, size, "%%");
break;
case '_':
snprintf(return_val, size, "_");
break;
}
}
/**
* Toggles the afk status of a player. 'afk' command.
*
* @param op
* player to toggle status for.
* @param params
* unused.
* @return
* 1.
*/
int command_afk(object *op, char *params) {
if QUERY_FLAG(op, FLAG_AFK) {
CLEAR_FLAG(op, FLAG_AFK);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_056), NULL);
} else {
SET_FLAG(op, FLAG_AFK);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_057), NULL);
}
return 1;
}
/**
* Display memory information.
*
* @param op
* player requesting information.
* @param params
* unused.
* @return
* 1.
*/
int command_malloc(object *op, char *params) {
malloc_info(op);
return 1;
}
/**
* 'mapinfo' command.
*
* @param op
* player requesting the information.
* @param params
* unused.
* @return
* 1.
*/
int command_mapinfo(object *op, char *params) {
current_map_info(op);
return 1;
}
/**
* 'whereami' command.
*
* @param op
* player requesting the information.
* @param params
* unused.
* @return
* 1.
*/
int command_whereami(object *op, char *params) {
current_region_info(op);
return 1;
}
/**
* 'maps' command.
*
* @param op
* player requesting the information.
* @param params
* region to restrict to.
*/
int command_maps(object *op, char *params) {
map_info(op, params);
return 1;
}
/**
* Various string-related statistics.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 1.
*/
int command_strings(object *op, char *params) {
char stats[HUGE_BUF];
ss_dump_statistics(stats, sizeof(stats));
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_LAST,
"[fixed]%s\n",
"%s",
stats);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_LAST,
ss_dump_table(SS_DUMP_TOTALS, stats, sizeof(stats)), NULL);
return 1;
}
/**
* Players asks for the time.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 1.
*/
int command_time(object *op, char *params) {
time_info(op);
return 1;
}
/**
* Archetype-related statistics. Wizard 'archs' command.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 1.
*/
int command_archs(object *op, char *params) {
arch_info(op);
return 1;
}
/**
* Player is asking for the hiscore.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 1.
*/
int command_hiscore(object *op, char *params) {
display_high_score(op, op == NULL ? 9999 : 50, params);
return 1;
}
/**
* Player wants to see/change the debug level.
*
* @param op
* player asking for information.
* @param params
* new debug value.
* @return
* 1.
*/
int command_debug(object *op, char *params) {
int i;
if (params == NULL || !sscanf(params, "%d", &i)) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_092),
i18n_translate(get_language(op), I18N_MSG_CMISC_092),
settings.debug);
return 1;
}
if (op != NULL && !QUERY_FLAG(op, FLAG_WIZ)) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_093), NULL);
return 1;
}
settings.debug = (enum LogLevel)FABS(i);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_094),
i18n_translate(get_language(op), I18N_MSG_CMISC_094),
i);
return 1;
}
/**
* Player wants to dump object below her.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_dumpbelow(object *op, char *params) {
if (op && op->below) {
StringBuffer *sb;
char *diff;
sb = stringbuffer_new();
dump_object(op->below, sb);
diff = stringbuffer_finish(sb);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE, diff, NULL);
free(diff);
/* Let's push that item on the dm's stack */
dm_stack_push(op->contr, op->below->count);
}
return 0;
}
/**
* Wizard toggling wall-crossing.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_wizpass(object *op, char *params) {
int i;
if (!op)
return 0;
if (!params)
i = (QUERY_FLAG(op, FLAG_WIZPASS)) ? 0 : 1;
else
i = onoff_value(params);
if (i) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_095), NULL);
SET_FLAG(op, FLAG_WIZPASS);
} else {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_096), NULL);
CLEAR_FLAG(op, FLAG_WIZPASS);
}
return 0;
}
/**
* Wizard toggling "cast everywhere" ability.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_wizcast(object *op, char *params) {
int i;
if (!op)
return 0;
if (!params)
i = (QUERY_FLAG(op, FLAG_WIZCAST)) ? 0 : 1;
else
i = onoff_value(params);
if (i) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_097), NULL);
SET_FLAG(op, FLAG_WIZCAST);
} else {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_098), NULL);
CLEAR_FLAG(op, FLAG_WIZCAST);
}
return 0;
}
/**
* Various object-related statistics.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_dumpallobjects(object *op, char *params) {
dump_all_objects();
return 0;
}
/**
* Various friendly object-related statistics.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_dumpfriendlyobjects(object *op, char *params) {
dump_friendly_objects();
return 0;
}
/**
* Various archetypes-related statistics.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_dumpallarchetypes(object *op, char *params) {
dump_all_archetypes();
return 0;
}
/**
* Various string-related statistics.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_ssdumptable(object *op, char *params) {
ss_dump_table(SS_DUMP_TABLE, NULL, 0);
return 0;
}
/**
* Various map-related statistics.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_dumpmap(object *op, char *params) {
if (op)
dump_map(op->map);
return 0;
}
/**
* Various map-related statistics.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_dumpallmaps(object *op, char *params) {
dump_all_maps();
return 0;
}
/**
* Various LOS-related statistics.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_printlos(object *op, char *params) {
if (op)
print_los(op);
return 0;
}
/**
* Server version.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_version(object *op, char *params) {
version(op);
return 0;
}
/**
* Output-sync command.
*
* @param op
* player asking for information.
* @param params
* new value.
* @return
* 1.
*/
int command_output_sync(object *op, char *params) {
int val;
if (!params) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_099),
i18n_translate(get_language(op), I18N_MSG_CMISC_099),
op->contr->outputs_sync);
return 1;
}
val = atoi(params);
if (val > 0) {
op->contr->outputs_sync = val;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_100),
i18n_translate(get_language(op), I18N_MSG_CMISC_100),
op->contr->outputs_sync);
} else
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_101), NULL);
return 1;
}
/**
* output-count command.
*
* @param op
* player asking for information.
* @param params
* new value.
* @return
* 1.
*/
int command_output_count(object *op, char *params) {
int val;
if (!params) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_102),
i18n_translate(get_language(op), I18N_MSG_CMISC_102),
op->contr->outputs_count);
return 1;
}
val = atoi(params);
if (val > 0) {
op->contr->outputs_count = val;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_103),
i18n_translate(get_language(op), I18N_MSG_CMISC_103),
op->contr->outputs_count);
} else
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_104), NULL);
return 1;
}
/**
* Change the player's listen level.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 1.
*/
int command_listen(object *op, char *params) {
int i;
if (params == NULL || !sscanf(params, "%d", &i)) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_105),
i18n_translate(get_language(op), I18N_MSG_CMISC_105),
op->contr->listening);
return 1;
}
if (i < 0) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_106), NULL);
return 1;
}
op->contr->listening = (char)i;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_107),
i18n_translate(get_language(op), I18N_MSG_CMISC_107),
i);
return 1;
}
/**
* Prints out some useful information for the character. Everything we print
* out can be determined by the docs, so we aren't revealing anything extra -
* rather, we are making it convenient to find the values. params have
* no meaning here.
*
* @param pl
* player asking for information.
* @param params
* unused.
* @return
* 1.
*/
int command_statistics(object *pl, char *params) {
char buf[MAX_BUF];
char buf2[MAX_BUF];
if (!pl->contr)
return 1;
strcpy(buf, i18n_translate(get_language(pl), I18N_MSG_CMISC_108));
strcpy(buf2, i18n_translate(get_language(pl), I18N_MSG_CMISC_109));
strcat(buf, FMT64);
strcat(buf2, FMT64);
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
buf,
buf2,
pl->stats.exp);
strcpy(buf, i18n_translate(get_language(pl), I18N_MSG_CMISC_110));
strcpy(buf2, i18n_translate(get_language(pl), I18N_MSG_CMISC_111));
strcat(buf, FMT64);
strcat(buf2, FMT64);
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
buf,
buf2,
level_exp(pl->level+1, pl->expmul));
draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
i18n_translate(get_language(pl), I18N_MSG_CMISC_112),
i18n_translate(get_language(pl), I18N_MSG_CMISC_113));
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
i18n_translate(get_language(pl), I18N_MSG_CMISC_114),
i18n_translate(get_language(pl), I18N_MSG_CMISC_115),
pl->contr->orig_stats.Str, pl->stats.Str, 20+pl->arch->clone.stats.Str);
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
i18n_translate(get_language(pl), I18N_MSG_CMISC_116),
i18n_translate(get_language(pl), I18N_MSG_CMISC_117),
pl->contr->orig_stats.Dex, pl->stats.Dex, 20+pl->arch->clone.stats.Dex);
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
i18n_translate(get_language(pl), I18N_MSG_CMISC_118),
i18n_translate(get_language(pl), I18N_MSG_CMISC_119),
pl->contr->orig_stats.Con, pl->stats.Con, 20+pl->arch->clone.stats.Con);
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
i18n_translate(get_language(pl), I18N_MSG_CMISC_120),
i18n_translate(get_language(pl), I18N_MSG_CMISC_121),
pl->contr->orig_stats.Int, pl->stats.Int, 20+pl->arch->clone.stats.Int);
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
i18n_translate(get_language(pl), I18N_MSG_CMISC_122),
i18n_translate(get_language(pl), I18N_MSG_CMISC_123),
pl->contr->orig_stats.Wis, pl->stats.Wis, 20+pl->arch->clone.stats.Wis);
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
i18n_translate(get_language(pl), I18N_MSG_CMISC_124),
i18n_translate(get_language(pl), I18N_MSG_CMISC_125),
pl->contr->orig_stats.Pow, pl->stats.Pow, 20+pl->arch->clone.stats.Pow);
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
i18n_translate(get_language(pl), I18N_MSG_CMISC_126),
i18n_translate(get_language(pl), I18N_MSG_CMISC_127),
pl->contr->orig_stats.Cha, pl->stats.Cha, 20+pl->arch->clone.stats.Cha);
draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_STATISTICS,
i18n_translate(get_language(pl), I18N_MSG_CMISC_128),
i18n_translate(get_language(pl), I18N_MSG_CMISC_129),
pl->contr->peaceful ? "Peaceful" : "Hostile");
/* Can't think of anything else to print right now */
return 0;
}
/**
* Wrapper to fix a player.
*
* @param op
* player asking to be fixed.
* @param params
* unused.
* @return
* 1.
*/
int command_fix_me(object *op, char *params) {
sum_weight(op);
fix_object(op);
return 1;
}
/**
* Display all known players.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_players(object *op, char *params) {
char buf[MAX_BUF];
char *t;
DIR *Dir;
snprintf(buf, sizeof(buf), "%s/%s/", settings.localdir, settings.playerdir);
t = buf+strlen(buf);
if ((Dir = opendir(buf)) != NULL) {
const struct dirent *Entry;
while ((Entry = readdir(Dir)) != NULL) {
/* skip '.' , '..' */
if (!((Entry->d_name[0] == '.' && Entry->d_name[1] == '\0')
|| (Entry->d_name[0] == '.' && Entry->d_name[1] == '.' && Entry->d_name[2] == '\0'))) {
struct stat Stat;
strcpy(t, Entry->d_name);
if (stat(buf, &Stat) == 0) {
/* This was not posix compatible
* if ((Stat.st_mode & S_IFMT)==S_IFDIR) {
*/
if (S_ISDIR(Stat.st_mode)) {
struct tm *tm = localtime(&Stat.st_mtime);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_130),
i18n_translate(get_language(op), I18N_MSG_CMISC_131),
Entry->d_name,
1900+tm->tm_year,
1+tm->tm_mon,
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
}
}
}
}
}
closedir(Dir);
return 0;
}
/**
* Players wants to change the apply mode, ie how to handle applying an item when no body slot available.
*
* @param op
* player asking for change.
* @param params
* new mode.
* @return
* 1.
*/
int command_applymode(object *op, char *params) {
unapplymode unapply = op->contr->unapply;
static const char *const types[] = {
"nochoice",
"never",
"always"
};
if (!params) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_132),
i18n_translate(get_language(op), I18N_MSG_CMISC_133),
types[op->contr->unapply]);
return 1;
}
if (!strcmp(params, "nochoice"))
op->contr->unapply = unapply_nochoice;
else if (!strcmp(params, "never"))
op->contr->unapply = unapply_never;
else if (!strcmp(params, "always"))
op->contr->unapply = unapply_always;
else {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_134),
i18n_translate(get_language(op), I18N_MSG_CMISC_134),
params);
return 0;
}
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_135),
i18n_translate(get_language(op), I18N_MSG_CMISC_135),
(unapply == op->contr->unapply ? "" : " now"),
types[op->contr->unapply]);
return 1;
}
/**
* Player wants to change the bowmode, how arrows are fired.
*
* @param op
* player asking for change.
* @param params
* new mode.
* @return
* 1.
*/
int command_bowmode(object *op, char *params) {
bowtype_t oldtype = op->contr->bowtype;
static const char *const types[] = {
"normal",
"threewide",
"spreadshot",
"firenorth",
"firene",
"fireeast",
"firese",
"firesouth",
"firesw",
"firewest",
"firenw",
"bestarrow",
"precise"
};
char buf[MAX_BUF];
int i, found;
if (!params) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_136),
i18n_translate(get_language(op), I18N_MSG_CMISC_136),
types[op->contr->bowtype]);
return 1;
}
for (i = 0, found = 0; i <= bow_precise; i++) {
if (!strcmp(params, types[i])) {
found++;
op->contr->bowtype = i;
break;
}
}
if (!found) {
snprintf(buf, sizeof(buf), "bowmode: Unknown options %s, valid options are:", params);
for (i = 0; i <= bow_precise; i++) {
strcat(buf, " ");
strcat(buf, types[i]);
if (i < bow_nw)
strcat(buf, ",");
else
strcat(buf, ".");
}
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG, buf, NULL);
return 0;
}
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_137),
i18n_translate(get_language(op), I18N_MSG_CMISC_137),
(oldtype == op->contr->bowtype ? "" : "now"),
types[op->contr->bowtype]);
return 1;
}
/**
* Player wants to change how her pets behave.
*
* @param op
* player asking for change.
* @param params
* new mode.
* @return
* 1.
*/
int command_petmode(object *op, char *params) {
petmode_t oldtype = op->contr->petmode;
static const char *const types[] = {
"normal",
"sad",
"defend",
"arena"
};
if (!params) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_138),
i18n_translate(get_language(op), I18N_MSG_CMISC_138),
types[op->contr->petmode]);
return 1;
}
if (!strcmp(params, "normal"))
op->contr->petmode = pet_normal;
else if (!strcmp(params, "sad"))
op->contr->petmode = pet_sad;
else if (!strcmp(params, "defend"))
op->contr->petmode = pet_defend;
else if (!strcmp(params, "arena"))
op->contr->petmode = pet_arena;
else {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_139),
i18n_translate(get_language(op), I18N_MSG_CMISC_139),
params);
return 0;
}
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_140),
i18n_translate(get_language(op), I18N_MSG_CMISC_140),
(oldtype == op->contr->petmode ? "" : "now"),
types[op->contr->petmode]);
return 1;
}
/**
* Players wants to know her pets.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_showpets(object *op, char *params) {
objectlink *obl, *next;
int counter = 0, target = 0;
int have_shown_pet = 0;
if (params != NULL)
target = atoi(params);
for (obl = first_friendly_object; obl != NULL; obl = next) {
object *ob = obl->ob;
next = obl->next;
if (get_owner(ob) == op) {
if (target == 0) {
if (counter == 0)
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_141), NULL);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_142),
i18n_translate(get_language(op), I18N_MSG_CMISC_142),
++counter, ob->name, ob->level);
} else if (!have_shown_pet && ++counter == target) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_143),
i18n_translate(get_language(op), I18N_MSG_CMISC_144),
ob->level, ob->name);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_145),
i18n_translate(get_language(op), I18N_MSG_CMISC_146),
ob->stats.hp, ob->stats.maxhp, ob->stats.sp, ob->stats.maxsp);
/* this is not a nice way to do this, it should be made to be more like the statistics command */
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_147),
i18n_translate(get_language(op), I18N_MSG_CMISC_148),
ob->stats.Str);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_149),
i18n_translate(get_language(op), I18N_MSG_CMISC_150),
ob->stats.Dex);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_151),
i18n_translate(get_language(op), I18N_MSG_CMISC_152),
ob->stats.Con);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_153),
i18n_translate(get_language(op), I18N_MSG_CMISC_154),
ob->stats.Int);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_155),
i18n_translate(get_language(op), I18N_MSG_CMISC_156),
ob->stats.Wis);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_157),
i18n_translate(get_language(op), I18N_MSG_CMISC_158),
ob->stats.Cha);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_159),
i18n_translate(get_language(op), I18N_MSG_CMISC_160),
ob->stats.Pow);
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_161),
i18n_translate(get_language(op), I18N_MSG_CMISC_162),
ob->stats.wc, ob->stats.dam, ob->stats.ac);
have_shown_pet = 1;
}
}
}
if (counter == 0)
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_163), NULL);
else if (target != 0 && have_shown_pet == 0)
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_164), NULL);
return 0;
}
/**
* Player wants to change how keys are used.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 1.
*/
int command_usekeys(object *op, char *params) {
usekeytype oldtype = op->contr->usekeys;
static const char *const types[] = {
"inventory",
"keyrings",
"containers"
};
if (!params) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_165),
i18n_translate(get_language(op), I18N_MSG_CMISC_165),
types[op->contr->usekeys]);
return 1;
}
if (!strcmp(params, "inventory"))
op->contr->usekeys = key_inventory;
else if (!strcmp(params, "keyrings"))
op->contr->usekeys = keyrings;
else if (!strcmp(params, "containers"))
op->contr->usekeys = containers;
else {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_166),
i18n_translate(get_language(op), I18N_MSG_CMISC_166),
params);
return 0;
}
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_167),
i18n_translate(get_language(op), I18N_MSG_CMISC_167),
(oldtype == op->contr->usekeys ? "" : "now"),
types[op->contr->usekeys]);
return 1;
}
/**
* Players wants to know her resistances.
*
* @param op
* player asking for information.
* @param params
* unused.
* @return
* 0.
*/
int command_resistances(object *op, char *params) {
int i;
if (!op)
return 0;
for (i = 0; i < NROFATTACKS; i++) {
if (i == ATNR_INTERNAL)
continue;
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_168),
i18n_translate(get_language(op), I18N_MSG_CMISC_169),
attacktype_desc[i], op->resist[i]);
}
/* If dragon player, let's display natural resistances */
if (is_dragon_pl(op)) {
int attack;
object *tmp;
for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
if ((tmp->type == FORCE) && (strcmp(tmp->arch->name, "dragon_skin_force") == 0)) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_170), NULL);
for (attack = 0; attack < NROFATTACKS; attack++) {
if (atnr_is_dragon_enabled(attack)) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_171),
i18n_translate(get_language(op), I18N_MSG_CMISC_171),
change_resist_msg[attack], tmp->resist[attack]);
}
}
break;
}
}
}
return 0;
}
/**
* Player wants to know available help topics.
*
* @param op
* player asking for information.
* @param what
* - 1: wizard topics.
* - 3: misc topics.
* - other: regular commands.
*/
static void help_topics(object *op, int what) {
DIR *dirp;
struct dirent *de;
char filename[MAX_BUF], line[HUGE_BUF];
char suffix[MAX_BUF];
int namelen;
const char *language;
language = language_codes[get_language(op)];
snprintf(suffix, sizeof(suffix), ".%s", language);
switch (what) {
case 1:
snprintf(filename, sizeof(filename), "%s/wizhelp", settings.datadir);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_172), NULL);
break;
case 3:
snprintf(filename, sizeof(filename), "%s/mischelp", settings.datadir);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_173), NULL);
break;
default:
snprintf(filename, sizeof(filename), "%s/help", settings.datadir);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_174), NULL);
break;
}
if (!(dirp = opendir(filename)))
return;
line[0] = '\0';
for (de = readdir(dirp); de; de = readdir(dirp)) {
namelen = NAMLEN(de);
if (namelen <= 2
&& *de->d_name == '.'
&& (namelen == 1 || de->d_name[1] == '.'))
continue;
if (strstr(de->d_name, suffix)) {
strcat(line, strtok(de->d_name, "."));
strcat(line, " ");
}
}
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
line, line);
closedir(dirp);
}
/**
* Helper function to display commands.
*
* @param op
* player asking for information.
* @param what
* - 1: display wizard commands.
* - 2: display communication commands.
* - other: display regular commands.
*/
static void show_commands(object *op, int what) {
char line[HUGE_BUF];
int i, size, namelen;
command_array_struct *ap;
switch (what) {
case 1:
ap = WizCommands;
size = WizCommandsSize;
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_175), NULL);
break;
case 2:
ap = CommunicationCommands;
size = CommunicationCommandSize;
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_176), NULL);
break;
default:
ap = Commands;
size = CommandsSize;
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_177), NULL);
break;
}
line[0] = '\0';
for (i = 0; i < size; i++) {
namelen = strlen(ap[i].name);
strcat(line, ap[i].name);
strcat(line, " ");
}
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, line, line);
}
/**
* Player is asking for some help.
*
* @param op
* player asking for information.
* @param params
* what kind of help to ask for.
* @return
* 0.
*/
int command_help(object *op, char *params) {
struct stat st;
FILE *fp;
char filename[MAX_BUF], line[MAX_BUF];
int len;
const char *language;
language = language_codes[get_language(op)];
/*
* Main help page?
*/
if (!params) {
snprintf(filename, sizeof(filename), "%s/def_help", settings.datadir);
if ((fp = fopen(filename, "r")) == NULL) {
LOG(llevError, "Cannot open help file %s: %s\n", filename, strerror_local(errno, line, sizeof(line)));
return 0;
}
while (fgets(line, MAX_BUF, fp)) {
line[MAX_BUF-1] = '\0';
len = strlen(line)-1;
if (line[len] == '\n')
line[len] = '\0';
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, line, NULL);
}
fclose(fp);
return 0;
}
/*
* Topics list
*/
if (!strcmp(params, "topics")) {
help_topics(op, 3);
help_topics(op, 0);
if (QUERY_FLAG(op, FLAG_WIZ))
help_topics(op, 1);
return 0;
}
/*
* Commands list
*/
if (!strcmp(params, "commands")) {
show_commands(op, 0);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "\n", NULL);
show_commands(op, 2); /* show comm commands */
if (QUERY_FLAG(op, FLAG_WIZ)) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, "\n", NULL);
show_commands(op, 1);
}
return 0;
}
/*
* User wants info about command
*/
if (strchr(params, '.') || strchr(params, ' ') || strchr(params, '/')) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_178),
i18n_translate(get_language(op), I18N_MSG_CMISC_178),
params);
return 0;
}
snprintf(filename, sizeof(filename), "%s/mischelp/%s.%s", settings.datadir, params, language);
if (stat(filename, &st) || !S_ISREG(st.st_mode)) {
if (op) {
snprintf(filename, sizeof(filename), "%s/help/%s.%s", settings.datadir, params, language);
if (stat(filename, &st) || !S_ISREG(st.st_mode)) {
if (QUERY_FLAG(op, FLAG_WIZ)) {
snprintf(filename, sizeof(filename), "%s/wizhelp/%s.%s", settings.datadir, params, language);
if (stat(filename, &st) || !S_ISREG(st.st_mode))
goto nohelp;
} else
goto nohelp;
}
}
}
/*
* Found that. Just cat it to screen.
*/
if ((fp = fopen(filename, "r")) == NULL) {
LOG(llevError, "Cannot open help file %s: %s\n", filename, strerror_local(errno, line, sizeof(line)));
return 0;
}
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_179),
i18n_translate(get_language(op), I18N_MSG_CMISC_179),
params);
while (fgets(line, MAX_BUF, fp)) {
line[MAX_BUF-1] = '\0';
len = strlen(line)-1;
if (line[len] == '\n')
line[len] = '\0';
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, line, NULL);
}
fclose(fp);
return 0;
/*
* No_help -escape
*/
nohelp:
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO,
i18n_translate(get_language(op), I18N_MSG_CMISC_180),
i18n_translate(get_language(op), I18N_MSG_CMISC_180),
params);
return 0;
}
/**
* Utility function to convert a reply to a yes/no or on/off value.
*
* @param line
* string to check.
* @retval 1
* line is one of on y k s d.
* @retval 0
* other value.
*/
int onoff_value(const char *line) {
int i;
if (sscanf(line, "%d", &i))
return (i != 0);
switch (line[0]) {
case 'o':
switch (line[1]) {
case 'n':
return 1; /* on */
default:
return 0; /* o[ff] */
}
case 'y': /* y[es] */
case 'k': /* k[ylla] */
case 's':
case 'd':
return 1;
case 'n': /* n[o] */
case 'e': /* e[i] */
case 'u':
default:
return 0;
}
}
/**
* Player wants to totally delete her character.
*
* @param op
* player wanting to delete her character.
* @param params
* unused.
* @return
* 1.
*/
int command_quit(object *op, char *params) {
send_query(&op->contr->socket, CS_QUERY_SINGLECHAR,
i18n_translate(get_language(op), I18N_MSG_CMISC_181));
op->contr->state = ST_CONFIRM_QUIT;
return 1;
}
/**
* Player wants to enter explore mode, that is never-dying mode.
*
* Don't allow people to exit explore mode. It otherwise becomes
* really easy to abuse this.
*
* @param op
* player asking for explore mode.
* @param params
* unused.
* @return
* 1.
*/
int command_explore(object *op, char *params) {
if (settings.explore_mode == FALSE) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_182), NULL);
return 1;
}
/*
* I guess this is the best way to see if we are solo or not. Actually,
* are there any cases when first_player->next==NULL and we are not solo?
*/
if ((first_player != op->contr) || (first_player->next != NULL)) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_183), NULL);
} else if (op->contr->explore)
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_184), NULL);
else {
op->contr->explore = 1;
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_185), NULL);
}
return 1;
}
/**
* Player wants to change sound status.
*
* @param op
* player asking for change.
* @param params
* unused.
* @return
* 1.
*/
int command_sound(object *op, char *params) {
if (!(op->contr->socket.sound&SND_MUTE)) {
op->contr->socket.sound = op->contr->socket.sound|SND_MUTE;
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_186), NULL);
} else {
op->contr->socket.sound = op->contr->socket.sound&~SND_MUTE;
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_187), NULL);
}
return 1;
}
/**
* A player just entered her name.
*
* Perhaps these should be in player.c, but that file is
* already a bit big.
*
* @param op
* player we're getting the name of.
*/
void receive_player_name(object *op) {
if (!check_name(op->contr, op->contr->write_buf+1)) {
get_name(op);
return;
}
FREE_AND_COPY(op->name, op->contr->write_buf+1);
FREE_AND_COPY(op->name_pl, op->contr->write_buf+1);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE, op->contr->write_buf, NULL);
op->contr->name_changed = 1;
get_password(op);
}
/**
* A player just entered her password, including for changing it.
*
* @param op
* player.
*/
void receive_player_password(object *op) {
unsigned int pwd_len = strlen(op->contr->write_buf);
if (pwd_len <= 1 || pwd_len > 17) {
if (op->contr->state == ST_CHANGE_PASSWORD_OLD
|| op->contr->state == ST_CHANGE_PASSWORD_NEW
|| op->contr->state == ST_CHANGE_PASSWORD_CONFIRM) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_188), NULL);
op->contr->state = ST_PLAYING;
} else
get_name(op);
return;
}
/* To hide the password better */
/* With currently clients, not sure if this is really the case - MSW */
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE, " ", NULL);
if (checkbanned(op->name, op->contr->socket.host)) {
LOG(llevInfo, "Banned player tried to add: [%s@%s]\n", op->name, op->contr->socket.host);
draw_ext_info(NDI_UNIQUE|NDI_RED, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_189), NULL);
get_name(op);
return;
}
if (op->contr->state == ST_CONFIRM_PASSWORD) {
if (!check_password(op->contr->write_buf+1, op->contr->password)) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_190), NULL);
get_name(op);
return;
}
LOG(llevInfo, "LOGIN: New player named %s from ip %s\n", op->name, op->contr->socket.host);
display_motd(op);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_191), NULL);
roll_again(op);
op->contr->state = ST_ROLL_STAT;
return;
}
if (op->contr->state == ST_CHANGE_PASSWORD_OLD) {
if (!check_password(op->contr->write_buf+1, op->contr->password)) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_192), NULL);
op->contr->state = ST_PLAYING;
} else {
send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, i18n_translate(get_language(op), I18N_MSG_CMISC_193));
op->contr->state = ST_CHANGE_PASSWORD_NEW;
}
return;
}
if (op->contr->state == ST_CHANGE_PASSWORD_NEW) {
strcpy(op->contr->new_password, crypt_string(op->contr->write_buf+1, NULL));
send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, i18n_translate(get_language(op), I18N_MSG_CMISC_194));
op->contr->state = ST_CHANGE_PASSWORD_CONFIRM;
return;
}
if (op->contr->state == ST_CHANGE_PASSWORD_CONFIRM) {
if (strcmp(crypt_string(op->contr->write_buf+1, op->contr->new_password), op->contr->new_password)) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_195), NULL);
} else {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_196), NULL);
strncpy(op->contr->password, op->contr->new_password, 13);
}
op->contr->state = ST_PLAYING;
return;
}
strcpy(op->contr->password, crypt_string(op->contr->write_buf+1, NULL));
op->contr->state = ST_ROLL_STAT;
check_login(op);
return;
}
/**
* Player wishes to change her title.
*
* @param op
* player asking for change.
* @param params
* new title.
* @return
* 1.
*/
int command_title(object *op, char *params) {
char buf[MAX_BUF];
if (settings.set_title == FALSE) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_197), NULL);
return 1;
}
/* dragon players cannot change titles */
if (is_dragon_pl(op)) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_198), NULL);
return 1;
}
if (params == NULL) {
if (op->contr->own_title[0] == '\0')
snprintf(buf, sizeof(buf), i18n_translate(get_language(op), I18N_MSG_CMISC_199), op->contr->title);
else
snprintf(buf, sizeof(buf), i18n_translate(get_language(op), I18N_MSG_CMISC_200), op->contr->own_title);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG, buf, NULL);
return 1;
}
if (strcmp(params, "clear") == 0 || strcmp(params, "default") == 0) {
if (op->contr->own_title[0] == '\0')
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_201), NULL);
else
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_202), NULL);
op->contr->own_title[0] = '\0';
return 1;
}
if ((int)strlen(params) >= MAX_NAME) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_203), NULL);
return 1;
}
strcpy(op->contr->own_title, params);
replace_unprintable_chars(op->contr->own_title);
return 1;
}
/**
* Player wants to get saved.
*
* @param op
* player.
* @param params
* unused.
* @return
* 1.
*/
int command_save(object *op, char *params) {
if (get_map_flags(op->map, NULL, op->x, op->y, NULL, NULL)&P_NO_CLERIC) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_204), NULL);
} else if (!op->stats.exp) {
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_205), NULL);
} else {
if (save_player(op, 1))
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_206), NULL);
else
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_207), NULL);
}
return 1;
}
/**
* Player toggles her peaceful status.
*
* @param op
* player.
* @param params
* unused.
* @return
* 1.
*/
int command_peaceful(object *op, char *params) {
if ((op->contr->peaceful = !op->contr->peaceful))
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_208), NULL);
else
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_209), NULL);
return 1;
}
/**
* Player wants to change how soon she'll flee.
*
* @param op
* player.
* @param params
* new value.
* @return
* 1.
*/
int command_wimpy(object *op, char *params) {
int i;
if (params == NULL || !sscanf(params, "%d", &i)) {
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_210),
i18n_translate(get_language(op), I18N_MSG_CMISC_210),
op->run_away);
return 1;
}
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_CONFIG,
i18n_translate(get_language(op), I18N_MSG_CMISC_211),
i18n_translate(get_language(op), I18N_MSG_CMISC_211),
i);
op->run_away = i;
return 1;
}
/**
* Player toggles her braced status.
*
* @param op
* player.
* @param params
* brace status (on/off).
* @return
* 1.
*/
int command_brace(object *op, char *params) {
if (!params)
op->contr->braced = !op->contr->braced;
else
op->contr->braced = onoff_value(params);
if (op->contr->braced)
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_212), NULL);
else
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_213), NULL);
fix_object(op);
return 0;
}
/**
* Player wants to get rid of pets.
*
* @param op
* player.
* @param params
* unused.
* @return
* 0.
*/
int command_kill_pets(object *op, char *params) {
objectlink *obl, *next;
int counter = 0, removecount = 0;
if (params == NULL) {
terminate_all_pets(op);
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_214), NULL);
} else {
int target = atoi(params);
for (obl = first_friendly_object; obl != NULL; obl = next) {
object *ob = obl->ob;
next = obl->next;
if (get_owner(ob) == op)
if (++counter == target || (target == 0 && !strcasecmp(ob->name, params))) {
if (!QUERY_FLAG(ob, FLAG_REMOVED))
remove_ob(ob);
remove_friendly_object(ob);
free_object(ob);
removecount++;
}
}
if (removecount != 0)
draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_215),
i18n_translate(get_language(op), I18N_MSG_CMISC_215),
removecount);
else
draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_SUBTYPE_NONE,
i18n_translate(get_language(op), I18N_MSG_CMISC_216), NULL);
}
return 0;
}
/**
* Player is asking to change password.
*
* @param pl
* player.
* @param params
* unused.
* @return
* 1.
*/
int command_passwd(object *pl, char *params) {
send_query(&pl->contr->socket, CS_QUERY_HIDEINPUT, i18n_translate(get_language(pl), I18N_MSG_CMISC_217));
pl->contr->state = ST_CHANGE_PASSWORD_OLD;
return 1;
}
/**
* Player is trying to harvest something.
* @param pl
* player trying to harvest.
* @param dir
* direction.
* @param skill
* skill being used.
* @return
* 0
*/
int do_harvest(object *pl, int dir, object *skill) {
sint16 x, y;
int count = 0, proba; /* Probability to get the item, 100 based. */
int level, exp;
object *found[10]; /* Found items that can be harvested. */
mapstruct *map;
object *item, *inv;
sstring trace, ttool, tspeed, race, tool, slevel, sexp;
float speed;
x = pl->x+freearr_x[dir];
y = pl->y+freearr_y[dir];
map = pl->map;
if (!pl->type == PLAYER)
return 0;
if (!map)
return 0;
if (get_map_flags(map, &map, x, y, &x, &y)&P_OUT_OF_MAP) {
draw_ext_info_format(NDI_WHITE, 0, pl, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You can't %s anything here.", NULL, skill->slaying);
return 0;
}
if (!pl->chosen_skill || pl->chosen_skill->skill != skill->skill)
return 0;
trace = get_ob_key_value(pl->chosen_skill, "harvest_race");
ttool = get_ob_key_value(pl->chosen_skill, "harvest_tool");
tspeed = get_ob_key_value(pl->chosen_skill, "harvest_speed");
if (!trace || strcmp(trace, "") == 0 || !ttool || strcmp(ttool, "") == 0 || !tspeed || strcmp(tspeed, "") == 0) {
draw_ext_info_format(NDI_WHITE, 0, pl, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You can't %s anything here.", NULL, skill->slaying);
LOG(llevError, "do_harvest: tool %s without harvest_[race|tool|speed]\n", pl->chosen_skill->name);
return 0;
}
item = GET_MAP_OB(map, x, y);
while (item && count < 10) {
for (inv = item->inv; inv; inv = inv->below) {
if (get_ob_key_value(inv, "harvestable") == NULL)
continue;
race = get_ob_key_value(inv, "harvest_race");
tool = get_ob_key_value(inv, "harvest_tool");
slevel = get_ob_key_value(inv, "harvest_level");
sexp = get_ob_key_value(inv, "harvest_exp");
if (race && (!slevel || !sexp)) {
LOG(llevError, "do_harvest: item %s without harvest_[level|exp]\n", inv->name);
continue;
}
if (race == trace && (!tool || tool == ttool))
found[count++] = inv;
}
item = item->above;
}
if (count == 0) {
draw_ext_info_format(NDI_WHITE, 0, pl, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You can't %s anything here.", NULL, skill->slaying);
return 0;
}
inv = found[rndm(0, count-1)];
assert(inv);
slevel = get_ob_key_value(inv, "harvest_level");
sexp = get_ob_key_value(inv, "harvest_exp");
level = atoi(slevel);
exp = atoi(sexp);
speed = atof(tspeed);
if (speed < 0)
speed = -speed*pl->speed;
pl->speed_left -= speed;
/* Now we found something to harvest, randomly try to get it. */
if (level > skill->level+10) {
draw_ext_info_format(NDI_WHITE, 0, pl, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You fail to %s anything.", NULL, skill->slaying);
return 0;
}
if (level >= skill->level)
/* Up to 10 more levels, 1 to 11 percent probability. */
proba = 10+skill->level-level;
else if (skill->level <= level+10)
proba = 10+(skill->level-level)*2;
else
proba = 30;
if (proba <= random_roll(0, 100, pl, 1)) {
draw_ext_info_format(NDI_WHITE, 0, pl, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You fail to %s anything.", NULL, skill->slaying);
return 0;
}
/* Ok, got it. */
item = get_object();
copy_object_with_inv(inv, item);
set_ob_key_value(item, "harvestable", NULL, 0);
if (QUERY_FLAG(item, FLAG_MONSTER)) {
int spot = find_free_spot(item, pl->map, pl->x, pl->y, 0, SIZEOFFREE);
if (spot == -1) {
/* Better luck next time...*/
remove_ob(item);
draw_ext_info_format(NDI_WHITE, 0, pl, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You fail to %s anything.", NULL, skill->slaying);
return 0;
}
item->x = pl->x+freearr_x[spot];
item->y = pl->y+freearr_y[spot];
insert_ob_in_map(item, pl->map, NULL, 0);
draw_ext_info_format(NDI_WHITE, 0, pl, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You %s a %s!", NULL, skill->slaying, item->name);
} else {
item = insert_ob_in_ob(item, pl);
draw_ext_info_format(NDI_WHITE, 0, pl, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You %s some %s", NULL, skill->slaying, item->name);
}
/* Get exp */
change_exp(pl, exp, skill->name, SK_EXP_ADD_SKILL);
return 0;
}