ssss/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | * * -----------------------------------------------------------| \\._.// * * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version) | (0...0) * * -----------------------------------------------------------| ).:.( * * SMAUG (C) 1994, 1995, 1996 by Derek Snider | {o o} * * -----------------------------------------------------------| / ' ' \ * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, |~'~.VxvxV.~'~* * Scryn, Swordbearer, Rennard, Tricops, and Gorog. | * * ------------------------------------------------------------------------ * * 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 Staerfeldt, Tom Madsen, and Katja Nyboe. * ****************************************************************************/ #include "stdafx.h" #include "smaug.h" #include "Smaugx.h" #include "SysData.h" #include "objects.h" #include "rooms.h" #include "boards.h" #include "SmaugWizDoc.h" #include "SmaugFiles.h" #include "descriptor.h" #include "character.h" /* Defines for voting on notes. -- Narn */ #define VOTE_NONE 0 #define VOTE_OPEN 1 #define VOTE_CLOSED 2 BOOL is_note_to (CCharacter *ch, CNoteData *pnote); void note_attach (CCharacter *ch); void do_note (CCharacter *ch, char *arg_passed, BOOL IS_MAIL); CNoteData *read_note (const char *notefile, FILE *fp); CBoardData::~CBoardData () { delete note_file; delete read_group; delete post_group; delete extra_readers; delete extra_removers; while (! m_NList.IsEmpty ()) { delete (CNoteData*) m_NList.RemoveTail (); } m_NList.RemoveAll (); } void CBoardList::RemoveAll () { while (!IsEmpty ()) { delete (CBoardData*) RemoveTail (); } CPtrList::RemoveAll (); } BOOL can_remove (CCharacter *ch, CBoardData *board) { /* If your trust is high enough, you can remove it. */ if (ch->GetTrustLevel () >= board->min_remove_level) return TRUE; if (board->extra_removers[0] != '\0') { if (is_name (ch->GetName (), board->extra_removers)) return TRUE; } return FALSE; } BOOL can_read (CCharacter *ch, CBoardData *board) { /* If your trust is high enough, you can read it. */ if (ch->GetTrustLevel () >= 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->GetPcData ()->GetClan () && !str_cmp (ch->GetPcData ()->GetClan ()->GetName (), board->read_group)) return TRUE; if (ch->GetPcData ()->council && !str_cmp (ch->GetPcData ()->council->name, board->read_group)) return TRUE; } if (board->extra_readers[0] != '\0') { if (is_name (ch->GetName (), board->extra_readers)) return TRUE; } return FALSE; } BOOL can_post (CCharacter *ch, CBoardData *board) { /* If your trust is high enough, you can post. */ if (ch->GetTrustLevel () >= 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->GetPcData ()->GetClan () && !str_cmp (ch->GetPcData ()->GetClan ()->GetName (), board->post_group)) return TRUE; if (ch->GetPcData ()->council && !str_cmp (ch->GetPcData ()->council->name, board->post_group)) return TRUE; } return FALSE; } // board commands. void CBoardList::WriteBoardsFile () { FILE *fp; fp = fopen (FileTable.GetName (SM_BOARD_FILE), "w"); if (! fp) { bug ("FATAL: cannot open board.txt for writing!\n\r"); return; } POSITION pos = GetHeadPosition (); while (pos) { CBoardData &Bd = *(CBoardData*) GetNext (pos); fprintf (fp, "Filename %s~\n", Bd.note_file); fprintf (fp, "Vnum %d\n", Bd.board_obj); fprintf (fp, "Min_read_level %d\n", Bd.min_read_level); fprintf (fp, "Min_post_level %d\n", Bd.min_post_level); fprintf (fp, "Min_remove_level %d\n", Bd.min_remove_level); fprintf (fp, "Max_posts %d\n", Bd.max_posts); fprintf (fp, "Type %d\n", Bd.type); fprintf (fp, "Read_group %s~\n", Bd.read_group); fprintf (fp, "Post_group %s~\n", Bd.post_group); fprintf (fp, "Extra_readers %s~\n", Bd.extra_readers); fprintf (fp, "Extra_removers %s~\n", Bd.extra_removers); fprintf (fp, "End\n"); } fclose (fp); } CBoardData *CBoardList::GetBoard (CObjData *obj) { CBoardData *board; POSITION pos = GetHeadPosition (); while (pos) { board = (CBoardData*) GetNext (pos); if (board->board_obj == obj->pIndexData->vnum) return board; } return NULL; } CBoardData *find_board (CCharacter *ch) { CObjData *obj; CBoardData *board; POSITION pos = ch->GetInRoom ()->GetHeadContentPos (); while (obj = ch->GetInRoom ()->GetNextContent (pos)) { if ((board = BoardList.GetBoard (obj)) != NULL) return board; } return NULL; } BOOL is_note_to (CCharacter *ch, CNoteData *pnote) { if (!str_cmp (ch->GetName (), pnote->sender)) return TRUE; if (is_name ("all", pnote->to_list)) return TRUE; if (ch->IsHero () && is_name ("immortal", pnote->to_list)) return TRUE; if (is_name (ch->GetName (), pnote->to_list)) return TRUE; return FALSE; } void note_attach (CCharacter *ch) { CNoteData *pnote; if (ch->GetNotes ()) return; pnote = new CNoteData; pnote->SetNext (NULL); pnote->SetPrev (NULL); pnote->sender = QUICKLINK (ch->GetName ()); pnote->date = STRALLOC (""); pnote->to_list = STRALLOC (""); pnote->subject = STRALLOC (""); pnote->text = STRALLOC (""); ch->SetNotes (pnote); } void CBoardData::WriteAllNotes () { FILE *fp; // Rewrite entire note list. fclose (fpReserve); CString nfn = FileTable.MakeName (SD_BOARD_DIR, note_file); if ((fp = fopen (nfn, "w")) == NULL) { perror (nfn); } else { POSITION pos = m_NList.GetHeadPosition (); while (pos) { CNoteData &Nd = *(CNoteData*) m_NList.GetNext (pos); fprintf (fp, "Sender %s~\nDate %s~\nTo %s~\nSubject " "%s~\nVoting %d\nYesvotes %s~\nNovotes %s~\nAbstentions " "%s~\nText\n%s~\n\n", Nd.sender, Nd.date, Nd.to_list, Nd.subject, Nd.voting, Nd.yesvotes, Nd.novotes, Nd.abstentions, strip_cr (Nd.text)); } fclose (fp); } fpReserve = fopen (FileTable.GetName (SM_NULL_FILE), "r"); } void CBoardData::RemoveNote (CNoteData *pnote) { ASSERT (this); POSITION pos = m_NList.Find (pnote); if (! pos) { bug ("CBoardData::RemoveNote: pnote not in list"); return; } m_NList.RemoveAt (pos); // Remove note from linked list. // for now STRFREE's are not done in destructors... STRFREE (pnote->text); STRFREE (pnote->subject); STRFREE (pnote->to_list); STRFREE (pnote->date); STRFREE (pnote->sender); delete pnote; --num_posts; WriteAllNotes (); // update the note file } CObjData *find_quill (CCharacter *ch) { CObjData *quill; POSITION pos = ch->GetHeadCarryPos (); while (quill = ch->GetNextCarrying (pos)) if (quill->item_type == ITEM_PEN && can_see_obj (ch, *quill)) return quill; return NULL; } void do_noteroom (CCharacter *ch, char *argument) { CBoardData *board; char arg[MAX_STRING_LENGTH]; char arg_passed[MAX_STRING_LENGTH]; strcpy (arg_passed, argument); switch (ch->GetSubstate ()) { 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) { ch->SendText ("There is no bulletin board here to look at.\n\r"); return; } if (board->type != BOARD_NOTE) { ch->SendText ("You can only use note commands on a note board.\n\r"); return; } else { do_note (ch, arg_passed, FALSE); return; } } } void do_mailroom (CCharacter *ch, char *argument) { CBoardData *board; char arg[MAX_STRING_LENGTH]; char arg_passed[MAX_STRING_LENGTH]; strcpy (arg_passed, argument); switch (ch->GetSubstate ()) { 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) { ch->SendText ("There is no mail facility here.\n\r"); return; } if (board->type != BOARD_MAIL) { ch->SendText ("You can only use mail commands in a post office.\n\r"); return; } else { do_note (ch, arg_passed, TRUE); return; } } } void do_note (CCharacter *ch, char *arg_passed, BOOL IS_MAIL) { char buf [MAX_STRING_LENGTH]; char arg [MAX_INPUT_LENGTH]; CNoteData *pnote; CBoardData *board; int vnum; int anum; int first_list; CObjData *quill, *paper, *tmpobj = NULL; char notebuf[MAX_STRING_LENGTH]; char short_desc_buf[MAX_STRING_LENGTH]; char long_desc_buf[MAX_STRING_LENGTH]; char keyword_buf[MAX_STRING_LENGTH]; BOOL mfound = FALSE; CExtraDescrData *ed = NULL; if (ch->IsNpc ()) return; if (!ch->GetDesc ()) { bug ("do_note: no descriptor", 0); return; } switch (ch->GetSubstate ()) { default: break; case SUB_WRITING_NOTE: if ((paper = get_eq_char (ch, WEAR_HOLD)) == NULL || paper->item_type != ITEM_PAPER) { bug ("do_note: player not holding paper"); ch->StopEditing (); return; } ed = (CExtraDescrData*) ch->dest_buf; STRFREE (ed->description); ed->description = ch->GetEditBuffer (); ch->StopEditing (); return; break; } set_char_color (AT_NOTE, ch); arg_passed = one_argument (arg_passed, arg); smash_tilde (arg_passed); if (!str_cmp (arg, "list")) { board = find_board (ch); if (!board) { ch->SendText ("There is no board here to look at.\n\r"); return; } if (! can_read (ch, board)) { ch->SendText ("You cannot make any sense of the cryptic " "scrawl on this board...\n\r"); return; } first_list = atoi (arg_passed); if (first_list) { if (IS_MAIL) { ch->SendText ("You cannot use a list number (at this time) " "with mail.\n\r"); return; } if (first_list < 1) { ch->SendText ("You can't read a note before 1!\n\r"); return; } } if (!IS_MAIL) { int nNote = 0; set_pager_color (AT_NOTE, ch); POSITION pos = board->GetFirstNotePosition (); while (pos) { CNoteData &Nd = *board->GetNextNote (pos); ++nNote; if ((first_list && nNote >= first_list) || !first_list) pager_printf (ch, "%2d%c %-12s%c %-12s %s\n\r", nNote, is_note_to (ch, &Nd) ? ')' : '}', Nd.sender, (Nd.voting != VOTE_NONE) ? (Nd.voting == VOTE_OPEN ? 'V' : 'C') : ':', Nd.to_list, Nd.subject); } act (AT_ACTION, "$n glances over the notes.", ch, NULL, NULL, TO_ROOM); return; } else { if (IS_MAIL) { // SB Mail check for Brit POSITION pos = board->GetFirstNotePosition (); while (pos) { pnote = board->GetNextNote (pos); if (is_note_to (ch, pnote)) { mfound = TRUE; break; } } if (!mfound && ch->GetTrustLevel() < SysData.ReadAllMailLev) { ch->SendTextf ("You have no mail.\n\r"); return; } } POSITION pos = board->GetFirstNotePosition (); int nNote = 0; while (pos) { pnote = board->GetNextNote (pos); if (is_note_to (ch, pnote) || ch->GetTrustLevel () > SysData.ReadAllMailLev) ch->SendTextf ("%2d%c %s: %s\n\r", ++nNote, is_note_to (ch, pnote) ? '-' : '}', pnote->sender, pnote->subject); } return; } } if (!str_cmp (arg, "read")) { BOOL fAll; board = find_board (ch); if (!board) { ch->SendText ("There is no board here to look at.\n\r"); return; } if (!can_read (ch, board)) { ch->SendText ("You cannot make any sense of the cryptic scrawl " "on this board...\n\r"); return; } if (!str_cmp (arg_passed, "all")) { fAll = TRUE; anum = 0; } else if (is_number (arg_passed)) { fAll = FALSE; anum = atoi (arg_passed); } else { ch->SendText ("Note read which number?\n\r"); return; } set_pager_color (AT_NOTE, ch); if (!IS_MAIL) { POSITION pos = board->GetFirstNotePosition (); int nNote = 0; while (pos) { pnote = board->GetNextNote (pos); ++nNote; if (nNote == anum || fAll) { pager_printf (ch, "[%3d] %s: %s\n\r%s\n\rTo: %s\n\r%s", nNote, 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_ROOM); return; } } ch->SendText ("No such note.\n\r"); return; } else { vnum = 0; POSITION pos = board->GetFirstNotePosition (); int nNote = 0; while (pos) { pnote = board->GetNextNote (pos); if (is_note_to (ch, pnote) || ch->GetTrustLevel () > SysData.ReadAllMailLev) { ++nNote; if (nNote == anum || fAll) { if (ch->GetGold () < 10 && ch->GetTrustLevel () < SysData.ReadMailFreeLev) { ch->SendText ("It costs 10 gold coins to read a " "message.\n\r"); return; } if (ch->GetTrustLevel () < SysData.ReadMailFreeLev) ch->AddGold (-10); pager_printf (ch, "[%3d] %s: %s\n\r%s\n\rTo: %s\n\r%s", nNote, pnote->sender, pnote->subject, pnote->date, pnote->to_list, pnote->text); return; } } } ch->SendText ("No such message.\n\r"); return; } } // Voting added by Narn, June '96 if (!str_cmp (arg, "vote")) { char arg2 [MAX_INPUT_LENGTH]; arg_passed = one_argument (arg_passed, arg2); board = find_board (ch); if (!board) { ch->SendText ("There is no bulletin board here.\n\r"); return; } if (!can_read (ch, board)) { ch->SendText ("You cannot vote on this board.\n\r"); return; } if (is_number (arg2)) anum = atoi (arg2); else { ch->SendText ("Note vote which number?\n\r"); return; } pnote = board->GetNoteByNumber (anum-1); if (!pnote) { ch->SendText ("No such note.\n\r"); 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->GetName (), pnote->sender)) { ch->SendText ("You are not the author of this note.\n\r"); return; } pnote->voting = VOTE_OPEN; act (AT_ACTION, "$n opens voting on a note.", ch, NULL, NULL, TO_ROOM); ch->SendText ("Voting opened.\n\r"); board->WriteAllNotes (); return; } if (!str_cmp (arg_passed, "close")) { if (str_cmp (ch->GetName (), pnote->sender)) { ch->SendText ("You are not the author of this note.\n\r"); return; } pnote->voting = VOTE_CLOSED; act (AT_ACTION, "$n closes voting on a note.", ch, NULL, NULL, TO_ROOM); ch->SendText ("Voting closed.\n\r"); board->WriteAllNotes (); return; } // Make sure the note is open for voting before going on. if (pnote->voting != VOTE_OPEN) { ch->SendText ("Voting is not open on this note.\n\r"); return; } // Can only vote once on a note. sprintf (buf, "%s %s %s", pnote->yesvotes, pnote->novotes, pnote->abstentions); if (is_name (ch->GetName (), buf)) { ch->SendText ("You have already voted on this note.\n\r"); return; } if (!str_cmp (arg_passed, "yes")) { sprintf (buf, "%s %s", pnote->yesvotes, ch->GetName ()); delete pnote->yesvotes; pnote->yesvotes = str_dup (buf); act (AT_ACTION, "$n votes on a note.", ch, NULL, NULL, TO_ROOM); ch->SendText ("Ok.\n\r"); board->WriteAllNotes (); return; } if (!str_cmp (arg_passed, "no")) { sprintf (buf, "%s %s", pnote->novotes, ch->GetName ()); delete pnote->novotes; pnote->novotes = str_dup (buf); act (AT_ACTION, "$n votes on a note.", ch, NULL, NULL, TO_ROOM); ch->SendText ("Ok.\n\r"); board->WriteAllNotes (); return; } if (!str_cmp (arg_passed, "abstain")) { sprintf (buf, "%s %s", pnote->abstentions, ch->GetName ()); delete pnote->abstentions; pnote->abstentions = str_dup (buf); act (AT_ACTION, "$n votes on a note.", ch, NULL, NULL, TO_ROOM); ch->SendText ("Ok.\n\r"); board->WriteAllNotes (); return; } do_note (ch, "", FALSE); } if (!str_cmp (arg, "write")) { if (ch->GetSubstate () == SUB_RESTRICTED) { ch->SendText ("You cannot write a note from within another command.\n\r"); return; } if (ch->GetTrustLevel () < SysData.WriteMailFreeLev) { quill = find_quill (ch); if (!quill) { ch->SendText ("You need a quill to write a note.\n\r"); return; } if (quill->value[0] < 1) { ch->SendText ("Your quill is dry.\n\r"); return; } } if ((paper = get_eq_char (ch, WEAR_HOLD)) == NULL || paper->item_type != ITEM_PAPER) { if (ch->GetTrustLevel () < SysData.WriteMailFreeLev) { ch->SendText ("You need to be holding a fresh piece of parchment to write a note.\n\r"); return; } paper = create_object (OIdxTable.GetObj (OBJ_VNUM_NOTE), 0); if ((tmpobj = get_eq_char (ch, WEAR_HOLD)) != NULL) unequip_char (ch, tmpobj); paper = obj_to_char (paper, ch); equip_char (ch, paper, WEAR_HOLD); 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->SetSubstate (SUB_WRITING_NOTE); ch->dest_buf = ed; if (ch->GetTrustLevel () < SysData.WriteMailFreeLev) --quill->value[0]; start_editing (ch, ed->description); return; } else { ch->SendText ("You cannot modify this note.\n\r"); return; } } if (!str_cmp (arg, "subject")) { if (ch->GetTrustLevel () < SysData.WriteMailFreeLev) { quill = find_quill (ch); if (!quill) { ch->SendText ("You need a quill to write a note.\n\r"); return; } if (quill->value[0] < 1) { ch->SendText ("Your quill is dry.\n\r"); return; } } if (!arg_passed || arg_passed[0] == '\0') { ch->SendText ("What do you wish the subject to be?\n\r"); return; } if ((paper = get_eq_char (ch, WEAR_HOLD)) == NULL || paper->item_type != ITEM_PAPER) { if (ch->GetTrustLevel () < SysData.WriteMailFreeLev) { ch->SendText ("You need to be holding a fresh piece of parchment to write a note.\n\r"); return; } paper = create_object (OIdxTable.GetObj (OBJ_VNUM_NOTE), 0); if ((tmpobj = get_eq_char (ch, WEAR_HOLD)) != NULL) unequip_char (ch, tmpobj); paper = obj_to_char (paper, ch); equip_char (ch, paper, WEAR_HOLD); 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) { ch->SendText ("You cannot modify this note.\n\r"); return; } else { paper->value[1] = 1; ed = SetOExtra (paper, "_subject_"); STRFREE (ed->description); ed->description = STRALLOC (arg_passed); ch->SendText ("Ok.\n\r"); return; } } if (!str_cmp (arg, "to")) { struct stat fst; char fname [1024]; if (ch->GetTrustLevel () < SysData.WriteMailFreeLev) { quill = find_quill (ch); if (!quill) { ch->SendText ("You need a quill to write a note.\n\r"); return; } if (quill->value[0] < 1) { ch->SendText ("Your quill is dry.\n\r"); return; } } if (!arg_passed || arg_passed[0] == '\0') { ch->SendText ("Please specify an addressee.\n\r"); return; } if ((paper = get_eq_char (ch, WEAR_HOLD)) == NULL || paper->item_type != ITEM_PAPER) { if (ch->GetTrustLevel () < SysData.WriteMailFreeLev) { ch->SendText ("You need to be holding a fresh piece of " "parchment to write a note.\n\r"); return; } paper = create_object (OIdxTable.GetObj (OBJ_VNUM_NOTE), 0); if ((tmpobj = get_eq_char (ch, WEAR_HOLD)) != NULL) unequip_char (ch, tmpobj); paper = obj_to_char (paper, ch); equip_char (ch, paper, WEAR_HOLD); 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) { ch->SendText ("You cannot modify this note.\n\r"); return; } arg_passed [0] = UPPER (arg_passed [0]); strcpy (fname, FileTable.PlayerName (capitalize (arg_passed))); if (!IS_MAIL || 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); ch->SendText ("Ok.\n\r"); return; } else { ch->SendText ("No player exists by that name.\n\r"); return; } } if (!str_cmp (arg, "show")) { char *subject, *to_list, *text; if ((paper = get_eq_char (ch, WEAR_HOLD)) == NULL || paper->item_type != ITEM_PAPER) { ch->SendText ("You are not holding a note.\n\r"); return; } if ((subject = GetExtraDescr ("_subject_", paper->ExDesList)) == NULL) subject = "(no subject)"; if ((to_list = GetExtraDescr ("_to_", paper->ExDesList)) == NULL) to_list = "(nobody)"; sprintf (buf, "%s: %s\n\rTo: %s\n\r", ch->GetName (), subject, to_list); ch->SendText (buf); if ((text = GetExtraDescr ("_text_", paper->ExDesList)) == NULL) text = "The note is blank.\n\r"; ch->SendText (text); return; } if (!str_cmp (arg, "post")) { if ((paper = get_eq_char (ch, WEAR_HOLD)) == NULL || paper->item_type != ITEM_PAPER) { ch->SendText ("You are not holding a note.\n\r"); return; } if (paper->value[0] == 0) { ch->SendText ("There is nothing written on this note.\n\r"); return; } if (paper->value[1] == 0) { ch->SendText ("This note has no subject.\n\r"); return; } if (paper->value[2] == 0) { ch->SendText ("This note is addressed to no one!\n\r"); return; } board = find_board (ch); if (!board) { ch->SendText ("There is no bulletin board here to post " "your note on.\n\r"); return; } if (!can_post (ch, board)) { ch->SendText ("A magical force prevents you from posting " "your note here...\n\r"); return; } if (board->num_posts >= board->max_posts) { ch->SendText ("There is no room on this board to post your note.\n\r"); return; } act (AT_ACTION, "$n posts a note.", ch, NULL, NULL, TO_ROOM); pnote = new CNoteData; pnote->date = STRALLOC (CurrentTime.GetString ()); char *text = GetExtraDescr ("_text_", paper->ExDesList); pnote->text = text ? STRALLOC (text) : STRALLOC (""); text = GetExtraDescr ("_to_", paper->ExDesList); pnote->to_list = text ? STRALLOC (text) : STRALLOC ("all"); text = GetExtraDescr ("_subject_", paper->ExDesList); pnote->subject = text ? STRALLOC (text) : STRALLOC (""); pnote->sender = QUICKLINK (ch->GetName ()); pnote->voting = 0; pnote->yesvotes = str_dup (""); pnote->novotes = str_dup (""); pnote->abstentions = str_dup (""); board->AddNote (pnote); board->WriteAllNotes (); ch->SendText ("You post your note on the board.\n\r"); 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) { ch->SendText ("There is no board here to take a note from!\n\r"); return; } if (!str_cmp (arg, "take")) take = 1; else if (!str_cmp (arg, "copy")) { if (ch->IsMortal ()) { ch->SendText ("Huh? Type 'help note' for usage.\n\r"); return; } take = 2; } else take = 0; if (!is_number (arg_passed)) { ch->SendText ("Note remove which number?\n\r"); return; } if (!can_read (ch, board)) { ch->SendText ("You can't make any sense of what's posted here, " "let alone remove anything!\n\r"); return; } anum = atoi (arg_passed); POSITION pos = board->GetFirstNotePosition (); int nNote = 0; while (pos) { pnote = board->GetNextNote (pos); if (IS_MAIL && ((is_note_to (ch, pnote)) || ch->GetTrustLevel () >= SysData.TakeOthersMailLev)) ++nNote; else if (!IS_MAIL) then ++nNote; if ((is_note_to (ch, pnote) || can_remove (ch, board)) && (nNote == anum)) { if ((is_name ("all", pnote->to_list)) && (ch->GetTrustLevel () < SysData.TakeOthersMailLev) && (take == 1)) { ch->SendText ("Notes addressed to 'all' can not be taken.\n\r"); return; } if (take != 0) { if (ch->GetGold () < 50 && ch->GetTrustLevel () < SysData.ReadMailFreeLev) { if (take == 1) ch->SendText ("It costs 50 coins to take your mail.\n\r"); else ch->SendText ("It costs 50 coins to copy your mail.\n\r"); return; } if (ch->GetTrustLevel () < SysData.ReadMailFreeLev) ch->AddGold (-50); paper = create_object (OIdxTable.GetObj (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, "\r\nTo: "); strcat (notebuf, pnote->to_list); strcat (notebuf, "\r\nSubject: "); strcat (notebuf, pnote->subject); strcat (notebuf, "\r\n\r\n"); strcat (notebuf, strip_cr (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); paper->SetShortDescr (short_desc_buf); sprintf (long_desc_buf, "A note from %s to %s lies on the ground.", pnote->sender, pnote->to_list); paper->SetDescription (long_desc_buf); sprintf (keyword_buf, "note parchment paper %s", pnote->to_list); paper->SetName (keyword_buf); } if (take != 2) board->RemoveNote (pnote); ch->SendText ("Ok.\n\r"); 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; } } ch->SendText ("No such note.\n\r"); return; } ch->SendText ("Huh? Type 'help note' for usage.\n\r"); return; } void CBoardData::Read (char* pLine, FILE* fp) { #ifdef KEY #undef KEY #endif #define KEY(literal,field,value) \ if (!str_cmp (word, literal)) { \ field = value; \ fMatch = TRUE; \ break; \ } if (str_cmp (ParseWord (pLine), "filename")) { bug ("CBoardData::Read: No notefile name in boards.txt"); return; } note_file = ParseStringNohash (pLine, fp); char *word; char buf [MAX_STRING_LENGTH]; BOOL fMatch; for (;;) { fMatch = FALSE; if (! feof (fp)) { pLine = fread_line (fp); word = ParseWord (pLine); } else word = "End"; switch (UPPER (word [0])) { case '*': fMatch = TRUE; break; case 'E': KEY ("Extra_readers", extra_readers, ParseStringNohash (pLine, fp)); KEY ("Extra_removers", extra_removers, ParseStringNohash (pLine, fp)); if (!str_cmp (word, "End")) { num_posts = 0; SetNext (NULL); SetPrev (NULL); if (!read_group) read_group = str_dup (""); if (!post_group) post_group = str_dup (""); if (!extra_readers) extra_readers = str_dup (""); if (!extra_removers) extra_removers = str_dup (""); return; } case 'M': KEY ("Min_read_level", min_read_level, ParseNumber (pLine)); KEY ("Min_post_level", min_post_level, ParseNumber (pLine)); KEY ("Min_remove_level", min_remove_level,ParseNumber (pLine)); KEY ("Max_posts", max_posts, ParseNumber (pLine)); case 'P': KEY ("Post_group", post_group, ParseStringNohash (pLine, fp)); case 'R': KEY ("Read_group", read_group, ParseStringNohash (pLine, fp)); case 'T': KEY ("Type", type, ParseNumber (pLine)); case 'V': KEY ("Vnum", board_obj, ParseNumber (pLine)); } if (! fMatch) { sprintf (buf, "CBoardData::Read: no match: %s", word); bug (buf); } } } CBoardData *CBoardList::ReadBoard (FILE *fp) { if (! feof (fp)) { char *pLine = fread_line (fp); if (*pLine) { CBoardData *pBoard = new CBoardData; pBoard->Read (pLine, fp); return pBoard; } } return NULL; } // Load boards file. void CBoardList::Load () { FILE *board_fp; FILE *note_fp; CBoardData *board; CNoteData *pnote; gpDoc->LogString ("Loading boards...", LOG_BOOT); if (! (board_fp = fopen (FileTable.GetName (SM_BOARD_FILE), "r"))) return; while ((board = ReadBoard (board_fp))) { AddTail (board); CString nfn = FileTable.MakeName (SD_BOARD_DIR, board->note_file); gpDoc->LogString (nfn, LOG_BOOT); if ((note_fp = fopen (nfn, "r")) != NULL) { while ((pnote = read_note (nfn, note_fp))) { board->m_NList.AddTail (pnote); board->num_posts++; } } } fclose (board_fp); } void do_makeboard (CCharacter *ch, char *argument) { CBoardData *board; if (!argument || argument[0] == '\0') { ch->SendText ("Usage: makeboard <filename>\n\r"); return; } smash_tilde (argument); board = new CBoardData; 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 (""); BoardList.AddBoard (board); } CNoteData *read_note (const char *notefile, FILE *fp) { char *word, *pLine; CNoteData *pNote = new CNoteData; for (;;) { if (feof (fp)) { fclose (fp); delete pNote; return NULL; } pLine = fread_line (fp); if (*pLine) { word = ParseWord (pLine); if (! str_cmp (word, "sender")) pNote->sender = ParseString (pLine, fp); else if (! str_cmp (word, "date")) pNote->date = ParseString (pLine, fp); else if (! str_cmp (word, "to")) pNote->to_list = ParseString (pLine, fp); else if (! str_cmp (word, "subject")) pNote->subject = ParseString (pLine, fp); else if (! str_cmp (word, "voting")) pNote->voting = ParseNumber (pLine); else if (! str_cmp (word, "yesvotes")) pNote->yesvotes = ParseStringNohash (pLine, fp); else if (! str_cmp (word, "novotes")) pNote->novotes = ParseStringNohash (pLine, fp); else if (! str_cmp (word, "abstentions")) pNote->abstentions = ParseStringNohash (pLine, fp); else if (! str_cmp (word, "text")) { pLine = fread_line (fp); pNote->text = ParseString (pLine, fp); break; } else { bug ("read_note: Bad keyword (%s)", word); ThrowSmaugException (SE_NOTES); } } } if (! pNote->yesvotes) pNote->yesvotes = str_dup (""); if (! pNote->novotes) pNote->novotes = str_dup (""); if (! pNote->abstentions) pNote->abstentions = str_dup (""); pNote->SetNext (NULL); pNote->SetPrev (NULL); return pNote; } void do_bset (CCharacter *ch, char *argument) { CBoardData *board; BOOL found; char arg1 [MAX_INPUT_LENGTH]; char arg2 [MAX_INPUT_LENGTH]; char buf [MAX_STRING_LENGTH]; int value; argument = one_argument (argument, arg1); argument = one_argument (argument, arg2); if (arg1[0] == '\0' || arg2[0] == '\0') { ch->SendText ("Usage: bset <board filename> <field> value\n\r"); ch->SendText ("\n\rField being one of:\n\r"); ch->SendText (" vnum read post remove maxpost filename type\n\r"); ch->SendText (" read_group post_group extra_readers extra_removers\n\r"); return; } value = atoi (argument); found = FALSE; POSITION pos = BoardList.GetHeadPosition (); while (pos) { board = BoardList.GetNext (pos); if (!str_cmp (arg1, board->note_file)) { found = TRUE; break; } } if (!found) { ch->SendText ("Board not found.\n\r"); return; } if (!str_cmp (arg2, "vnum")) { if (!OIdxTable.GetObj (value)) { ch->SendText ("No such object.\n\r"); return; } board->board_obj = value; BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "read")) { if (value < 0 || value > MAX_LEVEL) { ch->SendText ("Value out of range.\n\r"); return; } board->min_read_level = value; BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "read_group")) { if (!argument || argument[0] == '\0') { ch->SendText ("No group specified.\n\r"); return; } delete board->read_group; if (!str_cmp (argument, "none")) board->read_group = str_dup (""); else board->read_group = str_dup (argument); BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "post_group")) { if (!argument || argument[0] == '\0') { ch->SendText ("No group specified.\n\r"); return; } delete board->post_group; if (!str_cmp (argument, "none")) board->post_group = str_dup (""); else board->post_group = str_dup (argument); BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "extra_removers")) { if (!argument || argument[0] == '\0') { ch->SendText ("No names specified.\n\r"); return; } if (!str_cmp (argument, "none")) buf[0] = '\0'; else sprintf (buf, "%s %s", board->extra_removers, argument); delete board->extra_removers; board->extra_removers = str_dup (buf); BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "extra_readers")) { if (!argument || argument[0] == '\0') { ch->SendText ("No names specified.\n\r"); return; } if (!str_cmp (argument, "none")) buf[0] = '\0'; else sprintf (buf, "%s %s", board->extra_readers, argument); delete board->extra_readers; board->extra_readers = str_dup (buf); BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "filename")) { if (!argument || argument[0] == '\0') { ch->SendText ("No filename specified.\n\r"); return; } delete board->note_file; board->note_file = str_dup (argument); BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "post")) { if (value < 0 || value > MAX_LEVEL) { ch->SendText ("Value out of range.\n\r"); return; } board->min_post_level = value; BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "remove")) { if (value < 0 || value > MAX_LEVEL) { ch->SendText ("Value out of range.\n\r"); return; } board->min_remove_level = value; BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "maxpost")) { if (value < 1 || value > 1000) { ch->SendText ("Value out of range.\n\r"); return; } board->max_posts = value; BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "type")) { if (value < 0 || value > 1) { ch->SendText ("Value out of range.\n\r"); return; } board->type = value; BoardList.WriteBoardsFile (); ch->SendText ("Done.\n\r"); return; } do_bset (ch, ""); } void do_bstat (CCharacter *ch, char *argument) { CBoardData *board; BOOL found; char arg [MAX_INPUT_LENGTH]; argument = one_argument (argument, arg); if (arg[0] == '\0') { ch->SendText ("Usage: bstat <board filename>\n\r"); return; } found = FALSE; POSITION pos = BoardList.GetHeadPosition (); while (pos) { board = BoardList.GetNext (pos); if (!str_cmp (arg, board->note_file)) { found = TRUE; break; } } if (!found) { ch->SendText ("Board not found.\n\r"); return; } ch->SendTextf ("%-12s Vnum: %5d Read: %2d Post: %2d Rmv: %2d Max: %2d " "Posts: %d Type: %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); ch->SendTextf ( "Read_group: %-15s Post_group: %-15s \n\rExtra_readers: %-10s\n\r", board->read_group, board->post_group, board->extra_readers); } void do_boards (CCharacter *ch, char *argument) { if (BoardList.IsEmpty ()) { ch->SendText ("There are no boards.\n\r"); return; } set_char_color (AT_NOTE, ch); POSITION pos = BoardList.GetHeadPosition (); while (pos) { CBoardData &Bd = *BoardList.GetNext (pos); ch->SendTextf ("%-16s Vnum: %5d Read: %2d Post: %2d Rmv: %2d " "Max: %2d Posts: %d Type: %d\n\r", Bd.note_file, Bd.board_obj, Bd.min_read_level, Bd.min_post_level, Bd.min_remove_level, Bd.max_posts, Bd.num_posts, Bd.type); } } void mail_count (CCharacter *ch) { int Count = 0; POSITION pos = BoardList.GetHeadPosition (); while (pos) { CBoardData &Bd = *BoardList.GetNext (pos); if (Bd.type == BOARD_MAIL && can_read (ch, &Bd)) { POSITION pos = Bd.GetFirstNotePosition (); while (pos) { if (is_note_to (ch, Bd.GetNextNote (pos))) ++Count; } } } if (Count) ch->SendTextf ("You have %d mail messages waiting.\n\r", Count); } CNoteData::~CNoteData () { delete yesvotes; delete novotes; delete abstentions; }