/*******************************************************************************
Save this file to your ./src directory, and if necessary, add zoom.o to your
Makefile.  Now, follow the rest of these instructions...
-------------------------------------------------------------------------merc.h-
Add this with your other maxes:

#define MAX_ZOOM           21


Now, add this to struct pc_data:

	bool			can_zoom[MAX_ZOOM];


Add this with your other GSNs:

extern    sh_int    gsn_zoom;
------------------------------------------------------------------------magic.h-
Add this to the bottom of the file.

DECLARE_SPELL_FUN(	spell_zoom			);
------------------------------------------------------------------------const.c-
Add this to your skill table.

    {
     "zoom", {25, 30, 40, 50}, {2, 3, 4, 4},
     spell_zoom, TAR_IGNORE, POS_STANDING,
     &gsn_zoom, SLOT (0), 10, 12,
     "", "!Zoom!", ""},
---------------------------------------------------------------------act_move.c-
At the top, add this:

extern int			zoom_vnum[MAX_ZOOM];
extern char * const zoom_name[MAX_ZOOM];


In the function move_char(), after the char_to_room() call:

	if (!IS_NPC(ch))
	{
		char buf[MSL];
		int i;

		for (i = 0; i < MAX_ZOOM; i++)
		{
			if (zoom_vnum[i] == ch->in_room->vnum
				&& !ch->pcdata->can_zoom[i]
				&& get_skill (ch, gsn_zoom) > 0)
			{
				ch->pcdata->can_zoom[i] = TRUE;
				sprintf (buf, "You have discovered a new Zoom"
							  " location to: %s!\n\r", zoom_name[i]);
				send_to_char (buf, ch);
				break;
			}
		}
	}
-------------------------------------------------------------------------save.c-
Tind this bit of code in fwrite_char():

    if (IS_NPC (ch))
    {
        fprintf (fp, "Vnum %d\n", ch->pIndexData->vnum);
    }
    else
    {


Anywhere within that else statement, add this block of code:

		fprintf (fp, "Zoom");
		for (i = 0; i < MAX_ZOOM; i++)
			fprintf (fp, " %d", ch->pcdata->can_zoom[i]);
		fprintf (fp, "\n");


Now, in fread_char(), create a 'Z' case:

            case 'Z':
                if (!str_cmp (word, "Zoom"))
                {
					int zoom;

					for (zoom = 0; zoom < MAX_ZOOM; zoom++)
						ch->pcdata->can_zoom[zoom] = fread_number (fp);

                    fMatch = TRUE;
                    break;
                }
				break;
---------------------------------------------------------------------------db.c-
Add this to your other GSNs:

sh_int gsn_zoom;
--------------------------------------------------------------------------------
If you followed those instructions, everything should be working.  Go ahead and
cut off these instructions, you're done.  Here is a default helpfile, if you
don't wish to write your own:

-1 'ZOOM'~
Syntax: cast 'zoom' <place>

The Zoom spell will instantly take you to a number of predefined places, if
you've visited them in the past.  When you find a new Zoom target, you will
be notified.  But be warned; no matter how hard your head, you can't fly
through the ceiling.
~

*******************************************************************************/

/***************************************************************************
 * You may use this code as you see fit within any non-commercial MUD.     *
 * My only conditions are that my comments remain in tact, that you do not *
 * hesitate to give me feedback on the code, and that you don't claim my   *
 * work as your own.  Enjoy.           .                        -- Midboss *
 * *********************************************************************** *
 * "Zoom" spell for instant transportation to predefined locations.        *
 ***************************************************************************/
#include <stdio.h>
#include <string.h>
#include "merc.h"
#include "interp.h"

/*
 * Comment this out if you want the spell to only transport the user.
 */
#define GROUP

/*
 * From magic.c.
 */
extern char *target_name;

/*
 * The zoom location stuff.  It's set up for the stock ROM areas, so adjust
 * the values to fit your MUD's world.
 */
char * const zoom_name[MAX_ZOOM] = {
	"Midgaard",	"New Thalos", "",
	"", "", "", "", "", "", "", "", "",
	"", "", "", "", "", "", "", "", ""
};

int zoom_vnum[MAX_ZOOM] = {
	 3001,  9506,     0,     0,     0,     0,     0,
	    0,     0,     0,     0,     0,     0,     0,   
	    0,     0,     0,     0,     0,     0,     0
};

int zoom_cost[MAX_ZOOM] = {
	  5,   5,   0,   0,   0,   0,   0,
	  0,   0,   0,   0,   0,   0,   0,   
	  0,   0,   0,   0,   0,   0,   0
};

/*
 * The 'zoom' spell.  It will take a player (or his group) to an area of his
 * or her choosing, but only to a predefined vnum within that area, and only
 * to specific areas.  Additionally, the player must have been to the area at
 * least once before to zoom to it.
 */
