/**************************************************************************/ // letters.cpp - see below /*************************************************************************** * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt * * >> A number of people have contributed to the Dawn codebase, with the * * majority of code written by Michael Garratt - www.dawnoftime.org * * >> To use this source code, you must fully comply with the dawn license * * in licenses.txt... In particular, you may not remove this copyright * * notice. * **************************************************************************/ /*************************************************************************** * FILE: letters.cpp - Letter writing system written by Kalahn and Kerenos * * ----------------------------------------------------------------------- * * The letter system works by having a buffer associated with the player * * in which the player typed in the contents of a letter into a letter * * workspace. The text contained within the workspace can be scribed to * * an actual parchment once completed. * ***************************************************************************/ #include "include.h" /**************************************************************************/ // core user interface of letter writting system // Syntax: // letter show - shows what the final letter will look like // letter edit - brings up the text of the letter in the string editor // letter + - adds a single line of text to a letter workspace // letter - - deletes a single line of text from a letter workspace // letter clear - clears the letter // letter peek - shows original and language letter (immort) // letter scribe - copys the letter text from the workspace to a parchment // letter seal - puts a seal on a letter struct letter_cmd_type { const char * name; DO_FUN *do_fun; int flags; const char * syntax; }; /**************************************************************************/ #define CMDLETTER_IMMORTAL_ONLY (A) // Imm only command #define CMDLETTER_TEXT_REQUIRED (B) // must have text (prevent scribing empty letters) #define CMDLETTER_AWAKE (C) // must be awake to use this command /**************************************************************************/ char *letter_generate_scroll( const char *header, const char *text ); DECLARE_DO_FUN(letter_addline); DECLARE_DO_FUN(letter_delline); DECLARE_DO_FUN(letter_breakseal); DECLARE_DO_FUN(letter_clear); DECLARE_DO_FUN(letter_edit); DECLARE_DO_FUN(letter_peek); DECLARE_DO_FUN(letter_scribe); DECLARE_DO_FUN(letter_seal); DECLARE_DO_FUN(letter_showscroll); DECLARE_DO_FUN(letter_showtext); DECLARE_DO_FUN(letter_tear); /**************************************************************************/ struct letter_cmd_type letter_cmd_table[]= { { "+", letter_addline, 0,"Add a single line of text to the letter."}, { "-", letter_delline, CMDLETTER_TEXT_REQUIRED, "Remove a single line of text from the letter."}, { "breakseal",letter_breakseal,CMDLETTER_AWAKE,"Breaks the seal on a letter - required to read a sealed letter"}, { "clear", letter_clear, CMDLETTER_TEXT_REQUIRED, "Clears the letter currently in progress."}, { "edit", letter_edit, 0, "Edits the current letter text in the string editor."}, { "peek", letter_peek, CMDLETTER_IMMORTAL_ONLY, "Peeks at a letter data (immortal only)."}, { "scribe", letter_scribe, CMDLETTER_TEXT_REQUIRED|CMDLETTER_AWAKE, "Scribes the working letter onto a parchment."}, { "seal", letter_seal, CMDLETTER_AWAKE,"Seals the letter with wax"}, { "showscroll",letter_showscroll, CMDLETTER_TEXT_REQUIRED, "Shows what the letter will look like once posted (in a scroll picture)."}, { "showtext", letter_showtext, CMDLETTER_TEXT_REQUIRED, "Shows the text of the letter you are working on."}, { "tear", letter_tear, 0,"Tear up and destroy a letter you are currently holding."}, { "", NULL, 0, ""} }; /**************************************************************************/ // letter writing interpreter - Kal void do_letter( char_data *ch, char *argument ) { char arg[MIL]; int i; // PC's only if ( IS_NPC( ch )) { ch->println( "Only players can write letters." ); return; } argument=one_argument(argument,arg); if(IS_NULLSTR(arg)){ // no args - show syntax ch->titlebar("Letter writing"); ch->println("Syntax:"); for(i=0;!IS_NULLSTR(letter_cmd_table[i].name); i++){ if(IS_SET(letter_cmd_table[i].flags, CMDLETTER_IMMORTAL_ONLY) && !IS_IMMORTAL(ch)){ continue; } ch->printlnf(" letter %-12s - %s", letter_cmd_table[i].name, letter_cmd_table[i].syntax); } ch->titlebar(""); return; } // find the command for(i=0;!IS_NULLSTR(letter_cmd_table[i].name); i++){ if(IS_SET(letter_cmd_table[i].flags, CMDLETTER_IMMORTAL_ONLY) && !IS_IMMORTAL(ch)){ continue; } if(!str_prefix(arg,letter_cmd_table[i].name)){ // found the command break; } } if(IS_NULLSTR(letter_cmd_table[i].name)){ ch->printlnf("Unrecognised IC letter writting command '%s'", arg); do_letter(ch,""); return; } // check if the command can be used in the current situation if( IS_SET(letter_cmd_table[i].flags, CMDLETTER_TEXT_REQUIRED) && IS_NULLSTR(ch->pcdata->letter_workspace_text)){ ch->printlnf("No text currently entered for the letter - no point in using %s at this stage.", letter_cmd_table[i].name); return; } if( IS_SET(letter_cmd_table[i].flags, CMDLETTER_AWAKE) && !IS_AWAKE(ch)){ ch->printlnf("You must be awake to use 'letter %s'", letter_cmd_table[i].name); return; } // run the command (*letter_cmd_table[i].do_fun) (ch, argument); } /**************************************************************************/ void letter_edit( char_data *ch, char *) { ch->println("Editing the text of your letter."); string_append(ch, &ch->pcdata->letter_workspace_text); } /**************************************************************************/ void letter_showtext( char_data *ch, char *) { ch->println("Letter Text:"); ch->wrapln(ch->pcdata->letter_workspace_text); } /**************************************************************************/ void letter_showscroll( char_data *ch, char *) { char header[MIL]; sprintf(header, "`YThis letter will be written in %s script.", ch->language->name); ch->sendpage(letter_generate_scroll(header, ch->pcdata->letter_workspace_text)); } /**************************************************************************/ char *getline( char *str, char *buf, int bufsize ); /**************************************************************************/ char *letter_generate_scroll( const char * header, const char *text) { static char buf[HSL]; char bufline[MSL], scroll_line[MSL]; char *ftext = str_dup(text); ftext=note_format_string_width(ftext, 61, true, true); char *string; if(IS_NULLSTR(header)){ // scroll header with no header strcpy( buf, "`y ___________________________________________________________________\r\n" " / //_\\\\\r\n" " | |\\\\_//|\r\n" " | |_\\__/\r\n" " | |\r\n" ); }else{ // scroll header with header sprintf( buf, "`y ___________________________________________________________________\r\n" " / //_\\\\\r\n" " | |\\\\_//|\r\n" " | %s `y|_\\__/\r\n" " | |\r\n", str_width(header,61)); } // the below converts "`1" into a "\n", but not "``1" into a "`\n" ftext=string_replace_all(ftext,"``","_KAL'S_H@CK_"); // :) ftext=string_replace_all(ftext,"`1","\n"); ftext=string_replace_all(ftext,"_KAL'S_H@CK_", "``"); strcat( buf, "`x`#`#"); // default text colour to white to start with // loop recursively creating message body text string=ftext; while ( *string ) { string = getline( string, bufline, MSL); sprintf(scroll_line,"`y |`& %s`#`y|\r\n", str_width(bufline,62)); strcat( buf, scroll_line); } // scroll footer strcat(buf, "`y | |\r\n" " | |\r\n" " |_______________________________________________________________|\r\n" " / //_\\|\r\n" "| |\\_/|\r\n" " \\_____________________________________________________________\\_/`x\r\n" ); free_string(ftext); return buf; } /**************************************************************************/ void letter_addline(char_data *ch, char *argument) { char **backup=ch->desc->pString; // prob dont even need to use the backup since how are they going to // get here and be in an editor at the same time. ch->desc->pString=&ch->pcdata->letter_workspace_text; if(TRUE_CH(ch)->pcdata){ PREFERENCE_TYPE backup_pref=TRUE_CH(ch)->pcdata->preference_dawnftp; TRUE_CH(ch)->pcdata->preference_dawnftp=PREF_OFF; string_add(ch,argument); // add our text TRUE_CH(ch)->pcdata->preference_dawnftp=backup_pref; }else{ string_add(ch,argument); // add our text } ch->desc->pString=backup; // check the length int len=str_len(ch->pcdata->letter_workspace_text)-(MSL*2); if(len>0){ ch->printlnf("`RWarning:`YThe text of your letter is %d character%s too long to be scribed!!!`x", len, len==1?"":"s"); }else{ len*=-1; if(len>MSL){ if(len<=1){ ch->wraplnf("Text added to letter, no more room to add any more to the text " "before it it scribed to a parchment."); }else{ ch->wraplnf("Text added to letter, up to %d more characters can be added to the letter " "before it it scribed to a parchment.", len); } }else{ ch->println("Text added to letter"); } } } /**************************************************************************/ void letter_delline(char_data *ch, char *) { char **backup=ch->desc->pString; ch->desc->pString=&ch->pcdata->letter_workspace_text; string_add(ch,".-"); // get rid of the bottom line ch->desc->pString=backup; // check the length int len=str_len(ch->pcdata->letter_workspace_text)-(MSL*2); if(len>0){ ch->printlnf("`RWarning:`YThe text of your letter is still too long to be scribed!!! (by %d character%s)`x", len, len==1?"":"s"); }else{ len*=-1; if(len>MSL){ if(len<=1){ ch->wraplnf("Bottom line removed - This letter can now be scribed to a parchment."); }else{ ch->wraplnf("Bottom line removed - up to %d more characters can fit before scribing.", len); } }else{ ch->println("Text removed from letter"); } } } /**************************************************************************/ void letter_clear(char_data *ch, char *) { replace_string(ch->pcdata->letter_workspace_text,""); ch->println("Letter in progress cleared"); } /**************************************************************************/ // prefix an extended to the extended description given - Kal April 00 EXTRA_DESCR_DATA *ed_prefix(EXTRA_DESCR_DATA *ed, char *keyword, char *description) { EXTRA_DESCR_DATA * new_ed = new_extra_descr(); new_ed->keyword = str_dup( keyword ); new_ed->description = str_dup( description ); new_ed->next = ed; return new_ed; } /**************************************************************************/ // scribe a working letter onto a parchment void letter_scribe(char_data *ch, char *) { if(IS_OOC(ch)){ ch->println("You can't scribe letters while in OOC!`x"); return; } // length check if(str_len(ch->pcdata->letter_workspace_text)>MSL*2){ ch->println("`RYou have too much information in your letter to fit on a single parchment.`x"); } obj_data *parchment; // check to see if they are holding a parchment type item parchment = get_eq_char( ch, WEAR_HOLD ); if ( !parchment || parchment->item_type != ITEM_PARCHMENT) { ch->println( "You need to be holding some parchment to scribe a letter." ); return; } // if parchment->value[1] (v1) is not 0, then the parchement isn't blank if ( parchment->value[1] != 0 ) { act( "$p has already been written on.", ch, parchment, NULL, TO_CHAR ); return; } if ( get_skill( TRUE_CH(ch), ch->language->gsn)<50) { ch->printlnf( "Your command of the %s language is insufficient.", ch->language->name ); return; } // BECAUSE DO_LOOK() REDIRECTS LOOKING AT EXTENDED DESCRIPTIONS TO LETTER_READ // WE CAN ENCODE ALL OUR INFO ON THE EXTENDED DESCRIPTIONS OF THE LETTER. char lbuf[HSL]; parchment->extra_descr=NULL; // _SCRIBED_BY sprintf(lbuf, "%s (%s) %d", ch->short_descr, ch->name, ch->vnum()); parchment->extra_descr=ed_prefix(parchment->extra_descr, "_SCRIBED_BY", lbuf); // _SCRIBED_TIME sprintf(lbuf, "%s", (char *) ctime( ¤t_time )); parchment->extra_descr=ed_prefix(parchment->extra_descr, "_SCRIBED_TIME", lbuf); // _ORIGINAL_TEXT parchment->extra_descr=ed_prefix(parchment->extra_descr, "_ORIGINAL_TEXT", ch->pcdata->letter_workspace_text); // _LANGUAGE_NAME parchment->extra_descr=ed_prefix(parchment->extra_descr, "_LANGUAGE_NAME", ch->language->name); // _LANGUAGE_TEXT translate_language( ch->language, false, ch, ch, ch->pcdata->letter_workspace_text, lbuf ); parchment->extra_descr=ed_prefix(parchment->extra_descr, "_LANGUAGE_TEXT", lbuf); // clear the writters buffer replace_string(ch->pcdata->letter_workspace_text,""); // adjust the flags // Flag the letter as being written [v1 = 0 is a blank parchment] parchment->value[1] = 1; // Make sure it's not flagged sealed [v2 = 0 is an unsealed parchment ] parchment->value[2] = 0; // v3 is the language the note is written in parchment->value[3] = ch->language->unique_id; // Language the note is written in [v4 = language skill] parchment->value[4] = ch->get_skill(ch->language->gsn); // restring shorts and longs replace_string(parchment->description, "A hand-written letter is here."); replace_string(parchment->short_descr, "a hand-written letter"); replace_string(parchment->name, "hand-written letter"); ch->println( "You scribe your letter to your parchment." ); act( "$n pens a letter.", ch, NULL, NULL, TO_ROOM ); WAIT_STATE( ch, PULSE_PER_SECOND * number_range( 2, 3 )); return; } /**************************************************************************/ void letter_seal(char_data *ch, char *argument) { obj_data *letter; letter = get_obj_list( ch, argument, ch->carrying ); if ( !letter ) { ch->println( "What do you want to seal?" ); return; } if ( letter->item_type != ITEM_PARCHMENT ) { ch->println( "You can't seal that, it must be a written letter." ); return; } // v2 > 0 == already sealed if (letter->value[2] != 0) { ch->println( "It is already sealed." ); return; } letter->value[2] = 1; // restring it again if(IS_NULLSTR( ch->pcdata->crest )){ replace_string(letter->description, "A letter is here, sealed with a blob of red wax."); replace_string(letter->short_descr, "a letter sealed with a blob of red wax"); replace_string(letter->name, "letter sealed blob red wax"); act( "$n seals a letter with a red blob of wax.", ch, NULL, NULL, TO_ROOM ); ch->println( "You seal the letter with a blob of red wax." ); }else{ char buf[MIL]; sprintf(buf, "A letter is here, sealed with a crest depicting %s.", ch->pcdata->crest); replace_string(letter->description, buf); sprintf(buf,"a letter sealed with a crest depicting %s", ch->pcdata->crest); replace_string(letter->short_descr, buf); sprintf(buf, "letter sealed crest depicting %s", ch->pcdata->crest); replace_string(letter->name, buf); sprintf(buf,"$n seals a letter with a crest depicting %s", ch->pcdata->crest); act( buf, ch, NULL, NULL, TO_ROOM ); ch->printlnf( "You seal the letter with a crest depicting %s.", ch->pcdata->crest); } WAIT_STATE( ch, PULSE_PER_SECOND * number_range( 3, 5 )); } /**************************************************************************/ void letter_breakseal(char_data *ch, char *argument) { obj_data *letter; letter = get_obj_list(ch,argument,ch->carrying); if ( !letter ) { ch->println( "What do you want to break the seal on?" ); return; } if ( letter->item_type != ITEM_PARCHMENT ) { ch->println( "You can't break the seal on that." ); return; } if ( letter->value[2] == 0 ) { ch->println( "The seal on that has already been broken." ); return; } // [v2 = 0 is an unsealed parchment ] letter->value[2] = 0; if(str_infix(letter->description, "crest")){ // first case when red blob of wax replace_string(letter->description, "A letter is here, with a broken blob of red wax."); replace_string(letter->short_descr, "a letter with a broken blob of red wax"); replace_string(letter->name, "letter broken blob red wax"); }else{ letter->description=string_replace(letter->description, "sealed with a crest", "with a broken crest"); letter->short_descr=string_replace(letter->short_descr, "sealed with a crest depicting","with a broken crest depicting"); letter->name=string_replace(letter->name, "sealed","broken"); } ch->println( "You break the seal on the letter." ); act("$n breaks the seal on a letter.", ch, NULL, NULL, TO_ROOM ); } /**************************************************************************/ void letter_tear( char_data *ch, char *argument ) { obj_data *letter; letter = get_obj_list(ch,argument,ch->carrying); if ( !letter ) { ch->println( "What do you want to tear apart?" ); return; } if ( letter->item_type != ITEM_PARCHMENT ) { ch->println( "You can only tear up hand written letters." ); return; } act( "You tear $p into a thousand pieces.", ch, letter, NULL, TO_CHAR ); act( "$n tears $p into a thousand pieces.", ch, letter, NULL, TO_ROOM ); extract_obj( letter ); return; } /**************************************************************************/ void letter_read( char_data *ch, obj_data *letter ) { char lbuf[MSL]; if (( letter->value[2] != 0)) { ch->println( "The letter is sealed." ); return; } if ( letter->value[1] == 0 ) { ch->println( "It is blank." ); return; } char *pdesc=get_extra_descr("_LANGUAGE_TEXT", letter->extra_descr); if(!pdesc){ ch->println( "There is nothing written there." ); return; }; translate_language(language_safe_lookup_by_id(letter->value[3]), false, ch, ch, pdesc, lbuf); char header[MIL]; sprintf(header, "`SYou unroll the letter and read in %s script.", language_safe_lookup_by_id(letter->value[3])->name); ch->sendpage(letter_generate_scroll(header, lbuf)); act("$n reads $p.",ch, letter, NULL, TO_ROOM); WAIT_STATE( ch, PULSE_PER_SECOND * number_range( 3, 5 )); } /**************************************************************************/ void letter_peek( char_data *ch, char *argument ) { obj_data *letter; letter = get_obj_list(ch,argument,ch->carrying); if ( !letter ) { ch->println( "What do you want to peek at?" ); return; } if ( letter->item_type != ITEM_PARCHMENT ) { ch->println( "You can only peek at hand written letters." ); return; } if ( !letter->extra_descr || IS_NULLSTR(letter->extra_descr->description )) { ch->println( "There is nothing written there." ); return; } char lbuf[HSL]; char fbuf[MSL]; lbuf[0]='\0'; char *pdesc; // SCRIBED BY pdesc=get_extra_descr("_SCRIBED_BY", letter->extra_descr); if(pdesc){ sprintf(fbuf,"SCRIBED BY: %s\r\n", pdesc); strcat(lbuf,fbuf); }; pdesc=get_extra_descr("_SCRIBED_TIME", letter->extra_descr); if(pdesc){ sprintf(fbuf,"SCRIBED TIME: %s\r\n", pdesc); strcat(lbuf,fbuf); }; pdesc=get_extra_descr("_ORIGINAL_TEXT", letter->extra_descr); if(pdesc){ sprintf(fbuf,"Original Text:\r\n%s\r\n", pdesc); strcat(lbuf,fbuf); }; pdesc=get_extra_descr("_LANGUAGE_TEXT", letter->extra_descr); if(pdesc){ sprintf(fbuf,"Language Text (%s):\r\n%s\r\n", language_safe_lookup_by_id(letter->value[3])->name, pdesc); strcat(lbuf,fbuf); }; if(IS_NULLSTR(lbuf)){ ch->println("This letter is empty."); }else{ ch->sendpage(lbuf); } } /**************************************************************************/