Mud20/accounts/
Mud20/accounts/c/
Mud20/accounts/f/
Mud20/accounts/k/
Mud20/accounts/s/
Mud20/accounts/t/
Mud20/area_current/
Mud20/area_current/newareas/
Mud20/bin/
Mud20/clans/
Mud20/gods/
Mud20/old-sources/
Mud20/player/
Mud20/player/a/del/
Mud20/player/b/
Mud20/player/b/bak/
Mud20/player/b/del/
Mud20/player/f/
Mud20/player/f/bak/
Mud20/player/f/del/
Mud20/player/k/
Mud20/player/k/bak/
Mud20/player/k/del/
Mud20/player/k/dmp/
Mud20/player/m/
Mud20/player/m/bak/
Mud20/player/o/
Mud20/player/o/bak/
Mud20/player/p/
Mud20/player/s/
Mud20/player/s/bak/
Mud20/player/s/del/
Mud20/player/t/
Mud20/player/t/del/
Mud20/player/v/
Mud20/public_html/
Mud20/races/
Mud20/skilltables/
__MACOSX/Mud20/accounts/
__MACOSX/Mud20/accounts/c/
__MACOSX/Mud20/accounts/f/
__MACOSX/Mud20/accounts/k/
__MACOSX/Mud20/accounts/s/
__MACOSX/Mud20/area_current/
__MACOSX/Mud20/area_current/core_areas/
__MACOSX/Mud20/area_current/helps/
__MACOSX/Mud20/area_current/newareas/
__MACOSX/Mud20/backups/
__MACOSX/Mud20/bin/
__MACOSX/Mud20/clans/
__MACOSX/Mud20/gods/
__MACOSX/Mud20/log/
__MACOSX/Mud20/old-sources/
__MACOSX/Mud20/player/
__MACOSX/Mud20/player/a/del/
__MACOSX/Mud20/player/b/
__MACOSX/Mud20/player/b/bak/
__MACOSX/Mud20/player/f/
__MACOSX/Mud20/player/f/bak/
__MACOSX/Mud20/player/f/del/
__MACOSX/Mud20/player/k/
__MACOSX/Mud20/player/k/bak/
__MACOSX/Mud20/player/k/del/
__MACOSX/Mud20/player/k/dmp/
__MACOSX/Mud20/player/m/
__MACOSX/Mud20/player/m/bak/
__MACOSX/Mud20/player/o/
__MACOSX/Mud20/player/o/bak/
__MACOSX/Mud20/player/p/
__MACOSX/Mud20/player/s/
__MACOSX/Mud20/player/s/bak/
__MACOSX/Mud20/player/t/del/
__MACOSX/Mud20/player/v/
__MACOSX/Mud20/public_html/
__MACOSX/Mud20/races/
__MACOSX/Mud20/skilltables/
/***************************************************************************
 * Mud20 1.0 by Todd H. Johnson (Kregor) a derivative of the Open Gaming   *
 * License by Wizards of the Coast. All comments referring to D20, OGL,    *
 * and SRD refer to the System Reference Document for the Open Gaming      *
 * system. Any inclusion of these derivatives must include credit to the   *
 * Mud20 system, the full and complete Open Gaming LIcense, and credit to  *
 * the respective authors. See ../doc/srd.txt for more information.        *
 *                                                                         *
 * Emud  2.2 by Igor van den Hoven, Michiel Lange, and Martin Bethlehem.   *
 *                                                                         *
 * MrMud 1.4 by David Bills, Dug Michael and Martin Gallwey                *
 *                                                                         *
 * Merc  2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael      *
 * Chastain, Michael Quan, and Mitchell Tse.                               *
 *                                                                         *
 * Original Diku Mud copyright (C) 1990 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeld, Tom Madsen, and Katje Nyboe.     *
 ***************************************************************************/

/************************************************************************/
/* mlkesl@stthomas.edu	=====>	Ascii Automapper utility								*/
/* Let me know if you use this. Give a newbie some _credit_,						*/
/* at least I'm not asking how to add classes...												*/
/* Also, if you fix something could ya send me mail about, thanks				*/
/* PLEASE mail me if you use this or like it, that way I will keep it up*/
/*																																			*/
/* Heavily modified by Kregor for Mud20 - 11/2012												*/
/************************************************************************/