void spell_zoom (int sn, int level, CHAR_DATA * ch, void *vo, int target)
{
#ifdef GROUP
	CHAR_DATA * gch, * gch_next;
#endif
	int i, where = -1;
	int members = 1;
	ROOM_INDEX_DATA * to_room, * was_in;

	if (IS_NPC (ch))
	{
		send_to_char ("Your spell fizzled.\n\r", ch);
		return;
	}

	/*
	 * Let's see if we can find a location.
	 */
	for (i = 0; i < MAX_ZOOM; i++)
	{
		if ((ch->pcdata->can_zoom[i] || IS_IMMORTAL (ch))
			&& !str_prefix (target_name, zoom_name[i]))
		{
			where = i;
			break;
		}
	}

	to_room = get_room_index (zoom_vnum[where]);
	was_in = ch->in_room;

	/*
	 * Make sure there was a proper argument, a location was found, the 
	 * destination room isn't NULL, and we aren't zooming in a circle.
	 */
	if (target_name[0] == '\0' || where == -1
		|| to_room == NULL || to_room == was_in)
	{
		/*
		 * Hit Z or R twice!
		 */
        act ("You fly into the air and do a barrel roll.",
				ch, NULL, NULL, TO_CHAR);
        act ("$n flies into the air and does a barrel roll.",
				ch, NULL, NULL, TO_ROOM);
		return;
	}

	/*
	 * Make sure the character has enough MP.  Checks for other members, 
	 * if needed.
	 */
#ifdef GROUP
	for (gch = ch->in_room->people; gch != NULL; gch = gch->next_in_room)
		if (is_same_group (gch, ch) && gch != ch)
			++members;
#endif

	if (ch->mana < members * zoom_cost[where])
	{
		ch->mana = 0;

        act ("You fly about aimlessly for a moment,"
			 " and forget where you were going.", ch, NULL, NULL, TO_CHAR);
        act ("You flies about aimlessly for a moment.",
			 ch, NULL, NULL, TO_CHAR);
		return;
	}

	/*
	 * Deduct the mana cost.
	 */
	ch->mana = UMAX (0, ch->mana - members * zoom_cost[where]);

	/*
	 * We can't fly through the ceiling, can we?
	 */
	if (!IS_SET(ch->in_room->room_flags, ROOM_INDOORS))
	{
		act ("You zoom head-first into the ceiling!",
				ch, NULL, NULL, TO_CHAR);
		act ("$n zooms head-first into the ceiling!",
				ch, NULL, NULL, TO_ROOM);
		ch->hit = UMAX (1, ch->hit - (ch->max_hit * 5 / 100));
		return;
	}

	/*
	 * Now transport the character, and if necessary, his or her party.
	 */
    act ("You hover in the air for a second, then zoom into the sky.",
			ch, NULL, NULL, TO_CHAR);
    act ("$n hovers in the air for a second, then zooms into the sky.",
			ch, NULL, NULL, TO_ROOM);

    char_from_room (ch);
    char_to_room (ch, to_room);

    act ("$n suddenly descends from the sky and lands.",
			ch, NULL, NULL, TO_ROOM);
    do_function (ch, &do_look, "auto");

#ifdef GROUP
	for (gch = was_in->people; gch != NULL; gch = gch_next)
	{
		gch_next = gch->next_in_room;

		if (is_same_group (gch, ch) && gch != ch)
		{
			act ("You zoom into the sky after $N.",
					gch, NULL, ch, TO_CHAR);
			act ("$n zooms into the sky after $N.",
					gch, NULL, ch, TO_ROOM);
			char_from_room (gch);
			char_to_room (gch, to_room);

			act ("$n suddenly descends from the sky and lands.",
					gch, NULL, NULL, TO_ROOM);
			do_function (gch, &do_look, "auto");
		}
	}
#endif
	return;
}

/*
 * Simple command to list all known zoom locations.  If you want your
 * MUD's users to have access to it, remember to add the command entry
 * and declaration to interp.c and interp.h respectively.
 */
void do_zoomlist (CHAR_DATA * ch, char * argument)
{
	char buf[MSL];
	int i, show = 0;

	if (IS_NPC (ch))
		return;

	if (get_skill (ch, gsn_zoom) < 1)
	{
		send_to_char ("Huh?\n\r", ch);
		return;
	}

	buf[0] = '\0';

	for (i = 0; i < MAX_ZOOM; i++)
	{
		if ((IS_IMMORTAL (ch) || ch->pcdata->can_zoom[i])
			&& zoom_name[i][0] != '\0')
		{
			++show;
			sprintf (buf + strlen (buf), "%-25s  %3dmp%s",
					zoom_name[i], zoom_cost[i],
					show % 2 == 0 ? "\n\r" : "      ");
		}
	}

	if (show < 1)
	{
		send_to_char ("You know of no Zoom locations.\n\r", ch);
		return;
	}
	
	send_to_char ("You know of the following Zoom locations:\n\r", ch);
	send_to_char (buf, ch);
}