Code   : Player Journals
>From   : amaron.mudservices.com:6001
Author : Felix
Email  : admins@amaron.mudservices.com
July, 2000


The following code will allow you to add Player Journals to your mud.
This will allow players to use a part of the ROM note system to "post"
their own text to an objects extra descriptions.  I use journals on Amaron
to promote roleplaying, quests, promoting player histories, etc.  The
possibilities are endless.

If you have any problems installing this code, you can reach me at the above
information or on the ROM mailing list.

The original idea for the journal code came from conversations between myself
and one of my players, Khalad.  I got the idea to use part of the ROM note
system from the "SIGN" code that is out there on the snippet sites.

A tip of the hat goes out to Kahlus Naester <kahlus@vicissitudes.net> for
assisting with a coding issue.



Installing the code:
====================

**STEP 1**

Open merc.h in your text editor.  Locate the following code in merc.h:
/*
 * Item types.
 * Used in #OBJECTS.
 */
#define ITEM_LIGHT		      1
#define ITEM_SCROLL		      2


Add the following code to the end of this list.  You may have to change the
numbers 36, 37 and 38 to fit your list.

-- ADD THESE LINES --
#define ITEM_INK			 36
#define ITEM_QUILL			 37
#define ITEM_JOURNAL		 38


The above objects are used to create the journal entries.  ITEM_JOURNAL is the
actual journal object.  I have already added ITEM_INK and ITEM_QUILL to my mud
to allow players to scribe scrolls.  The journal code also checks to see if the
player is holding a bottle of ink and a quill before allowing them to write a
journal entry.  If you don't want to use them, then don't add them.


Locate the following code in merc.h:
/*
 * Data structure for notes.
 */

#define NOTE_NOTE		0
#define NOTE_IDEA		1
#define NOTE_PENALTY	2
#define NOTE_NEWS		3


Add the following code to the end of this list.  You may have to change the number
8 to fir your list.

-- ADD THIS LINE --
#define NOTE_JOURNAL	8


Close and save merc.h




**STEP 2**

Open const.c with your text editor.  Locate the following code in const.c:

/* item type list */
const struct item_type		item_table	[]	=
{
    {	ITEM_LIGHT,		"light"		},
    {	ITEM_SCROLL,	"scroll"	},


Add the following code to this list.

-- ADD THESE LINES --
    {   ITEM_INK,		"ink"		},	/* Felix - Journal Code */
    {   ITEM_QUILL,		"quill"		},	/* Felix - Journal Code */
	{   ITEM_JOURNAL,	"journal"	},	/* Felix - Journal Code */

Save and close const.c




**STEP 3**

Open db.c with your text editor.  Locate the following code in db.c:
    case ITEM_TREASURE:
    case ITEM_WARP_STONE:
    case ITEM_ROOM_KEY:
    case ITEM_GEM:


Add the following code to this list.

-- ADD THESE LINES --
    case ITEM_INK:		/* Felix - Journal Code */
    case ITEM_QUILL:	/* Felix - Journal Code */
    case ITEM_JOURNAL:	/* Felix - Journal Code */

Save and close db.c




**STEP 4**

Open limbo.are with your text editor.  We are going to add the objects for
the INK, QUILL and JOURNAL.  Again, if you don't want to use the INK and QUILL
then don't add the objects and don't add the above code for them to const.c and
db.c


- ADD THESE OBJECTS TO LIMBO.ARE --
#28
ink~
a small bottle of ink~
A small bottle of ink has been left here.~
glass~
ink 0 A
0 0 0 0 0
1 10 100 P

#29
quill~
a quill~
A quill used for writing has been left here.~
feather~
quill 0 A
0 0 0 0 0
1 10 50 P

#137
journal~
a journal~
A leather journal with many pages of writing.~
paper~
journal ORY A
0 0 0 0 0
1 10 10 P


You may have to change the VNUMs of the above objects to fit your limbo.are file.
At the very least, you'll have to change the journal object.  The stock limbo.are
file only goes to a VNUM of 99.

Save and close limbo.are




**STEP 5**

Open interp.c with your text editor.  Locate the following code:
    { "sleep",		do_sleep,	POS_SLEEPING,	 0,  LOG_NORMAL, 1 },
    { "sneak",		do_sneak,	POS_STANDING,	 0,  LOG_NORMAL, 1 },
    { "split",		do_split,	POS_RESTING,	 0,  LOG_NORMAL, 1 },


This is where you are going to add the journal command.  You can add it to the
bottom of the command list, or adding it aplabetically.  Whatever floats your boat.

-- ADD THIS LINE --
    { "journal",	do_journal, POS_STANDING,	 0,	 LOG_NORMAL, 1 },


Save and close interp.c




**STEP 6**

Open interp.h with your text editor.  Locate the following code:
DECLARE_DO_FUN(	do_invis	);
DECLARE_DO_FUN(	do_jail		);


-- ADD THIS LINE --
DECLARE_DO_FUN(	do_journal	);


I added the aobve code right between do_jail and do_kick.  If that works for
you, good.  If not, put it where you want.


Save and close interp.h




**STEP 7**

Open act_obj.c with your text editor.  Locate the following code at the very top
of the act_obj.c file:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "merc.h"
#include "interp.h"


Add the following line right after #include "interp.h" :

-- ADD THIS LINE --
#include "recycle.h"



Immediately following this code you will see the following lines of code:
/*
 * Local functions.
 */
#define CD CHAR_DATA
#define OD OBJ_DATA
bool    remove_obj      args( (CHAR_DATA *ch, int iWear, bool fReplace ) );
void    wear_obj        args( (CHAR_DATA *ch, OBJ_DATA *obj, bool fReplace ) );
CD *    find_keeper     args( (CHAR_DATA *ch ) );
int     get_cost        args( (CHAR_DATA *keeper, OBJ_DATA *obj, bool fBuy ) );
void    obj_to_keeper   args( (OBJ_DATA *obj, CHAR_DATA *ch ) );
OD *    get_obj_keeper  args( (CHAR_DATA *ch,CHAR_DATA *keeper,char *argument));

#undef OD
#undef  CD



Add the following line of code immediately after the above lines of code:

-- ADD THIS LINE --
void parse_journal(CHAR_DATA *ch, char *argument, int type);


Now scroll all the way to the bottom of act_obj.c add the following code:

-- ADD THESE LINES OF CODE--
void do_journal(CHAR_DATA *ch,char *argument)
{
    parse_journal(ch,argument,NOTE_JOURNAL);
}


void journal_attach( CHAR_DATA *ch, int type )
{
    NOTE_DATA *pnote;

    if ( ch->pnote != NULL )
		return;

    pnote = new_note();
    pnote->next		= NULL;
    pnote->sender	= str_dup( ch->name );
    pnote->date		= str_dup( "" );
    pnote->to_list	= str_dup( "" );
    pnote->subject	= str_dup( "" );
    pnote->text		= str_dup( "" );
    pnote->type		= type;
    ch->pnote		= pnote;
    return;
}


void parse_journal( CHAR_DATA *ch, char *argument, int type )
{
	char arg[MAX_INPUT_LENGTH];
	char buf[MAX_STRING_LENGTH];
   	EXTRA_DESCR_DATA *ed;
    BUFFER *buffer;
    BUFFER *keybuf;
    BUFFER *descbuf;
    OBJ_DATA *obj;
    int x = 0;


	/* Handle IMMs who are switched into MOBs */
	if (IS_NPC(ch))
	{
		send_to_char ( "MOBS can't make journals.\n\r", ch );
		return;
	}

    /* Do we have any ink ?
     * If you decided to not use the INK object, remove this
     * FOR loop.
     */
    for ( obj = ch->carrying; obj; obj = obj->next_content )
    {
		if ( obj->item_type == ITEM_INK )
		    break;
    }

	/* Can't find any ink
	 * If you decided to not use the INK object, remove this
	 * IF statement.
     */
    if ( !obj )
    {
		send_to_char( "You do not have any ink in your inventory.\n\r", ch );
		return;
    }

    /* Do we have a quill?
     * If you decided to not use the QUILL object, remove this
     * FOR loop.
     */
    for ( obj = ch->carrying; obj; obj = obj->next_content )
    {
		if ( obj->item_type == ITEM_QUILL )
		    break;
    }

	/* Can't find a quill
     * If you decided to not use the QUILL object, remove this
     * IF statement.
     */
    if ( !obj )
    {
		send_to_char( "You do not have a quill in your inventory.\n\r", ch );
		return;
    }

	/* Do we have a journal ?
	 * Make sure this FOR loop is always placed after the above two
	 * FOR loops.  Otherwise, the code will think the INK or QUILL
	 * objects are the journal and all extra description info will be
	 * added to the INK or QUILL.
	 */
    for ( obj = ch->carrying; obj; obj = obj->next_content )
    {
		if ( obj->item_type == ITEM_JOURNAL )
	    break;
    }

	/* Can't find a journal */
    if ( !obj )
    {
		send_to_char( "You do not own a journal.  Go purchase one.\n\r", ch );
		return;
    }

    argument = one_argument( argument, arg );
    smash_tilde( argument );

    if ( arg[0] == '\0' )
    {
		send_to_char( "{WSyntax:{x journal <add> <keyword>\n\r", ch );
		send_to_char( "{WSyntax:{x journal + <line of text>\n\r", ch );
		send_to_char( "{WSyntax:{x journal - <line of text>\n\r", ch );
		send_to_char( "{WSyntax:{x journal <show>\n\r", ch );
		send_to_char( "{WSyntax:{x journal <clear>\n\r", ch );
		send_to_char( "{WSyntax:{x journal <post>\n\r", ch );
		return;
    }

    if ( !str_prefix( arg, "add" ) )
    {
		journal_attach( ch, type );

        if (ch->pnote->type != type)
        {
            send_to_char("You already have a different note in progress.\n\r",ch);
            return;
        }

		/* Does the journal already have a journal entry (extra description) ?
		 * If so, is the name of the journal entry being added the same as an
		 * existing journal entry ?  If so, stop and tell the player they can't
		 * do that.
		 *
		 * This loop is also used to count the number of extra descriptions the
		 * journal has.  I set a limit of 10 journal entries per journal.  Afterall,
		 * the journal only has so much paper.  Feel free to remove the limit or
		 * change it to whatever you want.
		 */
	    if ( obj->extra_descr != NULL )
	    {
			for ( ed = obj->extra_descr; ed != NULL; ed = ed->next )
			{
				if ( (ed->keyword == str_dup( argument )) )
				{
					send_to_char( "This journal already has an entry with that name.\n\r", ch );
					return;
				}

				x += 1;
			}
	    }

		if ( x > 9 )
		{
			send_to_char( "You have run out of blank pages in your journal.\n\r", ch );
			send_to_char( "Time to buy a new one.\n\r", ch );
			return;
		}

		free_string( ch->pnote->to_list );
		free_string( ch->pnote->subject );
		ch->pnote->subject = str_dup( argument );
		send_to_char( "Ok.\n\r", ch );
		return;
    }

    if ( !str_cmp( arg, "+" ) )
    {
		journal_attach( ch,type );

		if (ch->pnote->type != type)
		{
		    send_to_char("You already have a different note in progress.\n\r",ch);
		    return;
		}

		if (strlen(ch->pnote->text)+strlen(argument) >= 4096)
		{
		    send_to_char( "Journal entry too long.\n\r", ch );
		    return;
		}

	 	buffer = new_buf();
		add_buf(buffer, ch->pnote->text);
		add_buf(buffer, argument);
		add_buf(buffer,"\n\r");
		free_string( ch->pnote->text );
		ch->pnote->text = str_dup( buf_string(buffer) );
		free_buf(buffer);
		send_to_char( "Ok.\n\r", ch );
		return;
    }

    if (!str_cmp(arg,"-"))
    {
 		int len;
		bool found = FALSE;

		journal_attach(ch,type);

		if (ch->pnote->type != type)
        {
            send_to_char("You already have a different note in progress.\n\r",ch);
            return;
        }

		if (ch->pnote->text == NULL || ch->pnote->text[0] == '\0')
		{
		    send_to_char("No lines left to remove.\n\r",ch);
		    return;
		}

		strcpy(buf,ch->pnote->text);

		for (len = strlen(buf); len > 0; len--)
 		{
		    if (buf[len] == '\r')
		    {
				if (!found)
				{
				    if (len > 0)
					len--;
				    found = TRUE;
				}
				else
				{
				    buf[len + 1] = '\0';
				    free_string(ch->pnote->text);
				    ch->pnote->text = str_dup(buf);
				    return;
				}
		    }
		}

		buf[0] = '\0';
		free_string(ch->pnote->text);
		ch->pnote->text = str_dup(buf);
		return;
    }

    if ( !str_prefix( arg, "clear" ) )
    {
		if ( ch->pnote != NULL )
		{
		    free_note(ch->pnote);
		    ch->pnote = NULL;
		}

		send_to_char( "Ok.\n\r", ch );
		return;
    }

    if ( !str_prefix( arg, "show" ) )
    {
		if ( ch->pnote == NULL )
		{
		    send_to_char( "You have no journal entry in progress.\n\r", ch );
		    return;
		}

		if (ch->pnote->type != type)
		{
		    send_to_char("You aren't working on that kind of note.\n\r",ch);
		    return;
		}

	    send_to_char( "Journal Entry: ", ch );
		send_to_char( ch->pnote->subject, ch );
	    send_to_char( "\n\r\n\r", ch );
		send_to_char( ch->pnote->text, ch );
		return;
    }

    if ( !str_prefix( arg, "post" ) )
    {
		if ( ch->pnote == NULL )
		{
		    send_to_char( "You have no journal entry in progress.\n\r", ch );
		    return;
		}

        if (ch->pnote->type != type)
        {
            send_to_char("You aren't working on that kind of note.\n\r",ch);
            return;
        }

		/* The following lines of code attach the name of the journal entry
		 * to the extra description as the keyword and also adds all the text
		 * entered by the player to the description of the keyword.
		 */
		ed = new_extra_descr();
		keybuf = new_buf();
		add_buf ( keybuf, ch->pnote->subject );
		ed->keyword = str_dup( buf_string( keybuf ) );
		buffer = new_buf();
		sprintf( buf, "Author: %s\n\r\n\r", ch->name );
   		add_buf( buffer, buf );
   		add_buf( buffer, ch->pnote->text );
		ed->description = str_dup( buf_string( buffer ) );
		ed->next = obj->extra_descr;
		obj->extra_descr = ed;


		/* The following lines of code modify the journals long description.
		 * It adds the name of the journal entry to the long description which
		 * allows players to look at the journal and see what journal entries
		 * have been made to the journal.
		 */
		descbuf = new_buf();
		sprintf( buf, obj->description );
		free_string( obj->description );
		add_buf( descbuf, buf );
		sprintf( buf, "\n\rJournal Entry: {c%s{x\n\r", ch->pnote->subject );
		add_buf( descbuf, buf );
		obj->description = str_dup( buf_string( descbuf ) );
		free_buf( descbuf );
		free_buf( buffer );
		free_buf( keybuf );
		ch->pnote = NULL;
		send_to_char("Your journal entry has been posted.\n\r",ch);
		return;
    }

	send_to_char( "{WSyntax:{x journal <add> <keyword>\n\r", ch );
	send_to_char( "{WSyntax:{x journal + <line of text>\n\r", ch );
	send_to_char( "{WSyntax:{x journal - <line of text>\n\r", ch );
	send_to_char( "{WSyntax:{x journal <show>\n\r", ch );
	send_to_char( "{WSyntax:{x journal <clear>\n\r", ch );
	send_to_char( "{WSyntax:{x journal <post>\n\r", ch );
	return;
}


Save and close act_obj.c
Delete all of your .O files and a recompile.  You're done.

You will want to make the INK, QUILL and JOURNAL objects for sale by some of
your shopkeeper mobs.  If you have no idea how to add resets (Why not ??), get
your builder to do it, or actually read the docs that come with ROM :).

