1stMud4.5.3/
1stMud4.5.3/backup/
1stMud4.5.3/bin/
1stMud4.5.3/bin/extras/
1stMud4.5.3/data/i3/
1stMud4.5.3/doc/1stMud/
1stMud4.5.3/doc/Diku/
1stMud4.5.3/doc/MPDocs/
1stMud4.5.3/doc/Rom/
1stMud4.5.3/notes/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*          1stMud ROM Derivative (c) 2001-2004 by Markanth                *
*            http://www.firstmud.com/  <markanth@firstmud.com>            *
*         By using this code you have agreed to follow the term of        *
*             the 1stMud license in ../doc/1stMud/LICENSE                 *
***************************************************************************/

#include "merc.h"
#include "interp.h"
#include "tables.h"

RoomIndex *get_random_room(CharData * ch)
{
	RoomIndex *room;

	for (;;)
	{
		room = get_room_index(number_range(0, 65535));
		if (room != NULL)
			if (can_see_room(ch, room) && !room_is_private(room)
				&& !IsSet(room->room_flags, ROOM_PRIVATE)
				&& !IsSet(room->room_flags, ROOM_SOLITARY)
				&& !IsSet(room->area->area_flags, AREA_CLOSED)
				&& !IsSet(room->room_flags, ROOM_ARENA)
				&& !IsSet(room->room_flags, ROOM_SAFE) && (IsNPC(ch)
														   || IsSet(ch->act,
																	ACT_AGGRESSIVE)
														   ||
														   !IsSet
														   (room->room_flags,
															ROOM_LAW)))
				break;
	}

	return room;
}

Do_Fun(do_enter)
{
	RoomIndex *location;

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

	if (!NullStr(argument))
	{
		RoomIndex *old_room;
		ObjData *portal;
		CharData *fch, *fch_next;

		old_room = ch->in_room;

		portal = get_obj_list(ch, argument, ch->in_room->content_first);

		if (portal == NULL)
		{
			chprintln(ch, "You don't see that here.");
			return;
		}

		if (portal->item_type != ITEM_PORTAL
			|| (IsSet(portal->value[1], EX_CLOSED) && !IsTrusted(ch, ANGEL)))
		{
			chprintln(ch, "You can't seem to find a way in.");
			return;
		}

		if (!IsTrusted(ch, ANGEL) && !IsSet(portal->value[2], GATE_NOCURSE)
			&& (IsAffected(ch, AFF_CURSE)
				|| IsSet(old_room->room_flags, ROOM_NO_RECALL)))
		{
			chprintln(ch, "Something prevents you from leaving...");
			return;
		}

		if (IsSet(portal->value[2], GATE_RANDOM) || portal->value[3] == -1)
		{
			location = get_random_room(ch);
			portal->value[3] = location->vnum;
		}
		else if (IsSet(portal->value[2], GATE_BUGGY)
				 && (number_percent() < 5))
			location = get_random_room(ch);
		else
			location = get_room_index(portal->value[3]);

		if (location == NULL || location == old_room
			|| !can_see_room(ch, location) || (room_is_private(location)
											   && !IsTrusted(ch,
															 IMPLEMENTOR)))
		{
			act("$p doesn't seem to go anywhere.", ch, portal, NULL, TO_CHAR);
			return;
		}

		if (IsNPC(ch) && IsSet(ch->act, ACT_AGGRESSIVE)
			&& IsSet(location->room_flags, ROOM_LAW))
		{
			chprintln(ch, "Something prevents you from leaving...");
			return;
		}

		act("$n steps into $p.", ch, portal, NULL, TO_ROOM);

		if (IsSet(portal->value[2], GATE_NORMAL_EXIT))
			act("You enter $p.", ch, portal, NULL, TO_CHAR);
		else
			act("You walk through $p and find yourself somewhere else...", ch,
				portal, NULL, TO_CHAR);

		char_from_room(ch);
		char_to_room(ch, location);

		if (IsSet(portal->value[2], GATE_GOWITH))
		{
			obj_from_room(portal);
			obj_to_room(portal, location);
		}

		if (IsSet(portal->value[2], GATE_NORMAL_EXIT))
			act("$n has arrived.", ch, portal, NULL, TO_ROOM);
		else
			act("$n has arrived through $p.", ch, portal, NULL, TO_ROOM);

		do_function(ch, &do_look, "auto");

		if (portal->value[0] > 0)
		{
			portal->value[0]--;
			if (portal->value[0] == 0)
				portal->value[0] = -1;
		}

		if (old_room == location)
			return;

		for (fch = old_room->person_first; fch != NULL; fch = fch_next)
		{
			fch_next = fch->next_in_room;

			if (portal == NULL || portal->value[0] == -1)

				continue;

			if (fch->master == ch && IsAffected(fch, AFF_CHARM)
				&& fch->position < POS_STANDING)
				do_function(fch, &do_stand, "");

			if (fch->master == ch && fch->position == POS_STANDING)
			{

				if (IsSet(ch->in_room->room_flags, ROOM_LAW)
					&& (IsNPC(fch) && IsSet(fch->act, ACT_AGGRESSIVE)))
				{
					act("You can't bring $N into the city.", ch, NULL, fch,
						TO_CHAR);
					act("You aren't allowed in the city.", fch, NULL, NULL,
						TO_CHAR);
					continue;
				}

				act("You follow $N.", fch, NULL, ch, TO_CHAR);
				do_function(fch, &do_enter, argument);
			}
		}

		if (portal != NULL && portal->value[0] == -1)
		{
			act("$p fades out of existence.", ch, portal, NULL, TO_CHAR);
			if (ch->in_room == old_room)
				act("$p fades out of existence.", ch, portal, NULL, TO_ROOM);
			else if (old_room->person_first != NULL)
			{
				act("$p fades out of existence.", old_room->person_first,
					portal, NULL, TO_CHAR);
				act("$p fades out of existence.", old_room->person_first,
					portal, NULL, TO_ROOM);
			}
			extract_obj(portal);
		}

		if (IsNPC(ch) && HasTriggerMob(ch, TRIG_ENTRY))
			p_percent_trigger(ch, NULL, NULL, NULL, NULL, NULL, TRIG_ENTRY);
		if (!IsNPC(ch))
		{
			p_greet_trigger(ch, PRG_MPROG);
			p_greet_trigger(ch, PRG_OPROG);
			p_greet_trigger(ch, PRG_RPROG);
		}

		return;
	}

	chprintln(ch, "Nope, can't do it.");
	return;
}

