/* Gendi's rdig snippet, originally implemented on Hunters Network (http://www.hunters-network.com)
Written at first for making a set of rooms from a prototype string, e.g. for SWR2's shipcode
However was later adapted as an rdig function.
This obviously has further uses than just do_rdig, but that is up to you

Currently problems:

  No diagonal directions

  The start vnum must be followed by enough free vnums in order to work
  This can be changed, but you'll have to do that yourself ;)

  This is NOT easy to understand

  Probably many other things.

  The room and exit flags will probably not fit your MUD

  Written on SWR, so SMAUG 1.4a coders will require work

  I am 99% certain this will NOT compile on your MUD without
  extra work by you.

  The code was not written to be released, don't expect it to be nice to you!



Here is the brief description given to the MUD I implemented it on, they got by ;)
If you have further questions, plz mailto:gendi@gendi.co.uk

syntax : rdig <creation string>
min level 102? 103?

what it does....

god help me, can I explain this?

Well, lets try a few examples...

Key: s=startroom, -=exit, x=room

rdig eeee

s-x-x-x-x

rdig nesw

x-x
| |
s-x

rdig ense

  x
  |
s-x-x

rdig eec1nneeessmw1 using a marker

    x-x-x-x
    |     |
    x     x
    |     |
s-x-x-----x



Okay, what did you see above?
Obvious n, s, e, w, d and u go in those directions and create rooms.
c<number> creates a marker in that room (0-9, can be reused).
m<direction><number> returns to a previously marked room in the direction specified.

Thats it.

Okay, I lied, that was the simple bit.

Also you can use rdig to set room flags and exit flags.
room flags are set using f<flag letters>. period at end is important.
exit flags are set using x<flags letters>.

e.g.

rdig exdcl.nfp.se

creates a rooms east, then a room north with the exit between the two being isdoor,
closed, locked. Sets the north room with the flags prison. Then comes back south
then creates a room east

room flags:-

very few right now, just p=prison and s=spacecraft

exit flags:-

d ISDOOR
c CLOSED
l LOCKED
b BASE
v BLASTDOOR
k CUTPROOF
p BASHPROOF
s SECRET
w SWIM
f FLY
h HIDDEN
m NOMOB 

*/

//Add in mud.h

//With other typedefs
typedef struct	coord_data		COORD_DATA; //used with rdig

//Above struct	room_index_data add
struct	coord_data
{
	int	x;
	int	y;
	int	z;
};

//In struct	room_index_data add
COORD_DATA	*	coords;

//If you don't like the use of COORD_DATA then write your own version
//It just made my life easier at the time


//Add required stuff for the new command do_rdig (you may wish to change
//the function name if you are using the other rdig snippet).



// Gendi's rdig snippet, originally implemented on Hunters Network (http://www.hunters-network.com)
// used to go through and destroy rooms created if an error has occured during creation
void rdig_destroy(ROOM_INDEX_DATA *startroom, int end, int firstdir)
{
	int x;
	ROOM_INDEX_DATA	*room;
	EXIT_DATA	*xit;


	if ( firstdir != DIR_SOMEWHERE && (xit = get_exit(startroom, firstdir)) != NULL )
		extract_exit(startroom, xit);

	for( x = startroom->vnum+1; x <= end; x++)
	{
		room = get_room_index(x);
		if ( room )
			delete_room( room );
	}
}


