/***************************************************************************
* 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. *
***************************************************************************/
/***************************************************************************
* _/ _/ *
* _/_/_/ _/_/ _/_/_/ _/ _/_/ _/ _/ _/_/_/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/_/_/ _/ _/_/ _/_/_/ _/_/_/ *
***************************************************************************
* Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius), *
* Additional credits are in the help file CODECREDITS *
* All Rights Reserved. *
***************************************************************************/
/****************************************************************************
* 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"
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", "bank"
};
char *const o_flags[] = {
"glow", "hum", "thrown",
"keep", "vanish" "invis", "magic",
"nodrop", "nolocate",
"antigood", "antievil",
"antineutral", "noremove",
"inventory", "loyal",
"shadowplane", "noclaim", "bless"
};
char *const w_flags[] = {
"take", "finger", "neck", "body", "head", "legs", "feet", "hands",
"arms",
"shield", "about", "waist", "wrist", "wield", "hold", "face"
};
char *const o_types[] = {
"none", "light", "scroll", "wand", "staff", "weapon",
"treasure", "armor", "potion", "furniture", "trash", "container",
"drinkcon", "key", "food", "money", "boat",
"corpse", "corpse_pc", "fountain", "pill",
"portal", "egg",
"voodoo", "stake",
"missile", "ammo",
"quest", "piece", "mithril",
"symbol", "book",
"page", "tool",
"wall", "copper",
"iron", "steel",
"adamantite", "gemstone",
"hilt"
};
char *const a_types[] = {
"none", "strength", "dexterity", "intelligence", "wisdom",
"constitution",
"sex", "class", "level", "age", "height", "weight", "mana", "hit",
"move",
"gold", "experience", "armor", "hitroll", "damroll", "save_para",
"save_rod", "save_petri",
"save_breath",
"save_spell",
"poly"
};
char *const a_flags[] = {
"blind", "invisible", "detect_evil", "detect_invis", "detect_magic",
"detect_hidden", "shadowplane", "sanctuary", "faerie_fire",
"infrared",
"curse",
"flaming", "poison", "protect", "ethereal", "sneak", "hide", "sleep",
"charm", "flying", "pass_door", "polymorph", "shadowsight", "webbed",
"tendrils", "drowfire", "zuloform", "shift", "peace", "infirmity",
"godbless", "totalblind",
"steelshield", "monkflaming"
};
/*
char * const act_flags [] =
{
"npc", "sentinel", "scavenger", "aggressive", "stayarea", "wimpy", "pet",
"train", "practice", "mount", "noparts", "noexp", "prototype", "notravel", "nosummon" };
*/
char *const plr_flags[] = {
"npc", "autoexit", "autoloot", "autosac", "blank", "brief", "brief5",
"combine",
"prompt", "telnet_ga", "holylight", "wizinvis", "ansi", "silence",
"vt102", "incog", "notell", "log", "deny", "freeze", "godless",
"watcher", "acid", "challenger", "challendged", "brief6",
"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_otype(char *type)
{
int x;
for (x = 0; x < (sizeof(o_types) / sizeof(o_types[0])); x++)
if (!str_cmp(type, o_types[x]))
return x;
return -1;
}
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_wflag(char *flag)
{
int x;
for (x = 0; x < 32; x++)
if (!str_cmp(flag, w_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];
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);
xprintf(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 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);
xprintf(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;
xprintf(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);
}
}
xprintf(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;
xprintf(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++)
{
xprintf(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)
{
xprintf(buf, "Do_help: %s tried '%s'", ch->name,
argument);
log_string(LOG_BUG, buf);
wiznet(buf, ch, NULL, WIZ_DEBUG, 0, 0);
}
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;
}
/*
* 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;
}
xprintf(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)
{
xprintf(buf, " %3d %s\n\r", help->level,
help->keyword);
stc(buf, ch);
++cnt;
}
if (cnt)
{
xprintf(buf, "\n\r%d pages found.\n\r", cnt);
stc(buf, ch);
}
else
send_to_char("None found.\n\r", ch);
}
int item_lookup(const char *name)
{
int type;
for (type = 0; item_table[type].name != NULL; type++)
{
if (LOWER(name[0]) == LOWER(item_table[type].name[0])
&& !str_prefix(name, item_table[type].name))
return item_table[type].type;
}
return -1;
}
int position_lookup(const char *name)
{
int pos;
for (pos = 0; position_table[pos].name != NULL; pos++)
{
if (LOWER(name[0]) == LOWER(position_table[pos].name[0])
&& !str_prefix(name, position_table[pos].name))
return pos;
}
return -1;
}
const struct item_type item_table[] = {
{ITEM_LIGHT, "light"},
{ITEM_SCROLL, "scroll"},
{ITEM_WAND, "wand"},
{ITEM_STAFF, "staff"},
{ITEM_WEAPON, "weapon"},
{ITEM_TREASURE, "treasure"},
{ITEM_ARMOR, "armor"},
{ITEM_POTION, "potion"},
{ITEM_FURNITURE, "furniture"},
{ITEM_TRASH, "trash"},
{ITEM_CONTAINER, "container"},
{ITEM_DRINK_CON, "drink"},
{ITEM_KEY, "key"},
{ITEM_FOOD, "food"},
{ITEM_MONEY, "money"},
{ITEM_BOAT, "boat"},
{ITEM_CORPSE_NPC, "npc_corpse"},
{ITEM_CORPSE_PC, "pc_corpse"},
{ITEM_FOUNTAIN, "fountain"},
{ITEM_PILL, "pill"},
{0, NULL}
};