Do_Fun(do_worship)
{
	CharData *priest;
	DeityData *i;

	if (NullStr(argument))
	{
		cmd_syntax(ch, NULL, n_fun, "<deity>", "list", NULL);
		return;
	}

	if (!str_cmp(argument, "list"))
	{
		int e;

		for (e = ETHOS_LAWFUL_GOOD; e != ETHOS_CHAOTIC_EVIL; e--)
		{
			for (i = deity_first; i; i = i->next)
			{
				if (i->ethos != (ethos_t) e)
					continue;

				chprintlnf(ch, "\t%-12s (%s): %s", i->name,
						   flag_string(ethos_types, i->ethos), i->desc);
			}
		}
		return;
	}

	for (priest = ch->in_room->person_first; priest != NULL;
		 priest = priest->next_in_room)
		if (IsNPC(priest) && IsSet(priest->act, ACT_IS_HEALER))
			break;

	if (priest == NULL)
	{
		chprintln(ch, "There is no priest here!");
		return;
	}

	if (ch->pcdata->quest.points < 250)
	{
		chprintln(ch, "You need 250 questpoints to change your deity.");
		return;
	}

	i = deity_lookup(argument);

	if (i == NULL)
	{
		chprintln(ch, "That deity doesn't exist.");
		return;
	}

	ch->deity = i;
	chprintlnf(ch, "You now worship %s.", i->name);
	ch->pcdata->quest.points -= 250;
	return;
}

Do_Fun(do_heel)
{
	if (ch->pet == NULL)
	{
		chprintln(ch, "You don't have a pet!");
		return;
	}
	if (IsSet(ch->in_room->room_flags, ROOM_ARENA))
	{
		act("$N can't hear your whistle with all the screaming.", ch, NULL,
			ch->pet, TO_CHAR);
		return;
	}
	char_from_room(ch->pet);
	char_to_room(ch->pet, ch->in_room);
	act("$n lets out a loud whistle and $N comes running.", ch, NULL, ch->pet,
		TO_ROOM);
	act("You let out a loud whistle and $N comes running.", ch, NULL, ch->pet,
		TO_CHAR);
}