// Gendi's rdig snippet, originally implemented on Hunters Network (http://www.hunters-network.com)
// count the number of rooms needed in rdig
// use this before rdig to make sure you have enough rooms in a straight line
// to allow rdig to work (currently rooms must be linear, i.e. 1-10. 1-2 with 4-11
// is not allowed
// I could return 0 when a problem occurs like an unknown identifier
int rdig_count(char *line)
{
	int count=0, x=0;
	while( line[x] && line[x] != '\0')
	{
		switch( LOWER(line[x]) )
		{
		case 'n':
		case 's':
		case 'e':
		case 'w':
		case 'u':
		case 'd':
			//moving to new room so count it
			count++;
			break;
		case 'm':
			//going back to a previous marker so skip room
			x++;
			break;
		case 'x':
		case 'f':
			//skip through flags
			//must do this as some flags look like directions!
			x++;
			while( line[x] && line[x] != '\0' && line[x] != '.' )
				x++;
			break;
// option 1, just ignore anything unknown
		default:
			//not moving room so move along the string
			break;
// end option 1
// option 2, return false when unknown found
			/*
		case 'c':
		//creating a marker requires no moving
			break;
		default:
			return 0;
			*/
// end option 2
		}
		//if check should never be false, but better to check!
		if( line[x] && line[x] != '\0' )
			x++;
	}
	return count;
}


// Gendi's rdig snippet, originally implemented on Hunters Network (http://www.hunters-network.com)
// room linking function
ROOM_INDEX_DATA * rdig_link_room(ROOM_INDEX_DATA *room,
								 ROOM_INDEX_DATA *toroom,
								 int edir,
								 int vnum,
								 int exit_flags,
								 ROOM_INDEX_DATA *startroom)
{
	EXIT_DATA *xit, *rxit;
	ROOM_INDEX_DATA *troom = toroom;
	int x, y, z;


	// find coords we are going to
	if ( !room || !room->coords ) // panic
	{
		bug("LINK_ROOM: No coords created for room!");
		return NULL;
	}

	x = room->coords->x;
	y = room->coords->y;
	z = room->coords->z;

	switch(edir)
	{
	case DIR_NORTH:
		y++;
		break;
	case DIR_SOUTH:
		y--;
		break;
	case DIR_EAST:
		x++;
		break;
	case DIR_WEST:
		x--;
		break;
	case DIR_UP:
		z++;
		break;
	case DIR_DOWN:
		z--;
		break;
	/*case DIR_NORTHEAST:
		y++;
		x++;
		break;
	case DIR_NORTHWEST:
		y++;
		x--;
		break;
	case DIR_SOUTHEAST:
		y--;
		x++;
		break;
	case DIR_SOUTHWEST:
		y--;
		x--;
		break;*/
	}

	// If no room supplied then look to see if there is a room in that
	// direction on the grid, and if so, use it for troom
	if( !troom )
	{
		int tint;


		for( tint = startroom->vnum; tint < vnum; tint++)
		{
			troom = get_room_index(tint);
			if( !troom || !troom->coords )
				continue;

			if( troom->coords->x == x &&
			    troom->coords->y == y &&
			    troom->coords->z == z )
			{
				break;
			}

			troom = NULL;
		}
	}

	if( !troom )
	{
		troom = make_room( vnum, NULL );// could use startroom here, but I don't want to copy name, description, flags
		troom->sector_type		= startroom->sector_type;
		troom->light			= startroom->light;
		troom->tunnel			= startroom->tunnel;
		troom->area				= startroom->area;

		CREATE( troom->coords, COORD_DATA, 1 );
		troom->coords->x = x;
		troom->coords->y = y;
		troom->coords->z = z;
	}

	if ( !get_exit(room, edir) )
	{
		if ( get_exit(troom, rev_dir[edir] ) )
			return NULL;

		xit = make_exit( room, troom, edir );
		xit->keyword		= STRALLOC( "" );
		xit->description	= STRALLOC( "" );
		xit->key			= -1;
		xit->exit_info		= exit_flags;
		
		rxit = make_exit( troom, room, rev_dir[edir] );
		rxit->keyword		= STRALLOC( "" );
		rxit->description	= STRALLOC( "" );
		rxit->key			= -1;
		rxit->exit_info		= exit_flags;
	}

	if ( exit_flags )
	{
		instaroom(startroom->area, room, TRUE);
		instaroom(startroom->area, troom, TRUE);
	}

	return troom;
}


