/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// * * -----------------------------------------------------------| (0...0) * * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( * * -----------------------------------------------------------| {o o} * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~* * Tricops and Fireblade | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Special boards module (Old Ones) * ****************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <string.h> #include <time.h> #include <sys/stat.h> #include "mud.h" /* Defines for voting on notes. -- Narn */ #define VOTE_NONE 0 #define VOTE_OPEN 1 #define VOTE_CLOSED 2 BOARD_DATA *first_board; BOARD_DATA *last_board; bool is_note_to args((CHAR_DATA * ch, NOTE_DATA * pnote)); void note_attach args((CHAR_DATA * ch)); void note_remove args((CHAR_DATA * ch, BOARD_DATA * board, NOTE_DATA * pnote)); void do_note args((CHAR_DATA * ch, char *arg_passed, bool IS_MAIL)); bool can_remove(CHAR_DATA * ch, BOARD_DATA * board) { /* If your trust is high enough, you can remove it. */ if (get_trust(ch) >= board->min_remove_level) return TRUE; if (board->extra_removers[0] != '\0') { if (is_name(ch->name, board->extra_removers)) return TRUE; } return FALSE; } bool can_read(CHAR_DATA * ch, BOARD_DATA * board) { /* If your trust is high enough, you can read it. */ if (get_trust(ch) >= board->min_read_level) return TRUE; /* Your trust wasn't high enough, so check if a read_group or extra readers have been set up. */ if (board->read_group[0] != '\0') { if (ch->pcdata->clan && !str_cmp(ch->pcdata->clan->name, board->read_group)) return TRUE; if (ch->pcdata->council && !str_cmp(ch->pcdata->council->name, board->read_group)) return TRUE; } if (board->extra_readers[0] != '\0') { if (is_name(ch->name, board->extra_readers)) return TRUE; } return FALSE; } bool can_post(CHAR_DATA * ch, BOARD_DATA * board) { /* If your trust is high enough, you can post. */ if (get_trust(ch) >= board->min_post_level) return TRUE; /* Your trust wasn't high enough, so check if a post_group has been set up. */ if (board->post_group[0] != '\0') { if (ch->pcdata->clan && !str_cmp(ch->pcdata->clan->name, board->post_group)) return TRUE; if (ch->pcdata->council && !str_cmp(ch->pcdata->council->name, board->post_group)) return TRUE; } return FALSE; } /* * board commands. */ void write_boards_txt() { BOARD_DATA *tboard; FILE *fpout; char filename[256]; sprintf(filename, "%s%s", BOARD_DIR, BOARD_FILE); fpout = fopen(filename, "w"); if (!fpout) { bug("FATAL: cannot open board.txt for writing!\n\r", 0); return; } for (tboard = first_board; tboard; tboard = tboard->next) { fprintf(fpout, "Filename %s~\n", tboard->note_file); fprintf(fpout, "Vnum %d\n", tboard->board_obj); fprintf(fpout, "Min_read_level %d\n", tboard->min_read_level); fprintf(fpout, "Min_post_level %d\n", tboard->min_post_level); fprintf(fpout, "Min_remove_level %d\n", tboard->min_remove_level); fprintf(fpout, "Max_posts %d\n", tboard->max_posts); fprintf(fpout, "Type %d\n", tboard->type); fprintf(fpout, "Read_group %s~\n", tboard->read_group); fprintf(fpout, "Post_group %s~\n", tboard->post_group); fprintf(fpout, "Extra_readers %s~\n", tboard->extra_readers); fprintf(fpout, "Extra_removers %s~\n", tboard->extra_removers); fprintf(fpout, "End\n"); } fclose(fpout); } BOARD_DATA *get_board(OBJ_DATA * obj) { BOARD_DATA *board; for (board = first_board; board; board = board->next) if (board->board_obj == obj->pIndexData->vnum) return board; return NULL; } BOARD_DATA *find_board(CHAR_DATA * ch) { OBJ_DATA *obj; BOARD_DATA *board; for (obj = ch->in_room->first_content; obj; obj = obj->next_content) { if ((board = get_board(obj)) != NULL && IN_SAME_ROOM_OBJ(ch, obj)) return board; } return NULL; } /* bool is_note_to( CHAR_DATA *ch, NOTE_DATA *pnote ) { if ( !str_cmp( ch->name, pnote->sender ) ) return TRUE; if ( is_name( "all", pnote->to_list ) ) return TRUE; if ( IS_HERO(ch) && is_name( "immortal", pnote->to_list ) ) return TRUE; if ( is_name( ch->name, pnote->to_list ) ) return TRUE; return FALSE; } */ void note_attach(CHAR_DATA * ch) { NOTE_DATA *pnote; if (ch->pnote) return; CREATE(pnote, NOTE_DATA, 1); pnote->next = NULL; pnote->prev = NULL; pnote->sender = QUICKLINK(ch->name); pnote->date = STRALLOC(""); pnote->to_list = STRALLOC(""); pnote->subject = STRALLOC(""); pnote->text = STRALLOC(""); ch->pnote = pnote; return; } void write_board(BOARD_DATA * board) { FILE *fp; char filename[256]; NOTE_DATA *pnote; /* * Rewrite entire list. */ fclose(fpReserve); sprintf(filename, "%s%s", BOARD_DIR, board->note_file); if ((fp = fopen(filename, "w")) == NULL) { perror(filename); } else { for (pnote = board->first_note; pnote; pnote = pnote->next) { fprintf(fp, "Sender %s~\nDate %s~\nTo %s~\nSubject %s~\nVoting %d\nYesvotes %s~\nNovotes %s~\nAbstentions %s~\nText\n%s~\n\n", pnote->sender, pnote->date, pnote->to_list, pnote->subject, pnote->voting, pnote->yesvotes, pnote->novotes, pnote->abstentions, pnote->text); } fclose(fp); } fpReserve = fopen(NULL_FILE, "r"); return; } void free_note(NOTE_DATA * pnote) { STRFREE(pnote->text); STRFREE(pnote->subject); STRFREE(pnote->to_list); STRFREE(pnote->date); STRFREE(pnote->sender); if (pnote->yesvotes) DISPOSE(pnote->yesvotes); if (pnote->novotes) DISPOSE(pnote->novotes); if (pnote->abstentions) DISPOSE(pnote->abstentions); DISPOSE(pnote); } void note_remove(CHAR_DATA * ch, BOARD_DATA * board, NOTE_DATA * pnote) { if (!board) { bug("note remove: null board", 0); return; } if (!pnote) { bug("note remove: null pnote", 0); return; } /* * Remove note from linked list. */ UNLINK(pnote, board->first_note, board->last_note, next, prev); --board->num_posts; free_note(pnote); write_board(board); } OBJ_DATA *find_quill(CHAR_DATA * ch) { OBJ_DATA *quill; for (quill = ch->last_carrying; quill; quill = quill->prev_content) if (quill->item_type == ITEM_PEN && can_see_obj(ch, quill)) return quill; return NULL; } void do_noteroom(CHAR_DATA * ch, char *argument) { BOARD_DATA *board; char arg[MSL]; char arg_passed[MSL]; strcpy(arg_passed, argument); switch (ch->substate) { case SUB_WRITING_NOTE: do_note(ch, arg_passed, FALSE); break; default: argument = one_argument(argument, arg); smash_tilde(argument); if (!str_cmp(arg, "write") || !str_cmp(arg, "to") || !str_cmp(arg, "subject") || !str_cmp(arg, "show")) { do_note(ch, arg_passed, FALSE); return; } board = find_board(ch); if (!board) { send_to_char("There is no bulletin board here to look at.\n\r", ch); return; } if (board->type != BOARD_NOTE) { send_to_char("You can only use note commands on a note board.\n\r", ch); return; } else { do_note(ch, arg_passed, FALSE); return; } } } void do_mailroom(CHAR_DATA * ch, char *argument) { BOARD_DATA *board; char arg[MSL]; char arg_passed[MSL]; strcpy(arg_passed, argument); switch (ch->substate) { case SUB_WRITING_NOTE: do_note(ch, arg_passed, TRUE); break; default: argument = one_argument(argument, arg); smash_tilde(argument); if (!str_cmp(arg, "write") || !str_cmp(arg, "to") || !str_cmp(arg, "subject") || !str_cmp(arg, "show")) { do_note(ch, arg_passed, TRUE); return; } board = find_board(ch); if (!board) { send_to_char("There is no mail facility here.\n\r", ch); return; } if (board->type != BOARD_MAIL) { send_to_char("You can only use mail commands in a post office.\n\r", ch); return; } else { do_note(ch, arg_passed, TRUE); return; } } } OBJ_DATA *find_inote(CHAR_DATA * ch) { OBJ_DATA *note; for (note = ch->first_carrying; note; note = note->next_content) { if (note->item_type == ITEM_PAPER) return note; } return NULL; } void do_note(CHAR_DATA * ch, char *arg_passed, bool IS_MAIL) { char buf[MSL]; char arg[MIL]; NOTE_DATA *pnote; BOARD_DATA *board; int vnum; int anum; int first_list; OBJ_DATA *quill = NULL, *paper = NULL; EXTRA_DESCR_DATA *ed = NULL; char notebuf[MSL]; char short_desc_buf[MSL]; char long_desc_buf[MSL]; char keyword_buf[MSL]; bool mfound = FALSE; if (IS_NPC(ch)) return; if (!ch->desc) { bug("do_note: no descriptor", 0); return; } switch (ch->substate) { default: break; case SUB_WRITING_NOTE: if ((paper = find_inote(ch)) == NULL || paper->item_type != ITEM_PAPER) { bug("do_note: player not holding paper", 0); stop_editing(ch); return; } ed = ch->dest_buf; STRFREE(ed->description); ed->description = copy_buffer(ch); stop_editing(ch); return; } set_char_color(AT_NOTE, ch); arg_passed = one_argument(arg_passed, arg); smash_tilde(arg_passed); /* Reusing alot of code but this will have to do till I can think * of a better way to do it. --Shaddai */ if (!str_cmp(arg, "date")) { board = find_board(ch); if (!board) { send_to_char("There is no board here to look at.\n\r", ch); return; } if (!can_read(ch, board)) { send_to_char("You cannot make any sense of the cryptic scrawl on this board...\n\r", ch); return; } first_list = atoi(arg_passed); if (first_list) { if (IS_MAIL) { send_to_char("You cannot use a list number (at this time) with mail.\n\r", ch); return; } if (first_list < 1) { send_to_char("You can't read a note before 1!\n\r", ch); return; } } if (!IS_MAIL) { set_pager_color(AT_NOTE, ch); vnum = 0; for (pnote = board->first_note; pnote; pnote = pnote->next) { vnum++; if ((first_list && vnum >= first_list) || !first_list) pager_printf(ch, "%2d%c %-12s%c %-24s : %-35s\n\r", vnum, is_note_to(ch, pnote) ? ')' : '}', pnote->sender, (pnote->voting != VOTE_NONE) ? (pnote->voting == VOTE_OPEN ? 'V' : 'C') : ':', pnote->date, pnote->subject); } act(AT_ACTION, "$n glances over the notes.", ch, NULL, NULL, TO_CANSEE); return; } else { vnum = 0; if (IS_MAIL) /* SB Mail check for Brit */ { for (pnote = board->first_note; pnote; pnote = pnote->next) if (is_note_to(ch, pnote)) mfound = TRUE; if (!mfound && get_trust(ch) < sysdata.read_all_mail) { ch_printf(ch, "You have no mail.\n\r"); return; } } for (pnote = board->first_note; pnote; pnote = pnote->next) if (is_note_to(ch, pnote) || get_trust(ch) >= sysdata.read_all_mail) ch_printf(ch, "%2d%c %-12s: %-13s : %s\n\r", ++vnum, is_note_to(ch, pnote) ? '-' : '}', pnote->sender, pnote->subject); return; } } if (!str_cmp(arg, "list")) { board = find_board(ch); if (!board) { send_to_char("There is no board here to look at.\n\r", ch); return; } if (!can_read(ch, board)) { send_to_char("You cannot make any sense of the cryptic scrawl on this board...\n\r", ch); return; } first_list = atoi(arg_passed); if (first_list) { if (IS_MAIL) { send_to_char("You cannot use a list number (at this time) with mail.\n\r", ch); return; } if (first_list < 1) { send_to_char("You can't read a note before 1!\n\r", ch); return; } } if (!IS_MAIL) { set_pager_color(AT_NOTE, ch); vnum = 0; for (pnote = board->first_note; pnote; pnote = pnote->next) { vnum++; if ((first_list && vnum >= first_list) || !first_list) pager_printf(ch, "%2d%c %-12s%c %-12.12s : %s\n\r", vnum, is_note_to(ch, pnote) ? ')' : '}', pnote->sender, (pnote->voting != VOTE_NONE) ? (pnote->voting == VOTE_OPEN ? 'V' : 'C') : ':', pnote->to_list, pnote->subject); } act(AT_ACTION, "$n glances over the notes.", ch, NULL, NULL, TO_CANSEE); return; } else { vnum = 0; if (IS_MAIL) /* SB Mail check for Brit */ { for (pnote = board->first_note; pnote; pnote = pnote->next) if (is_note_to(ch, pnote)) mfound = TRUE; if (!mfound && get_trust(ch) < sysdata.read_all_mail) { ch_printf(ch, "You have no mail.\n\r"); return; } } for (pnote = board->first_note; pnote; pnote = pnote->next) if (is_note_to(ch, pnote) || get_trust(ch) >= sysdata.read_all_mail) ch_printf(ch, "%2d%c %s: %s\n\r", ++vnum, is_note_to(ch, pnote) ? '-' : '}', pnote->sender, pnote->subject); return; } } if (!str_cmp(arg, "read")) { bool fAll; board = find_board(ch); if (!board) { send_to_char("There is no board here to look at.\n\r", ch); return; } if (!can_read(ch, board)) { send_to_char("You cannot make any sense of the cryptic scrawl on this board...\n\r", ch); return; } if (!str_cmp(arg_passed, "all")) { fAll = TRUE; anum = 0; } else if (is_number(arg_passed)) { fAll = FALSE; anum = atoi(arg_passed); } else { send_to_char("Note read which number?\n\r", ch); return; } set_pager_color(AT_NOTE, ch); if (!IS_MAIL) { vnum = 0; for (pnote = board->first_note; pnote; pnote = pnote->next) { vnum++; if (vnum == anum || fAll) { pager_printf(ch, "[%3d] %s: %s\n\r%s\n\rTo: %s\n\r%s", vnum, pnote->sender, pnote->subject, pnote->date, pnote->to_list, pnote->text); if (pnote->yesvotes[0] != '\0' || pnote->novotes[0] != '\0' || pnote->abstentions[0] != '\0') { send_to_pager("------------------------------------------------------------\n\r", ch); pager_printf(ch, "Votes:\n\rYes: %s\n\rNo: %s\n\rAbstain: %s\n\r", pnote->yesvotes, pnote->novotes, pnote->abstentions); } act(AT_ACTION, "$n reads a note.", ch, NULL, NULL, TO_CANSEE); return; } } send_to_char("No such note.\n\r", ch); return; } else { vnum = 0; for (pnote = board->first_note; pnote; pnote = pnote->next) { if (is_note_to(ch, pnote) || get_trust(ch) >= sysdata.read_all_mail) { vnum++; if (vnum == anum || fAll) { if (ch->gold < 10 && get_trust(ch) < sysdata.read_mail_free) { send_to_char("It costs 10 gold coins to read a message.\n\r", ch); return; } if (get_trust(ch) < sysdata.read_mail_free) ch->gold -= 10; pager_printf(ch, "[%3d] %s: %s\n\r%s\n\rTo: %s\n\r%s", vnum, pnote->sender, pnote->subject, pnote->date, pnote->to_list, pnote->text); return; } } } send_to_char("No such message.\n\r", ch); return; } } /* Voting added by Narn, June '96 */ if (!str_cmp(arg, "vote")) { char arg2[MIL]; arg_passed = one_argument(arg_passed, arg2); board = find_board(ch); if (!board) { send_to_char("There is no bulletin board here.\n\r", ch); return; } if (!can_read(ch, board)) { send_to_char("You cannot vote on this board.\n\r", ch); return; } if (is_number(arg2)) anum = atoi(arg2); else { send_to_char("Note vote which number?\n\r", ch); return; } vnum = 1; for (pnote = board->first_note; pnote && vnum < anum; pnote = pnote->next) vnum++; if (!pnote) { send_to_char("No such note.\n\r", ch); return; } /* Options: open close yes no abstain */ /* If you're the author of the note and can read the board you can open and close voting, if you can read it and voting is open you can vote. */ if (!str_cmp(arg_passed, "open")) { if (str_cmp(ch->name, pnote->sender)) { send_to_char("You are not the author of this note.\n\r", ch); return; } pnote->voting = VOTE_OPEN; act(AT_ACTION, "$n opens voting on a note.", ch, NULL, NULL, TO_ROOM); send_to_char("Voting opened.\n\r", ch); write_board(board); return; } if (!str_cmp(arg_passed, "close")) { if (str_cmp(ch->name, pnote->sender)) { send_to_char("You are not the author of this note.\n\r", ch); return; } pnote->voting = VOTE_CLOSED; act(AT_ACTION, "$n closes voting on a note.", ch, NULL, NULL, TO_ROOM); send_to_char("Voting closed.\n\r", ch); write_board(board); return; } /* Make sure the note is open for voting before going on. */ if (pnote->voting != VOTE_OPEN) { send_to_char("Voting is not open on this note.\n\r", ch); return; } /* Can only vote once on a note. */ sprintf(buf, "%s %s %s", pnote->yesvotes, pnote->novotes, pnote->abstentions); if (is_name(ch->name, buf)) { send_to_char("You have already voted on this note.\n\r", ch); return; } if (!str_cmp(arg_passed, "yes")) { sprintf(buf, "%s %s", pnote->yesvotes, ch->name); DISPOSE(pnote->yesvotes); pnote->yesvotes = str_dup(buf); act(AT_ACTION, "$n votes on a note.", ch, NULL, NULL, TO_ROOM); send_to_char("Ok.\n\r", ch); write_board(board); return; } if (!str_cmp(arg_passed, "no")) { sprintf(buf, "%s %s", pnote->novotes, ch->name); DISPOSE(pnote->novotes); pnote->novotes = str_dup(buf); act(AT_ACTION, "$n votes on a note.", ch, NULL, NULL, TO_ROOM); send_to_char("Ok.\n\r", ch); write_board(board); return; } if (!str_cmp(arg_passed, "abstain")) { sprintf(buf, "%s %s", pnote->abstentions, ch->name); DISPOSE(pnote->abstentions); pnote->abstentions = str_dup(buf); act(AT_ACTION, "$n votes on a note.", ch, NULL, NULL, TO_ROOM); send_to_char("Ok.\n\r", ch); write_board(board); return; } do_note(ch, "", FALSE); } if (!str_cmp(arg, "write")) { if (ch->substate == SUB_RESTRICTED) { send_to_char("You cannot write a note from within another command.\n\r", ch); return; } if (get_trust(ch) < sysdata.write_mail_free) { quill = find_quill(ch); if (!quill) { send_to_char("You need a quill to write a note.\n\r", ch); return; } if (quill->value[0] < 1) { send_to_char("Your quill is dry.\n\r", ch); return; } } if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER) { if (get_trust(ch) < sysdata.write_mail_free) { send_to_char("You need to be holding a fresh piece of parchment to write a note.\n\r", ch); return; } paper = create_object(get_obj_index(OBJ_VNUM_NOTE), 0); paper = obj_to_char(paper, ch); act(AT_MAGIC, "A piece of parchment magically appears in $n's hands!", ch, NULL, NULL, TO_ROOM); act(AT_MAGIC, "A piece of parchment appears in your hands.", ch, NULL, NULL, TO_CHAR); } if (paper->value[0] < 2) { paper->value[0] = 1; ed = SetOExtra(paper, "_text_"); ch->substate = SUB_WRITING_NOTE; ch->dest_buf = ed; if (get_trust(ch) < sysdata.write_mail_free) --quill->value[0]; start_editing(ch, ed->description); { char *subject, *to_list; if ((subject = get_extra_descr("_subject_", paper->first_extradesc)) == NULL) subject = "(no subject)"; if ((to_list = get_extra_descr("_to_", paper->first_extradesc)) == NULL) to_list = "(nobody)"; editor_desc_printf(ch, "Note entitled '%s', addressed to %s.", subject, to_list); } return; } else { send_to_char("You cannot modify this note.\n\r", ch); return; } } if (!str_cmp(arg, "subject")) { if (get_trust(ch) < sysdata.write_mail_free) { quill = find_quill(ch); if (!quill) { send_to_char("You need a quill to write a note.\n\r", ch); return; } if (quill->value[0] < 1) { send_to_char("Your quill is dry.\n\r", ch); return; } } if (!arg_passed || arg_passed[0] == '\0') { send_to_char("What do you wish the subject to be?\n\r", ch); return; } if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER) { if (get_trust(ch) < sysdata.write_mail_free) { send_to_char("You need to be holding a fresh piece of parchment to write a note.\n\r", ch); return; } paper = create_object(get_obj_index(OBJ_VNUM_NOTE), 0); paper = obj_to_char(paper, ch); act(AT_MAGIC, "A piece of parchment magically appears in $n's hands!", ch, NULL, NULL, TO_ROOM); act(AT_MAGIC, "A piece of parchment appears in your hands.", ch, NULL, NULL, TO_CHAR); } if (paper->value[1] > 1) { send_to_char("You cannot modify this note.\n\r", ch); return; } else { paper->value[1] = 1; ed = SetOExtra(paper, "_subject_"); STRFREE(ed->description); ed->description = STRALLOC(arg_passed); send_to_char("Ok.\n\r", ch); return; } } if (!str_cmp(arg, "to")) { struct stat fst; /* char *pn;*/ char fname[1024]; bool imc = FALSE; if (get_trust(ch) < sysdata.write_mail_free) { quill = find_quill(ch); if (!quill) { send_to_char("You need a quill to write a note.\n\r", ch); return; } if (quill->value[0] < 1) { send_to_char("Your quill is dry.\n\r", ch); return; } } if (!arg_passed || arg_passed[0] == '\0') { send_to_char("Please specify an addressee.\n\r", ch); return; } if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER) { if (get_trust(ch) < sysdata.write_mail_free) { send_to_char("You need to be holding a fresh piece of parchment to write a note.\n\r", ch); return; } paper = create_object(get_obj_index(OBJ_VNUM_NOTE), 0); paper = obj_to_char(paper, ch); act(AT_MAGIC, "A piece of parchment magically appears in $n's hands!", ch, NULL, NULL, TO_ROOM); act(AT_MAGIC, "A piece of parchment appears in your hands.", ch, NULL, NULL, TO_CHAR); } if (paper->value[2] > 1) { send_to_char("You cannot modify this note.\n\r", ch); return; } arg_passed[0] = UPPER(arg_passed[0]); /* if ((pn = strchr(arg_passed, '@'))!=NULL)*/ if (strchr(arg_passed, '@') != NULL) { if (get_trust(ch) < sysdata.imc_mail_level) { ch_printf(ch, "You need to be at least level %d to send " "notes to other muds.\n\r", sysdata.imc_mail_level); return; } /* *pn = '\0'; if (is_name("all", arg_passed)) { ch_printf(ch, "You cannot send IMC mail to ALL.\n\r"); return; } *pn = '@';*/ imc = TRUE; } sprintf(fname, "%s%c/%s", PLAYER_DIR, tolower(arg_passed[0]), capitalize(arg_passed)); if (!IS_MAIL || imc || stat(fname, &fst) != -1 || !str_cmp(arg_passed, "all")) { paper->value[2] = 1; ed = SetOExtra(paper, "_to_"); STRFREE(ed->description); ed->description = STRALLOC(arg_passed); send_to_char("Ok.\n\r", ch); return; } else { send_to_char("No player exists by that name.\n\r", ch); return; } } if (!str_cmp(arg, "show")) { char *subject, *to_list, *text; if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER) { send_to_char("You are not holding a note.\n\r", ch); return; } if ((subject = get_extra_descr("_subject_", paper->first_extradesc)) == NULL) subject = "(no subject)"; if ((to_list = get_extra_descr("_to_", paper->first_extradesc)) == NULL) to_list = "(nobody)"; sprintf(buf, "%s: %s\n\rTo: %s\n\r", ch->name, subject, to_list); send_to_char(buf, ch); if ((text = get_extra_descr("_text_", paper->first_extradesc)) == NULL) text = "The note is blank.\n\r"; send_to_char(text, ch); return; } if (!str_cmp(arg, "post")) { char *strtime, *to, *subj, *text /*, *np = NULL */ ; bool imc = FALSE; if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER) { send_to_char("You are not holding a note.\n\r", ch); return; } if (paper->value[0] == 0) { send_to_char("There is nothing written on this note.\n\r", ch); return; } if (paper->value[1] == 0) { send_to_char("This note has no subject.\n\r", ch); return; } if (paper->value[2] == 0) { send_to_char("This note is addressed to no one!\n\r", ch); return; } strtime = ctime(¤t_time); strtime[strlen(strtime) - 1] = '\0'; /* handle IMC notes */ to = get_extra_descr("_to_", paper->first_extradesc); subj = get_extra_descr("_subject_", paper->first_extradesc); text = get_extra_descr("_text_", paper->first_extradesc); /* if (to && (np = strchr(to, '@'))!=NULL)*/ if (to && strchr(to, '@') != NULL) { if (!subj || !*subj) { send_to_char("You must specify a subject for IMC mail.\n\r", ch); return; } if (!text || !*text) { send_to_char("You must have text in IMC mail.\n\r", ch); return; } /* { send_to_char( "The IMC board is not here.\n\r", ch ); return; }*/ imc = TRUE; } board = find_board(ch); if (!board) { send_to_char("There is no bulletin board here to post your note on.\n\r", ch); return; } if ((imc && board->board_obj != sysdata.imc_mail_vnum) || (!imc && board->board_obj == sysdata.imc_mail_vnum)) { send_to_char("You can only post IMC mail on the IMC board.\n\r", ch); return; } /* if (imc) { if (np) *np = '\0'; if (is_name("all", to)) { send_to_char( "You may not post notes to ALL on the IMC board.\n\r", ch); return; } if (np) *np = '@'; }*/ if (!can_post(ch, board)) { send_to_char("A magical force prevents you from posting your note here...\n\r", ch); return; } if (board->num_posts >= board->max_posts) { send_to_char("There is no room on this board to post your note.\n\r", ch); return; } act(AT_ACTION, "$n posts a note.", ch, NULL, NULL, TO_ROOM); CREATE(pnote, NOTE_DATA, 1); pnote->date = STRALLOC(strtime); pnote->to_list = to ? STRALLOC(to) : STRALLOC("all"); pnote->text = text ? STRALLOC(text) : STRALLOC(""); pnote->subject = subj ? STRALLOC(subj) : STRALLOC(""); pnote->sender = QUICKLINK(ch->name); pnote->voting = 0; pnote->yesvotes = str_dup(""); pnote->novotes = str_dup(""); pnote->abstentions = str_dup(""); LINK(pnote, board->first_note, board->last_note, next, prev); board->num_posts++; write_board(board); send_to_char("You post your note on the board.\n\r", ch); extract_obj(paper); return; } if (!str_cmp(arg, "remove") || !str_cmp(arg, "take") || !str_cmp(arg, "copy")) { char take; board = find_board(ch); if (!board) { send_to_char("There is no board here to take a note from!\n\r", ch); return; } if (!str_cmp(arg, "take")) take = 1; else if (!str_cmp(arg, "copy")) { if (!IS_IMMORTAL(ch)) { send_to_char("Huh? Type 'help note' for usage.\n\r", ch); return; } take = 2; } else take = 0; if (!is_number(arg_passed)) { send_to_char("Note remove which nunumber?\n\r", ch); return; } if (!can_read(ch, board)) { send_to_char("You can't make anyense of what's posted here, let alone remove anything!\n\r", ch); return; } anum = atoi(arg_passed); vnum = 0; for (pnote = board->first_note; pnote; pnote = pnote->next) { if (IS_MAIL && ((is_note_to(ch, pnote)) || get_trust(ch) >= sysdata.take_others_mail)) vnum++; else if (!IS_MAIL) vnum++; if ((is_note_to(ch, pnote) || can_remove(ch, board)) && (vnum == anum)) { if ((is_name("all", pnote->to_list)) && (get_trust(ch) < sysdata.take_others_mail) && (take == 1)) { send_to_char("Notes addressed to 'all' can not be taken.\n\r", ch); return; } if (take != 0) { if (ch->gold < 50 && get_trust(ch) < sysdata.read_mail_free) { if (take == 1) send_to_char("It costs 50 coins to take your mail.\n\r", ch); else send_to_char("It costs 50 coins to copy your mail.\n\r", ch); return; } if (get_trust(ch) < sysdata.read_mail_free) ch->gold -= 50; paper = create_object(get_obj_index(OBJ_VNUM_NOTE), 0); ed = SetOExtra(paper, "_sender_"); STRFREE(ed->description); ed->description = QUICKLINK(pnote->sender); ed = SetOExtra(paper, "_text_"); STRFREE(ed->description); ed->description = QUICKLINK(pnote->text); ed = SetOExtra(paper, "_to_"); STRFREE(ed->description); ed->description = QUICKLINK(pnote->to_list); ed = SetOExtra(paper, "_subject_"); STRFREE(ed->description); ed->description = QUICKLINK(pnote->subject); ed = SetOExtra(paper, "_date_"); STRFREE(ed->description); ed->description = QUICKLINK(pnote->date); ed = SetOExtra(paper, "note"); STRFREE(ed->description); sprintf(notebuf, "From: "); strcat(notebuf, pnote->sender); strcat(notebuf, "\n\rTo: "); strcat(notebuf, pnote->to_list); strcat(notebuf, "\n\rSubject: "); strcat(notebuf, pnote->subject); strcat(notebuf, "\n\r\n\r"); strcat(notebuf, pnote->text); strcat(notebuf, "\n\r"); ed->description = STRALLOC(notebuf); paper->value[0] = 2; paper->value[1] = 2; paper->value[2] = 2; sprintf(short_desc_buf, "a note from %s to %s", pnote->sender, pnote->to_list); STRFREE(paper->short_descr); paper->short_descr = STRALLOC(short_desc_buf); sprintf(long_desc_buf, "A note from %s to %s lies on the ground.", pnote->sender, pnote->to_list); STRFREE(paper->description); paper->description = STRALLOC(long_desc_buf); sprintf(keyword_buf, "note parchment paper %s", pnote->to_list); STRFREE(paper->name); paper->name = STRALLOC(keyword_buf); } if (take != 2) note_remove(ch, board, pnote); send_to_char("Ok.\n\r", ch); if (take == 1) { act(AT_ACTION, "$n takes a note.", ch, NULL, NULL, TO_ROOM); obj_to_char(paper, ch); } else if (take == 2) { act(AT_ACTION, "$n copies a note.", ch, NULL, NULL, TO_ROOM); obj_to_char(paper, ch); } else act(AT_ACTION, "$n removes a note.", ch, NULL, NULL, TO_ROOM); return; } } send_to_char("No such note.\n\r", ch); return; } send_to_char("Huh? Type 'help note' for usage.\n\r", ch); return; } BOARD_DATA *read_board(char *boardfile, FILE * fp) { BOARD_DATA *board; char *word; char buf[MSL]; bool fMatch; char letter; do { letter = getc(fp); if (feof(fp)) { fclose(fp); return NULL; } } while (isspace(letter)); ungetc(letter, fp); CREATE(board, BOARD_DATA, 1); #ifdef KEY #undef KEY #endif #define KEY( literal, field, value ) \ if ( !str_cmp( word, literal ) ) \ { \ field = value; \ fMatch = TRUE; \ break; \ } for (;;) { word = feof(fp) ? "End" : fread_word(fp); fMatch = FALSE; switch (UPPER(word[0])) { case '*': fMatch = TRUE; fread_to_eol(fp); break; case 'E': KEY("Extra_readers", board->extra_readers, fread_string_nohash(fp)); KEY("Extra_removers", board->extra_removers, fread_string_nohash(fp)); if (!str_cmp(word, "End")) { board->num_posts = 0; board->first_note = NULL; board->last_note = NULL; board->next = NULL; board->prev = NULL; if (!board->read_group) board->read_group = str_dup(""); if (!board->post_group) board->post_group = str_dup(""); if (!board->extra_readers) board->extra_readers = str_dup(""); if (!board->extra_removers) board->extra_removers = str_dup(""); return board; } case 'F': KEY("Filename", board->note_file, fread_string_nohash(fp)); case 'M': KEY("Min_read_level", board->min_read_level, fread_number(fp)); KEY("Min_post_level", board->min_post_level, fread_number(fp)); KEY("Min_remove_level", board->min_remove_level, fread_number(fp)); KEY("Max_posts", board->max_posts, fread_number(fp)); case 'P': KEY("Post_group", board->post_group, fread_string_nohash(fp)); case 'R': KEY("Read_group", board->read_group, fread_string_nohash(fp)); case 'T': KEY("Type", board->type, fread_number(fp)); case 'V': KEY("Vnum", board->board_obj, fread_number(fp)); } if (!fMatch) { sprintf(buf, "read_board: no match: %s", word); bug(buf, 0); } } return board; } NOTE_DATA *read_note(char *notefile, FILE * fp) { NOTE_DATA *pnote; char *word; for (;;) { char letter; do { letter = getc(fp); if (feof(fp)) { fclose(fp); return NULL; } } while (isspace(letter)); ungetc(letter, fp); CREATE(pnote, NOTE_DATA, 1); if (str_cmp(fread_word(fp), "sender")) break; pnote->sender = fread_string(fp); if (str_cmp(fread_word(fp), "date")) break; pnote->date = fread_string(fp); if (str_cmp(fread_word(fp), "to")) break; pnote->to_list = fread_string(fp); if (str_cmp(fread_word(fp), "subject")) break; pnote->subject = fread_string(fp); word = fread_word(fp); if (!str_cmp(word, "voting")) { pnote->voting = fread_number(fp); if (str_cmp(fread_word(fp), "yesvotes")) break; pnote->yesvotes = fread_string_nohash(fp); if (str_cmp(fread_word(fp), "novotes")) break; pnote->novotes = fread_string_nohash(fp); if (str_cmp(fread_word(fp), "abstentions")) break; pnote->abstentions = fread_string_nohash(fp); word = fread_word(fp); } if (str_cmp(word, "text")) break; pnote->text = fread_string(fp); if (!pnote->yesvotes) pnote->yesvotes = str_dup(""); if (!pnote->novotes) pnote->novotes = str_dup(""); if (!pnote->abstentions) pnote->abstentions = str_dup(""); pnote->next = NULL; pnote->prev = NULL; return pnote; } bug("read_note: bad key word."); exit(1); } /* * Load boards file. */ void load_boards(void) { FILE *board_fp; FILE *note_fp; BOARD_DATA *board; NOTE_DATA *pnote; char boardfile[256]; char notefile[256]; first_board = NULL; last_board = NULL; sprintf(boardfile, "%s%s", BOARD_DIR, BOARD_FILE); if ((board_fp = fopen(boardfile, "r")) == NULL) return; while ((board = read_board(boardfile, board_fp)) != NULL) { LINK(board, first_board, last_board, next, prev); sprintf(notefile, "%s%s", BOARD_DIR, board->note_file); log_string(notefile); if ((note_fp = fopen(notefile, "r")) != NULL) { while ((pnote = read_note(notefile, note_fp)) != NULL) { LINK(pnote, board->first_note, board->last_note, next, prev); board->num_posts++; } } } return; } void do_makeboard(CHAR_DATA * ch, char *argument) { BOARD_DATA *board; if (!argument || argument[0] == '\0') { send_to_char("Usage: makeboard <filename>\n\r", ch); return; } smash_tilde(argument); CREATE(board, BOARD_DATA, 1); LINK(board, first_board, last_board, next, prev); board->note_file = str_dup(strlower(argument)); board->read_group = str_dup(""); board->post_group = str_dup(""); board->extra_readers = str_dup(""); board->extra_removers = str_dup(""); } void do_bset(CHAR_DATA * ch, char *argument) { BOARD_DATA *board; bool found; char arg1[MIL]; char arg2[MIL]; char buf[MSL]; int value; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); set_char_color(AT_NOTE, ch); if (arg1[0] == '\0' || arg2[0] == '\0') { send_to_char("Usage: bset <board filename> <field> value\n\r", ch); send_to_char("\n\rField being one of:\n\r", ch); send_to_char(" ovnum read post remove maxpost filename type\n\r", ch); send_to_char(" read_group post_group extra_readers extra_removers\n\r", ch); return; } value = atoi(argument); found = FALSE; for (board = first_board; board; board = board->next) if (!str_cmp(arg1, board->note_file)) { found = TRUE; break; } if (!found) { send_to_char("Board not found.\n\r", ch); return; } if (!str_cmp(arg2, "ovnum")) { if (!get_obj_index(value)) { send_to_char("No such object.\n\r", ch); return; } board->board_obj = value; write_boards_txt(); send_to_char("Done. (board's object vnum set)\n\r", ch); return; } if (!str_cmp(arg2, "read")) { if (value < 0 || value > MAX_LEVEL) { send_to_char("Value outside valid character level range.\n\r", ch); return; } board->min_read_level = value; write_boards_txt(); send_to_char("Done. (minimum reading level set)\n\r", ch); return; } if (!str_cmp(arg2, "read_group")) { if (!argument || argument[0] == '\0') { send_to_char("No reading group specified.\n\r", ch); return; } DISPOSE(board->read_group); if (!str_cmp(argument, "none")) board->read_group = str_dup(""); else board->read_group = str_dup(argument); write_boards_txt(); send_to_char("Done. (reading group set)\n\r", ch); return; } if (!str_cmp(arg2, "post_group")) { if (!argument || argument[0] == '\0') { send_to_char("No posting group specified.\n\r", ch); return; } DISPOSE(board->post_group); if (!str_cmp(argument, "none")) board->post_group = str_dup(""); else board->post_group = str_dup(argument); write_boards_txt(); send_to_char("Done. (posting group set)\n\r", ch); return; } if (!str_cmp(arg2, "extra_removers")) { if (!argument || argument[0] == '\0') { send_to_char("No names specified.\n\r", ch); return; } if (!str_cmp(argument, "none")) buf[0] = '\0'; else sprintf(buf, "%s %s", board->extra_removers, argument); DISPOSE(board->extra_removers); board->extra_removers = str_dup(buf); write_boards_txt(); send_to_char("Done. (extra removers set)\n\r", ch); return; } if (!str_cmp(arg2, "extra_readers")) { if (!argument || argument[0] == '\0') { send_to_char("No names specified.\n\r", ch); return; } if (!str_cmp(argument, "none")) buf[0] = '\0'; else sprintf(buf, "%s %s", board->extra_readers, argument); DISPOSE(board->extra_readers); board->extra_readers = str_dup(buf); write_boards_txt(); send_to_char("Done. (extra readers set)\n\r", ch); return; } if (!str_cmp(arg2, "filename")) { if (!argument || argument[0] == '\0') { send_to_char("No filename specified.\n\r", ch); return; } DISPOSE(board->note_file); board->note_file = str_dup(argument); write_boards_txt(); send_to_char("Done. (board's filename set)\n\r", ch); return; } if (!str_cmp(arg2, "post")) { if (value < 0 || value > MAX_LEVEL) { send_to_char("Value outside valid character level range.\n\r", ch); return; } board->min_post_level = value; write_boards_txt(); send_to_char("Done. (minimum posting level set)\n\r", ch); return; } if (!str_cmp(arg2, "remove")) { if (value < 0 || value > MAX_LEVEL) { send_to_char("Value outside valid character level range.\n\r", ch); return; } board->min_remove_level = value; write_boards_txt(); send_to_char("Done. (minimum remove level set)\n\r", ch); return; } if (!str_cmp(arg2, "maxpost")) { if (value < 1 || value > 999) { send_to_char("Value out of range.\n\r", ch); return; } board->max_posts = value; write_boards_txt(); send_to_char("Done. (maximum number of posts set)\n\r", ch); return; } if (!str_cmp(arg2, "type")) { if (value < 0 || value > 1) { send_to_char("Value out of range.\n\r", ch); return; } board->type = value; write_boards_txt(); send_to_char("Done. (board's type set)\n\r", ch); return; } do_bset(ch, ""); return; } void do_bstat(CHAR_DATA * ch, char *argument) { BOARD_DATA *board; bool found; char arg[MIL]; argument = one_argument(argument, arg); found = FALSE; for (board = first_board; board; board = board->next) if (!str_cmp(arg, board->note_file)) { found = TRUE; break; } if (!found) { if (argument && argument[0] != '\0') { send_to_char_color("&GBoard not found. Usage: bstat <board filename>\n\r", ch); return; } else { board = find_board(ch); if (!board) { send_to_char_color("&GNo board present. Usage: bstat <board filename>\n\r", ch); return; } } } ch_printf_color(ch, "\n\r&GFilename: &W%-15.15s &GOVnum: &W%-5d &GRead: &W%-2d &GPost: &W%-2d &GRemove: &W%-2d\n\r&GMaxpost: &W%-3d >ype: &W%d\n\r&GPosts: %d\n\r", board->note_file, board->board_obj, board->min_read_level, board->min_post_level, board->min_remove_level, board->max_posts, board->type, board->num_posts); ch_printf_color(ch, "&GRead_group: &W%s\n\r&GPost_group: &W%s\n\r&GExtra_readers: &W%s\n\r&GExtra_removers: &W%s\n\r", board->read_group, board->post_group, board->extra_readers, board->extra_removers); return; } void do_boards(CHAR_DATA * ch, char *argument) { BOARD_DATA *board; if (!first_board) { send_to_char_color("T&Ghere are no boards yet.\n\r", ch); return; } for (board = first_board; board; board = board->next) pager_printf_color(ch, "&G%-15.15s #: %5d Read: %2d Post: %2d Rmv: %2d Max: %3d Posts: &g%3d >ype: %d\n\r", board->note_file, board->board_obj, board->min_read_level, board->min_post_level, board->min_remove_level, board->max_posts, board->num_posts, board->type); } void mail_count(CHAR_DATA * ch) { BOARD_DATA *board; NOTE_DATA *note; int cnt = 0; for (board = first_board; board; board = board->next) if (board->type == BOARD_MAIL && can_read(ch, board)) for (note = board->first_note; note; note = note->next) if (is_note_to(ch, note)) ++cnt; if (cnt) ch_printf(ch, "You have %d mail message%swaiting.\n\r", cnt, (cnt > 1) ? "s " : " "); return; }