/* This file needs some header text, doesn't it? */ #include <strings.h> #include <stdio.h> #include <ctype.h> #include "utils.h" #include "structs.h" #include "comm.h" #include "db.h" #define MAX_MSGS 50 /* Max number of messages. */ /* So we don't have all these messy ifs and duplicate functions */ struct board { char *filename; char *msgs[MAX_MSGS]; char *head[MAX_MSGS]; int msg_num; int has_loaded; int message_written; int remove_level; int view_level; bool trusted_only; }; #define MORTAL_SAVE_FILE "board.messages" /* Name of file for saving messages */ #define GOD_SAVE_FILE "god.messages" /* File for god's board */ #define PLAN_SAVE_FILE "planning.messages" /* Board in Planning Office */ #define REIMB_SAVE_FILE "reimb.messages" /* Board for reimbursement */ #define WAR_SAVE_FILE "war.messages" /* Board in the War Room */ #define FIVE_SAVE_FILE "five.messages" /* Board in the Room of Five*/ #define SEVEN_SAVE_FILE "seven.messages" /* Board in the Room of Seven*/ #define WILD_SAVE_FILE "wild.messages" /* Board in the wilderness */ #define MAX_MESSAGE_LENGTH 2048 /* that should be enough */ extern struct time_info_data time_info; char *MORTmsgs[MAX_MSGS]; char *MORThead[MAX_MSGS]; struct board MORTboard; char *GODmsgs[MAX_MSGS]; char *GODhead[MAX_MSGS]; struct board GODboard; char *PLANmsgs[MAX_MSGS]; char *PLANhead[MAX_MSGS]; struct board PLANboard; char *REIMBmsgs[MAX_MSGS]; char *REIMBhead[MAX_MSGS]; struct board REIMBboard; char *WARmsgs[MAX_MSGS]; char *WARhead[MAX_MSGS]; struct board WARboard; char *FIVEmsgs[MAX_MSGS]; char *FIVEhead[MAX_MSGS]; struct board FIVEboard; char *SEVENmsgs[MAX_MSGS]; char *SEVENhead[MAX_MSGS]; struct board SEVENboard; char *WILDmsgs[MAX_MSGS]; char *WILDhead[MAX_MSGS]; struct board WILDboard; void board_write_msg(struct char_data *ch, char *arg, struct board *board); int board_display_msg(struct char_data *ch, char *arg, struct board *board); int board_remove_msg(struct char_data *ch, char *arg, struct board *board); void board_save_board(char *file, char **head, char **msgs, int *msg_num); void board_load_board(char *file, char **head, char **msgs, int *msg_num); void board_reset_board(char **head, char **msgs, int *msg_num); void error_log(); void board_fix_long_desc(int num, char *headers[MAX_MSGS]); int board_show_board(struct char_data *ch, char *arg, struct board *board); /* This function initializes everything necessary to use the board */ void initialize_boards() { PLANboard.filename=PLAN_SAVE_FILE; PLANboard.has_loaded=0; PLANboard.message_written=0; PLANboard.remove_level=23; PLANboard.view_level=0; PLANboard.trusted_only=TRUE; GODboard.filename=GOD_SAVE_FILE; GODboard.has_loaded=0; GODboard.message_written=0; GODboard.remove_level=23; GODboard.view_level=21; GODboard.trusted_only=TRUE; MORTboard.filename=MORTAL_SAVE_FILE; MORTboard.has_loaded=0; MORTboard.message_written=0; MORTboard.remove_level=22; MORTboard.view_level=0; MORTboard.trusted_only=FALSE; REIMBboard.filename=REIMB_SAVE_FILE; REIMBboard.has_loaded=0; REIMBboard.message_written=0; REIMBboard.remove_level=23; REIMBboard.view_level=1; REIMBboard.trusted_only=TRUE; WARboard.filename=WAR_SAVE_FILE; WARboard.has_loaded=0; WARboard.message_written=0; WARboard.remove_level=26; WARboard.view_level=25; WARboard.trusted_only=TRUE; FIVEboard.filename=FIVE_SAVE_FILE; FIVEboard.has_loaded=0; FIVEboard.message_written=0; FIVEboard.remove_level=25; FIVEboard.view_level=25; FIVEboard.trusted_only=TRUE; SEVENboard.filename=SEVEN_SAVE_FILE; SEVENboard.has_loaded=0; SEVENboard.message_written=0; SEVENboard.remove_level=25; SEVENboard.view_level=25; SEVENboard.trusted_only=TRUE; WILDboard.filename=WILD_SAVE_FILE; WILDboard.has_loaded=0; WILDboard.message_written=0; WILDboard.remove_level=21; WILDboard.view_level=0; WILDboard.trusted_only=FALSE; } /* I have used cmd number 180-182 as the cmd numbers here. */ /* The commands would be, in order : NOTE <header> */ /* READ <message number>, REMOVE <message number> */ /* LOOK AT BOARD should give the long desc of the board */ /* and that should equal a list of message numbers and */ /* headers. This is done by calling a function that sets */ /* the long desc in the board object. This function is */ /* called when someone does a REMOVE or NOTE command. */ /* I have named the function board_fix_long_desc(). In the */ /* board_write_msg() function there is a part that should */ /* be replaced with a call to some dreadful routine used */ /* by the STRING command to receive player input. It is */ /* reputed to lurk somewhere within the limits of an evil */ /* file named act.comm.c.....*/ /* saving the board after the addition of a new messg */ /* poses a slight problem, since the text isn't actually */ /* entered in board_write. What I'll do is to let board() */ /* save the first time a 'look' is issued in the room.. */ /* ugh! that's ugly - gotta think of something better. */ /* -quinn */ /* And here is the board...correct me if I'm wrong. */ extern struct index_data *obj_index; int board(struct obj_data *obj,struct char_data *ch, int cmd, char *arg) { int irc; struct board *this_board; int message_num; switch(obj_index[obj->item_number].virtual) { case 9: /* Planning board */ this_board=&PLANboard; break; case 55: /* Five board */ this_board=&FIVEboard; break; case 59: /* War board */ this_board=&WARboard; break; case 66: /* Reimb board */ this_board=&REIMBboard; break; case 77: /* Seven board */ this_board=&SEVENboard; break; case 3098: /* God/wiz/immortal board */ this_board=&GODboard; break; case 3099: /* Mortal board */ this_board=&MORTboard; break; case 12005: /* Wilderness board */ this_board=&WILDboard; break; default: log("Bad object number in bulletin board handler!"); return(FALSE); break; } if (!ch->desc) return(FALSE); /* By MS or all NPC's will be trapped at the board */ /* note: I'll let display and remove return 0 if the arg was non-board- */ /* related. Thus, it'll be possible to read other things than the board */ /* while you're in the room. Conceiveably, you could do this for write, */ /* too, but I'm not in the mood for such hacking. */ if (!this_board->has_loaded) { board_load_board(this_board->filename, this_board->head, this_board->msgs, &this_board->msg_num); this_board->has_loaded = 1; } switch (cmd) { case 15: /* look */ irc = board_show_board(ch, arg, this_board); break; case 149: /* write */ board_write_msg(ch, arg, this_board); this_board->message_written = TRUE; return (1); /* Dont save in this case */ break; case 63: /* read */ irc = board_display_msg(ch, arg, this_board); break; case 66: /* remove */ irc = board_remove_msg(ch, arg, this_board); board_save_board(this_board->filename, this_board->head, this_board->msgs, &this_board->msg_num); break; default: irc = 0; break; } /* switch */ if (this_board->message_written) { this_board->message_written = FALSE; board_save_board(this_board->filename, this_board->head, this_board->msgs, &this_board->msg_num); } /* if */ return irc; } void board_write_msg(struct char_data *ch, char *arg, struct board *board) { char buf[MAX_STRING_LENGTH]; if(board->trusted_only && !IS_TRUSTED(ch)) { send_to_char("You are not holy enough.\n\r", ch); return; } if(GET_LEVEL(ch) < board->view_level) { send_to_char("Nobody left any space for you!\n\r",ch); return; } if (board->msg_num > MAX_MSGS - 1) { send_to_char("The board is full already.\n\r", ch); return; } /* skip blanks */ for(; isspace(*arg); arg++); if (!*arg) { send_to_char("We must have a headline!\n\r", ch); return; } if(strlen(arg)>50) { /* Rather arbitrary, to leave room for name,date */ send_to_char("Your headline is too long!\n\r",ch); return; } sprintf(buf,"[%d/%d/%d]",time_info.day+1,time_info.month+1,time_info.year); board->head[board->msg_num] = (char *)malloc(strlen(arg) + strlen(GET_NAME(ch)) + 5 + strlen(buf)); /* +5 is for a space, a null, and '()' around the character name. */ if (!board->head[board->msg_num]) { error_log("Malloc for board header failed.\n\r"); send_to_char("The board is malfunctioning - sorry.\n\r", ch); return; } sprintf(board->head[board->msg_num],"%s %s (%s)",buf,arg,GET_NAME(ch)); board->msgs[board->msg_num] = NULL; send_to_char("Write your message. Terminate with a @.\n\r\n\r", ch); act("$n starts to write a message.", TRUE, ch, 0, 0, TO_ROOM); ch->desc->str = &board->msgs[board->msg_num]; ch->desc->max_str = MAX_MESSAGE_LENGTH; board->msg_num++; } int board_remove_msg(struct char_data *ch, char *arg, struct board *board) { int ind, msg, pos, length; char buf[256], number[MAX_INPUT_LENGTH]; one_argument(arg, number); if (!*number || !isdigit(*number)) return(0); if (!(msg = atoi(number))) return(0); if (GET_LEVEL(ch) < board->view_level) { send_to_char("What messages?\n\r",ch); return(1); } if (!board->msg_num) { send_to_char("The board is empty!\n\r", ch); return(1); } if (msg < 1 || msg > board->msg_num) { send_to_char("That message exists only in your imagination..\n\r", ch); return(1); } if (!IS_TRUSTED(ch) || GET_LEVEL(ch) < board->remove_level) { pos=length=strlen(board->head[msg-1]); while(board->head[msg-1][pos]!='(' && pos>=0) pos--; strncpy(buf,&board->head[msg-1][pos+1],length-pos-2); buf[length-pos-2]='\0'; if(strcmp(GET_NAME(ch),buf)) { send_to_char("That message seems pretty solidly tacked into the board.\n\r", ch); return(1); } } ind = msg; free(board->head[--ind]); if (board->msgs[ind]) free(board->msgs[ind]); for (; ind < (board->msg_num-1); ind++) { board->head[ind] = board->head[ind + 1]; board->msgs[ind] = board->msgs[ind + 1]; } board->msg_num--; send_to_char("Message removed.\n\r", ch); /* Anybody have any idea*/ sprintf(buf, "$n just removed message %d.", msg/* + 1*/); /* <--- */ act(buf, FALSE, ch, 0, 0, TO_ROOM); /* was there? --Sman */ return(1); } void board_save_board(char *file, char **head, char **msgs, int *msg_num) { FILE *the_file; int ind, len; if (!*msg_num) { error_log("No messages to save.\n\r"); return; } the_file = fopen(file, "wb"); if (!the_file) { error_log("Unable to open/create savefile..\n\r"); return; } fwrite(msg_num, sizeof(int), 1, the_file); for (ind = 0; ind < *msg_num; ind++) { len = strlen(head[ind]) + 1; fwrite(&len, sizeof(int), 1, the_file); fwrite(head[ind], sizeof(char), len, the_file); len = msgs[ind] ? strlen(msgs[ind]) + 1 : 0; fwrite(&len, sizeof(int), 1, the_file); if(msgs[ind]) fwrite(msgs[ind], sizeof(char), len, the_file); } fclose(the_file); /* board_fix_long_desc(msg_num, head); */ return; } void board_load_board(char *file, char **head, char **msgs, int *msg_num) { FILE *the_file; int ind, len = 0; board_reset_board(head, msgs, msg_num); the_file = fopen(file, "rb"); if (!the_file) { error_log("Can't open message file. Board will be empty.\n\r",0); return; } fread(msg_num, sizeof(int), 1, the_file); /*changed 1 to a 0 below this line---randall*/ if (*msg_num < 0 || *msg_num > MAX_MSGS || feof(the_file)) { error_log("Board-message file corrupt or nonexistent.\n\r"); *msg_num = 0; fclose(the_file); return; } for (ind = 0; ind < *msg_num; ind++) { fread(&len, sizeof(int), 1, the_file); head[ind] = (char *)malloc(len + 1); if (!head[ind]) { error_log("Malloc for board header failed.\n\r"); board_reset_board(head, msgs, msg_num); fclose(the_file); return; } fread(head[ind], sizeof(char), len, the_file); fread(&len, sizeof(int), 1, the_file); msgs[ind] = (char *)malloc(len + 1); if (!msgs[ind]) { error_log("Malloc for board msg failed..\n\r"); board_reset_board(head, msgs, msg_num); fclose(the_file); return; } fread(msgs[ind], sizeof(char), len, the_file); } fclose(the_file); /* board_fix_long_desc(msg_num, head); */ return; } void board_reset_board(char **head, char **msgs, int *msg_num) { int ind; for (ind = 0; ind < MAX_MSGS; ind++) { free(head[ind]); free(msgs[ind]); } *msg_num = 0; /* board_fix_long_desc(0, head); */ return; } void error_log(char *str) { /* The original error-handling was MUCH */ fputs("Board : ", stderr); /* more competent than the current but */ fputs(str, stderr); /* I got the advice to cut it out..;) */ return; } int board_display_msg(struct char_data *ch, char *arg, struct board *board) { char buf[512], number[MAX_INPUT_LENGTH], buffer[MAX_STRING_LENGTH]; int msg; one_argument(arg, number); if (!*number || !isdigit(*number)) return(0); if (!(msg = atoi(number))) return(0); if(board->trusted_only && !IS_TRUSTED(ch)) { send_to_char("Your eyes are not holy enough.\n\r", ch); return(1); } /* if */ if (!board->msg_num || GET_LEVEL(ch) < board->view_level) { send_to_char("The board is empty!\n\r", ch); return(1); } if (msg < 1 || msg > board->msg_num) { send_to_char("That message exists only in your imagination..\n\r", ch); return(1); } /* Can PERFORM() handle this...? no. Sorry*/ /* sprintf(ch, "Message %d : %s\n\r%s", msg, head[msg - 1], msgs[msg - 1]); */ /* Bad news */ sprintf(buffer, "Message %d : %s\n\r\n\r%s", msg, board->head[msg - 1], board->msgs[msg - 1]); page_string(ch->desc, buffer, 1); return(1); } #if defined XYZZY /* Disabled */ void board_fix_long_desc(int num, char *headers[MAX_MSGS]) { struct obj_data *ob; /**** Assign the right value to this pointer..how? ****/ /**** It should point to the bulletin board object ****/ /**** Then make ob.description point to a malloced ****/ /**** space containing itoa(msg_num) and all the ****/ /**** headers. In the format : This is a bulletin board. Usage : READ/REMOVE <message #>, NOTE <header> There are 12 messages on the board. 1 : Re : Whatever and something else too. 2 : I don't agree with Rainbird. 3 : Me neither. 4 : Groo got hungry again - bug or sabotage? Well...something like that..;) ****/ /**** It is always to contain the first line and ****/ /**** the second line will vary in how many notes ****/ /**** the board has. Then the headers and message ****/ /**** numbers will be listed. ****/ return; } #endif int board_show_board(struct char_data *ch, char *arg, struct board *board) { int i; char buf[MAX_STRING_LENGTH], tmp[MAX_INPUT_LENGTH]; one_argument(arg, tmp); if (!*tmp || !isname(tmp, "board bulletin")) return(0); if(board->trusted_only && !IS_TRUSTED(ch)){ send_to_char("Your eyes are not holy enough.\n\r", ch); return(1); } /* if */ if(board->view_level > GET_LEVEL(ch)) { send_to_char("Those messages must be written invisible ink!\n\r",ch); return(0); } act("$n studies the board.", TRUE, ch, 0, 0, TO_ROOM); strcpy(buf, "This is a bulletin board. Usage: READ/REMOVE <messg #>, WRITE <header>\n\r"); if (!board->msg_num) strcat(buf, "The board is empty.\n\r"); else { sprintf(buf + strlen(buf), "There are %d messages on the board.\n\r", board->msg_num); for (i = 0; i < board->msg_num; i++) sprintf(buf + strlen(buf), "%-2d %s\n\r", i + 1, board->head[i]); } page_string(ch->desc, buf, 1); return(1); }