#include <ctype.h>  /* for isalpha */
#include <string.h>
#include <stdlib.h>
#include <stdio.h> 
#include <time.h> 
#include "mud.h"

#define MAX_MAP 160
#define MAX_MAP_DIR 4

int map[MAX_MAP][MAX_MAP];
int offsets[4][2] ={ {-1, 0},{ 0, 1},{ 1, 0},{ 0,-1} };

/*
 * Saved lines by splitting this out of a switch
 * in each function to a simple constant array - Kregor
 */
char * const map_sectors [] =
{
	"{108}#",
	"{178}+",
	"{038}\"",
	"{028}^",
	"{128}^",
	"{038}^",
	"{148}~",
	"{068}~",
	"{048}~",
	"{168}~",
	"{138}:",
	"{118}~",
	"{168}:",
	"{178}~",
	"{058}~",
	"{108}+",
	"{108}=",
	"{078}+",
	"{028}~",
	"{138}~",
	"{178}:",
	"{108}:",
	"*"
};

/*
 * Standard sector color strings to add to text descs - Kregor
 */
char * const map_colors [] =
{
	"{108}",
	"{178}",
	"{128}",
	"{028}",
	"{128}",
	"{038}",
	"{148}",
	"{068}",
	"{048}",
	"{168}",
	"{138}",
	"{118}",
	"{168}",
	"{178}",
	"{058}",
	"{108}",
	"{108}",
	"{078}",
	"{028}",
	"{138}",
	"{178}",
	"{108}",
	"*"
};

char * const sector_names [] =
{
	"Inside",
	"A city street",
	"A grassy field",
	"Within a forest",
	"Rolling hills",
	"Steep mountains",
	"A placid lake",
	"A flowing river",
	"A deep ocean",
	"In the air",
	"In the desert",
	"A pool of lava",
	"In the Ethereal wastes",
	"On the astral plane",
	"In the murky depths",
	"In an earthen tunnel",
	"In a dank cavern",
	"A well-travelled path",
	"In the marshlands",
	"On the shoreline",
	"The frozen wastes",
	"Barren terrain",
	"nothing"
};

char *get_dynamic_room_title( ROOM_INDEX_DATA *room )
{
	push_call("get_dynamic_room_title()");
	
	if (!IS_SET(room->room_flags, ROOM_DYNAMIC|ROOM_WILDERNESS) && !IS_SET(room->area->flags, AFLAG_WILDERNESS))
	{
		pop_call();
		return room->name;
	}
	if (!is_string(room->name) || !strcasecmp(room->name, "Floating in a void"))
	{
		if ( room->sector_type >= SECT_MAX)
		{
			pop_call();
			return "nothing";
		}
		pop_call();
		return(sector_names[room->sector_type]);
	}
	pop_call();
	return room->name;
}

/* mlk ::
when given (int array[5]) with vnum in [0], it will return
1	north sector_type, 
2	east sector_type, 
3	south sector_type,
4	east_sector_type &
5	number of exits leading to rooms of the same sector
*/
int *get_exit_sectors(int *exit_sectors)
{
	ROOM_INDEX_DATA *room, *to_room;
	EXIT_DATA *pExit;
	int door;
	
	push_call("get_exit_sectors()");
	
	room = get_room_index(exit_sectors[0]);
	exit_sectors[4] = 0;
	
	for ( door = 0 ; door < MAX_MAP_DIR ; door++ ) 
	{
		if ((pExit = room->exit[door]) != NULL
		&& (to_room = room_index[pExit->to_room]) != NULL)
		{   
			exit_sectors[door] = to_room->sector_type;	
			if (to_room->sector_type == room->sector_type)
				exit_sectors[4]++;
		} 
		else
			exit_sectors[door] = -1;	
	}	   
	pop_call();
	return(exit_sectors);
}


char *get_map_sector( int sector )
{
	push_call("get_map_sector()");

	sector = UMAX(0, sector);
	
	if (sector < SECT_MAX)
	{
		pop_call();
		return map_sectors[sector];
	}
	if (sector == SECT_MAX + 1)
	{
		pop_call();
		return "{108}?";
	}
	if (sector == SECT_MAX)
	{
		pop_call();
		return " ";
	}
	if (sector == SECT_MAX + 3)
	{
		pop_call();
		return "{078}|";
	}
	if (sector == SECT_MAX + 4)
	{
		pop_call();
		return "{078}-";
	}
	pop_call();
	return "{118}X";
}

