/* ************************************************************************
* 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 <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include "structs.h"
#include "awake.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"
#include "olc.h"
#include "quest.h"
#include "newmagic.h"
#include "mag_create.h"
void show_string(struct descriptor_data *d, char *input);
void qedit_disp_menu(struct descriptor_data *d);
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 *
************************************************************************ */
int add_spaces(char *str, int size, int from, int spaces)
{
int i;
if (strlen(str) + spaces > (u_int)size)
return 0;
for (i = strlen(str) + spaces; i > from + spaces - 1; i--)
str[i] = str[i-spaces];
return 1;
}
void format_string(struct descriptor_data *d, int indent)
{
int i, j, k, line;
// if the editor is an implementor and begins with the sequence
// /**/, then we know not to format this string
if (*(*d->str) == '/' && access_level(d->character, LVL_OWNER) &&
*(*d->str + 1) == *(*d->str + 2) == '*' && *(*d->str + 3) == '/') {
for (i = 0; i < (int)(strlen(*d->str) - 4); i++)
(*d->str)[i] = (*d->str)[i+4];
return;
}
char *format = new char[d->max_str];
for (i = 0; (*d->str)[i]; i++)
while ((*d->str)[i] == '\r' || (*d->str)[i] == '\n') {
if ((*d->str)[i] == '\n' && (*d->str)[i+1] != '\r')
(*d->str)[i] = ' ';
else for (j = i; (*d->str)[j]; j++)
(*d->str)[j] = (*d->str)[j+1];
if ((*d->str)[i] == '\r') {
i += 2;
if (indent && add_spaces(*d->str, d->max_str, i, 3)) {
(*d->str)[i] = (*d->str)[i+1] = (*d->str)[i+2] = ' ';
while ((*d->str)[i+3] == ' ')
for (j = i+3; (*d->str)[j]; j++)
(*d->str)[j] = (*d->str)[j+1];
(*d->str)[i+3] = UPPER((*d->str)[i+3]);
} else if (add_spaces(*d->str, d->max_str, i, 2)) {
(*d->str)[i] = '\r';
(*d->str)[i+1] = '\n';
while ((*d->str)[i+2] == ' ')
for (j = i+2; (*d->str)[j]; j++)
(*d->str)[j] = (*d->str)[j+1];
(*d->str)[i+2] = UPPER((*d->str)[i+2]);
}
}
}
sprintf(format, "%s%s\r\n", indent ? " " : "", *d->str);
for (k = 0; strlen(format) > (u_int)k;) {
line = 78;
for (i = k, j = 0; format[i] && j < 79; i++)
if (format[i] == '^' && (i < 1 || format[i-1] != '^') && format[i+1]) {
switch (LOWER(format[i+1])) {
case 'b': case 'c': case 'g': case 'l': case 'm':
case 'n': case 'r': case 'w': case 'y':
line += 2;
break;
case '^':
line++;
j++;
break;
default:
j += 2;
break;
}
} else j++;
for (i = MIN(strlen(format) - 1, k + line); i > k; i--)
if (format[i] == '\n' && format[i-1] == '\r') {
k = i + 1;
break;
}
for (i = MIN(strlen(format) - 1, k + line); i > k; i--)
if (isspace(format[i]) && isprint(format[i-1]) && !isspace(format[i-1])) {
format[i] = '\r';
if (format[i+1] != ' ')
add_spaces(format, d->max_str, i, 1);
format[i+1] = '\n';
i += 2;
while (format[i] == ' ')
for (j = i; format[j]; j++)
format[j] = format[j+1];
k = i;
break;
}
}
i = MAX(strlen(format)-1, 3);
if (format[i] == '\n' && format[i-1] == '\r' && format[i-2] == '\n' && format[i-3] == '\r')
format[i-1] = '\0';
delete [] *d->str;
*d->str = format;
}
/* 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';
else if (*str == '$' && !str_cmp(str, "$abort") && !d->connected) {
SEND_TO_Q("Aborted.\r\n", d);
d->mail_to = 0;
delete [] *d->str;
delete d->str;
d->str = NULL;
if (!IS_NPC(d->character))
REMOVE_BIT(PLR_FLAGS(d->character), PLR_MAILING | PLR_WRITING);
return;
}
if (!(*d->str)) {
if (strlen(str) > (u_int)d->max_str) {
send_to_char("String too long - Truncated.\r\n",
d->character);
*(str + d->max_str) = '\0';
terminator = 1;
}
*d->str = new char[strlen(str) + 3];
strcpy(*d->str, str);
} else {
if (strlen(str) + strlen(*d->str) > (u_int)d->max_str) {
send_to_char("String too long. Last line skipped.\r\n", d->character);
terminator = 1;
} else {
//if (!(*d->str = (char *) xrealloc(*d->str, strlen(*d->str) +
// strlen(str) + 3))) {
char *temp = new char[strlen(*d->str) + strlen(str) + 3];
if (!temp) {
perror("string_add");
exit(1);
}
strcpy (temp, *d->str);
strcat(temp, str);
delete [] *d->str;
*d->str = temp;
}
}
if (terminator) {
extern void iedit_disp_menu(struct descriptor_data *d);
extern void iedit_disp_extradesc_menu(struct descriptor_data *d);
extern void redit_disp_menu(struct descriptor_data *d);
extern void redit_disp_extradesc_menu(struct descriptor_data *d);
extern void redit_disp_exit_menu(struct descriptor_data *d);
extern void medit_disp_menu(struct descriptor_data *d);
extern void cedit_disp_menu(struct descriptor_data *d, int mode);
if (STATE(d) == CON_IEDIT) {
switch(d->edit_mode) {
case IEDIT_EXTRADESC_DESCRIPTION:
if (((struct extra_descr_data *)*d->misc_data)->description)
delete [] ((struct extra_descr_data *)*d->misc_data)->description;
format_string(d, 0);
((struct extra_descr_data *)*d->misc_data)->description =
str_dup(*d->str);
delete [] *d->str;
delete d->str;
iedit_disp_extradesc_menu(d);
break;
case IEDIT_LONGDESC:
if (d->edit_obj->long_description)
delete [] d->edit_obj->long_description;
format_string(d, 0);
d->edit_obj->long_description = str_dup(*d->str);
delete [] *d->str;
delete d->str;
iedit_disp_menu(d);
break;
}
} else if (STATE(d) == CON_MEDIT) {
switch(d->edit_mode) {
case MEDIT_LONG_DESCR:
if (d->edit_mob->player.description)
delete [] d->edit_mob->player.description;
format_string(d, 0);
d->edit_mob->player.description = str_dup(*d->str);
delete [] *d->str;
delete d->str;
medit_disp_menu(d);
break;
case MEDIT_REG_DESCR:
if (d->edit_mob->player.long_descr)
delete [] d->edit_mob->player.long_descr;
format_string(d, 0);
d->edit_mob->player.long_descr = str_dup(*d->str);
delete [] *d->str;
delete d->str;
medit_disp_menu(d);
break;
}
} else if (STATE(d) == CON_REDIT) {
switch(d->edit_mode) {
case REDIT_DESC:
if (d->edit_room->description)
delete [] d->edit_room->description;
format_string(d, 1);
d->edit_room->description = str_dup(*d->str);
delete [] *d->str;
delete d->str;
redit_disp_menu(d);
break;
case REDIT_EXTRADESC_DESCRIPTION:
if (((struct extra_descr_data *)*d->misc_data)->description)
delete ((struct extra_descr_data *)*d->misc_data)->description;
format_string(d, 0);
((struct extra_descr_data *)*d->misc_data)->description =
str_dup(*d->str);
delete [] *d->str;
delete d->str;
redit_disp_extradesc_menu(d);
break;
case REDIT_EXIT_DESCRIPTION:
if (d->edit_room->dir_option[d->edit_number2]->general_description)
delete [] d->edit_room->dir_option[d->edit_number2]->general_description;
format_string(d, 0);
d->edit_room->dir_option[d->edit_number2]->general_description =
str_dup(*d->str);
delete [] *d->str;
delete d->str;
redit_disp_exit_menu(d);
break;
}
} else if (STATE(d) == CON_QEDIT && d->edit_mode == QEDIT_INFO) {
if (d->edit_quest->info)
delete [] d->edit_quest->info;
format_string(d, 0);
d->edit_quest->info = str_dup(*d->str);
delete [] *d->str;
delete d->str;
qedit_disp_menu(d);
} else if (STATE(d) == CON_PCUSTOMIZE || STATE(d) == CON_ACUSTOMIZE) {
switch(d->edit_mode) {
case CEDIT_LONG_DESC:
if (d->edit_mob->player.description)
delete [] d->edit_mob->player.description;
format_string(d, 0);
d->edit_mob->player.description = str_dup(*d->str);
delete [] *d->str;
delete d->str;
cedit_disp_menu(d, 0);
break;
case CEDIT_DESC:
if (d->edit_mob->player.long_descr)
delete [] d->edit_mob->player.long_descr;
format_string(d, 0);
d->edit_mob->player.long_descr = str_dup(*d->str);
delete [] *d->str;
delete d->str;
cedit_disp_menu(d, 0);
break;
}
} else if (!d->connected && (PLR_FLAGGED(d->character, PLR_MAILING))) {
store_mail(d->mail_to, GET_IDNUM(d->character), *d->str);
d->mail_to = 0;
delete [] *d->str;
delete 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);
}
if (d->mail_to >= BOARD_MAGIC) {
time_t now = time(0);
char *tmstr = (char *) asctime(localtime(&now)), tmp[80], time[9];
int i, day, month, year;
for (i = 0; i < 3; i++)
tmp[i] = tmstr[4+i];
tmp[3] = '\0';
switch (tmp[0]) {
case 'A':
if (tmp[1] == 'p') month = 4;
else month = 8;
break;
case 'D': month = 12; break;
case 'F': month = 2; break;
case 'J':
if (tmp[1] == 'a') month = 1;
else if (tmp[2] == 'n') month = 6;
else month = 7;
break;
case 'M':
if (tmp[2] == 'r') month = 3;
else month = 5;
break;
case 'N': month = 11; break;
case 'O': month = 10; break;
case 'S': month = 9; break;
default: month = 0; break;
}
for (i = 0; i < 2; i++)
tmp[i] = tmstr[8+i];
tmp[2] = '\0';
day = atoi(tmp);
for (i = 0; i < 8; i++)
time[i] = tmstr[11+i];
time[8] = '\0';
for (i = 0; i < 2; i++)
tmp[i] = tmstr[22+i];
tmp[2] = '\0';
year = atoi(tmp);
sprintf(tmp, "\r\n--%s (%s/%s%d-%s%d-%s%d)\r\n",
GET_NAME(d->character), time, month < 10 ? "0" : "", month,
day < 10 ? "0" : "", day, year < 10 ? "0" : "", year);
char *ptr = new char[strlen(*d->str) + strlen(tmp) + 1];
if (!ptr) {
perror("string_add");
exit(1);
}
strcpy (ptr, *d->str);
strcat(ptr, tmp);
delete [] *d->str;
*d->str = ptr;
Board_save_board(d->mail_to - BOARD_MAGIC);
d->mail_to = 0;
}
d->str = NULL;
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;
extern int max_ability(int i);
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:\r\n");
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("\r\n", 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.\r\n", ch);
return;
}
if (*argument != '\'') {
send_to_char("Skill must be enclosed in: ''\r\n", 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: ''\r\n", ch);
return;
}
strcpy(help, (argument + 1));
help[qend - 1] = '\0';
if ((skill = find_skill_num(help)) <= 0) {
send_to_char("Unrecognized skill.\r\n", ch);
return;
}
argument += qend + 1; /* skip to next parameter */
argument = one_argument(argument, buf);
if (!*buf) {
send_to_char("Learned value expected.\r\n", ch);
return;
}
value = atoi(buf);
if (value < 0) {
send_to_char("Minimum value for learned is 0.\r\n", ch);
return;
}
if (value > 100) {
send_to_char("Max value for learned is 100.\r\n", ch);
return;
}
if (IS_NPC(vict)) {
send_to_char("You can't set NPC skills.\r\n", ch);
return;
}
sprintf(buf2, "%s changed %s's %s to %d.", GET_NAME(ch), GET_NAME(vict),
spells[skill], value);
mudlog(buf2, ch, LOG_WIZLOG, TRUE);
if (skill > SKILL_CLIMBING && skill <= SKILL_RESISTANCE)
value = MIN(value, max_ability(skill));
SET_SKILL(vict, skill, value);
sprintf(buf2, "You change %s's %s to %d.\r\n", GET_NAME(vict), spells[skill], value);
send_to_char(buf2, ch);
if ( skill > MAX_SPELLS )
return;
struct spell_data *spell = find_spell(vict, spells[skill]);
if (!spell)
{
extern spell_a grimoire[];
spell = new struct spell_data;
i = strlen(spells[skill]);
spell->name = new char[i + 1];
strcpy(spell->name, spells[skill]);
spell->physical = grimoire[skill].physical;
spell->category = grimoire[skill].category;
spell->target = grimoire[skill].target;
spell->drain = grimoire[skill].drain;
spell->damage = grimoire[skill].damage;
spell->effect = SPELL_EFFECT_NONE;
spell->type = skill;
spell->next = NULL;
if (!vict->spells) {
vict->spells = spell;
spell->next = NULL;
} else {
spell->next = vict->spells;
vict->spells = spell;
}
}
spell->force = value;
}
/* db stuff *********************************************** */
/* One_Word is like one_argument, execpt that words in quotes "" are */
/* regarded as ONE word */
char *one_word(char *argument, char *first_arg)
{
int found, begin, look_at;
found = begin = 0;
do {
for (; isspace(*(argument + begin)); begin++);
if (*(argument + begin) == '\"') { /* is it a quote */
begin++;
for (look_at = 0; (*(argument + begin + look_at) >= ' ') &&
(*(argument + begin + look_at) != '\"'); look_at++)
*(first_arg + look_at) = LOWER(*(argument + begin + look_at));
if (*(argument + begin + look_at) == '\"')
begin++;
} else {
for (look_at = 0; *(argument + begin + look_at) > ' '; look_at++)
*(first_arg + look_at) = LOWER(*(argument + begin + look_at));
}
*(first_arg + look_at) = '\0';
begin += look_at;
} while (fill_word(first_arg));
return (argument + begin);
}
struct help_index_element *build_help_index(FILE * fl, int *num)
{
int nr = -1, issorted, i;
struct help_index_element *list = 0, mem;
char buf[128], tmp[128], *scan;
long pos;
int count_hash_records(FILE * fl);
i = count_hash_records(fl) * 5;
rewind(fl);
list = new struct help_index_element[i];
for (;;) {
pos = ftell(fl);
fgets(buf, 128, fl);
*(buf + strlen(buf) - 1) = '\0';
scan = buf;
for (;;) {
/* extract the keywords */
scan = one_word(scan, tmp);
if (!*tmp)
break;
nr++;
list[nr].pos = pos;
list[nr].keyword = new char[strlen(tmp) + 1];
strcpy(list[nr].keyword, tmp);
}
/* skip the text */
do
fgets(buf, 128, fl);
while (*buf != '#');
if (*(buf + 1) == '~')
break;
}
/* we might as well sort the stuff */
do {
issorted = 1;
for (i = 0; i < nr; i++)
if (str_cmp(list[i].keyword, list[i + 1].keyword) > 0) {
mem = list[i];
list[i] = list[i + 1];
list[i + 1] = mem;
issorted = 0;
}
} while (!issorted);
*num = nr;
return (list);
}
void page_string(struct descriptor_data *d, char *str, int keep_internal)
{
if (!d)
return;
if (keep_internal) {
d->showstr_head = new char[strlen(str) + 1];
strcpy(d->showstr_head, str);
d->showstr_point = d->showstr_head;
} else
d->showstr_point = str;
show_string(d, "");
}
// this adds text onto the string paging system
void add_page_string(struct descriptor_data *d, char *str)
{
#ifdef DEBUG
if (!d)
return;
#endif
if (d->showstr_head)
{
register char *temp = d->showstr_head;
register int point;
for (point = 0; *temp != '\0'; temp++, point++)
if (temp == d->showstr_point)
break;
temp = d->showstr_head;
int newsize = strlen(d->showstr_head) + strlen(str) + 1;
d->showstr_head = new char[newsize];
strcpy(d->showstr_head, temp);
strcat(d->showstr_head, str);
d->showstr_point = d->showstr_head + point;
delete [] temp;
}
else
{
d->showstr_head = new char[strlen(str) + 1];
strcpy(d->showstr_head, str);
d->showstr_point = d->showstr_head;
}
show_string(d, "");
}
void show_string(struct descriptor_data *d, char *input)
{
char buffer[MAX_STRING_LENGTH], buf[MAX_INPUT_LENGTH];
register char *scan, *chk;
int lines = 0, toggle = 1;
one_argument(input, buf);
if (*buf) {
if (d->showstr_head) {
delete [] d->showstr_head;
d->showstr_head = 0;
}
d->showstr_point = 0;
return;
}
/* show a chunk */
for (scan = buffer;; scan++, d->showstr_point++) {
if ((((*scan = *d->showstr_point) == '\n') || (*scan == '\r')) &&
((toggle = -toggle) < 0))
lines++;
else if (!*scan || (lines >= 22)) {
if (lines >= 22) {
/* We need to make sure that if we're breaking the input here, we
* must set showstr_point to the right place and null terminate the
* character after the last '\n' or '\r' so we don't lose it.
* -- Michael Buselli
*/
d->showstr_point++;
*(++scan) = '\0';
}
SEND_TO_Q(buffer, d);
/* see if this is the end (or near the end) of the string */
for (chk = d->showstr_point; isspace(*chk); chk++);
if (!*chk) {
if (d->showstr_head) {
delete [] d->showstr_head;
d->showstr_head = 0;
}
d->showstr_point = 0;
}
return;
}
}
}