/*
 * This is a little utility I wrote when we were reorganizing our areas
 * and managed to lose our map.  What is does is list all the links to
 * different areas from one area, including rooms and directions.  I also
 * has the option to dump everything to a text file to look over, though
 * you may want to disable this capability to avoid filling up your area
 * directory with a bunch of junk.  To install it, there are just a couple
 * of changes you need to make.  First after the following lines in
 * merc.h:
 *	extern          HELP_DATA         *     help_first;
 *	extern          HELP_DATA         *     help_last;
 *	extern          SHOP_DATA         *     shop_first;
 * add the following line:
 *	extern          AREA_DATA         *     area_first;
 *
 * And, after these lines in merc.h:
 *	extern          TIME_INFO_DATA          time_info;
 *	extern          WEATHER_DATA            weather_info;
 * add this line:
 *	extern          ROOM_INDEX_DATA   *	room_index_hash[MAX_KEY_HASH];
 *
 * Add the following line to interp.h
 *	DECLARE_DO_FUN( do_arealinks    );
 *
 * In interp.c after the following line:
 *	{ "advance",	do_advance,     POS_DEAD,       ML, LOG_ALWAYS, 1 },
 * add this line:
 *	{ "arealinks",  do_arealinks,   POS_DEAD,       ML, LOG_NORMAL, 1 },
 *
 * Then, just paste the function below at the bottom of some file,
 * probably act_wiz.c would be most appropriate.
 *
 * Alternately, you could just paste the function at the bottom of db.c
 * and avoid the above changes to merc.h, but that leaves your code kind
 * of disorganized.
 *
 * Finally do a clean make (rm *.o, followed by make) and start her up,
 * then check links to your heart's content.
 *
 * I've also provided a help entry at the bottom of this file that you can
 * add for convenience.  Note that I have this set up as an Implementor
 * level command because of the file output capability.  You can change the
 * help entry and interp.c entry to comply to whatever level you want to
 * make it available at.
 *
 * You don't have to give me credit or anything since I plastered my name
 * all over the help entry, but any kudos would be appreciated.  If you
 * want, you can also e-mail and tell me you're using this piece of code,
 * but I don't require that either.  If you have any questions about this
 * code you can e-mail and i'll try to respond but I won't promise a
 * response.  If you find any bugs please e-mail me and I'll try and get
 * those fixed ASAP.  Right now the biggest potential problem I see is
 * that I do absolutely no checking on the provided filename.  That about
 * covers it, enjoy.
 *
 *		Kyless
 *		slaughterdog@yahoo.com
 *		The Mind's Eye
 *		mindeye.mudservices.com 7777 (for now)
 *		mindeye.mudrealms.net 7777 (if the first one doesn't work)
 */

