/***************************************************************************
* file: modify.c Part of DIKUMUD *
* Usage: Run-time modification (by users) of game variables *
* Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
* *
* Copyright (C) 1992, 1993 Michael Chastain, Michael Quan, Mitchell Tse *
* Performance optimization and bug fixes by MERC Industries. *
* You can use our stuff in any way you like whatsoever so long as this *
* copyright notice remains intact. If you like it please drop a line *
* to mec@garnet.berkeley.edu. *
* *
* This is free software and you are benefitting. We hope that you *
* share your changes too. What goes around, comes around. *
***************************************************************************/
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include "structs.h"
#include "mob.h"
#include "obj.h"
#include "utils.h"
#include "interp.h"
#include "handler.h"
#include "db.h"
#define REBOOT_AT 10 /* 0-23, time of optional reboot if -e lib/reboot */
#define TP_MOB 0
#define TP_OBJ 1
#define TP_ERROR 2
void show_string(struct descriptor_data *d, char *input);
extern char menu[];
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
};
char *skill_fields[] =
{
"learned",
"recognize",
"\n"
};
/* ************************************************************************
* 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)
{
char *scan;
int terminator = 0;
/* determine if this is the terminal string, and truncate if so */
for (scan = str; *scan; scan++)
if ( ( terminator = (*scan == '@') != 0 ) )
{
*scan = '\0';
break;
}
if (!(*d->str))
{
if (strlen(str) > d->max_str)
{
send_to_char("String too long - Truncated.\n\r",
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.\n\r",
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)
{
d->str = 0;
if (d->connected == CON_EXDSCR)
{
write_to_q( menu, &d->output );
d->connected = CON_SELECT_MENU;
}
}
else
strcat(*d->str, "\n\r");
}
#undef MAX_STR
/* interpret an argument for do_string */
void quad_arg(char *arg, int *type, char *name, int *field, char *string)
{
char buf[MAX_STRING_LENGTH];
/* determine type */
arg = one_argument(arg, buf);
if (is_abbrev(buf, "char"))
*type = TP_MOB;
else if (is_abbrev(buf, "obj"))
*type = TP_OBJ;
else
{
*type = TP_ERROR;
return;
}
/* find name */
arg = one_argument(arg, name);
/* field name and number */
arg = one_argument(arg, buf);
if (!(*field = old_search_block(buf, 0, strlen(buf), string_fields, 0)))
return;
/* string */
for (; isspace(*arg); arg++);
for (; ( *string = *arg ) != '\0' ; arg++, string++)
;
return;
}
/* modification of malloc'ed strings in chars/objects */
void do_string(struct char_data *ch, char *arg, int cmd)
{
char name[MAX_STRING_LENGTH], string[MAX_STRING_LENGTH];
int field, type;
struct char_data *mob;
struct obj_data *obj;
struct extra_descr_data *ed, *tmp;
if (IS_NPC(ch))
return;
quad_arg(arg, &type, name, &field, string);
if (type == TP_ERROR)
{
send_to_char(
"Syntax:\n\rstring ('obj'|'char') <name> <field> [<string>].\n\r",
ch);
return;
}
if (!field)
{
send_to_char("No field by that name. Try 'help string'.\n\r",
ch);
return;
}
if (type == TP_MOB)
{
/* locate the beast */
if (!(mob = get_char_vis(ch, name)))
{
send_to_char("I don't know anyone by that name...\n\r",
ch);
return;
}
switch(field)
{
case 1:
if (!IS_NPC(mob) && GET_LEVEL(ch) < 34)
{
send_to_char("You can't change that field for players.", ch);
return;
}
ch->desc->str = &GET_NAME(mob);
if (!IS_NPC(mob))
send_to_char(
"WARNING: You have changed the name of a player.\n\r",
ch);
break;
case 2:
if (!IS_NPC(mob))
{
send_to_char(
"That field is for monsters only.\n\r", ch);
return;
}
ch->desc->str = &mob->player.short_descr;
break;
case 3:
if (!IS_NPC(mob))
{
send_to_char(
"That field is for monsters only.\n\r", ch);
return;
}
ch->desc->str = &mob->player.long_descr;
break;
case 4:ch->desc->str = &mob->player.description; break;
case 5:
if (IS_NPC(mob))
{
send_to_char("Monsters have no titles.\n\r",
ch);
return;
}
ch->desc->str = &mob->player.title;
break;
default:
send_to_char(
"That field is undefined for monsters.\n\r", ch);
return;
break;
}
}
else /* type == TP_OBJ */
{
/* locate the object */
if (!(obj = get_obj_vis(ch, name)))
{
send_to_char("Can't find such a thing here..\n\r", ch);
return;
}
switch(field)
{
case 1: ch->desc->str = &obj->name; break;
case 2: ch->desc->str = &obj->short_description; break;
case 3: ch->desc->str = &obj->description; break;
case 4:
if (!*string)
{
send_to_char("You have to supply a keyword.\n\r", ch);
return;
}
/* try to locate extra description */
for (ed = obj->ex_description; ; ed = ed->next)
if (!ed) /* the field was not found. create a new one. */
{
CREATE(ed , struct extra_descr_data, 1);
ed->next = obj->ex_description;
obj->ex_description = ed;
CREATE(ed->keyword, char, strlen(string) + 1);
strcpy(ed->keyword, string);
ed->description = 0;
ch->desc->str = &ed->description;
send_to_char("New field.\n\r", ch);
break;
}
else if (!str_cmp(ed->keyword, string))
/* the field exists */
{
free(ed->description);
ed->description = 0;
ch->desc->str = &ed->description;
send_to_char(
"Modifying description.\n\r", ch);
break;
}
ch->desc->max_str = MAX_STRING_LENGTH;
/* the stndrd (see below) procedure does not apply here */
return;
break;
case 6:
if (!*string)
{
send_to_char("You must supply a field name.\n\r", ch);
return;
}
/* try to locate field */
for (ed = obj->ex_description; ; ed = ed->next)
if (!ed)
{
send_to_char("No field with that keyword.\n\r", ch);
return;
}
else if (!str_cmp(ed->keyword, string))
{
free(ed->keyword);
if (ed->description)
free(ed->description);
/* delete the entry in the desr list */
if (ed == obj->ex_description)
obj->ex_description = ed->next;
else
{
for(tmp = obj->ex_description; tmp->next != ed;
tmp = tmp->next);
tmp->next = ed->next;
}
free(ed);
send_to_char("Field deleted.\n\r", ch);
return;
}
break;
default:
send_to_char(
"That field is undefined for objects.\n\r", ch);
return;
break;
}
}
if (*ch->desc->str)
{
free(*ch->desc->str);
}
if (*string) /* there was a string in the argument array */
{
if (strlen(string) > length[field - 1])
{
send_to_char("String too long - truncated.\n\r", ch);
*(string + length[field - 1]) = '\0';
}
CREATE(*ch->desc->str, char, strlen(string) + 1);
strcpy(*ch->desc->str, string);
ch->desc->str = 0;
send_to_char("Ok.\n\r", ch);
}
else /* there was no string. enter string mode */
{
send_to_char("Enter string. terminate with '@'.\n\r", ch);
CREATE(*ch->desc->str, char, length[field - 1]);
ch->desc->max_str = length[field - 1];
}
}
/* 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);
}
#define MAX_HELP 256
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[81], tmp[81], *scan;
long pos;
CREATE( list, struct help_index_element, MAX_HELP );
for (;;)
{
pos = ftell(fl);
fgets(buf, 81, fl);
*(buf + strlen(buf) - 1) = '\0';
scan = buf;
for (;;)
{
/* extract the keywords */
scan = one_word(scan, tmp);
if (!*tmp)
break;
if ( ++nr >= MAX_HELP )
{
perror( "Too many help keywords." );
exit( 1 );
}
list[nr].keyword = str_dup(tmp);
list[nr].pos = pos;
}
/* skip the text */
do
fgets(buf, 81, 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)
{
CREATE(d->showstr_head, char, strlen(str) + 1);
strcpy(d->showstr_head, str);
d->showstr_point = d->showstr_head;
}
else
d->showstr_point = str;
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)
{
free(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))
{
*scan = '\0';
write_to_q( buffer, &d->output );
/* 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)
{
free(d->showstr_head);
d->showstr_head = 0;
}
d->showstr_point = 0;
}
return;
}
}