/* ************************************************************************
* File: modify.c Part of CircleMUD *
* Usage: Run-time modification of game variables *
* *
* All rights reserved. See license.doc for complete information. *
* *
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
************************************************************************ */
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "comm.h"
#include "spells.h"
#include "mail.h"
#include "boards.h"
void show_string(struct descriptor_data *d, char *input);
char *string_fields[] =
{
"name",
"short",
"long",
"description",
"title",
"delete-description",
"\n"
};
/* maximum length for text field x+1 */
int length[] =
{
15,
60,
256,
240,
60
};
/* ************************************************************************
* modification of malloc'ed strings *
************************************************************************ */
/* Add user input to the 'current' string (as defined by d->str) */
void string_add(struct descriptor_data *d, char *str)
{
int terminator = 0;
extern char *MENU;
/* determine if this is the terminal string, and truncate if so */
/* changed to only accept '@' at the beginning of line - J. Elson 1/17/94 */
delete_doubledollar(str);
if ((terminator = (*str == '@')))
*str = '\0';
if (!(*d->str)) {
if (strlen(str) > d->max_str) {
send_to_char("String too long - Truncated.\r\n",
d->character);
*(str + d->max_str) = '\0';
terminator = 1;
}
CREATE(*d->str, char, strlen(str) + 3);
strcpy(*d->str, str);
} else {
if (strlen(str) + strlen(*d->str) > d->max_str) {
send_to_char("String too long. Last line skipped.\r\n", d->character);
terminator = 1;
} else {
if (!(*d->str = (char *) realloc(*d->str, strlen(*d->str) +
strlen(str) + 3))) {
perror("string_add");
exit(1);
}
strcat(*d->str, str);
}
}
if (terminator) {
if (!d->connected && (PLR_FLAGGED(d->character, PLR_MAILING))) {
store_mail(d->mail_to, GET_IDNUM(d->character), *d->str);
d->mail_to = 0;
free(*d->str);
free(d->str);
SEND_TO_Q("Message sent!\r\n", d);
if (!IS_NPC(d->character))
REMOVE_BIT(PLR_FLAGS(d->character), PLR_MAILING | PLR_WRITING);
}
d->str = NULL;
if (d->mail_to >= BOARD_MAGIC) {
Board_save_board(d->mail_to - BOARD_MAGIC);
d->mail_to = 0;
}
if (d->connected == CON_EXDESC) {
SEND_TO_Q(MENU, d);
d->connected = CON_MENU;
}
if (!d->connected && d->character && !IS_NPC(d->character))
REMOVE_BIT(PLR_FLAGS(d->character), PLR_WRITING);
} else
strcat(*d->str, "\r\n");
}
/* **********************************************************************
* Modification of character skills *
********************************************************************** */
ACMD(do_skillset)
{
extern char *spells[];
struct char_data *vict;
char name[100], buf2[100], buf[100], help[MAX_STRING_LENGTH];
int skill, value, i, qend;
argument = one_argument(argument, name);
if (!*name) { /* no arguments. print an informative text */
send_to_char("Syntax: skillset <name> '<skill>' <value>\r\n", ch);
strcpy(help, "Skill being one of the following:\n\r");
for (i = 0; *spells[i] != '\n'; i++) {
if (*spells[i] == '!')
continue;
sprintf(help + strlen(help), "%18s", spells[i]);
if (i % 4 == 3) {
strcat(help, "\r\n");
send_to_char(help, ch);
*help = '\0';
}
}
if (*help)
send_to_char(help, ch);
send_to_char("\n\r", ch);
return;
}
if (!(vict = get_char_vis(ch, name))) {
send_to_char(NOPERSON, ch);
return;
}
skip_spaces(&argument);
/* If there is no chars in argument */
if (!*argument) {
send_to_char("Skill name expected.\n\r", ch);
return;
}
if (*argument != '\'') {
send_to_char("Skill must be enclosed in: ''\n\r", ch);
return;
}
/* Locate the last quote && lowercase the magic words (if any) */
for (qend = 1; *(argument + qend) && (*(argument + qend) != '\''); qend++)
*(argument + qend) = LOWER(*(argument + qend));
if (*(argument + qend) != '\'') {
send_to_char("Skill must be enclosed in: ''\n\r", ch);
return;
}
strcpy(help, (argument + 1));
help[qend - 1] = '\0';
if ((skill = find_skill_num(help)) <= 0) {
send_to_char("Unrecognized skill.\n\r", ch);
return;
}
argument += qend + 1; /* skip to next parameter */
argument = one_argument(argument, buf);
if (!*buf) {
send_to_char("Learned value expected.\n\r", ch);
return;
}
value = atoi(buf);
if (value < 0) {
send_to_char("Minimum value for learned is 0.\n\r", ch);
return;
}
if (value > 100) {
send_to_char("Max value for learned is 100.\n\r", ch);
return;
}
if (IS_NPC(vict)) {
send_to_char("You can't set NPC skills.\n\r", ch);
return;
}
sprintf(buf2, "%s changed %s's %s to %d.", GET_NAME(ch), GET_NAME(vict),
spells[skill], value);
mudlog(buf2, BRF, -1, TRUE);
SET_SKILL(vict, skill, value);
sprintf(buf2, "You change %s's %s to %d.\n\r", GET_NAME(vict),
spells[skill], value);
send_to_char(buf2, ch);
}
/*********************************************************************
* New Pagination Code
* Michael Buselli submitted the following code for an enhanced pager
* for CircleMUD. All functions below are his. --JE 8 Mar 96
*
*********************************************************************/
#define PAGE_LENGTH 22
#define PAGE_WIDTH 80
/* Traverse down the string until the begining of the next page has been
* reached. Return NULL if this is the last page of the string.
*/
char *next_page(char *str)
{
int col = 1, line = 1, spec_code = FALSE;
for (;; str++) {
/* If end of string, return NULL. */
if (*str == '\0')
return NULL;
/* If we're at the start of the next page, return this fact. */
else if (line > PAGE_LENGTH)
return str;
/* Check for the begining of an ANSI color code block. */
else if (*str == '\x1B' && !spec_code)
spec_code = TRUE;
/* Check for the end of an ANSI color code block. */
else if (*str == 'm' && spec_code)
spec_code = FALSE;
/* Check for everything else. */
else if (!spec_code) {
/* Carriage return puts us in column one. */
if (*str == '\r')
col = 1;
/* Newline puts us on the next line. */
else if (*str == '\n')
line++;
/* We need to check here and see if we are over the page width,
* and if so, compensate by going to the begining of the next line.
*/
else if (++col > PAGE_WIDTH) {
col = 1;
line++;
}
}
}
}
/* Function that returns the number of pages in the string. */
int count_pages(char *str)
{
int pages;
for (pages = 1; (str = next_page(str)); pages++);
return pages;
}
/* This function assigns all the pointers for showstr_vector for the
* page_string function, after showstr_vector has been allocated and
* showstr_count set.
*/
void paginate_string(char *str, struct descriptor_data *d)
{
int i;
if (d->showstr_count)
*(d->showstr_vector) = str;
for (i = 1; i < d->showstr_count && str; i++)
str = d->showstr_vector[i] = next_page(str);
d->showstr_page = 0;
}
/* The call that gets the paging ball rolling... */
void page_string(struct descriptor_data *d, char *str, int keep_internal)
{
if (!d)
return;
if (!str || !*str) {
send_to_char("", d->character);
return;
}
CREATE(d->showstr_vector, char *, d->showstr_count = count_pages(str));
if (keep_internal) {
d->showstr_head = str_dup(str);
paginate_string(d->showstr_head, d);
} else
paginate_string(str, d);
show_string(d, "");
}
/* The call that displays the next page. */
void show_string(struct descriptor_data *d, char *input)
{
char buffer[MAX_STRING_LENGTH];
int diff;
one_argument(input, buf);
/* Q is for quit. :) */
if (LOWER(*buf) == 'q') {
free(d->showstr_vector);
d->showstr_count = 0;
if (d->showstr_head) {
free(d->showstr_head);
d->showstr_head = 0;
}
return;
}
/* R is for refresh, so back up one page internally so we can display
* it again.
*/
else if (LOWER(*buf) == 'r')
d->showstr_page = MAX(0, d->showstr_page - 1);
/* B is for back, so back up two pages internally so we can display the
* correct page here.
*/
else if (LOWER(*buf) == 'b')
d->showstr_page = MAX(0, d->showstr_page - 2);
/* Feature to 'goto' a page. Just type the number of the page and you
* are there!
*/
else if (isdigit(*buf))
d->showstr_page = MAX(0, MIN(atoi(buf) - 1, d->showstr_count - 1));
else if (*buf) {
send_to_char(
"Valid commands while paging are RETURN, Q, R, B, or a numeric value.\r\n",
d->character);
return;
}
/* If we're displaying the last page, just send it to the character, and
* then free up the space we used.
*/
if (d->showstr_page + 1 >= d->showstr_count) {
send_to_char(d->showstr_vector[d->showstr_page], d->character);
free(d->showstr_vector);
d->showstr_count = 0;
if (d->showstr_head) {
free(d->showstr_head);
d->showstr_head = NULL;
}
}
/* Or if we have more to show.... */
else {
strncpy(buffer, d->showstr_vector[d->showstr_page],
diff = ((int) d->showstr_vector[d->showstr_page + 1])
- ((int) d->showstr_vector[d->showstr_page]));
buffer[diff] = '\0';
send_to_char(buffer, d->character);
d->showstr_page++;
}
}