/*
--------------------------------------------------------------------------------
 This snippet will enable your mobiles to keep track of an instanced dialogue
 for each character.  It's similar to mpstatus, but, again, instanced to each
 player character.  As with any other snippet, I urge you to read it carefully
 and make sure you know how it works before installing it.
--------------------------------------------------------------------------------
mob_prog.c
----------
Add this with your other defines.

#define CHK_DIALOGUE    (52)
Modify the numerical value to suit your needs.

Now, in the list of if-check keywords:
    "dialogue",        //if dialogue $n == 2 - dialogue stage check

Add this to the bottom of the last cmd_eval switch:
 (mine is right below the CHK_GRPSIZE case)

    case CHK_DIALOGUE:
        if (lval_char != NULL)
		{
			sh_int dlg;

			one_argument (line, buf);

			if (!is_number (buf))
				dlg = 0;
			else
				dlg = atoi (buf);

			if (dlg < 0 || dlg > 24)
				return dlg = 0;

			lval = check_stage_char (mob, lval_char, dlg);
		}
        break;

mob_cmds.c/h
------------
Add a table entry for the mpdialogue command and a DECLARE_DO_FUN() for it.


merc.h
------
Add this with your other typedefs:
typedef struct    dialogue         DIALOGUE;

Add this structure anywhere:
struct dialogue
{
	DIALOGUE *	next;
	bool		valid;
	CHAR_DATA * victim;
	sh_int		stage[25];
};

Add the following to struct char_data:
	DIALOGUE *		   dialogues;

Finally, add the following prototypes:

// dialogue.c
int			check_stage_char	(CHAR_DATA * ch, CHAR_DATA * vch, int dlg);
DIALOGUE *	get_dialogue		(CHAR_DATA * ch, CHAR_DATA * vch);
DIALOGUE *	new_dialogue		(void);
void		free_dialogue		(DIALOGUE * dialogue);

--------------------------------------------------------------------------------
Now, add dialogue.c to your source directory and recompile.
--------------------------------------------------------------------------------
This code is provided as-is without any warranty.  It should work fine, but I'm
not responsible if something goes wrong (as things always do with mprogs).  Any
credit or feedback is much appreciated, but not required.
                                 Enjoy!  -- Midboss (eclipsing.souls@gmail.com)
--------------------------------------------------------------------------------
Here is a sample program, using mpdialogue:

if dialogue $n == 0
say Ok, we shall begin...
mob dialogue $n 1
break
endif
if dialogue $n == 1
say This is the first stage..
mob dialogue $n 2
break
endif
if dialogue $n == 2
say This is the second stage..
mob dialogue $n 3
break
endif
if dialogue $n == 3
say This is the final stage..
mob dialogue $n clear
break
endif

*/

/***************************************************************************
 * This code may be used freely within any non-commercial MUD, all I ask   *
 * is that these comments remain in tact and that you give me any feedback *
 * or bug reports you come up with.  Credit in a helpfile might be nice,   *
 * too.                             -- Midboss (eclipsing.souls@gmail.com) *
 ***************************************************************************/
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "merc.h"

/*
 * Sets the 'stage' of an mobile's prog.  Useful for quests and extended
 * dialogues via a 'talk' command.
 *
 * Syntax: mob dialogue <victim> <new stage|clear> [which]
 */
void do_mpdialogue (CHAR_DATA * ch, char *argument)
{
    char arg[MIL], arg2[MIL];
    CHAR_DATA *victim;
	DIALOGUE *dialogue;
	sh_int iDlg;

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

	//If your MUD has o/rprogs installed, remove the NULL arg.
    if ((victim = get_char_room (ch, NULL, arg)) == NULL)
        return;


	if (argument[0] != '\0' && is_number (argument))
		iDlg = atoi (argument);
	else
		iDlg = 0;

	if (iDlg < 0 || iDlg > 24)
	{
        bug ("MpDialogue: Bad dialogue from vnum %d.",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
	}


	//Make sure there's an argument.
	if (arg2[0] == '\0')
	{
        bug ("MpDialogue: No argument from vnum %d.",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
	}
	//mob dialogue [victim] clear
	if (!str_cmp (arg2, "clear"))
	{
		//No dialogue found.
		if ((dialogue = get_dialogue (ch, victim)) == NULL)
		{
			bug ("MpDialogue: No dialogue to clear from vnum %d.",
				 IS_NPC (ch) ? ch->pIndexData->vnum : 0);
			return;
		}

		//Remove it.
		if (dialogue == ch->dialogues)
			ch->dialogues = dialogue->next;
		else
		{
			DIALOGUE *prev;

			for (prev = ch->dialogues; prev != NULL; prev = prev->next)
				if (prev->next == dialogue)
				{
					prev->next = dialogue->next;
					break;
				}
		}

		//Free the struct.
		free_dialogue (dialogue);
		return;
	}
	//mob dialogue [victim] ##
	else if (is_number (arg2))
	{
		int stage = atoi (arg2);

		//Dialogue exists.
		if ((dialogue = get_dialogue (ch, victim)) != NULL)
			dialogue->stage[iDlg] = stage;
		//Create new dialogue.
		else
		{
			dialogue			  = new_dialogue ();
			dialogue->victim	  = victim;
			dialogue->stage[iDlg] = stage;
			dialogue->next		  = ch->dialogues;
			ch->dialogues		  = dialogue;
		}
		return;
	}
	else
	{
        bug ("MpDialogue: Bad argument from vnum %d.",
             IS_NPC (ch) ? ch->pIndexData->vnum : 0);
        return;
	}
    return;
}

/*
 * Checks a character's dialogue stage.
 */
int check_stage_char (CHAR_DATA * ch, CHAR_DATA * vch, int dlg)
{
	DIALOGUE * dialogue;

	if ((dialogue = get_dialogue (ch, vch)) != NULL)
		return dialogue->stage[dlg];
	
	return 0;
}


/* 
 * Grabs player vch's dialogue from mobile ch's list.
 */
DIALOGUE *get_dialogue (CHAR_DATA * ch, CHAR_DATA * vch)
{
	DIALOGUE * dialogue;

	for (dialogue = ch->dialogues; dialogue != NULL; dialogue = dialogue->next)
		if (dialogue->victim == vch)
			return dialogue;

	return NULL;
}

/* recycling stuff for mpdialogue */
DIALOGUE *dialogue_free;

DIALOGUE *new_dialogue (void)
{
    static DIALOGUE dialogue_zero;
    DIALOGUE *dialogue;

    if (dialogue_free == NULL)
        dialogue = alloc_perm (sizeof (*dialogue));
    else
    {
        dialogue = dialogue_free;
        dialogue_free = dialogue_free->next;
    }

    *dialogue = dialogue_zero;
    VALIDATE (dialogue);

	dialogue->victim = NULL;
	bzero (dialogue->stage, sizeof(dialogue->stage));

    return dialogue;
}

void free_dialogue (DIALOGUE * dialogue)
{
    if (!IS_VALID (dialogue))
        return;

	INVALIDATE (dialogue);

    dialogue->next = dialogue_free;
    dialogue_free  = dialogue;
}