char *path_to_area(CharData * ch, AreaData * pArea)
{
	ExitData *pexit, *pexit2;
	RoomIndex *pRoomIndex, *queueIn, *queueOut, *source;
	int iHash = 0, door, door2;
	static char buf[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];

	if ((source = ch->in_room) == NULL)
		return "Not accessable.";

	if (!pArea)
	{
		bug("passing invalid area");
		return "Ah this is an error.";
	}

	if (AreaFlag(pArea, AREA_CLOSED) || pArea->clan)
		return "Restricted Area.";

	if (source->area == pArea)
		return "You are here.";

	buf[0] = NUL;
	for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
	{
		for (pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL;
			 pRoomIndex = pRoomIndex->next)
		{
			pRoomIndex->distance_from_source = INT_MAX;
			pRoomIndex->shortest_from_room = NULL;
			pRoomIndex->shortest_next_room = NULL;
		}
	}
	source->distance_from_source = 0;
	queueIn = source;
	for (queueOut = source; queueOut; queueOut = queueOut->shortest_next_room)
	{
		if (AreaFlag(queueOut->area, AREA_PLAYER_HOMES)
			|| queueOut->area->clan != NULL)
			continue;

		for (door = 0; door < MAX_DIR; door++)
		{
			if ((pexit = queueOut->exit[door]) != NULL
				&& pexit->u1.to_room != NULL)
			{
				if (pexit->u1.to_room->distance_from_source >
					queueOut->distance_from_source + 1)
				{
					pexit->u1.to_room->distance_from_source =
						queueOut->distance_from_source + 1;
					if (pexit->u1.to_room->area == pArea)
					{
						int count = 1;
						char buf3[3];

						sprintf(buf3, "%c", dir_name[door][0]);
						sprintf(buf2, "%s", buf3);
						for (pRoomIndex = queueOut;
							 pRoomIndex->shortest_from_room;
							 pRoomIndex = pRoomIndex->shortest_from_room)
						{
							for (door2 = 0; door2 < MAX_DIR; door2++)
							{
								if (
									(pexit2 =
									 pRoomIndex->shortest_from_room->
									 exit[door2]) != NULL
									&& pexit2->u1.to_room == pRoomIndex)
								{
									if (dir_name[door2][0] == buf3[0])
									{
										count++;
									}
									else
									{
										sprintf(buf, "%s", buf2);
										if (count > 1)
										{

											sprintf(buf2, "%c%d%s",
													dir_name[door2][0], count,
													buf);
										}
										else
										{
											sprintf(buf2, "%c%s",
													dir_name[door2][0], buf);
										}
										count = 1;
										sprintf(buf3, "%c",
												dir_name[door2][0]);
									}
								}
							}
						}
						if (count > 1)
						{
							sprintf(buf, "%s", buf2);
							sprintf(buf2, "%d%s", count, buf);
						}
						sprintf(buf, "%s", buf2);
						return (buf);
					}
					pexit->u1.to_room->shortest_from_room = queueOut;
					queueIn->shortest_next_room = pexit->u1.to_room;
					queueIn = pexit->u1.to_room;
				}
			}
		}
	}
	return "Not accessable.";
}

