/************************************************************************** * File: ibt.c Part of tbaMUD * * Usage: Loading/saving/editing of Ideas, Bugs and Typos lists * * * * All rights reserved. See license for complete information. * * * * Created by Vash (aka Frenze) for Trigun MUD and the tbaMUD codebase * * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * **************************************************************************/ //#if defined(macintosh) //#include <types.h> //#include <time.h> //#else //#include <sys/types.h> //#include <sys/time.h> //#endif #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" #include "comm.h" #include "db.h" #include "handler.h" #include "interpreter.h" //#include "genobj.h" #include "constants.h" //#include "fight.h" #include "screen.h" #include "act.h" #include "utils.h" #include "ibt.h" #include "oasis.h" #include "improved-edit.h" #include "modify.h" IBT_DATA * first_bug = NULL; IBT_DATA * last_bug = NULL; IBT_DATA * first_idea = NULL; IBT_DATA * last_idea = NULL; IBT_DATA * first_typo = NULL; IBT_DATA * last_typo = NULL; const char *ibt_types[]={ "Bug", "Idea", "Typo", "\n" }; /* Internal (static) functions */ static IBT_DATA *new_ibt(void); static void free_ibt_list(IBT_DATA *first_ibt, IBT_DATA *last_ibt); static IBT_DATA *read_ibt(char *filename, FILE *fp); static IBT_DATA *get_first_ibt(int mode); static IBT_DATA *get_last_ibt(int mode); static bool is_ibt_logger(IBT_DATA *ibtData, struct char_data *ch); /* Internal (static) OLC functions */ static void ibtedit_setup(struct descriptor_data *d); static void ibtedit_save(struct descriptor_data *d); static void ibtedit_disp_main_menu(struct descriptor_data *d); static void ibtedit_disp_flags(struct descriptor_data *d); static IBT_DATA *new_ibt(void) { int i; IBT_DATA *ibtData; CREATE( ibtData, IBT_DATA, 1); ibtData->next = NULL; ibtData->prev = NULL; ibtData->name = NULL; ibtData->text = NULL; ibtData->body = NULL; ibtData->notes = NULL; ibtData->level = 0; ibtData->id_num = NOBODY; ibtData->room = NOWHERE; ibtData->dated = 0; for (i=0; i<IBT_ARRAY_MAX; i++) ibtData->flags[i] = 0; return ibtData; } static void free_ibt_list(IBT_DATA *first_ibt, IBT_DATA *last_ibt) { IBT_DATA **top_ptr, **bot_ptr, *this_ibt; if ((first_ibt == NULL) || (last_ibt == NULL)) return; top_ptr = &(first_ibt); bot_ptr = &(last_ibt); while (first_ibt) { this_ibt = first_ibt; /* Disconnect from the list */ UNLINK(this_ibt, first_ibt, last_ibt, next, prev); /* Free the strings first */ if (this_ibt->body) STRFREE(this_ibt->body); if (this_ibt->name) STRFREE(this_ibt->name); if (this_ibt->text) STRFREE(this_ibt->text); if (this_ibt->notes) STRFREE(this_ibt->notes); /* And free the struct */ DISPOSE(this_ibt); } *(top_ptr) = NULL; *(bot_ptr) = NULL; } static IBT_DATA *read_ibt( char *filename, FILE *fp ) { IBT_DATA *ibtData; char *word, *id_num=NULL, *dated=NULL; char buf[MAX_STRING_LENGTH]; bool fMatch, flgCheck; char letter; do { letter = getc( fp ); if( feof(fp) ) { fclose( fp ); return NULL; } } while( isspace(letter) ); ungetc( letter, fp ); ibtData = new_ibt(); ibtData->name = STRALLOC(""); ibtData->text = STRALLOC(""); ibtData->body = STRALLOC(""); for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER(word[0]) ) { case 'B': if (!str_cmp(word, "Body")) STRFREE(ibtData->body); KEY("Body", ibtData->body, fread_clean_string( fp, buf )); break; case 'D': TXT_KEY("Dated", dated, fread_line(fp)); break; case 'E': if (!str_cmp(word, "End")) { if ( id_num ) { ibtData->id_num = atol(id_num); STRFREE( id_num ); } if ( dated ) { ibtData->dated = atol(dated); STRFREE( dated ); } if ( !ibtData->name ) ibtData->name = STRALLOC(""); if ( !ibtData->text ) ibtData->text = STRALLOC(""); if ( !ibtData->body ) ibtData->body = STRALLOC(""); if ( !ibtData->notes ) ibtData->notes = STRALLOC(""); return ibtData; } break; case 'F': KEY("Flags", flgCheck, fread_flags(fp, ibtData->flags, IBT_ARRAY_MAX)); break; case 'I': TXT_KEY("IdNum", id_num, fread_line(fp)); break; case 'L': KEY("Level", ibtData->level, fread_number(fp)); break; case 'N': if (!str_cmp(word, "Name") && ibtData->name) STRFREE(ibtData->name); if (!str_cmp(word, "Notes") && ibtData->notes) STRFREE(ibtData->notes); TXT_KEY("Name", ibtData->name, fread_line( fp )); KEY("Notes", ibtData->notes, fread_clean_string( fp, buf )); break; case 'R': KEY("Room", ibtData->room, fread_number(fp)); break; case 'T': if (!str_cmp(word, "Text")) STRFREE(ibtData->text); TXT_KEY("Text", ibtData->text, fread_line( fp )); break; case '*': /* Handle comments */ fread_to_eol(fp); fMatch = TRUE; break; default: log("SYSERR: Invalid keyword (%s) in IBT file", word); break; } if ( !fMatch ) { fread_to_eol(fp); log( "read_ibt (%s): no match: %s - aborting line!", filename, word ); } } log ("read_ibt: Aborted! Returning NULL"); if ( ibtData->name) STRFREE( ibtData->name); if ( ibtData->text) STRFREE( ibtData->text); if ( ibtData->body) STRFREE( ibtData->body); if ( id_num ) STRFREE( id_num ); if ( dated ) STRFREE( dated ); DISPOSE( ibtData); return NULL; } void load_ibt_file(int mode) { char filename[MAX_INPUT_LENGTH]; FILE *fp; IBT_DATA *ibtData, *first_ibt, *last_ibt; switch(mode) { case SCMD_BUG : sprintf( filename, "%s",BUGS_FILE ); first_ibt = first_bug; last_ibt = last_bug; break; case SCMD_IDEA: sprintf( filename, "%s",IDEAS_FILE ); first_ibt = first_idea; last_ibt = last_idea; break; case SCMD_TYPO: sprintf( filename, "%s",TYPOS_FILE ); first_ibt = first_typo; last_ibt = last_typo; break; default : log("SYSERR: Invalid mode (%d) in load_ibt_file", mode); return; } /* Remove and free the old list */ if ((first_ibt) && (last_ibt)) { free_ibt_list(first_ibt, last_ibt); first_ibt = NULL; last_ibt = NULL; } if( ( fp = fopen( filename, "r" ) ) == NULL ) { log("No File: %s", filename); return; } while( ( ibtData = read_ibt( filename, fp ) ) != NULL ) { switch(mode) { case SCMD_BUG : LINK( ibtData, first_bug, last_bug, next, prev ); break; case SCMD_IDEA: LINK( ibtData, first_idea, last_idea, next, prev ); break; case SCMD_TYPO: LINK( ibtData, first_typo, last_typo, next, prev ); break; } } return; } void save_ibt_file(int mode) { IBT_DATA *ibtData, *first_ibt, *last_ibt; FILE *fp; char filename[256]; switch(mode) { case SCMD_BUG : sprintf( filename, "%s",BUGS_FILE ); first_ibt = first_bug; last_ibt = last_bug; break; case SCMD_IDEA: sprintf( filename, "%s",IDEAS_FILE ); first_ibt = first_idea; last_ibt = last_idea; break; case SCMD_TYPO: sprintf( filename, "%s",TYPOS_FILE ); first_ibt = first_typo; last_ibt = last_typo; break; default : log("SYSERR: Invalid mode (%d) in save_ibt_file", mode); return; } if (( fp = fopen(filename,"w")) == NULL) { log("SYSERR: Unable to open IBT file for writing in save_ibt_file"); log(" IBT File: %s", filename); return; } else { for (ibtData = first_ibt;ibtData;ibtData=ibtData->next) { if (ibtData->text && *(ibtData->text)) fprintf(fp,"Text %s~\n",ibtData->text); if (ibtData->body && *(ibtData->body)) fprintf(fp,"Body %s~\n",ibtData->body); if (ibtData->name && *(ibtData->name)) fprintf(fp,"Name %s~\n",ibtData->name); if (ibtData->notes && *(ibtData->notes)) fprintf(fp,"Notes %s~\n",ibtData->notes); if (ibtData->id_num != NOBODY) fprintf(fp,"IdNum %ld\n",ibtData->id_num); if (ibtData->dated != 0) fprintf(fp,"Dated %ld\n",ibtData->dated); fprintf(fp,"Level %d\n",ibtData->level); fprintf(fp,"Room %d\n",ibtData->room); fprintf(fp,"Flags %d %d %d %d\n",ibtData->flags[0],ibtData->flags[1], ibtData->flags[2],ibtData->flags[3]); fprintf(fp,"End\n"); } fclose(fp); return; } } static IBT_DATA *get_first_ibt(int mode) { IBT_DATA *first_ibt = NULL; switch(mode) { case SCMD_BUG : first_ibt = first_bug; break; case SCMD_IDEA: first_ibt = first_idea; break; case SCMD_TYPO: first_ibt = first_typo; break; default : log("SYSERR: Invalid mode (%d) in get_first_ibt", mode); break; } return (first_ibt); } static IBT_DATA *get_last_ibt(int mode) { IBT_DATA *last_ibt = NULL; switch(mode) { case SCMD_BUG : last_ibt = last_bug; break; case SCMD_IDEA: last_ibt = last_idea; break; case SCMD_TYPO: last_ibt = last_typo; break; default : log("SYSERR: Invalid mode (%d) in get_last_ibt", mode); break; } return (last_ibt); } IBT_DATA *get_ibt_by_num(int mode, int target_num) { int no=0; IBT_DATA *target_ibt, *first_ibt; if ((first_ibt = get_first_ibt(mode)) == NULL) return NULL; for (target_ibt=first_ibt;target_ibt;target_ibt=target_ibt->next) { no++; if (no==target_num) { return target_ibt; } } return NULL; } /* Search the IBT list, and return true if ibt is found there */ bool ibt_in_list(int mode, IBT_DATA *ibt) { IBT_DATA *target_ibt, *first_ibt; if ((first_ibt = get_first_ibt(mode)) == NULL) return FALSE; for (target_ibt=first_ibt;target_ibt;target_ibt=target_ibt->next) { if (target_ibt == ibt) { return TRUE; } } return FALSE; } /* Free up an IBT struct, removing it from the list if necessary */ /* returns TRUE on success */ bool free_ibt(int mode, IBT_DATA *ibtData) { if (ibtData == NULL) return FALSE; /* If this IBT is in the IBT list, take it out */ if (ibt_in_list(mode, ibtData)) { switch(mode) { case SCMD_BUG : UNLINK(ibtData,first_bug,last_bug,next,prev); break; case SCMD_IDEA: UNLINK(ibtData,first_idea,last_idea,next,prev); break; case SCMD_TYPO: UNLINK(ibtData,first_typo,last_typo,next,prev); break; } } /* Free the strings first */ if (ibtData->body) STRFREE(ibtData->body); if (ibtData->name) STRFREE(ibtData->name); if (ibtData->text) STRFREE(ibtData->text); /* And free the struct */ DISPOSE(ibtData); return TRUE; } /* Return TRUE if 'ch' is the person who logged the IBT */ static bool is_ibt_logger(IBT_DATA *ibtData, struct char_data *ch) { if ( ch && !IS_NPC(ch) && ibtData ) { /* Check the ID number first (in case of name change) */ if ((ibtData->id_num != NOBODY) && (ibtData->id_num == GET_IDNUM(ch))) return TRUE; /* Check the name next (in case of deletion/recreation) */ if (strcmp(ibtData->name, GET_NAME(ch)) == 0) return TRUE; } return FALSE; } ACMD(do_ibt) { char arg[MAX_STRING_LENGTH], arg2[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH], *arg_text, imp[30], timestr[128]; int i, num_res, num_unres; IBT_DATA *ibtData, *first_ibt, *last_ibt; int ano=0; if (IS_NPC(ch)) return; arg_text = one_argument(argument, arg); argument = two_arguments(argument, arg, arg2); first_ibt = get_first_ibt(subcmd); last_ibt = get_last_ibt(subcmd); if ((!*arg)){ if (GET_LEVEL(ch) >= LVL_GRGOD){ send_to_char(ch, "Usage: %s%s submit <header>%s\r\n" " %s%s list%s\r\n" " %s%s show <num>%s\r\n" " %s%s remove <num>%s\r\n" " %s%s edit <num>%s\r\n" " %s%s resolve <num>%s\r\n", QYEL, CMD_NAME, QNRM, QYEL, CMD_NAME, QNRM, QYEL, CMD_NAME, QNRM, QYEL, CMD_NAME, QNRM, QYEL, CMD_NAME, QNRM, QYEL, CMD_NAME, QNRM); return; } else if (GET_LEVEL(ch) >= LVL_IMMORT) { send_to_char(ch, "Usage: %s%s submit <header>%s\r\n" " %s%s list%s\r\n" " %s%s show <num>%s\r\n", QYEL, CMD_NAME, QNRM, QYEL, CMD_NAME, QNRM, QYEL, CMD_NAME, QNRM); return; } else { send_to_char(ch, "Usage: %s%s submit <header>%s\r\n" " %s%s list%s\r\n" " %s%s show <num>%s\r\n", QYEL, CMD_NAME, QNRM, QYEL, CMD_NAME, QNRM, QYEL, CMD_NAME, QNRM); send_to_char(ch, "Note: Only %ss logged by you will be listed or shown.\r\n", CMD_NAME); return; } } else if(is_abbrev(arg,"show")) { if (!is_number(arg2)) { send_to_char(ch, "Show which %s?\r\n", CMD_NAME); return; } ano = atoi(arg2); if ((ibtData = get_ibt_by_num(subcmd, ano)) == NULL) { send_to_char(ch, "That %s doesn't exist.\r\n", CMD_NAME); return; } else { if ((GET_LEVEL(ch) < LVL_IMMORT) && (!is_ibt_logger(ibtData, ch))) { send_to_char(ch, "Sorry but you may only view %ss you have posted yourself.\n\r", ibt_types[subcmd]); } else { send_to_char(ch, "%s%s by %s%s\r\n",QCYN, ibt_types[subcmd], QYEL, ibtData->name); if (ibtData->dated != 0) { strftime(timestr, sizeof(timestr), "%c", localtime(&(ibtData->dated))); } else { strcpy(timestr, "Unknown"); } send_to_char(ch, "%sSubmitted: %s%s\r\n", QCYN, QYEL, timestr); if (GET_LEVEL(ch) >= LVL_IMMORT) { send_to_char(ch, "%sLevel: %s%d\r\n",QCYN, QYEL, ibtData->level); send_to_char(ch, "%sRoom : %s%d\r\n",QCYN, QYEL, ibtData->room); } send_to_char(ch, "%sTitle: %s%s\r\n",QCYN, QYEL, ibtData->text); send_to_char(ch, "%s%s Details%s\r\n%s\r\n",QCYN, ibt_types[subcmd], QYEL, ibtData->body); if (ibtData->notes && *(ibtData->notes)) send_to_char(ch, "%s%s Notes%s\r\n%s\r\n",QCYN, ibt_types[subcmd], QYEL, ibtData->notes); send_to_char(ch, "%s%s Status: %s%s%s%s\r\n",QCYN, ibt_types[subcmd], IBT_FLAGGED(ibtData, IBT_RESOLVED) ? QBGRN : QBRED, IBT_FLAGGED(ibtData, IBT_RESOLVED) ? "Resolved" : "Unresolved", IBT_FLAGGED(ibtData, IBT_INPROGRESS) ? " (In Progress)" : "", QNRM); } } return; } else if(is_abbrev(arg,"list")) { if (first_ibt) { if (GET_LEVEL(ch) < LVL_IMMORT) { send_to_char(ch,"%s No %s|%s Description\r\n", QCYN, QGRN, QCYN); send_to_char(ch,"%s ---|--------------------------------------------------%s\r\n", QGRN, QNRM); } else { send_to_char(ch,"%s No %s|%sName %s|%sRoom %s|%sLevel%s|%s Description\r\n", QCYN, QGRN, QCYN, QGRN, QCYN, QGRN, QCYN, QGRN, QCYN); send_to_char(ch,"%s ---|------------|------|-----|--------------------------------------------------%s\r\n", QGRN, QNRM); } i=num_res=num_unres=0; for (ibtData=first_ibt;ibtData;ibtData = ibtData->next) { i++; /* For mortals, skip IBT's that they didn't log */ if ((GET_LEVEL(ch) < LVL_IMMORT) && !is_ibt_logger(ibtData,ch)) continue; /* Set up the 'important' flag */ if (IBT_FLAGGED(ibtData, IBT_IMPORTANT)) sprintf(imp, "%s!%s", QBFRED, QNRM); else sprintf(imp, "%c", ' '); if (IBT_FLAGGED(ibtData, IBT_RESOLVED)) { if (GET_LEVEL(ch) < LVL_IMMORT) { send_to_char(ch, "%s%s%3d|%s%s\r\n", imp, QGRN, i, ibtData->text, QNRM); } else { send_to_char(ch, "%s%s%3d%s|%s%-12s%s|%s%6d%s|%s%5d%s|%s%s%s\r\n", imp, QGRN, i, QGRN, QGRN, ibtData->name, QGRN, QGRN, ibtData->room, QGRN, QGRN, ibtData->level, QGRN, QGRN, ibtData->text, QNRM); } num_res++; } else if (IBT_FLAGGED(ibtData, IBT_INPROGRESS)) { if (GET_LEVEL(ch) < LVL_IMMORT) { send_to_char(ch, "%s%s%3d%s|%s%s%s\r\n", imp, QYEL, i, QGRN, QYEL, ibtData->text, QNRM); } else { send_to_char(ch, "%s%s%3d%s|%s%-12s%s|%s%6d%s|%s%5d%s|%s%s%s\r\n", imp, QYEL, i, QGRN, QYEL, ibtData->name, QGRN, QYEL, ibtData->room, QGRN, QYEL, ibtData->level, QGRN, QYEL, ibtData->text, QNRM); } num_unres++; } else { if (GET_LEVEL(ch) < LVL_IMMORT) { send_to_char(ch, "%s%s%3d%s|%s%s%s\r\n", imp, QRED, i, QGRN, QRED, ibtData->text, QNRM); } else { send_to_char(ch, "%s%s%3d%s|%s%-12s%s|%s%6d%s|%s%5d%s|%s%s%s\r\n", imp, QRED, i, QGRN, QRED, ibtData->name, QGRN, QRED, ibtData->room, QGRN, QRED, ibtData->level, QGRN, QRED, ibtData->text, QNRM); } num_unres++; } } if ((num_res + num_unres) > 0) { send_to_char(ch,"\n\r%s%d %ss in file. %s%d%s resolved, %s%d%s unresolved%s\r\n",QCYN, i, CMD_NAME, QBGRN, num_res, QCYN, QBRED, num_unres, QCYN, QNRM); send_to_char(ch,"%s%ss in %sRED%s are unresolved %ss.\r\n", QCYN, ibt_types[subcmd], QRED, QCYN, CMD_NAME); send_to_char(ch,"%s%ss in %sYELLOW%s are in-progress %ss.\r\n", QCYN, ibt_types[subcmd], QYEL, QCYN, CMD_NAME); send_to_char(ch,"%s%ss in %sGREEN%s are resolved %ss.\r\n", QCYN, ibt_types[subcmd], QGRN, QCYN, CMD_NAME); } else { send_to_char(ch,"No %ss have been found that were reported by you!\r\n", CMD_NAME); } if (GET_LEVEL(ch) >= LVL_GRGOD) { send_to_char(ch,"%sYou may use %s remove, resolve or edit to change the list..%s\r\n", QCYN, CMD_NAME, QNRM); } send_to_char(ch,"%sYou may use %s%s show <number>%s to see more indepth about the %s.%s\r\n", QCYN, QYEL, CMD_NAME, QCYN, CMD_NAME, QNRM); } else { send_to_char(ch,"No %ss have been reported!\r\n", CMD_NAME); } return; } else if (is_abbrev(arg,"submit")) { if (!*arg_text) { send_to_char(ch, "You need to add a heading!\r\n"); return; } switch (subcmd) { case SCMD_IDEA: SET_BIT_AR(PLR_FLAGS(ch), PLR_IDEA); break; case SCMD_BUG : SET_BIT_AR(PLR_FLAGS(ch), PLR_BUG); break; case SCMD_TYPO: SET_BIT_AR(PLR_FLAGS(ch), PLR_TYPO); break; default : log("Invalid subcmd (%d) in do_ibt", subcmd); return; } SET_BIT_AR(PLR_FLAGS(ch), PLR_WRITING); ibtData = new_ibt(); send_to_char(ch, "Write your %s.\r\n", CMD_NAME); send_editor_help(ch->desc); sprintf(buf, "$n starts to give %s %s.", TANA(CMD_NAME), CMD_NAME); act(buf, TRUE, ch, 0, 0, TO_ROOM); string_write(ch->desc, &(ibtData->body),MAX_IBT_LENGTH, 0, NULL); ibtData->room = GET_ROOM_VNUM(IN_ROOM(ch)); ibtData->level = GET_LEVEL(ch); ibtData->text = STRALLOC(arg_text); ibtData->name = STRALLOC(GET_NAME(ch)); ibtData->id_num = GET_IDNUM(ch); ibtData->dated = time(0); switch(subcmd) { case SCMD_BUG : LINK( ibtData, first_bug, last_bug, next, prev ); break; case SCMD_IDEA: LINK( ibtData, first_idea, last_idea, next, prev ); break; case SCMD_TYPO: LINK( ibtData, first_typo, last_typo, next, prev ); break; } mudlog(NRM,LVL_IMMORT, FALSE, "%s has posted %s %s!", GET_NAME(ch), TANA(CMD_NAME), CMD_NAME); return; } else if (is_abbrev(arg,"resolve")) { if (GET_LEVEL(ch) < LVL_GRGOD){ send_to_char(ch, "%s what?\r\n", ibt_types[subcmd]); return; } if (!is_number(arg2)) { send_to_char(ch, "Resolve which %s?\r\n", CMD_NAME); return; } ano = atoi(arg2); if ((ibtData = get_ibt_by_num(subcmd, ano)) == NULL) { send_to_char(ch, "%s not found\r\n", ibt_types[subcmd]); return; } else { if (IBT_FLAGGED(ibtData, IBT_RESOLVED)){ send_to_char(ch, "That %s has already been resolved!\r\n", CMD_NAME); } else { send_to_char(ch,"%s %d resolved!\r\n", ibt_types[subcmd], ano); SET_BIT_AR(IBT_FLAGS(ibtData), IBT_RESOLVED); if (CONFIG_IBT_AUTOSAVE) { save_ibt_file(subcmd); } } } return; } else if (is_abbrev(arg,"remove")) { if (GET_LEVEL(ch) < LVL_GRGOD){ send_to_char(ch, "%s what?\r\n", ibt_types[subcmd]); return; } if (!is_number(arg2)) { send_to_char(ch, "Remove which %s?\r\n", CMD_NAME); return; } ano = atoi(arg2); if ((ibtData = get_ibt_by_num(subcmd, ano)) == NULL) { send_to_char(ch, "%s not found\r\n", ibt_types[subcmd]); return; } else { if (free_ibt(subcmd, ibtData)) { send_to_char(ch,"%s%s Number %d removed.%s\r\n", QCYN, ibt_types[subcmd], ano, QNRM); if (CONFIG_IBT_AUTOSAVE) { save_ibt_file(subcmd); } } else { send_to_char(ch,"%sUnable to remove %s %d!%s\r\n", QRED, CMD_NAME, ano, QNRM); } } return; } else if (is_abbrev(arg,"save")) { if (GET_LEVEL(ch) < LVL_GRGOD){ send_to_char(ch, "%s what?\r\n", ibt_types[subcmd]); return; } save_ibt_file(subcmd); send_to_char(ch,"%s list saved.\r\n", ibt_types[subcmd]); } else if (is_abbrev(arg,"edit")) { if (GET_LEVEL(ch) < LVL_GRGOD){ send_to_char(ch, "%s what?\r\n", ibt_types[subcmd]); return; } /* Pass control to the OLC without the 'edit' arg */ do_oasis_ibtedit(ch, arg_text, cmd, subcmd); } else { if (GET_LEVEL(ch) < LVL_GRGOD){ send_to_char(ch, "%s what?\r\n", ibt_types[subcmd]); send_to_char(ch, "Usage: %s submit <text>\r\n", ibt_types[subcmd]); return; } else { send_to_char(ch, "Usage: %s (submit/list/show/remove/resolve)\r\n", CMD_NAME); return; } } } /* IBT Editor OLC */ /* OLC_VAL(d) - The IBT 'mode' - Idea, Bug or Typo */ /* OLC_NUM(d) - The IBT number (shown in 'list') */ /* OLC_ZNUM(d) - Used as 'has changed' flag */ ACMD(do_oasis_ibtedit) { int number = NOTHING; struct descriptor_data *d; char buf1[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH], *buf3; /* No editing as a mob or while being forced. */ if (IS_NPC(ch) || !ch->desc || STATE(ch->desc) != CON_PLAYING) return; /* Parse any arguments */ buf3 = two_arguments(argument, buf1, buf2); if (!*buf1) { send_to_char(ch, "Specify a %s number to edit.\r\n", ibt_types[subcmd]); return; } else if (!isdigit(*buf1)) { send_to_char(ch, "Yikes! Stop that, someone will get hurt!\r\n"); return; } /* If a numeric argument was given (like a room number), get it. */ if (number == NOTHING) number = atoi(buf1); /* Validate that the IBT number exists */ if (get_ibt_by_num(subcmd, number) == NULL) { send_to_char(ch, "That %s number doesn't exist!\r\n", ibt_types[subcmd]); return; } /* Check that whatever it is isn't already being edited. */ for (d = descriptor_list; d; d = d->next) { if (STATE(d) == CON_IBTEDIT) { if (d->olc && OLC_NUM(d) == number) { send_to_char(ch, "That %s is currently being edited by %s.\r\n", ibt_types[subcmd], GET_NAME(d->character)); return; } } } d = ch->desc; /* Give descriptor an OLC structure. */ if (d->olc) { mudlog(BRF, LVL_IMMORT, TRUE, "SYSERR: do_oasis_ibtedit: Player already had olc structure."); free(d->olc); } CREATE(d->olc, struct oasis_olc_data, 1); /* Set OLC variables. */ OLC_NUM(d) = number; OLC_VAL(d) = subcmd; OLC_ZNUM(d) = 0; /* setup the OLC structure. */ ibtedit_setup(d); /* Show the main IBT edit menu */ ibtedit_disp_main_menu(d); STATE(d) = CON_IBTEDIT; /* Display the OLC messages to the players in the same room as the editor and also log it. */ act("$n starts using OLC.", TRUE, d->character, 0, 0, TO_ROOM); SET_BIT_AR(PLR_FLAGS(ch), PLR_WRITING); mudlog(CMP, LVL_IMMORT, TRUE,"OLC: %s starts editing %s %d", GET_NAME(ch), IBT_TYPE, OLC_NUM(d)); } /*-------------------------------------------------------------------*/ /* Copy IBT data into the OLC structure */ static void ibtedit_setup(struct descriptor_data *d) { IBT_DATA *ibtData; int i; /* Set up a blank IBT struct */ OLC_IBT(d) = new_ibt(); /* Should always be the case, but just to make sure */ if ((ibtData = get_ibt_by_num(OLC_VAL(d), OLC_NUM(d))) != NULL) { if ((ibtData->text) && *(ibtData->text)) { OLC_IBT(d)->text = STRALLOC(ibtData->text); } if ((ibtData->body) && *(ibtData->body)) { OLC_IBT(d)->body = STRALLOC(ibtData->body); } if ((ibtData->name) && *(ibtData->name)) { OLC_IBT(d)->name = STRALLOC(ibtData->name); } if ((ibtData->notes) && *(ibtData->notes)) { OLC_IBT(d)->notes = STRALLOC(ibtData->notes); } OLC_IBT(d)->level = ibtData->level; OLC_IBT(d)->room = ibtData->room; for (i=0; i<IBT_ARRAY_MAX; i++) { OLC_IBT(d)->flags[i] = ibtData->flags[i]; } } } /*-------------------------------------------------------------------*/ /* Copy IBT data back to the correct list */ static void ibtedit_save(struct descriptor_data *d) { IBT_DATA *ibtData; int i; /* Should always be the case, but just to make sure */ if ((ibtData = get_ibt_by_num(OLC_VAL(d), OLC_NUM(d))) != NULL) { if ((OLC_IBT(d)->text) && *(OLC_IBT(d)->text)) { if (ibtData->text) STRFREE(ibtData->text); ibtData->text = STRALLOC(OLC_IBT(d)->text); STRFREE(OLC_IBT(d)->text); } if ((OLC_IBT(d)->body) && *(OLC_IBT(d)->body)) { if (ibtData->body) STRFREE(ibtData->body); ibtData->body = STRALLOC(OLC_IBT(d)->body); STRFREE(OLC_IBT(d)->body); } if ((OLC_IBT(d)->name) && *(OLC_IBT(d)->name)) { if (ibtData->name) STRFREE(ibtData->name); ibtData->name = STRALLOC(OLC_IBT(d)->name); STRFREE(OLC_IBT(d)->name); } if ((OLC_IBT(d)->notes) && *(OLC_IBT(d)->notes)) { if (ibtData->notes) STRFREE(ibtData->notes); ibtData->notes = STRALLOC(OLC_IBT(d)->notes); STRFREE(OLC_IBT(d)->notes); } ibtData->level = OLC_IBT(d)->level; ibtData->room = OLC_IBT(d)->room; for (i=0; i<IBT_ARRAY_MAX; i++) { ibtData->flags[i] = OLC_IBT(d)->flags[i]; } } else { log("SYSERR: ibtedit_save: Invalid IBT vnum (%d) in OLC struct", OLC_NUM(d)); log(" IBT possibly removed while being edited"); return; } save_ibt_file(OLC_VAL(d)); } void free_olc_ibt(IBT_DATA *toFree) { if (!toFree) return; if (toFree->text) { STRFREE(toFree->text); } if (toFree->body) { STRFREE(toFree->body); } if (toFree->name) { STRFREE(toFree->name); } if (toFree->notes) { STRFREE(toFree->notes); } free(toFree); } /*-------------------------------------------------------------------*/ /* main ibtedit menu function... */ static void ibtedit_disp_main_menu(struct descriptor_data *d) { struct char_data *ch = d->character; char flg_text[MAX_STRING_LENGTH]; room_rnum rr; get_char_colors(ch); clear_screen(d); rr = real_room(OLC_IBT(d)->room); sprintbitarray(OLC_IBT(d)->flags, ibt_bits, IBT_ARRAY_MAX, flg_text); send_to_char(ch, "%s-- Edit %s Number %s[%s%d%s]\r\n" "%s1%s) Reported By: %s%-12s\r\n" "%s2%s) Reported In: %s[%s%-5d%s]%s - %s%s\r\n" "%s3%s) Header Text: %s%s\r\n" "%s4%s) Flags : %s%s\r\n" "%s5%s) Details:\r\n%s%s\r\n" "%s6%s) Admin Notes:\r\n%s%s\r\n" "%sQ%s) Quit %s Editor\r\n", QBGRN, IBT_TYPE, cyn, yel, OLC_NUM(d), cyn, yel, nrm, yel, OLC_IBT(d)->name, yel, nrm, cyn, yel, OLC_IBT(d)->room, cyn, nrm, (rr == NOWHERE) ? CCRED(d->character, C_NRM) : cyn, (rr == NOWHERE) ? "<Invalid Room!>" : world[rr].name, yel, nrm, yel, OLC_IBT(d)->text, yel, nrm, cyn, flg_text, yel, nrm, yel, OLC_IBT(d)->body ? OLC_IBT(d)->body : "<Not Set!>", yel, nrm, yel, OLC_IBT(d)->notes ? OLC_IBT(d)->notes : "<Not Set!>", yel, nrm, IBT_TYPE); OLC_MODE(d) = IBTEDIT_MAIN_MENU; } /*-------------------------------------------------------------------*/ /* Display IBT-flags menu. */ static void ibtedit_disp_flags(struct descriptor_data *d) { char buf[MAX_STRING_LENGTH]; get_char_colors(d->character); clear_screen(d); column_list(d->character, 2, ibt_bits, NUM_IBT_FLAGS, TRUE); sprintbitarray(OLC_IBT(d)->flags, ibt_bits, IBT_ARRAY_MAX, buf); write_to_output(d, "\r\nCurrent flags : %s%s%s\r\nEnter flags (0 to quit) : ", cyn, buf, nrm); OLC_MODE(d) = IBTEDIT_FLAGS; } /*-------------------------------------------------------------------*/ /* main clanedit parser function... interpreter throws all input to here. */ void ibtedit_parse(struct descriptor_data *d, char *arg) { int i; char *oldtext = NULL; switch (OLC_MODE(d)) { case IBTEDIT_CONFIRM_SAVESTRING: switch (*arg) { case 'y': case 'Y': /* Save the IBT in memory and to disk. */ ibtedit_save(d); mudlog(CMP, MAX(LVL_BUILDER, GET_INVIS_LEV(d->character)), TRUE, "OLC: %s edits %s %d", GET_NAME(d->character), IBT_TYPE, OLC_NUM(d)); cleanup_olc(d, CLEANUP_ALL); return; case 'n': case 'N': /* If not saving, we must free the OLC memory. */ cleanup_olc(d, CLEANUP_ALL); return; default: write_to_output(d, "Invalid choice!\r\n"); write_to_output(d, "Do you wish to save your changes? : "); return; } break; case IBTEDIT_MAIN_MENU: switch (*arg) { case 'q': case 'Q': if (OLC_ZNUM(d)) { /* Anything been changed? */ write_to_output(d, "Do you wish to save your changes? : "); OLC_MODE(d) = IBTEDIT_CONFIRM_SAVESTRING; } else cleanup_olc(d, CLEANUP_ALL); return; case '1': OLC_MODE(d) = IBTEDIT_NAME; write_to_output(d, "Who reported this %s? : ", IBT_TYPE); return; case '2': OLC_MODE(d) = IBTEDIT_ROOM; write_to_output(d, "Enter the room VNUM for this %s? : ", IBT_TYPE); return; case '3': OLC_MODE(d) = IBTEDIT_TEXT; write_to_output(d, "Enter the header text for this %s? : ", IBT_TYPE); return; case '4': ibtedit_disp_flags(d); return; case '5': OLC_MODE(d) = IBTEDIT_BODY; send_editor_help(d); write_to_output(d, "Enter %s description:\r\n\r\n", IBT_TYPE); if (OLC_IBT(d)->body) { write_to_output(d, "%s", OLC_IBT(d)->body); if (oldtext) STRFREE(oldtext); oldtext = STRALLOC(OLC_IBT(d)->body); } string_write(d, &OLC_IBT(d)->body, MAX_IBT_LENGTH, 0, oldtext); OLC_ZNUM(d) = 1; return; case '6': OLC_MODE(d) = IBTEDIT_NOTES; send_editor_help(d); write_to_output(d, "Enter %s notes:\r\n\r\n", IBT_TYPE); if (OLC_IBT(d)->notes) { write_to_output(d, "%s", OLC_IBT(d)->notes); if (oldtext) STRFREE(oldtext); oldtext = STRALLOC(OLC_IBT(d)->notes); } string_write(d, &OLC_IBT(d)->notes, MAX_IBT_LENGTH, 0, oldtext); OLC_ZNUM(d) = 1; return; default: ibtedit_disp_main_menu(d); return; } break; case IBTEDIT_NAME: smash_tilde(arg); if (OLC_IBT(d)->name) STRFREE(OLC_IBT(d)->name); OLC_IBT(d)->name = STRALLOC(arg); break; case IBTEDIT_ROOM: i = atoi(arg); if (i == 0) { /* Cancel option */ ibtedit_disp_main_menu(d); return; } if (real_room(i) == NOWHERE) { write_to_output(d, "That room does not exist!\r\n" "Enter room VNUM (0 to cancel) : "); return; } OLC_IBT(d)->room = i; /* Drop through to re-show main menu and set 'edited' flag */ break; case IBTEDIT_TEXT: smash_tilde(arg); if (OLC_IBT(d)->text) STRFREE(OLC_IBT(d)->text); OLC_IBT(d)->text = STRALLOC(arg); break; case IBTEDIT_FLAGS: if ((i = atoi(arg)) <= 0) break; else if (i <= NUM_IBT_FLAGS) TOGGLE_BIT_AR(IBT_FLAGS(OLC_IBT(d)), (i - 1)); ibtedit_disp_flags(d); return; case IBTEDIT_BODY: /* We should never get here, modify.c throws user through ibtedit_string_cleanup. */ cleanup_olc(d, CLEANUP_ALL); mudlog(BRF, LVL_BUILDER, TRUE, "SYSERR: OLC: ibtedit_parse(): Reached BODY case!"); write_to_output(d, "Oops...\r\n"); break; case IBTEDIT_NOTES: /* We should never get here, modify.c throws user through ibtedit_string_cleanup. */ cleanup_olc(d, CLEANUP_ALL); mudlog(BRF, LVL_BUILDER, TRUE, "SYSERR: OLC: ibtedit_parse(): Reached NOTES case!"); write_to_output(d, "Oops...\r\n"); break; default: /* We should never get here. */ cleanup_olc(d, CLEANUP_ALL); mudlog(BRF, LVL_BUILDER, TRUE, "SYSERR: OLC: ibtedit_parse(): Reached default case!"); write_to_output(d, "Oops...\r\n"); break; } /* If we get here, something was changed */ OLC_ZNUM(d) = 1; ibtedit_disp_main_menu(d); } /*-------------------------------------------------------------------*/ void ibtedit_string_cleanup(struct descriptor_data *d, int terminator) { switch (OLC_MODE(d)) { case IBTEDIT_BODY: case IBTEDIT_NOTES: default: ibtedit_disp_main_menu(d); break; } } /*-------------------------------------------------------------------*/ void free_ibt_lists() { IBT_DATA *first_ibt, *last_ibt; int mode; for( mode=0; mode <=2; mode++){ first_ibt = get_first_ibt(mode); last_ibt = get_last_ibt(mode); free_ibt_list(first_ibt, last_ibt); } }