// Gendi's rdig snippet, originally implemented on Hunters Network (http://www.hunters-network.com)
// line is the string with creation data in
char *rdig( ROOM_INDEX_DATA *startroom, char *line)
{
	ROOM_INDEX_DATA *room;
	int markers[10]; //for simplicity just have an array that allows for 10 markers (0-9)
	int i, nextvnum, exit_flags, rooms, marker;
	char *buf2;
	char buf[MAX_STRING_LENGTH];
	char tchar[2];
	int firstdir = DIR_SOMEWHERE, edir = DIR_SOMEWHERE;


	room = startroom;
	nextvnum = startroom->vnum + 1;
	exit_flags = 0;
	tchar[0] = '0';
	tchar[1] = '\0';

	CREATE( startroom->coords, COORD_DATA, 1 );
	startroom->coords->x = 0;
	startroom->coords->y = 0;
	startroom->coords->z = 0;

	rooms = rdig_count(line);

	//used with option 2 of rdig_count
	/*if ( !rooms )
		return "Unknown flag found or no rooms would be created.\n\r";*/
	//end option 2

	//check enough rooms available
	if ( startroom->area->hi_r_vnum - rooms < startroom->vnum )
		return "Not enough rooms left in your area.\n\r";

	for ( i = startroom->vnum + 1; i <= startroom->vnum + rooms; i++)
	{
		if ( get_room_index(i) )
			return "Not enough rooms available\n\r";
	}

	for ( i = 0; line[i] && line[i] != '\0'; i++)
	{
		sprintf( buf, "character %c", line[i]);
		// check next letter
		switch(LOWER(line[i]))
		{
		case 'n':
			/*if( line[i+1] && line[i+1] != '\0' && line[i+1] = 'e' )
			{
				edir = DIR_NORTHEAST;
				i++;
			}
			else if( line[i+1] && line[i+1] != '\0' && line[i+1] = 'w' )
			{
				edir = DIR_NORTHEWST;
				i++;
			}
			else*/
				edir = DIR_NORTH;
			room = rdig_link_room(room, NULL, edir, nextvnum++, exit_flags, startroom);
			exit_flags = 0;
			break;
		case 's':
			/*if( line[i+1] && line[i+1] != '\0' && line[i+1] = 'e' )
			{
				edir = DIR_SOUTHEAST;
				i++;
			}
			else if( line[i+1] && line[i+1] != '\0' && line[i+1] = 'w' )
			{
				edir = DIR_SOUTHEWST;
				i++;
			}
			else*/
				edir = DIR_SOUTH;
			room = rdig_link_room(room, NULL, edir, nextvnum++, exit_flags, startroom);
			exit_flags = 0;
			break;
		case 'e':
			edir = DIR_EAST;
			room = rdig_link_room(room, NULL, edir, nextvnum++, exit_flags, startroom);
			exit_flags = 0;
			break;
		case 'w':
			edir = DIR_WEST;
			room = rdig_link_room(room, NULL, edir, nextvnum++, exit_flags, startroom);
			exit_flags = 0;
			break;
		case 'u':
			edir = DIR_UP;
			room = rdig_link_room(room, NULL, edir, nextvnum++, exit_flags, startroom);
			exit_flags = 0;
			break;
		case 'd':
			edir = DIR_DOWN;
			room = rdig_link_room(room, NULL, edir, nextvnum++, exit_flags, startroom);
			exit_flags = 0;
			break;
	
		case 'x':
			exit_flags = 0;
			i++;
			while( line[i] && line[i] != '.' && line[i] != '\0' )
			{
				switch(LOWER(line[i]))
				{
				case 'd':
					SET_BIT(exit_flags, EX_ISDOOR);
					break;
				case 'c':
					SET_BIT(exit_flags, EX_CLOSED);
					break;
				case 'l':
					SET_BIT(exit_flags, EX_LOCKED);
					break;
				case 'b':
					SET_BIT(exit_flags, EX_BASE);
					break;
				case 'v':
					SET_BIT(exit_flags, EX_BLASTDOOR);
					break;
				case 'k':
					SET_BIT(exit_flags, EX_CUTPROOF);
					break;
				case 'p':
					SET_BIT(exit_flags, EX_BASHPROOF);
					break;
				case 's':
					SET_BIT(exit_flags, EX_SECRET);
					break;
				case 'w':
					SET_BIT(exit_flags, EX_SWIM);
					break;
				case 'f':
					SET_BIT(exit_flags, EX_FLY);
					break;
				case 'h':
					SET_BIT(exit_flags, EX_HIDDEN);
					break;
				case 'm':
					SET_BIT(exit_flags, EX_NOMOB);
					break;
				default:
					sprintf( buf, "Uknown eXit flag %c\n\r", line[i]);
					buf2 = STRALLOC(buf);
					rdig_destroy(startroom, nextvnum, firstdir);
					return buf2;
				}
				i++;
			}
			break;
		case 'f':
			i++;
			while( line[i] && line[i] != '.' && line[i] != '\0' )
			{
				switch(LOWER(line[i]))
				{
				case 's':
					SET_BIT(room->room_flags, ROOM_SPACECRAFT);
					break;
				case 'p':
					SET_BIT(room->room_flags2, ROOM2_PRISON);
					break;
				// All the other suitable room flags
				default:
					sprintf( buf, "Uknown room Flag %c\n\r", line[i]);
					buf2 = STRALLOC(buf);
					rdig_destroy(startroom, nextvnum, firstdir);
					return buf2;
				}
				i++;
			}
			break;
		case 'c':
			tchar[0] = line[++i];
			marker = atoi(tchar);
			markers[marker] = room->vnum;
			// remember markers can to reused.
			break;
		case 'm':
			tchar[0] = line[++i];
			edir = get_dir(tchar);
			if( edir == DIR_SOMEWHERE || ( edir == DIR_NORTH && tchar[0] != 'n' ) )
			{
				rdig_destroy(startroom, nextvnum, firstdir);
				return "Bad direction for marker\n\r";
			}
			tchar[0] = line[++i];
			if ( !is_number(tchar) )
				return "Bad number for marker\n\r";
			marker = atoi(tchar);
			if ( !markers[marker] || !get_room_index(markers[marker]) )
			{
				sprintf( buf, "No marker stored at %d\n\r", marker);
				buf2 = STRALLOC(buf);
				rdig_destroy(startroom, nextvnum, firstdir);
				return buf2;
			}
			rdig_link_room(room, get_room_index(markers[marker]), edir, ++nextvnum, exit_flags, startroom);
			exit_flags = 0;
			break;
		// default not reached when option 2 of rdig_count used
		default:
			sprintf( buf, "Unknown identifier %c\n\r", line[i]);
			buf2 = STRALLOC(buf);
			rdig_destroy(startroom, nextvnum, firstdir);
			return buf2;

		}

		if ( firstdir == DIR_SOMEWHERE && edir != DIR_SOMEWHERE )
			firstdir = edir;

		if ( !room )
		{
			return "There seems to have been a problem and the rooms cannot be created\n\rRemember exits cannot be created where one already exists\n\r";
			rdig_destroy(startroom, nextvnum, firstdir);
		}
	}
	return NULL;
	// returning NULL shows no problems occured, so no error message sent
}


// Gendi's rdig snippet, originally implemented on Hunters Network (http://www.hunters-network.com)
void do_rdig( CHAR_DATA *ch, char *argument )
{
	char *buf;
	char arg[MAX_STRING_LENGTH];



	if ( !ch->pcdata || !ch->pcdata->area )
	{
		send_to_char("You don't have an area assigned.\n\r", ch);
		return;
	}

	if ( ch->pcdata->area != ch->in_room->area )
	{
		send_to_char("You are not in your area.\n\r", ch);
		return;
	}

	argument = one_argument( argument, arg );
	
	if ( !arg || arg[0] == '\0' )
	{
		send_to_char("You must specify a creation line.\n\r", ch);
		return;
	}

	buf = rdig( ch->in_room, arg);

	if ( !buf )
		send_to_char("Done.", ch);
	else
		send_to_char( buf, ch);

	return;
}