Do_Fun(do_path)
{
	RoomIndex *pRoomIndex, *queueIn, *queueOut, *source, *destination = NULL;
	int iHash, door, door2;
	ExitData *pexit, *pexit2;
	char buf[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];
	bool fArea = false;
	CharData *victim = NULL;
	AreaData *area;

	// Use a breadth-first search to find shortest path.
	if (NullStr(argument))
	{
		cmd_syntax(ch, NULL, n_fun, "<destination player, mob, or area>",
				   NULL);
		return;
	}
	// First, find source and destination rooms:
	if ((source = ch->in_room) == NULL)
	{
		chprintln(ch, "You must be somewhere to go anywhere.");
		return;
	}

	if ((area = area_lookup(argument)) != NULL)
	{
		destination = area_begin(area);
		fArea = true;
	}
	else if ((victim = get_char_world(ch, argument)) != NULL
			 || victim->in_room == NULL || !can_see_room(ch, victim->in_room)
			 || IsSet(victim->in_room->room_flags,
					  ROOM_SAFE | ROOM_ARENA | ROOM_PRIVATE | ROOM_SOLITARY |
					  ROOM_NO_RECALL)
			 || IsSet(ch->in_room->room_flags, ROOM_ARENA | ROOM_NO_RECALL)
			 || (IsNPC(victim)
				 && is_gqmob(NULL, victim->pIndexData->vnum) != -1)
			 || (IsNPC(victim) && IsQuester(ch)
				 && ch->pcdata->quest.mob == victim)
			 || victim->level >= ch->level + 3 || (is_clan(victim)
												   && !is_same_clan(ch,
																	victim))
			 || (!IsNPC(victim) && victim->level >= MAX_MORTAL_LEVEL)
			 || (IsNPC(victim) && IsSet(victim->imm_flags, IMM_SUMMON))
			 || (IsNPC(victim) && saves_spell(ch->level, victim, DAM_OTHER)))
		destination = victim->in_room;

	if (destination == NULL)
	{
		chprintln(ch, "No such destination.");
		return;
	}

	if ((fArea && source->area == destination->area) || source == destination)
	{
		chprintln(ch, "No need to walk to get there!");
		return;
	}

	if (AreaFlag(destination->area, AREA_CLOSED) || destination->area->clan)
	{
		chprintln(ch, "That area is restricted.");
		return;
	}

	for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
	{
		for (pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL;
			 pRoomIndex = pRoomIndex->next)
		{
			pRoomIndex->distance_from_source = INT_MAX;
			pRoomIndex->shortest_from_room = NULL;
			pRoomIndex->shortest_next_room = NULL;
		}
	}
	// Now set source distance to 0 and put it on the "search" queue
	source->distance_from_source = 0;
	queueIn = source;
	// Now, set distance for all adjacent rooms to search room + 1 until
	// destination.
	// If destination not found, put each unsearched adjacent room on queue
	// and repeat
	for (queueOut = source; queueOut; queueOut = queueOut->shortest_next_room)
	{
		if (AreaFlag(queueOut->area, AREA_PLAYER_HOMES)
			|| queueOut->area->clan != NULL)
			continue;

		// for each exit to search room:
		for (door = 0; door < MAX_DIR; door++)
		{
			if ((pexit = queueOut->exit[door]) != NULL
				&& pexit->u1.to_room != NULL)
			{
				// if we haven't looked here, set distance and add to search
				// list
				if (pexit->u1.to_room->distance_from_source >
					queueOut->distance_from_source + 1)
				{
					pexit->u1.to_room->distance_from_source =
						queueOut->distance_from_source + 1;
					// if we've found destination, we're done!
					if (
						(fArea
						 && pexit->u1.to_room->area == destination->area)
						|| pexit->u1.to_room == destination)
					{
						int count = 1;
						char buf3[3];

						// print the directions in reverse order as we walk
						// back
						sprintf(buf3, "%c", dir_name[door][0]);
						sprintf(buf2, "%s", buf3);
						for (pRoomIndex = queueOut;
							 pRoomIndex->shortest_from_room;
							 pRoomIndex = pRoomIndex->shortest_from_room)
						{
							for (door2 = 0; door2 < MAX_DIR; door2++)
							{
								if (
									(pexit2 =
									 pRoomIndex->shortest_from_room->
									 exit[door2]) != NULL
									&& pexit2->u1.to_room == pRoomIndex)
								{
									if (dir_name[door2][0] == buf3[0])
									{
										count++;
									}
									else
									{
										sprintf(buf, "%s", buf2);
										if (count > 1)
										{
											sprintf(buf2, "%c%d%s",
													dir_name[door2][0], count,
													buf);
										}
										else
										{
											sprintf(buf2, "%c%s",
													dir_name[door2][0], buf);
										}
										count = 1;
										sprintf(buf3, "%c",
												dir_name[door2][0]);
									}
								}
							}
						}
						if (count > 1)
						{
							sprintf(buf, "%s", buf2);
							sprintf(buf2, "%d%s", count, buf);
						}
						if (fArea)
						{
							chprintlnf(ch,
									   "Shortest path to %s is %d steps: %s.",
									   destination->area->name,
									   pexit->u1.
									   to_room->distance_from_source, buf2);
						}
						else if (victim)
						{
							chprintlnf(ch,
									   "Shortest path to %s is %d steps: %s.",
									   GetName(victim),
									   pexit->u1.
									   to_room->distance_from_source, buf2);
						}
						return;
					}
					// Didn't find destination, add to queue
					pexit->u1.to_room->shortest_from_room = queueOut;
					queueIn->shortest_next_room = pexit->u1.to_room;
					queueIn = pexit->u1.to_room;
				}
			}
		}
	}
	chprintln(ch, "No path to destination.");
	return;
}