If you have any problems installing this code, you can reach me at information
listed at the top of this file.


The following is the associated help file entry for the journal code.


-1 JOURNALS~
.
Syntax: journal <add> <keyword>
        journal + <line of text>
        journal - <line of text>
        journal <show>
        journal <clear>
        journal <post>

The journal command allows you to create you own personal journal entries
and save them to a journal.  You can purchase a journal and the necessary
ink and quill from many stores in the three major cities of Amaron.

The journal command functions very similar to the note system.  Use the
add command to add a new journal entry.  Ex: {cjournal add Page1{x.
To add lines of text to the journal entry "Page1", use the {cjournal +{x
command.  Ex: journal + It was a dark and stormy night.

The {cjournal -{x command will remove the last line of text entered and
{cjournal clear{x will remove and clear the entire journal entry and all
lines of text that were entered.

The {cjournal show{x command will display the name of the journal entry
and the current text that has been entered.  Ex: {cjournal show{x

Journal Entry: Page1

It was a dark and stormy night.

Once you are satisfied with your journal entry, use the {cjournal post{x
command to save the journal entry into your journal.  You can save a maximum
of ten (10) journal entries to one journal.  Also keep in mind you cannot
add a journal entry if the same name already has been used in the journal.
So, you cannot have to entries called "Page1".

When you wish to read a journal entry, look at the journal.  Ex: look journal.
You will a description similar to the following:

A leather journal with many pages of writing.
Journal Entry: Page1

Journal Entry: Page2

This will tell you what journal entries are contained in this journal.  To
read them, look at a journal entries name.  Ex: look Page1


Journal Code written by Felix of Amaron Mud.
~