void map_area( ROOM_INDEX_DATA *room, CHAR_DATA *ch, int x, int y, int min, int max )
{
	ROOM_INDEX_DATA *next_room;
	EXIT_DATA *pExit;
	int door;
	int exit[5];
	
	push_call("map_area()");

	// marks the room as visited
	map[x][y] = room->sector_type;

	if (room->sector_type == SECT_ROAD)
	{
		exit[0] = room->vnum;
		get_exit_sectors(exit);
		
		// These override the standard '+' for roads
		// so roads travel in the right direction on the map - Kregor.
		if (exit[4] && exit[4] != 4 && exit[4] != 3)
		{
			if ((exit[4] == 2 && exit[0] == SECT_ROAD && exit[2] == SECT_ROAD)
			|| (exit[4] == 1 && (exit[0] == SECT_ROAD || exit[2] == SECT_ROAD)))
			{
				map[x][y] = SECT_MAX + 3;
			}
			if ((exit[4] == 2 && exit[1] == SECT_ROAD && exit[3] == SECT_ROAD)
			|| (exit[4] == 1 && (exit[1] == SECT_ROAD || exit[3] == SECT_ROAD)))
			{
				map[x][y] = SECT_MAX + 4;
			}
		}
	}

	for ( door = 0; door < MAX_MAP_DIR; door++ ) 
	{
		if ((pExit = room->exit[door]) != NULL
		&&   (next_room = room_index[pExit->to_room]) != NULL 
		&&   !IS_SET(pExit->exit_info, EX_CLOSED))
		{
			if ((x < min) || (y < min) || (x > max) || (y > max))
			{
				pop_call();
				return;
			}
			
			if (next_room->exit[rev_dir[door]]
			&& room_index[next_room->exit[rev_dir[door]]->to_room] != room)
			{
				map[x][y] = SECT_MAX + 1; // one way into area OR maze
				pop_call();
				return;
			} /* end two way */
	
			if ((next_room->sector_type == SECT_MOUNTAIN)  // players cant see past these
			|| (next_room->sector_type == SECT_HILLS) 
			|| (next_room->sector_type == SECT_CITY) 
			|| (next_room->sector_type == SECT_INSIDE))
			{ 
				map[x + offsets[door][0]][y + offsets[door][1]] = next_room->sector_type;
	
// 				if (door != 0) 
// 				{
// 					pop_call();
// 					return;
// 				}
			}

			if (map[x + offsets[door][0]][y + offsets[door][1]] == SECT_MAX)
			{
				map_area (next_room, ch, x + offsets[door][0], y + offsets[door][1], min, max);
			}
		}
	}
	pop_call();
	return;
}

/* 
 * Prints automap of specified size to provided string
 * adds room desc and title optionally - Kregor
 */