void do_arealinks(CHAR_DATA *ch, char *argument)
{
    FILE *fp;
    BUFFER *buffer;
    AREA_DATA *parea;
    EXIT_DATA *pexit;
    ROOM_INDEX_DATA *to_room;
    ROOM_INDEX_DATA *from_room;
    char buf[MAX_STRING_LENGTH];
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    int vnum = 0;
    int iHash, door;
    bool found = FALSE;

    /* To provide a convenient way to translate door numbers to words */
    static char * const dir_name[] = {"north","east","south","west","up","down"};

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

    /* First, the 'all' option */
    if (!str_cmp(arg1,"all"))
    {
	/*
	 * If a filename was provided, try to open it for writing
	 * If that fails, just spit output to the screen.
	 */
	if (arg2[0] != '\0')
	{
	    fclose(fpReserve);
	    if( (fp = fopen(arg2, "w")) == NULL)
	    {
		send_to_char("Error opening file, printing to screen.\n\r",ch);
		fclose(fp);
		fpReserve = fopen(NULL_FILE, "r");
		fp = NULL;
	    }
	}
	else
	    fp = NULL;

	/* Open a buffer if it's to be output to the screen */
	if (!fp)
	    buffer = new_buf();

	/* Loop through all the areas */
	for (parea = area_first; parea != NULL; parea = parea->next)
	{
	    /* First things, add area name  and vnums to the buffer */
	    sprintf(buf, "*** %s (%d to %d) ***\n\r",
			 parea->name, parea->min_vnum, parea->max_vnum);
	    fp ? fprintf(fp, buf) : add_buf(buffer, buf);

	    /* Now let's start looping through all the rooms. */
	    found = FALSE;
	    for(iHash = 0; iHash < MAX_KEY_HASH; iHash++)
	    {
		for( from_room = room_index_hash[iHash];
		     from_room != NULL;
		     from_room = from_room->next )
		{
		    /*
		     * If the room isn't in the current area,
		     * then skip it, not interested.
		     */
		    if ( from_room->vnum < parea->min_vnum
		    ||   from_room->vnum > parea->max_vnum )
			continue;

		    /* Aha, room is in the area, lets check all directions */
		    for (door = 0; door < 5; door++)
		    {
			/* Does an exit exist in this direction? */
			if( (pexit = from_room->exit[door]) != NULL )
			{
			    to_room = pexit->u1.to_room;

			    /*
			     * If the exit links to a different area
			     * then add it to the buffer/file
			     */
			    if( to_room != NULL
			    &&  (to_room->vnum < parea->min_vnum
			    ||   to_room->vnum > parea->max_vnum) )
			    {
				found = TRUE;
				sprintf(buf, "    (%d) links %s to %s (%d)\n\r",
				    from_room->vnum, dir_name[door],
				    to_room->area->name, to_room->vnum);

				/* Add to either buffer or file */
				if(fp == NULL)
				    add_buf(buffer, buf);
				else
				    fprintf(fp, buf);
			    }
			}
		    }
		}
	    }

	    /* Informative message for areas with no external links */
	    if (!found)
		add_buf(buffer, "    No links to other areas found.\n\r");
	}

	/* Send the buffer to the player */
	if (!fp)
	{
	    page_to_char(buf_string(buffer), ch);
	    free_buf(buffer);
	}
	/* Or just clean up file stuff */
	else
	{
	    fclose(fp);
	    fpReserve = fopen(NULL_FILE, "r");
	}

	return;
    }

    /* No argument, let's grab the char's current area */
    if(arg1[0] == '\0')
    {
	parea = ch->in_room ? ch->in_room->area : NULL;

	/* In case something wierd is going on, bail */
	if (parea == NULL)
	{
	    send_to_char("You aren't in an area right now, funky.\n\r",ch);
	    return;
	}
    }
    /* Room vnum provided, so lets go find the area it belongs to */
    else if(is_number(arg1))
    {
	vnum = atoi(arg1);

	/* Hah! No funny vnums! I saw you trying to break it... */
	if (vnum <= 0 || vnum > 65536)
	{
	    send_to_char("The vnum must be between 1 and 65536.\n\r",ch);
	    return;
	}

	/* Search the areas for the appropriate vnum range */
	for (parea = area_first; parea != NULL; parea = parea->next)
	{
	    if(vnum >= parea->min_vnum && vnum <= parea->max_vnum)
		break;
	}

	/* Whoops, vnum not contained in any area */
	if (parea == NULL)
	{
	    send_to_char("There is no area containing that vnum.\n\r",ch);
	    return;
	}
    }
    /* Non-number argument, must be trying for an area name */
    else
    {
	/* Loop the areas, compare the name to argument */
	for(parea = area_first; parea != NULL; parea = parea->next)
	{
	    if(!str_prefix(arg1, parea->name))
		break;
	}

	/* Sorry chum, you picked a goofy name */
	if (parea == NULL)
	{
	    send_to_char("There is no such area.\n\r",ch);
	    return;
	}
    }

    /* Just like in all, trying to fix up the file if provided */
    if (arg2[0] != '\0')
    {
	fclose(fpReserve);
	if( (fp = fopen(arg2, "w")) == NULL)
	{
	    send_to_char("Error opening file, printing to screen.\n\r",ch);
	    fclose(fp);
	    fpReserve = fopen(NULL_FILE, "r");
	    fp = NULL;
	}
    }
    else
	fp = NULL;

    /* And we loop the rooms */
    for(iHash = 0; iHash < MAX_KEY_HASH; iHash++)
    {
	for( from_room = room_index_hash[iHash];
	     from_room != NULL;
	     from_room = from_room->next )
	{
	    /* Gotta make sure the room belongs to the desired area */
	    if ( from_room->vnum < parea->min_vnum
	    ||   from_room->vnum > parea->max_vnum )
		continue;

	    /* Room's good, let's check all the directions for exits */
	    for (door = 0; door < 5; door++)
	    {
		if( (pexit = from_room->exit[door]) != NULL )
		{
		    to_room = pexit->u1.to_room;

		    /* Found an exit, does it lead to a different area? */
		    if( to_room != NULL
		    &&  (to_room->vnum < parea->min_vnum
		    ||   to_room->vnum > parea->max_vnum) )
		    {
			found = TRUE;
			sprintf(buf, "%s (%d) links %s to %s (%d)\n\r",
				    parea->name, from_room->vnum, dir_name[door],
				    to_room->area->name, to_room->vnum);

			/* File or buffer output? */
			if(fp == NULL)
			    send_to_char(buf, ch);
			else
			    fprintf(fp, buf);
		    }
		}
	    }
	}
    }

    /* Informative message telling you it's not externally linked */
    if(!found)
    {
	send_to_char("No links to other areas found.\n\r",ch);
	/* Let's just delete the file if no links found */
	if (fp)
	    unlink(arg2);
	return;
    }

    /* Close up and clean up file stuff */
    if(fp)
    {
	fclose(fp);
	fpReserve = fopen(NULL_FILE, "r");
    }

}


/************ EMAIL FROM THE ROMLIST *****************/
Arealinks Snippet Fix
From: Leath Chad CL <cleath@visteon.com>
To: 'romromorg' <rom@rom.org>
Date: Thu, 01 Feb 2001 10:52:53 -0500


I know that this is not a major issue and that almost anyone could figure it
out, but if you were not looking for it you might miss it.
What I am talking about is the fact that this snippet (Arealinks) does not
search all directions.
To fix this you need to change two sections of the code where:: door < 5  ::
appears and change it to:: door < 6 ::
I just wanted to let everyone know in case you downloaded the snippet from
Kyndig's site. 

I know that this is not a major issue or major fix but just something that
you might over look :)
/****************END EMAIL ****************************/

/**** Here is the help entry ****/

60 AREALINKS~
Provided to you by Kyless of The Mind's Eye (slaughterdog@yahoo.com).

Syntax: arealinks [vnum|area|all] [filename]

AREALINKS, with no arguments, gives a listing of all of the rooms that
link to a different area from the area you are currently in.

AREALINKS with a room vnum provided will provide all links from the
area that the vnum is in.  Note that the room does not have to exist, but
merely has to be a vnum within the area's vnum range.

AREALINKS with an area name will list all of the links to different areas
for that area.

AREALINKS with the all option will list the areas one by one, their vnum
ranges, and all their links to different areas.

AREALINKS also provides an optional filename argument which allows you to
output all of the information into a file in the area directory in
the shell rather that outputting it to the screen.  Of course, you still
need shell access to be able to read the file created.

This function and help file were originally written by Kyless on The
Mind's Eye (slaughterdog@yahoo.com).
~

