/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
/****************************************************************************
* Online Building and Editing Module *
*****************************************************************************/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#if !defined(WIN32)
#include <unistd.h>
#endif
#include "merc.h"
extern int top_ed;
EXTRA_DESCR_DATA *SetRExtra( ROOM_INDEX_DATA *room, char *keywords )
{
EXTRA_DESCR_DATA *ed;
for ( ed = room->first_extradesc; ed; ed = ed->next )
{
if ( is_name( keywords, ed->keyword ) )
break;
}
if ( !ed )
{
CREATE( ed, EXTRA_DESCR_DATA, 1 );
LINK( ed, room->first_extradesc, room->last_extradesc, next, prev);
ed->keyword = STRALLOC( keywords );
ed->description = STRALLOC( "" );
top_ed++;
}
return ed;
}
bool DelRExtra( ROOM_INDEX_DATA *room, char *keywords )
{
EXTRA_DESCR_DATA *rmed;
for ( rmed = room->first_extradesc; rmed; rmed = rmed->next )
{
if ( is_name( keywords, rmed->keyword ) )
break;
}
if ( !rmed )
return FALSE;
UNLINK( rmed, room->first_extradesc, room->last_extradesc, next, prev);
STRFREE( rmed->keyword );
STRFREE( rmed->description );
DISPOSE( rmed );
top_ed--;
return TRUE;
}
EXTRA_DESCR_DATA *SetOExtra( OBJ_DATA *obj, char *keywords )
{
EXTRA_DESCR_DATA *ed;
for ( ed = obj->first_extradesc; ed; ed = ed->next )
{
if ( is_name( keywords, ed->keyword ) )
break;
}
if ( !ed )
{
CREATE( ed, EXTRA_DESCR_DATA, 1 );
LINK( ed, obj->first_extradesc, obj->last_extradesc, next, prev );
ed->keyword = STRALLOC( keywords );
ed->description = STRALLOC( "" );
top_ed++;
}
return ed;
}
bool DelOExtra( OBJ_DATA *obj, char *keywords )
{
EXTRA_DESCR_DATA *rmed;
for ( rmed = obj->first_extradesc; rmed; rmed = rmed->next )
{
if ( is_name( keywords, rmed->keyword ) )
break;
}
if ( !rmed )
return FALSE;
UNLINK( rmed, obj->first_extradesc, obj->last_extradesc, next, prev );
STRFREE( rmed->keyword );
STRFREE( rmed->description );
DISPOSE( rmed );
top_ed--;
return TRUE;
}
EXTRA_DESCR_DATA *SetOExtraProto( OBJ_INDEX_DATA *obj, char *keywords )
{
EXTRA_DESCR_DATA *ed;
for ( ed = obj->first_extradesc; ed; ed = ed->next )
{
if ( is_name( keywords, ed->keyword ) )
break;
}
if ( !ed )
{
CREATE( ed, EXTRA_DESCR_DATA, 1 );
LINK( ed, obj->first_extradesc, obj->last_extradesc, next, prev );
ed->keyword = STRALLOC( keywords );
ed->description = STRALLOC( "" );
top_ed++;
}
return ed;
}
bool DelOExtraProto( OBJ_INDEX_DATA *obj, char *keywords )
{
EXTRA_DESCR_DATA *rmed;
for ( rmed = obj->first_extradesc; rmed; rmed = rmed->next )
{
if ( is_name( keywords, rmed->keyword ) )
break;
}
if ( !rmed )
return FALSE;
UNLINK( rmed, obj->first_extradesc, obj->last_extradesc, next, prev );
STRFREE( rmed->keyword );
STRFREE( rmed->description );
DISPOSE( rmed );
top_ed--;
return TRUE;
}
/*
* Function to get the equivelant exit of DIR 0-MAXDIR out of linked list.
* Made to allow old-style diku-merc exit functions to work. -Thoric
*/
EXIT_DATA *get_exit( ROOM_INDEX_DATA *room, sh_int dir )
{
EXIT_DATA *xit;
if ( !room )
{
bug( "Get_exit: NULL room", 0 );
return NULL;
}
for (xit = room->first_exit; xit; xit = xit->next )
if ( xit->vdir == dir )
return xit;
return NULL;
}
/*
* Function to get an exit, leading the the specified room
*/
EXIT_DATA *get_exit_to( ROOM_INDEX_DATA *room, sh_int dir, int vnum )
{
EXIT_DATA *xit;
if ( !room )
{
bug( "Get_exit: NULL room", 0 );
return NULL;
}
for (xit = room->first_exit; xit; xit = xit->next )
if ( xit->vdir == dir && xit->vnum == vnum )
return xit;
return NULL;
}
/*
* Function to get the nth exit of a room -Thoric
*/
EXIT_DATA *get_exit_num( ROOM_INDEX_DATA *room, sh_int count )
{
EXIT_DATA *xit;
int cnt;
if ( !room )
{
bug( "Get_exit: NULL room", 0 );
return NULL;
}
for (cnt = 0, xit = room->first_exit; xit; xit = xit->next )
if ( ++cnt == count )
return xit;
return NULL;
}
/*
* Returns value 0 - 9 based on directional text.
*/
int get_dir( char *txt )
{
int edir;
char c1,c2;
c1 = txt[0];
if ( c1 == '\0' )
return 0;
c2 = txt[1];
edir = 0;
switch ( c1 )
{
case 'n':
switch ( c2 )
{
default: edir = 0; break; /* north */
}
break; case '0': edir = 0; break; /* north */
case 'e': case '1': edir = 1; break; /* east */
case 's':
switch ( c2 )
{
default: edir = 2; break; /* south */
}
break; case '2': edir = 2; break; /* south */
case 'w': case '3': edir = 3; break; /* west */
case 'u': case '4': edir = 4; break; /* up */
case 'd': case '5': edir = 5; break; /* down */
}
return edir;
}
char * const ex_flags [] =
{
"isdoor", "closed", "locked", "pickproof"
};
char * const r_flags [] =
{
"dark", "no_otrans",
"nomob", "indoors",
"private", "safe",
"solitary", "petshop",
"norecall", "noteleport",
"totaldarkness",
"blade_barrier", "arena",
"flaming", "silence"
};
char * const o_flags [] =
{
"glow", "hum", "thrown",
"keep", "vanish",
"invis", "magic",
"nodrop", "bless",
"antigood", "antievil",
"antineutral", "noremove",
"inventory", "loyal",
"shadowplane"
};
char * const plr_flags [] =
{
"npc", "autoexit", "autoloot", "autosac", "blank", "brief", "combine",
"prompt", "telnet_ga", "holylight", "wizinvis", "ansi", "silence",
"vt102", "incog", "notell", "log", "deny", "freeze", "godless",
"watcher", "acid", "challenger","challendged",
"r1", "r2"
};
char * const wear_locs [] =
{
"light", "finger1", "finger2", "neck1", "neck2", "body", "head", "legs",
"feet", "hands", "arms", "shield", "about", "waist", "wrist1", "wrist2",
"wield", "hold", "third", "fourth", "r1", "r2"
};
bool can_rmodify( CHAR_DATA *ch, ROOM_INDEX_DATA *room )
{
if ( IS_NPC( ch ) )
return FALSE;
if ( get_trust( ch ) >= MAX_LEVEL - 1 )
return TRUE;
if ( !IS_SET( room->room_flags, ROOM_PROTOTYPE) )
{
send_to_char( "You cannot modify this room.\n\r", ch );
return FALSE;
}
send_to_char( "That room is not in your allocated range.\n\r", ch
);
return FALSE;
}
bool can_oedit( CHAR_DATA *ch, OBJ_INDEX_DATA *obj )
{
if ( IS_NPC( ch ) )
return FALSE;
if ( get_trust( ch ) >= MAX_LEVEL - 1 )
return TRUE;
if ( !IS_OBJ_STAT( obj, ITEM_PROTOTYPE) )
{
send_to_char( "You cannot modify this object.\n\r", ch );
return FALSE;
}
send_to_char( "That object is not in your allocated range.\n\r",ch );
return FALSE;
}
bool can_mmodify( CHAR_DATA *ch, CHAR_DATA *mob )
{
if ( mob == ch )
return TRUE;
if ( !IS_NPC( mob ) )
{
if ( get_trust( ch ) >= MAX_LEVEL - 1 && get_trust(ch) >
get_trust( mob ) )
return TRUE;
else
send_to_char( "You can't do that.\n\r", ch );
return FALSE;
}
if ( IS_NPC( ch ) )
return FALSE;
if ( get_trust( ch ) >= MAX_LEVEL - 1 )
return TRUE;
if ( !IS_SET( mob->act, ACT_PROTOTYPE) )
{
send_to_char( "You cannot modify this mobile.\n\r", ch );
return FALSE;
}
send_to_char( "That mobile is not in your allocated range.\n\r",ch );
return FALSE;
}
bool can_medit( CHAR_DATA *ch, MOB_INDEX_DATA *mob )
{
if ( IS_NPC( ch ) )
return FALSE;
if ( get_trust( ch ) >= MAX_LEVEL - 1 )
return TRUE;
if ( !IS_SET( mob->act, ACT_PROTOTYPE) )
{
send_to_char( "You cannot modify this mobile.\n\r", ch );
return FALSE;
}
send_to_char( "That mobile is not in your allocated range.\n\r",ch );
return FALSE;
}
int get_wearloc( char *type )
{
int x;
for ( x = 0; x < MAX_WEAR; x++ )
if ( !str_cmp( type, wear_locs[x] ) )
return x;
return -1;
}
int get_exflag( char *flag )
{
int x;
for ( x = 0; x <= MAX_EXFLAG; x++ )
if ( !str_cmp( flag, ex_flags[x] ) )
return x;
return -1;
}
int get_rflag( char *flag )
{
int x;
for ( x = 0; x < 32; x++ )
if ( !str_cmp( flag, r_flags[x] ) )
return x;
return -1;
}
int get_oflag( char *flag )
{
int x;
for ( x = 0; x < 32; x++ )
if ( !str_cmp( flag, o_flags[x] ) )
return x;
return -1;
}
int get_plrflag( char *flag )
{
int x;
for ( x = 0; x < 32; x++ )
if ( !str_cmp( flag, plr_flags[x] ) )
return x;
return -1;
}
/*
* Simple but nice and handle line editor. -Thoric
*/
void edit_buffer( CHAR_DATA *ch, char *argument )
{
DESCRIPTOR_DATA *d;
EDITOR_DATA *edit;
char cmd[MAX_INPUT_LENGTH];
char buf[MAX_INPUT_LENGTH];
sh_int x, line, max_buf_lines;
bool save;
if ( (d = ch->desc) == NULL )
{
send_to_char( "You have no descriptor.\n\r", ch );
return;
}
if ( d->connected != CON_EDITING )
{
send_to_char( "You can't do that!\n\r", ch );
bug( "Edit_buffer: d->connected != CON_EDITING", 0 );
return;
}
if ( ch->substate <= SUB_PAUSE )
{
send_to_char( "You can't do that!\n\r", ch );
sprintf(buf,"Edit_buffer: illegal ch->substate (%d)", ch->substate);
bug(buf,0);
d->connected = CON_PLAYING;
return;
}
if ( !ch->editor )
{
send_to_char( "You can't do that!\n\r", ch );
bug( "Edit_buffer: null editor", 0 );
d->connected = CON_PLAYING;
return;
}
edit = ch->editor;
save = FALSE;
max_buf_lines = 24;
if ( ch->substate == SUB_MPROG_EDIT || ch->substate == SUB_HELP_EDIT )
max_buf_lines = 48;
if ( argument[0] == '/' || argument[0] == '\\' )
{
one_argument( argument, cmd );
if ( !str_cmp( cmd+1, "?" ) )
{
send_to_char( "Editing commands\n\r---------------------------------\n\r", ch );
send_to_char( "/l list buffer\n\r", ch );
send_to_char( "/c clear buffer\n\r", ch );
send_to_char( "/d [line] delete line\n\r", ch );
send_to_char( "/g <line> goto line\n\r", ch );
send_to_char( "/i <line> insert line\n\r", ch );
send_to_char( "/r <old> <new> global replace\n\r", ch );
send_to_char( "/a abort editing\n\r", ch );
if ( get_trust(ch) > MAX_LEVEL - 4 )
send_to_char( "/! <command> execute command (do not use another editing command)\n\r", ch );
send_to_char( "/s save buffer\n\r\n\r> ",ch );
return;
}
if ( !str_cmp( cmd+1, "c" ) )
{
memset( edit, '\0', sizeof(EDITOR_DATA) );
edit->numlines = 0;
edit->on_line = 0;
send_to_char( "Buffer cleared.\n\r> ", ch );
return;
}
if ( !str_cmp( cmd+1, "r" ) )
{
char word1[MAX_INPUT_LENGTH];
char word2[MAX_INPUT_LENGTH];
char *sptr, *wptr, *lwptr;
int x, count, wordln, word2ln, lineln;
sptr = one_argument( argument, word1 );
sptr = one_argument( sptr, word1 );
sptr = one_argument( sptr, word2 );
if ( word1[0] == '\0' || word2[0] == '\0' )
{
send_to_char( "Need word to replace, and replacement.\n\r>", ch );
return;
}
if ( strcmp( word1, word2 ) == 0 )
{
send_to_char( "Done.\n\r> ", ch );
return;
}
count = 0; wordln = strlen(word1); word2ln = strlen(word2);
sprintf( buf, "Replacing all occurrences of %s with %s...\n\r", word1, word2 );
stc(buf, ch);
for ( x = edit->on_line; x < edit->numlines; x++ )
{
lwptr = edit->line[x];
while ( (wptr = strstr( lwptr, word1 )) != NULL )
{
sptr = lwptr;
lwptr = wptr + wordln;
sprintf( buf, "%s%s", word2, wptr + wordln );
lineln = wptr - edit->line[x] - wordln;
++count;
if ( strlen(buf) + lineln > 79 )
{
lineln = UMAX(0, (79 - strlen(buf)));
buf[lineln] = '\0';
break;
}
else
lineln = strlen(buf);
buf[lineln] = '\0';
strcpy( wptr, buf );
}
}
sprintf( buf, "Found and replaced %d occurrence(s).\n\r> ", count );
stc(buf, ch);
return;
}
if ( !str_cmp( cmd+1, "i" ) )
{
if ( edit->numlines >= max_buf_lines )
send_to_char( "Buffer is full.\n\r> ", ch );
else
{
if ( argument[2] == ' ' )
line = atoi( argument + 2 ) - 1;
else
line = edit->on_line;
if ( line < 0 )
line = edit->on_line;
if ( line < 0 || line > edit->numlines )
send_to_char( "Out of range.\n\r> ", ch );
else
{
for ( x = ++edit->numlines; x > line; x-- )
strcpy( edit->line[x], edit->line[x-1] );
strcpy( edit->line[line], "" );
send_to_char( "Line inserted.\n\r> ", ch );
}
}
return;
}
if ( !str_cmp( cmd+1, "d" ) )
{
if ( edit->numlines == 0 )
send_to_char( "Buffer is empty.\n\r> ", ch );
else
{
if ( argument[2] == ' ' )
line = atoi( argument + 2 ) - 1;
else
line = edit->on_line;
if ( line < 0 )
line = edit->on_line;
if ( line < 0 || line > edit->numlines )
send_to_char( "Out of range.\n\r> ", ch );
else
{
if ( line == 0 && edit->numlines == 1 )
{
memset( edit, '\0', sizeof(EDITOR_DATA) );
edit->numlines = 0;
edit->on_line = 0;
send_to_char( "Line deleted.\n\r> ", ch );
return;
}
for ( x = line; x < (edit->numlines - 1); x++ )
strcpy( edit->line[x], edit->line[x+1] );
strcpy( edit->line[edit->numlines--], "" );
if ( edit->on_line > edit->numlines )
edit->on_line = edit->numlines;
send_to_char( "Line deleted.\n\r> ", ch );
}
}
return;
}
if ( !str_cmp( cmd+1, "g" ) )
{
if ( edit->numlines == 0 )
send_to_char( "Buffer is empty.\n\r> ", ch );
else
{
if ( argument[2] == ' ' )
line = atoi( argument + 2 ) - 1;
else
{
send_to_char( "Goto what line?\n\r> ", ch );
return;
}
if ( line < 0 )
line = edit->on_line;
if ( line < 0 || line > edit->numlines )
send_to_char( "Out of range.\n\r> ", ch );
else
{
edit->on_line = line;
sprintf( buf, "(On line %d)\n\r> ", line+1 );
stc(buf,ch);
}
}
return;
}
if ( !str_cmp( cmd+1, "l" ) )
{
if ( edit->numlines == 0 )
send_to_char( "Buffer is empty.\n\r> ", ch );
else
{
send_to_char( "------------------\n\r", ch );
for ( x = 0; x < edit->numlines; x++ )
{
sprintf( buf, "%2d> %s\n\r", x+1, edit->line[x] );
stc(buf, ch);
}
send_to_char( "------------------\n\r> ", ch );
}
return;
}
if ( !str_cmp( cmd+1, "a" ) )
{
send_to_char( "\n\rAborting... ", ch );
stop_editing( ch );
return;
}
if ( get_trust(ch) > LEVEL_IMMORTAL && !str_cmp( cmd+1, "!" ) )
{
int substate = ch->substate;
ch->substate = SUB_RESTRICTED;
interpret(ch, argument+3);
ch->substate = substate;
send_to_char( "\n\r> ", ch );
return;
}
}
if ( edit->size + strlen(argument) + 1 >= MAX_STRING_LENGTH - 1 )
send_to_char( "You buffer is full.\n\r", ch );
else
{
if ( strlen(argument) > 79 )
{
strncpy( buf, argument, 79 );
buf[79] = 0;
send_to_char( "(Long line trimmed)\n\r> ", ch );
}
else
strcpy( buf, argument );
strcpy( edit->line[edit->on_line++], buf );
if ( edit->on_line > edit->numlines )
edit->numlines++;
if ( edit->numlines > max_buf_lines )
{
edit->numlines = max_buf_lines;
send_to_char( "Buffer full.\n\r", ch );
save = TRUE;
}
}
if ( save )
{
d->connected = CON_PLAYING;
if ( !ch->last_cmd )
return;
(*ch->last_cmd) ( ch, "" );
return;
}
send_to_char( "> ", ch );
}
/*
* Remove carriage returns from a line
*/
char *strip_cr( char *str )
{
static char newstr[MAX_STRING_LENGTH];
int i, j;
for ( i=j=0; str[i] != '\0'; i++ )
if ( str[i] != '\r' )
{
newstr[j++] = str[i];
}
newstr[j] = '\0';
return newstr;
}
void smush_tilde( char *str )
{
int len;
char last;
char *strptr;
strptr = str;
len = strlen( str );
if ( len )
last = strptr[len-1];
else
last = '\0';
for ( ; *str != '\0'; str++ )
{
if ( *str == '~' )
*str = '-';
}
if ( len )
strptr[len-1] = last;
return;
}
void start_editing( CHAR_DATA *ch, char *data )
{
EDITOR_DATA *edit;
sh_int lines, size, lpos;
char c;
if ( !ch->desc )
{
bug( "Fatal: start_editing: no desc", 0 );
return;
}
if ( ch->substate == SUB_RESTRICTED )
bug( "NOT GOOD: start_editing: ch->substate == SUB_RESTRICTED", 0 );
send_to_char( "Begin entering your text now (/? = help /s = save /c = clear /l = list)\n\r", ch );
send_to_char( "-----------------------------------------------------------------------\n\r> ", ch );
if ( ch->editor )
stop_editing( ch );
CREATE( edit, EDITOR_DATA, 1 );
edit->numlines = 0;
edit->on_line = 0;
edit->size = 0;
size = 0; lpos = 0; lines = 0;
if ( !data )
bug("editor: data is NULL!\n\r",0);
else
for ( ;; )
{
c = data[size++];
if ( c == '\0' )
{
edit->line[lines][lpos] = '\0';
break;
}
else
if ( c == '\r' );
else
if ( c == '\n' || lpos > 78)
{
edit->line[lines][lpos] = '\0';
lines++;
lpos = 0;
}
else
edit->line[lines][lpos++] = c;
if ( lines >= 49 || size > 4096 )
{
edit->line[lines][lpos] = '\0';
break;
}
}
edit->numlines = lines;
edit->size = size;
edit->on_line = lines;
ch->editor = edit;
ch->desc->connected = CON_EDITING;
}
char *copy_buffer( CHAR_DATA *ch )
{
char buf[MAX_STRING_LENGTH];
char tmp[100];
sh_int x, len;
if ( !ch )
{
bug( "copy_buffer: null ch", 0 );
return STRALLOC( "" );
}
if ( !ch->editor )
{
bug( "copy_buffer: null editor", 0 );
return STRALLOC( "" );
}
buf[0] = '\0';
for ( x = 0; x < ch->editor->numlines; x++ )
{
strcpy( tmp, ch->editor->line[x] );
smush_tilde( tmp );
len = strlen(tmp);
if ( tmp && tmp[len-1] == '~' )
tmp[len-1] = '\0';
else
strcat( tmp, "\n\r" );
strcat( buf, tmp );
}
return STRALLOC( buf );
}
void stop_editing( CHAR_DATA *ch )
{
DISPOSE( ch->editor );
ch->editor = NULL;
send_to_char( "Done.\n\r", ch );
ch->dest_buf = NULL;
ch->substate = SUB_NONE;
if ( !ch->desc )
{
bug( "Fatal: stop_editing: no desc", 0 );
return;
}
ch->desc->connected = CON_PLAYING;
}
/*
* Moved into a separate function so it can be used for other things
* ie: online help editing -Thoric
*/
HELP_DATA *get_help( CHAR_DATA *ch, char *argument )
{
char argall[MAX_INPUT_LENGTH];
char argone[MAX_INPUT_LENGTH];
char argnew[MAX_INPUT_LENGTH];
HELP_DATA *pHelp;
int lev;
if ( argument[0] == '\0' )
argument = "summary";
if ( isdigit(argument[0]) )
{
lev = number_argument( argument, argnew );
argument = argnew;
}
else
lev = -2;
/*
* Tricky argument handling so 'help a b' doesn't match a.
*/
argall[0] = '\0';
while ( argument[0] != '\0' )
{
argument = one_argument( argument, argone );
if ( argall[0] != '\0' )
strcat( argall, " " );
strcat( argall, argone );
}
for ( pHelp = first_help; pHelp; pHelp = pHelp->next )
{
if ( pHelp->level > get_trust( ch ) )
continue;
if ( lev != -2 && pHelp->level != lev )
continue;
if ( is_name( argall, pHelp->keyword ) )
return pHelp;
}
return NULL;
}
/*
* Now this is cleaner
*/
void do_help( CHAR_DATA *ch, char *argument )
{
char buf[MAX_STRING_LENGTH];
HELP_DATA *pHelp;
if ( (pHelp = get_help( ch, argument )) == NULL )
{
send_to_char( "No help on that word.\n\r", ch );
check_help_soundex(argument, ch);
/* what help files does newbies want ? */
if ((get_age(ch) - 17) < 2)
{
sprintf(buf, "Do_help: %s tried '%s'", ch->name, argument);
log_string2(buf);
}
return;
}
if ( pHelp->level >= 0 && str_cmp( argument, "motd" ) )
{
stc( pHelp->keyword, ch );
stc( "\n\r", ch );
}
/*
* Strip leading '.' to allow initial blanks.
*/
if ( pHelp->text[0] == '.' )
stc( pHelp->text+1, ch );
else
stc( pHelp->text, ch );
return;
}
/*
* Help editor -Thoric
*
void do_hedit( CHAR_DATA *ch, char *argument )
{
HELP_DATA *pHelp;
if ( !ch->desc )
{
send_to_char( "You have no descriptor.\n\r", ch );
return;
}
switch( ch->substate )
{
default:
break;
case SUB_HELP_EDIT:
if ( (pHelp = ch->dest_buf) == NULL )
{
bug( "hedit: sub_help_edit: NULL ch->dest_buf", 0 );
stop_editing( ch );
return;
}
STRFREE( pHelp->text );
pHelp->text = copy_buffer( ch );
stop_editing( ch );
return;
}
if ( (pHelp = get_help( ch, argument )) == NULL )
{
char argnew[MAX_INPUT_LENGTH];
int lev;
if ( isdigit(argument[0]) )
{
lev = number_argument( argument, argnew );
argument = argnew;
}
else
lev = get_trust(ch);
CREATE( pHelp, HELP_DATA, 1 );
pHelp->keyword = STRALLOC( strupper(argument) );
pHelp->text = STRALLOC( "" );
pHelp->level = lev;
add_help( pHelp );
}
ch->substate = SUB_HELP_EDIT;
ch->dest_buf = pHelp;
start_editing( ch, pHelp->text );
}
*/
/*
* Stupid leading space muncher fix -Thoric
*/
char *help_fix( char *text )
{
char *fixed;
if ( !text )
return "";
fixed = strip_cr(text);
if ( fixed[0] == ' ' )
fixed[0] = '.';
return fixed;
}
void do_hset( CHAR_DATA *ch, char *argument )
{
HELP_DATA *pHelp;
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
smash_tilde( argument );
argument = one_argument( argument, arg1 );
if ( arg1[0] == '\0' )
{
send_to_char( "Syntax: hset <field> [value] [help page]\n\r", ch
);
send_to_char( "\n\r", ch
);
send_to_char( "Field being one of:\n\r", ch
);
send_to_char( " level keyword remove save\n\r", ch
);
return;
}
if ( !str_cmp( arg1, "save" ) )
{
FILE *fpout;
rename( "help.are", "help.are.bak" );
fclose( fpReserve );
if ( ( fpout = fopen( "help.are", "w" ) ) == NULL )
{
bug( "hset save: fopen", 0 );
perror( "help.are" );
fpReserve = fopen( NULL_FILE, "r" );
return;
}
fprintf( fpout, "#HELPS\n\n" );
for ( pHelp = first_help; pHelp; pHelp = pHelp->next )
fprintf( fpout, "%d %s~\n%s~\n\n",
pHelp->level, pHelp->keyword,help_fix(pHelp->text) );
fprintf( fpout, "0 $~\n\n\n#$\n" );
fclose( fpout );
fpReserve = fopen( NULL_FILE, "r" );
send_to_char( "Saved.\n\r", ch );
return;
}
if ( str_cmp( arg1, "remove" ) )
argument = one_argument( argument, arg2 );
if ( (pHelp = get_help( ch, argument )) == NULL )
{
send_to_char( "Cannot find help on that subject.\n\r", ch );
return;
}
if ( !str_cmp( arg1, "remove" ) )
{
UNLINK( pHelp, first_help, last_help, next, prev );
STRFREE( pHelp->text );
STRFREE( pHelp->keyword );
DISPOSE( pHelp );
send_to_char( "Removed.\n\r", ch );
return;
}
if ( !str_cmp( arg1, "level" ) )
{
pHelp->level = atoi( arg2 );
send_to_char( "Done.\n\r", ch );
return;
}
if ( !str_cmp( arg1, "keyword" ) )
{
STRFREE( pHelp->keyword );
pHelp->keyword = STRALLOC( strupper(arg2) );
send_to_char( "Done.\n\r", ch );
return;
}
do_hset( ch, "" );
}
/*
* Show help topics in a level range -Thoric
* Idea suggested by Gorog
*/
void do_hlist( CHAR_DATA *ch, char *argument )
{
int min, max, minlimit, maxlimit, cnt;
char arg[MAX_INPUT_LENGTH];
char buf[MAX_STRING_LENGTH];
HELP_DATA *help;
maxlimit = get_trust(ch);
minlimit = maxlimit >= (MAX_LEVEL - 3) ? -1 : 0;
argument = one_argument( argument, arg );
if ( arg[0] != '\0' )
{
min = URANGE( minlimit, atoi(arg), maxlimit );
if ( argument[0] != '\0' )
max = URANGE( min, atoi(argument), maxlimit );
else
max = maxlimit;
}
else
{
min = minlimit;
max = maxlimit;
}
sprintf( buf, "Help Topics in level range %d to %d:\n\r\n\r", min, max);
stc(buf,ch);
for ( cnt = 0, help = first_help; help; help = help->next )
if ( help->level >= min && help->level <= max )
{
sprintf( buf, " %3d %s\n\r", help->level, help->keyword );
stc(buf, ch);
++cnt;
}
if ( cnt )
{
sprintf( buf, "\n\r%d pages found.\n\r", cnt );
stc(buf,ch);
}
else
send_to_char( "None found.\n\r", ch );
}