void sprintf_wilderness_map( CHAR_DATA *ch, char *outbuf, int size, bool room )
{
	ROOM_INDEX_DATA *in_room;
	int x, y, min, max, center, str_pos = 0, desc_pos = 0, start;
	char buf[MAX_STRING_LENGTH];
	char buf2[MAX_STRING_LENGTH];
	char desc[MAX_STRING_LENGTH];
	char line[MAX_INPUT_LENGTH];

	push_call("show_wilderness()");

	size = URANGE(6, size, MAX_MAP);
	center = MAX_MAP/2;
	
	min = MAX_MAP/2 - size/2;
	max = MAX_MAP/2 + size/2;
	
	for (x = 0; x < MAX_MAP; ++x)
		for (y = 0; y < MAX_MAP; ++y)
			map[x][y] = SECT_MAX;

	/* starts the mapping with the center room */
	map_area(ch->in_room, ch, center, center, min-1, max-1); 
	
	/* marks the center, where ch is */
	map[center][center] = SECT_MAX + 2;

	if (room)
	{
		in_room = ch->in_room;
		map[min][min] = SECT_MAX; map[max-1][max-1] = SECT_MAX; /* mlk :: rounds edges */
		map[min][max-1] = SECT_MAX; map[max-1][min] = SECT_MAX;
	
		strcpy(desc, ansi_justify(get_dynamic_description(ch), get_page_width(ch) - (size + 6)));
	
		if (show_build_vnum(ch, in_room->vnum))
		{
			sprintf(buf, "%s(%d) %s%s\n\r", get_color_string(ch, COLOR_PROMPT, VT102_DIM), in_room->vnum, get_color_string(ch, COLOR_PROMPT,VT102_BOLD), get_dynamic_room_title(in_room));
		}
		else
		{
			sprintf(buf, "%s%s\n\r", get_color_string(ch, COLOR_PROMPT,VT102_BOLD), get_dynamic_room_title(in_room) );
		}
		if (ch->desc && IS_SET(CH(ch->desc)->act, PLR_AUTOEXIT))
		{
			sprintf_exits(buf2, ch, TRUE);
			strcat(buf, buf2);
		}
	}
	else
	{
		*buf = '\0';
	}
	
	for (x = min ; x < max ; x++) 
	{
		strcat(buf, "  ");

		for (y = min ; y < max ; y++)
		{
			strcat(buf, get_map_sector(map[x][y]));
		}
	
		if (!room)
		{
			strcat(buf, "\n\r");
			continue;
		}

		start = str_pos;

		if (x == min) // space between exits and desc - Kregor
		{
			strcat(buf, "\n\r");
			continue;
		}
		for (desc_pos = desc_pos ; desc[desc_pos] != '\0' ; desc_pos++)
		{ 
			if (desc[desc_pos] == '\n')
			{
				line[str_pos - start] = '\0';
				str_pos += 3;
				desc_pos += 2;
				break;
			}
			else if (desc[desc_pos] == '\r')
			{
				line[str_pos-start] = '\0';
				str_pos += 2;
				break;
			}
			else
			{
				line[str_pos-start] = desc[desc_pos];
				str_pos += 1;
			}
		}
		line[str_pos-start] = '\0';
		strcat(buf, "    ");
		strcat(buf, map_colors[in_room->sector_type]);
		strcat(buf, line);
		strcat(buf, "{300}");

		strcat(buf, "\n\r"); 
	}
	// added because long room descs get cut off - Kregor 111/2012
	if (room && desc[desc_pos] != '\0')
	{
		strcat(buf, map_colors[in_room->sector_type]);
		// reflow leftover text to full width to wrap around mini map - Kregor
		strcat(buf, text_wrap(&desc[desc_pos], get_page_width(ch)));
		strcat(buf, "\n\r");
	}
	strcpy(outbuf, buf);
	
	pop_call();
	return;
}

/* shows a map, specified by size */
void show_map( CHAR_DATA *ch, int size )
{
	char outbuf[MAX_STRING_LENGTH];

	push_call("show_map()");

	*outbuf = '\0';
	sprintf_wilderness_map(ch, outbuf, size, FALSE);
	send_to_char_color(outbuf, ch);

	pop_call();
	return;
}

/* shows a map, specified by size */
void show_room_map( CHAR_DATA *ch, int size )
{
	char outbuf[MAX_STRING_LENGTH];

	push_call("show_room_map()");

	*outbuf = '\0';
	sprintf_wilderness_map(ch, outbuf, size, TRUE);
	send_to_char_color(outbuf, ch);

	pop_call();
	return;
}

void do_map( CHAR_DATA *ch, char *argument )
{
	int size, center, x, y, min, max;
	char arg1[10];
	
	push_call("do_map()");
	
	argument = one_argument( argument, arg1 );
	size = atoi (arg1);
	
	size = URANGE(6, size, MAX_MAP);
	center = MAX_MAP/2;
	
	min = MAX_MAP/2 - size/2;
	max = MAX_MAP/2 + size/2;
	
	for (x = 0; x < MAX_MAP; ++x)
		for (y = 0; y < MAX_MAP; ++y)
			map[x][y] = SECT_MAX;

	/* starts the mapping with the center room */
	map_area(ch->in_room, ch, center, center, min-1, max-1); 
	
	/* marks the center, where ch is */
	map[center][center] = SECT_MAX + 2; /* can be any number above SECT_MAX + 1 	*/
	
	if (!IS_PLR(ch, PLR_HOLYLIGHT))
	{
		if (!can_see_in_room(ch, ch->in_room)) 
		{
			send_to_char_color("{108}It is pitch black.\n\r", ch );
			pop_call();
			return;
		}
	}

	if (!strcasecmp(arg1, "room") || (is_string(argument) && !strcasecmp(argument, "room")))
	{
		show_room_map(ch, size); 
		pop_call();
		return;
	}
		
	show_map(ch, size);

	pop_call();
	return;
}