/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments 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. *
* *
* Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
/***************************************************************************
* _/ _/ *
* _/_/_/ _/_/ _/_/_/ _/ _/_/ _/ _/ _/_/_/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/_/_/ _/ _/_/ _/_/_/ _/_/_/ *
***************************************************************************
* Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius), *
* Additional credits are in the help file CODECREDITS *
* All Rights Reserved. *
***************************************************************************/
/*
* The core of the automap system was taken from the snippet by Dingo
* which can be accessed at : http://www.vidler.clara.net/automap.html
*
* A few minor extensions to spiff it up was made by Jobo.
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "merc.h"
/* The map itself */
struct map_type map[MAPX + 1][MAPY + 1];
/* Take care of some repetitive code for later */
void get_exit_dir( int dir, int *x, int *y, int xorig, int yorig )
{
/* Get the next coord based on direction */
switch( dir )
{
case 0: /* North */
*x = xorig;
*y = yorig - 1;
break;
case 1: /* East */
*x = xorig + 1;
*y = yorig;
break;
case 2: /* South */
*x = xorig;
*y = yorig + 1;
break;
case 3: /* West */
*x = xorig - 1;
*y = yorig;
break;
default:
*x = -1;
*y = -1;
break;
}
}
/* Clear one map coord */
void clear_coord( int x, int y )
{
map[x][y].tegn = ' ';
map[x][y].vnum = 0;
map[x][y].depth = 0;
map[x][y].info = 0;
map[x][y].can_see = TRUE;
}
/* Clear all exits for one room */
void clear_room( int x, int y )
{
int dir, exitx, exity;
/* Cycle through the four directions */
for( dir = 0; dir < 4; dir++ )
{
/* Find next coord in this direction */
get_exit_dir( dir, &exitx, &exity, x, y );
/* If coord is valid, clear it */
if ( !BOUNDARY( exitx, exity ) ) clear_coord( exitx, exity );
}
}
/* This function is recursive, ie it calls itself */
void map_exits(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoom, int x, int y, int depth)
{
static char map_chars [4] = "|-|-";
int door;
int exitx = 0, exity = 0;
int roomx = 0, roomy = 0;
char buf[200]; // bugs
EXIT_DATA *pExit;
/* Setup this coord as a room */
switch(pRoom->sector_type)
{
case SECT_CITY:
case SECT_INSIDE:
case SECT_UNUSED:
map[x][y].tegn = 'O';
break;
case SECT_FIELD:
case SECT_FOREST:
case SECT_HILLS:
map[x][y].tegn = '*';
break;
case SECT_MOUNTAIN:
map[x][y].tegn = '@';
break;
case SECT_WATER_SWIM:
case SECT_WATER_NOSWIM:
map[x][y].tegn = '=';
break;
case SECT_AIR:
map[x][y].tegn = '~';
break;
case SECT_DESERT:
map[x][y].tegn = '+';
break;
default:
map[x][y].tegn = 'O';
sprintf(buf, "Map_exits: Bad sector type (%d) in room %d.",
pRoom->sector_type, pRoom->vnum);
bug(buf, 0);
break;
}
map[x][y].vnum = pRoom->vnum;
map[x][y].depth = depth;
map[x][y].info = pRoom->room_flags;
map[x][y].can_see = room_is_dark( pRoom );
/* Limit recursion */
if ( depth > MAXDEPTH ) return;
/* This room is done, deal with it's exits */
for( door = 0; door < 4; door++ )
{
/* Skip if there is no exit in this direction */
if ( ( pExit = pRoom->exit[door] ) == NULL ) continue;
/* Get the coords for the next exit and room in this direction */
get_exit_dir( door, &exitx, &exity, x, y );
get_exit_dir( door, &roomx, &roomy, exitx, exity );
/* Skip if coords fall outside map */
if ( BOUNDARY( exitx, exity ) || BOUNDARY( roomx, roomy )) continue;
/* Skip if there is no room beyond this exit */
if ( pExit->to_room == NULL ) continue;
/* Ensure there are no clashes with previously defined rooms */
if ( ( map[roomx][roomy].vnum != 0 ) &&
( map[roomx][roomy].vnum != pExit->to_room->vnum ))
{
/* Use the new room if the depth is higher */
if ( map[roomx][roomy].depth <= depth ) continue;
/* It is so clear the old room */
clear_room( roomx, roomy );
}
/* No exits at MAXDEPTH */
if ( depth == MAXDEPTH ) continue;
/* No need for exits that are already mapped */
if ( map[exitx][exity].depth > 0 ) continue;
/* Fill in exit */
map[exitx][exity].depth = depth;
map[exitx][exity].vnum = pExit->to_room->vnum;
map[exitx][exity].info = pExit->exit_info;
map[exitx][exity].tegn = map_chars[door];
/* More to do? If so we recurse */
if ( ( depth < MAXDEPTH ) &&
( ( map[roomx][roomy].vnum == pExit->to_room->vnum ) ||
( map[roomx][roomy].vnum == 0 ) ) )
{
/* Depth increases by one each time */
map_exits( ch, pExit->to_room, roomx, roomy, depth + 1 );
}
}
}
/* Reformat room descriptions to exclude undesirable characters */
void reformat_desc( char *desc )
{
/* Index variables to keep track of array/pointer elements */
int i, j;
char buf[MAX_STRING_LENGTH], *p;
i = 0;
j = 0;
buf[0] = '\0';
if ( !desc ) return;
/* Replace all "\n" and "\r" with spaces */
for( i = 0; i <= strlen( desc ); i++ )
{
if ( ( desc[i] == '\n' ) || ( desc[i] == '\r' ) ) desc[i] = ' ';
}
/* Remove multiple spaces */
for( p = desc; *p != '\0'; p++ )
{
buf[j] = *p;
j++;
/* Two or more consecutive spaces? */
if ( ( *p == ' ' ) && ( *( p + 1 ) == ' ' ) )
{
do
{
p++;
}
while( *(p + 1) == ' ' );
}
}
buf[j] = '\0';
/* Copy to desc */
sprintf( desc, buf );
}
int get_line( char *desc, int max_len )
{
int i, j = 0, length;
length = strlen(desc);
/* Return if it's short enough for one line */
if ( length <= max_len ) return 0;
/* Calculate end point in string without color */
for( i = 0; i <= length; i++ )
{
/* Here you need to skip your color sequences */
j++;
if ( j > max_len ) break;
}
/* End point is now in i, find the nearest space */
for( j = i; j > 0; j-- )
{
if ( desc[j] == ' ' ) break;
}
/* There could be a problem if there are no spaces on the line */
return j + 1;
}
/* Display the map to the player */
void show_map( CHAR_DATA *ch, char *text )
{
char buf[MAX_STRING_LENGTH * 2];
int x, y, pos;
char *p;
bool alldesc = FALSE; /* Has desc been fully displayed? */
if ( !text ) alldesc = TRUE;
pos = 0;
p = text;
buf[0] = '\0';
/* Top of map frame */
if (ch->level > 6)
sprintf( buf, "#0/----#CMAP#0----\\#n %s #0[#w%d#0]#n\n\r",
//sprintf( buf, "#0+-----------+#n %s #0[#w%d#0]#n\n\r",
ch->in_room->name, ch->in_room->vnum);
else
sprintf( buf, "#0/----#CMAP#0----\\#n %s\n\r", ch->in_room->name);
/* Write out the main map area with text */
for( y = 0; y <= MAPY; y++ )
{
strcat( buf, "#0<#n" );
for( x = 0; x <= MAPX; x++ )
{
switch(map[x][y].tegn)
{
case '-':
case '|':
sprintf(buf + strlen(buf), "#y%c#n", map[x][y].tegn);
break;
case 'X':
sprintf(buf + strlen(buf), "#R%c#n", map[x][y].tegn);
break;
case '*':
sprintf(buf + strlen(buf), "#g%c#n", map[x][y].tegn);
break;
case '@':
sprintf(buf + strlen(buf), "#y%c#n", map[x][y].tegn);
break;
case '=':
sprintf(buf + strlen(buf), "#B%c#n", map[x][y].tegn);
break;
case '~':
sprintf(buf + strlen(buf), "#C%c#n", map[x][y].tegn);
break;
case '+':
sprintf(buf + strlen(buf), "#Y%c#n", map[x][y].tegn);
break;
default:
sprintf( buf + strlen( buf ), "%c", map[x][y].tegn );
}
}
strcat( buf, "#0>#n " );
if (y == 0 && IS_SET(ch->act2, PLR_AUTOEXIT)) // the autoexits
{
sprintf(buf + strlen( buf ), "%s", get_exits(ch));
continue;
}
/* Add the text, if necessary */
if ( !alldesc )
{
pos = get_line( p, 63 );
if ( pos > 0 )
{
strncat( buf, p, pos );
p += pos;
}
else
{
strcat( buf, p );
alldesc = TRUE;
}
}
strcat( buf, "\n\r" );
}
/* Finish off map area */
strcat( buf, "#0\\___________/#n " );
//strcat( buf, "#0+-----------+#n " );
if ( !alldesc )
{
pos = get_line( p, 63 );
if ( pos > 0 )
{
strncat( buf, p, pos );
strcat(buf, "\n\r");
p += pos;
}
else
{
strcat( buf, p );
alldesc = TRUE;
}
}
/* Deal with any leftover text */
if ( !alldesc )
{
do
{
/* Note the number - no map to detract from width */
pos = get_line( p, 78 );
if ( pos > 0 )
{
strncat( buf, p, pos );
strcat(buf, "\n\r");
p += pos;
}
else
{
strcat( buf, p );
alldesc = TRUE;
}
}
while( !alldesc );
}
strcat(buf, "\n\r");
send_to_char(buf, ch);
}
/* Clear, generate and display the map */
void draw_map2( CHAR_DATA *ch, char *desc )
{
int x, y;
static char buf[MAX_STRING_LENGTH];
sprintf( buf, desc );
/* Remove undesirable characters */
reformat_desc( buf );
/* Clear map */
for( y = 0; y <= MAPY; y++ )
{
for( x = 0; x <= MAPX; x++ )
{
clear_coord( x, y );
}
}
/* Start with players pos at centre of map */
x = MAPX / 2;
y = MAPY / 2;
map[x][y].vnum = ch->in_room->vnum;
map[x][y].depth = 0;
/* Generate the map */
map_exits( ch, ch->in_room, x, y, 0 );
/* Current position should be a "X" */
map[x][y].tegn = 'X';
/* Send the map */
show_map( ch, buf );
}