/*************************************************************************** * 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} };