/*****************************************************************************
* DikuMUD (C) 1990, 1991 by: *
* Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen, *
* and Katja Nyboe. *
*---------------------------------------------------------------------------*
* MERC 2.1 (C) 1992, 1993 by: *
* Michael Chastain, Michael Quan, and Mitchell Tse. *
*---------------------------------------------------------------------------*
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider. *
* Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
* gorog, Grishnakh, Nivek, Tricops, and Fireblade. *
*---------------------------------------------------------------------------*
* SMAUG 1.7 FUSS by: Samson and others of the SMAUG community. *
* Their contributions are greatly appreciated. *
*---------------------------------------------------------------------------*
* LoP (C) 2006, 2007, 2008 by: the LoP team. *
*---------------------------------------------------------------------------*
* v. 0.9: 6/19/95: Converts an ascii map to rooms. *
* v. 1.0: 7/05/95: Read/write maps to .are files. Efficient storage. *
* Room qualities based on map code. Can add & remove rms *
* from a map. (Somewhat) intelligent exit decisions. *
* v. 1.1: 7/11/95: Various display options. *
*****************************************************************************/
#include <stdio.h>
#include "h/mud.h"
typedef struct map_index_data MAP_INDEX_DATA; /* maps */
struct map_index_data
{
MAP_INDEX_DATA *next;
int vnum; /* vnum of the map */
int map_of_vnums[49][81]; /* room vnums aranged as a map */
};
MAP_INDEX_DATA *first_map; /* maps */
MAP_INDEX_DATA *get_map_index( int vnum );
void init_maps( void );
/* Useful Externals */
extern int top_exit;
void note_attach( CHAR_DATA *ch );
/* Local function prototypes */
MAP_INDEX_DATA *make_new_map_index( int vnum );
void map_to_rooms( CHAR_DATA *ch, MAP_INDEX_DATA *m_index );
void map_stats( CHAR_DATA *ch, int *rooms, int *rows, int *cols );
int num_rooms_avail( CHAR_DATA *ch );
/* Local Variables & Structs */
char text_map[MSL];
extern MAP_INDEX_DATA *first_map; /* should be global */
struct map_stuff
{
int vnum;
int exits;
int index;
char code;
};
/* Be careful not to give
* this an existing map_index
*/
MAP_INDEX_DATA *make_new_map_index( int vnum )
{
MAP_INDEX_DATA *map_index;
int i, j;
CREATE( map_index, MAP_INDEX_DATA, 1 );
map_index->vnum = vnum;
for( i = 0; i < 49; i++ )
{
for( j = 0; j < 78; j++ )
map_index->map_of_vnums[i][j] = -1;
}
map_index->next = first_map;
first_map = map_index;
return map_index;
}
char count_lines( char *txt )
{
int i;
char *c, buf[MSL];
if( !txt )
return ( char )'0';
i = 1;
for( c = txt; *c != '\0'; c++ )
if( *c == '\n' )
i++;
if( i > 9 )
return ( char )'+';
snprintf( buf, sizeof( buf ), "%d", i );
return ( buf[0] );
}
MAP_INDEX_DATA *get_map_index( int vnum )
{
MAP_INDEX_DATA *map;
for( map = first_map; map; map = map->next )
{
if( map->vnum == vnum )
return map;
}
return NULL;
}
void map_stats( CHAR_DATA *ch, int *rooms, int *rows, int *cols )
{
int row, col, n;
int leftmost, rightmost;
char *l, c;
if( !ch->pnote )
{
bug( "%s: ch->pnote is NULL!", __FUNCTION__ );
return;
}
n = 0;
row = col = 0;
leftmost = rightmost = 0;
l = ch->pnote->text;
do
{
c = l[0];
switch( c )
{
case '\r':
break;
case '\n':
col = 0;
row++;
break;
case ' ':
col++;
break;
}
if( c == 'I' || c == 'C' || c == 'f' || c == 'F' || c == 'H' || c == 'M' || c == 's' || c == 'S'
|| c == 'A' || c == 'D' || c == 'O' || c == 'u' || c == 'U' || c == 'L' || c == 'W' || c == '#' )
{
/* This is a room */
n++;
/* This will later handle a letter etc */
col++;
if( col < leftmost )
leftmost = col;
if( col > rightmost )
rightmost = col;
}
if( c == ' ' || c == '-' || c == '|' || c == '=' || c == '\\' || c == '/' || c == '^' || c == ':' || c == 'X' || c == '+' )
col++;
l++;
}
while( c != '\0' );
*cols = ( rightmost - leftmost );
*rows = row; /* [sic.] */
*rooms = n;
}
void do_mapout( CHAR_DATA *ch, char *argument )
{
char arg[MIL];
OBJ_DATA *map_obj; /* an obj made with map as an ed */
OBJ_INDEX_DATA *map_obj_index; /* obj_index for previous */
EXTRA_DESCR_DATA *ed; /* the ed for it to go in */
int rooms, rows, cols, avail_rooms;
if( !ch )
{
bug( "%s: null ch", __FUNCTION__ );
return;
}
if( is_npc( ch ) )
{
send_to_char( "Not for mobs.\r\n", ch );
return;
}
if( !ch->desc )
{
bug( "%s: no descriptor", __FUNCTION__ );
return;
}
switch( ch->substate )
{
default:
break;
case SUB_MAP_EDIT:
if( ch->dest_buf != ch->pnote )
bug( "%s: sub_writing_map: ch->dest_buf != ch->pnote", __FUNCTION__ );
STRFREE( ch->pnote->text );
ch->pnote->text = copy_buffer( ch );
stop_editing( ch );
return;
}
set_char_color( AT_NOTE, ch );
argument = one_argument( argument, arg );
if( !str_cmp( arg, "stat" ) )
{
if( !ch->pnote )
{
send_to_char( "You have no map in progress.\r\n", ch );
return;
}
map_stats( ch, &rooms, &rows, &cols );
ch_printf( ch, "Map represents %d rooms, %d rows, and %d columns\r\n", rooms, rows, cols );
avail_rooms = num_rooms_avail( ch );
ch_printf( ch, "You currently have %d unused rooms.\r\n", avail_rooms );
act( AT_ACTION, "$n glances at an etherial map.", ch, NULL, NULL, TO_ROOM );
return;
}
if( !str_cmp( arg, "write" ) )
{
note_attach( ch );
ch->substate = SUB_MAP_EDIT;
ch->dest_buf = ch->pnote;
start_editing( ch, ch->pnote->text );
return;
}
if( !str_cmp( arg, "clear" ) )
{
if( !ch->pnote )
{
send_to_char( "You have no map in progress\r\n", ch );
return;
}
STRFREE( ch->pnote->text );
STRFREE( ch->pnote->subject );
STRFREE( ch->pnote->to_list );
STRFREE( ch->pnote->sender );
DISPOSE( ch->pnote );
ch->pnote = NULL;
send_to_char( "Map cleared.\r\n", ch );
return;
}
if( !str_cmp( arg, "show" ) )
{
if( !ch->pnote )
{
send_to_char( "You have no map in progress.\r\n", ch );
return;
}
send_to_char( ch->pnote->text, ch );
do_mapout( ch, (char *)"stat" );
return;
}
if( !str_cmp( arg, "create" ) )
{
if( !ch->pnote )
{
send_to_char( "You have no map in progress.\r\n", ch );
return;
}
map_stats( ch, &rooms, &rows, &cols );
avail_rooms = num_rooms_avail( ch );
/* check for not enough rooms */
if( rooms > avail_rooms )
{
send_to_char( "You don't have enough unused rooms allocated!\r\n", ch );
return;
}
act( AT_ACTION, "$n warps the very dimensions of space!", ch, NULL, NULL, TO_ROOM );
map_to_rooms( ch, NULL ); /* this does the grunt work */
if( ( map_obj_index = get_obj_index( OBJ_VNUM_MAP ) ) )
{
if( !( map_obj = create_object( map_obj_index, 0 ) ) )
{
ch_printf( ch, "Couldn't give you a map. create_object failed for object vnum %d\r\n", OBJ_VNUM_MAP );
return;
}
ed = SetOExtra( map_obj, (char *)"runes map scrawls" );
STRSET( ed->description, ch->pnote->text );
obj_to_char( map_obj, ch );
}
else
{
ch_printf( ch, "Couldn't give you a map. Need object vnum %d\r\n", OBJ_VNUM_MAP );
return;
}
do_mapout( ch, (char *)"clear" );
send_to_char( "Your written map has been turned into rooms in your assigned room vnum range.\r\n", ch );
return;
}
send_to_char( "mapout write: create a map in edit buffer.\r\n", ch );
send_to_char( "mapout stat: get information about a written, but not yet created map.\r\n", ch );
send_to_char( "mapout clear: clear a written, but not yet created map.\r\n", ch );
send_to_char( "mapout show: show a written, but not yet created map.\r\n", ch );
send_to_char( "mapout create: turn a written map into rooms in your assigned room vnum range.\r\n", ch );
}
int add_new_room_to_map( CHAR_DATA *ch, char code )
{
int i, start, end;
ROOM_INDEX_DATA *location;
/* Get an unused room to copy to */
if( ch->pcdata->area )
{
start = ch->pcdata->area->low_vnum;
end = ch->pcdata->area->hi_vnum;
}
else
{
start = ch->pcdata->range_lo;
end = ch->pcdata->range_hi;
}
for( i = start; i <= end; i++ )
{
if( !get_room_index( i ) )
{
if( !( location = make_room( i, ch->pcdata->area ) ) )
{
bug( "%s: make_room failed", __FUNCTION__ );
return -1;
}
location->area = ch->pcdata->area;
location->name = STRALLOC( "Floating in a Void" );
location->description = NULL;
xCLEAR_BITS( location->room_flags );
location->light = 0;
if( code == 'I' )
location->sector_type = SECT_INSIDE;
else if( code == 'C' )
location->sector_type = SECT_CITY;
else if( code == 'f' )
location->sector_type = SECT_FIELD;
else if( code == 'F' )
location->sector_type = SECT_FOREST;
else if( code == 'H' )
location->sector_type = SECT_HILLS;
else if( code == 'M' )
location->sector_type = SECT_MOUNTAIN;
else if( code == 's' )
location->sector_type = SECT_WATER_SWIM;
else if( code == 'S' )
location->sector_type = SECT_WATER_NOSWIM;
else if( code == 'A' )
location->sector_type = SECT_AIR;
else if( code == 'D' )
location->sector_type = SECT_DESERT;
else if( code == 'O' )
location->sector_type = SECT_OCEANFLOOR;
else if( code == 'u' )
location->sector_type = SECT_UNDERGROUND;
else if( code == 'U' )
location->sector_type = SECT_UNDERWATER;
else if( code == 'L' )
location->sector_type = SECT_LAVA;
else if( code == 'W' )
location->sector_type = SECT_SWAMP;
else
location->sector_type = SECT_DUNNO;
return i;
}
}
send_to_char( "No available room in your vnums!", ch );
return -1;
}
int num_rooms_avail( CHAR_DATA *ch )
{
int i, n = 0, start = 0, end = 0;
if( !ch || !ch->pcdata )
return 0;
if( ch->pcdata->area )
{
start = ch->pcdata->area->low_vnum;
end = ch->pcdata->area->hi_vnum;
}
else
{
start = ch->pcdata->range_lo;
end = ch->pcdata->range_hi;
}
if( !start && !end )
return 0;
for( i = start; i <= end; i++ )
if( !get_room_index( i ) )
n++;
return n;
}
/*
* This function takes the character string in ch->pnote and
* creates rooms laid out in the appropriate configuration.
*/
void map_to_rooms( CHAR_DATA *ch, MAP_INDEX_DATA *m_index )
{
struct map_stuff map[49][78]; /* size of edit buffer */
int row, col, i, n, x, y, tvnum, leftmost, rightmost;
int newx, newy, start, end;
char *l, c;
ROOM_INDEX_DATA *newrm;
MAP_INDEX_DATA *map_index = NULL, *tmp;
EXIT_DATA *xit; /* these are for exits */
if( !ch->pnote )
{
bug( "%s: ch->pnote is NULL!", __FUNCTION__ );
return;
}
n = 0;
row = col = 0;
leftmost = rightmost = 0;
if( ch->pcdata->area )
{
start = ch->pcdata->area->low_vnum;
end = ch->pcdata->area->hi_vnum;
}
else
{
start = ch->pcdata->range_lo;
end = ch->pcdata->range_hi;
}
/*
* Check to make sure map_index exists.
* If not, then make a new one.
*/
if( !m_index )
{ /* Make a new vnum */
for( i = start; i <= end; i++ )
{
if( !( tmp = get_map_index( i ) ) )
{
map_index = make_new_map_index( i );
break;
}
}
}
else
{
map_index = m_index;
}
if( !map_index )
{
send_to_char( "Couldn't find or make a map_index for you!\r\n", ch );
bug( "%s: Couldn't find or make a map_index.", __FUNCTION__ );
return;
}
for( x = 0; x < 49; x++ )
{
for( y = 0; y < 78; y++ )
{
map[x][y].vnum = 0;
map[x][y].exits = 0;
map[x][y].index = 0;
}
}
l = ch->pnote->text;
do
{
c = l[0];
switch( c )
{
case '\r':
break;
case '\n':
col = 0;
row++;
break;
}
if( c != ' ' && c != '-' && c != '|' && c != '=' && c != '\\' && c != '/' && c != '^'
&& c != ':' && c != '^' && c != 'X' && c != '+' && c != 'W' && c != 'L' && c != 'U'
&& c != 'u' && c != 'O' && c != 'D' && c != 'A' && c != 'S' && c != 's' && c != 'M'
&& c != 'H' && c != 'F' && c != 'f' && c != 'C' && c != 'I' && c != '#' )
{
l++;
continue;
}
if( c == 'W' || c == 'L' || c == 'U' || c == 'u' || c == 'O' || c == 'D' || c == 'A'
|| c == 'S' || c == 's' || c == 'M' || c == 'H' || c == 'F' || c == 'f' || c == 'C'
|| c == 'I' || c == '#' )
{
n++;
/* Actual room info */
map[row][col].vnum = add_new_room_to_map( ch, c );
map_index->map_of_vnums[row][col] = map[row][col].vnum;
}
else
{
map_index->map_of_vnums[row][col] = 0;
map[row][col].vnum = 0;
map[row][col].exits = 0;
}
map[row][col].code = c;
col++;
l++;
}
while( c != '\0' );
for( y = 0; y < ( row + 1 ); y++ )
{ /* rows */
for( x = 0; x < 78; x++ )
{ /* cols (78, i think) */
if( map[y][x].vnum == 0 )
continue;
/* Continue if no newrm */
if( !( newrm = get_room_index( map[y][x].vnum ) ) )
continue;
/* Check up */
if( y > 1 )
{
newx = x;
newy = y;
newy--;
while( newy >= 0 && ( map[newy][x].code == '^' ) )
newy--;
if( map[y][x].vnum != map[newy][x].vnum && ( tvnum = map[newy][x].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_UP );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
xCLEAR_BITS( xit->exit_info );
}
}
/* Check down */
if( y < 48 )
{
newx = x;
newy = y;
newy++;
while( newy <= 48 && ( map[newy][x].code == '^' ) )
newy++;
if( map[y][x].vnum != map[newy][x].vnum && ( tvnum = map[newy][x].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_DOWN );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
xCLEAR_BITS( xit->exit_info );
}
}
/* Check north */
if( y > 1 )
{
newx = x;
newy = y;
newy--;
while( newy >= 0 && ( map[newy][x].code == '|' || map[newy][x].code == ':' || map[newy][x].code == '='
|| map[newy][x].code == '+' ) )
newy--;
if( map[y][x].vnum != map[newy][x].vnum && ( tvnum = map[newy][x].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_NORTH );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
if( map[newy + 1][x].code == ':' || map[newy + 1][x].code == '=' )
{
xSET_BIT( xit->exit_info, EX_ISDOOR );
xSET_BIT( xit->exit_info, EX_CLOSED );
}
else
xCLEAR_BITS( xit->exit_info );
}
}
/* Check south */
if( y < 48 )
{
newx = x;
newy = y;
newy++;
while( newy <= 48 && ( map[newy][x].code == '|' || map[newy][x].code == ':' || map[newy][x].code == '='
|| map[newy][x].code == '+' ) )
newy++;
if( map[y][x].vnum != map[newy][x].vnum && ( tvnum = map[newy][x].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_SOUTH );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
if( map[newy - 1][x].code == ':' || map[newy - 1][x].code == '=' )
{
xSET_BIT( xit->exit_info, EX_ISDOOR );
xSET_BIT( xit->exit_info, EX_CLOSED );
}
else
xCLEAR_BITS( xit->exit_info );
}
}
/* Check east */
if( x < 79 )
{
newx = x;
newy = y;
newx++;
while( newx <= 79 && ( map[y][newx].code == '-' || map[y][newx].code == ':' || map[y][newx].code == '='
|| map[y][newx].code == '+' ) )
newx++;
if( map[y][x].vnum != map[y][newx].vnum && ( tvnum = map[y][newx].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_EAST );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
if( map[y][newx - 2].code == ':' || map[y][newx - 2].code == '=' )
{
xSET_BIT( xit->exit_info, EX_ISDOOR );
xSET_BIT( xit->exit_info, EX_CLOSED );
}
else
xCLEAR_BITS( xit->exit_info );
}
}
/* Check west */
if( x > 1 )
{
newx = x;
newy = y;
newx--;
while( newx >= 0 && ( map[y][newx].code == '-' || map[y][newx].code == ':' || map[y][newx].code == '='
|| map[y][newx].code == '+' ) )
newx--;
if( map[y][x].vnum != map[y][newx].vnum && ( tvnum = map[y][newx].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_WEST );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
if( map[y][newx + 2].code == ':' || map[y][newx + 2].code == '=' )
{
xSET_BIT( xit->exit_info, EX_ISDOOR );
xSET_BIT( xit->exit_info, EX_CLOSED );
}
else
xCLEAR_BITS( xit->exit_info );
}
}
/* Check southeast */
if( y < 48 && x < 79 )
{
newx = x;
newy = y;
newx++;
newy++;
while( newx <= 79 && newy <= 48
&& ( map[newy][newx].code == '\\' || map[newy][newx].code == ':'
|| map[newy][newx].code == '=' || map[newy][newx].code == 'X' ) )
{
newx++;
newy++;
}
if( map[y][x].vnum != map[newy][newx].vnum && ( tvnum = map[newy][newx].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_SOUTHEAST );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
xCLEAR_BITS( xit->exit_info );
}
}
/* Check northeast */
if( y > 1 && x < 79 )
{
newx = x;
newy = y;
newx++;
newy--;
while( newx >= 0 && newy <= 48
&& ( map[newy][newx].code == '/' || map[newy][newx].code == ':'
|| map[newy][newx].code == '=' || map[newy][newx].code == 'X' ) )
{
newx++;
newy--;
}
if( map[y][x].vnum != map[newy][newx].vnum && ( tvnum = map[newy][newx].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_NORTHEAST );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
xCLEAR_BITS( xit->exit_info );
}
}
/* Check northwest */
if( y > 1 && x > 1 )
{
newx = x;
newy = y;
newx--;
newy--;
while( newx >= 0 && newy >= 0
&& ( map[newy][newx].code == '\\' || map[newy][newx].code == ':'
|| map[newy][newx].code == '=' || map[newy][newx].code == 'X' ) )
{
newx--;
newy--;
}
if( map[y][x].vnum != map[newy][newx].vnum && ( tvnum = map[newy][newx].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_NORTHWEST );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
xCLEAR_BITS( xit->exit_info );
}
}
/* Check southwest */
if( y < 48 && x > 1 )
{
newx = x;
newy = y;
newx--;
newy++;
while( newx >= 0 && newy <= 48
&& ( map[newy][newx].code == '/' || map[newy][newx].code == ':'
|| map[newy][newx].code == '=' || map[newy][newx].code == 'X' ) )
{
newx--;
newy++;
}
if( map[y][x].vnum != map[newy][newx].vnum && ( tvnum = map[newy][newx].vnum ) != 0 )
{
xit = make_exit( newrm, get_room_index( tvnum ), DIR_SOUTHWEST );
xit->keyword = NULL;
xit->description = NULL;
xit->key = -1;
xCLEAR_BITS( xit->exit_info );
}
}
}
}
}