I've fixed up some of the things from the ascii map on circlemud.org. Here's how to add the new one:
-Rikishi

1. Open utils.h, somewhere in the file add this:

#define MAPS(a, b, c)          ((b) < (a) ? (a) : ((b) > (c) ? (c) : (b)))

2. close utils.h

3. Open act.informative.c, and: find send_to_char(ch, "%s", world[target_room].description);
under that add:

do_map(ch, " ");

4. now open Makefile. Then add the map.o, and map.c in the right spots.

5. now in interpreter.c define do_map as a command

6. open map.c, now that made a new file, now add this:

#include "conf.h"
#include "sysdep.h"

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"
#include "house.h"
#include "constants.h"
#include "dg_scripts.h"

#define MAX_MAP 72
#define MAX_MAP_DIR 4
#define SECT_MAX 22

extern struct room_data *world;
int add_to_save_list(zone_vnum zone, int type);
int can_edit_zone(struct char_data *ch, int number);

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

/* Heavily modified - Edward */
void MapArea(room_rnum room, struct char_data *ch, int x, int y, int min, int max)
{
  room_rnum prospect_room;
  struct room_direction_data *pexit;
  int door;

  /* marks the room as visited */
  map[x][y] = world[room].sector_type;

  /* Otherwise we get a nasty crash */
/*  if (!IS_SET(world[ch->in_room].room_flags, ROOM_WILDERNESS))
    return;*/

  for ( door = 0; door < MAX_MAP_DIR; door++ ) {
      if ( (pexit = world[room].dir_option[door]) > 0  &&   
           (pexit->to_room > 0 ) &&
	   (!IS_SET(pexit->exit_info, EX_CLOSED)))
        {
          if ( (x < min) || ( y < min) || ( x > max ) || ( y >max) ) return;
          prospect_room = pexit->to_room;
         
          /* one way into area OR maze */	
          /* if not two way */
          if ( world[prospect_room].dir_option[rev_dir[door]] &&
	     world[prospect_room].dir_option[rev_dir[door]]->to_room != room)
          { 
	    map[x][y] = SECT_MAX + 1;
	    return;
          }
          /* end two way */
          /* players cant see past these */
          if ( (world[prospect_room].sector_type == SECT_CITY) 
	        ||(world[prospect_room].sector_type == SECT_HILLS) 
	        ||(world[prospect_room].sector_type == SECT_INSIDE))
	  { 
	    map[x+offsets[door][0]][y+offsets[door][1]] = world[prospect_room].sector_type;
            /* ^--two way into area */		
	  }

         if ( map[x+offsets[door][0]][y+offsets[door][1]] == SECT_MAX ) {
           MapArea(pexit->to_room,ch,x + offsets[door][0], y + offsets[door][1], min, max);
         }
      } /* end if exit there */
  }
  return;
}

/* mlk :: shows a map, specified by size */
void ShowMap( struct char_data* ch, int min, int max)
{
  int x, y;

  /* every row */
  for (x = min; x < max; ++x) { 
    /* every column */
    for (y = min; y < max; ++y) { 
        if ( (y==min) || (map[x][y-1]!=map[x][y]) ) {
          switch(map[x][y]) {
            case SECT_MAX:	  send_to_char(ch," ");		break;
            case SECT_FOREST:	  send_to_char(ch,"@g@");	break;
            case SECT_FIELD:	  send_to_char(ch,"@G\"");	break;
            case SECT_HILLS:	  send_to_char(ch,"@G^");	break;
            case SECT_MOUNTAIN:	  send_to_char(ch,"@y^");	break;
            case SECT_WATER_SWIM: send_to_char(ch,"@B:");	break;
            case SECT_WATER_NOSWIM:send_to_char(ch,"@b:");	break;
            case SECT_INSIDE:	  send_to_char(ch,"@W@");	break;
            case SECT_CITY:	  send_to_char(ch,"@W#");	break;
            case (SECT_MAX+1):	  send_to_char(ch,"@D?");	break;
            default: 		  send_to_char(ch,"@R*");	break;
          }
        }
        else {
          switch(map[x][y]) {
	    case SECT_MAX:	send_to_char(ch," ");		break;
	    case SECT_FOREST:	send_to_char(ch,"@");		break;
	    case SECT_FIELD:	send_to_char(ch,"\"");		break;
	    case SECT_HILLS:	send_to_char(ch,"^");		break;
	    case SECT_MOUNTAIN:	send_to_char(ch,"^");		break;
	    case SECT_WATER_SWIM:send_to_char(ch,":");		break;
	    case SECT_WATER_NOSWIM:send_to_char(ch,":");	break;
	    case SECT_INSIDE:	send_to_char(ch,"@");		break;
	    case SECT_CITY:	send_to_char(ch,"#");		break;
	    case (SECT_MAX+1):	send_to_char(ch,"?");		break;
	    default: 		send_to_char(ch,"*");
          } 
        }
    }
    send_to_char(ch,"\n\r"); 
  }
  return;
}


/* This is for simplicities sake, if the room's name if
** like An unfinished room, it will replace it with a fake
** room name here - Edward 
*/
void get_room_name(struct char_data *ch, int argument)
{
  char buf[500];
   switch(argument) {
       case SECT_MAX:
           sprintf(buf,"&n   &cThe Wilderness&n");break;
       case SECT_FOREST:
           sprintf(buf,"&n   &cWithin a Forest&n");break;
       case SECT_FIELD:
           sprintf(buf,"&n   &cOn an Open Field&n");break;
       case SECT_HILLS:
           sprintf(buf,"&n   &cOn a Hill&n");break;
       case SECT_MOUNTAIN:
           sprintf(buf,"&n   &cClimbing a Mountain&n");break;
       case SECT_WATER_SWIM:
           sprintf(buf,"&n   &cIn Shallow Water&n");break;
       case SECT_WATER_NOSWIM:
           sprintf(buf,"&n   &cAdrift In Deep Water&n");break;
       case SECT_INSIDE:
           sprintf(buf,"&n   &cThe Wilderness&n");break;
       case SECT_CITY:
           sprintf(buf,"&n   &cWithin a City&n");break;
       case (SECT_MAX+1):
           sprintf(buf,"&n   &cThe Wilderness&n");break;
       default:
           sprintf(buf,"&n   &cThe Wilderness&n");break;
  }
  send_to_char(ch, buf);
}

/* will put a small map with current room desc and title */
/* this is the main function to show the map, its do_map with " " */

/* Heavily modified - Edward */
void ShowRoom( struct char_data *ch, int min, int max)
{
  int x, y;
  char buf[500];
  char desc[500];

  strcpy(desc,world[ch->in_room].description);
  /* mlk :: rounds edges */
  map[min][min]=SECT_MAX;map[max-1][max-1]=SECT_MAX;
  map[min][max-1]=SECT_MAX;map[max-1][min]=SECT_MAX;

  /* every row */
  for (x = min; x < max; ++x) { 
    /* every column */
    for (y = min; y < max; ++y) { 
        if ( (y==min) || (map[x][y-1]!=map[x][y]) )
           switch(map[x][y]) {
	     case SECT_MAX:		send_to_char(ch," ");	break;
	     case SECT_FOREST:	send_to_char(ch,"@g@");		break;
	     case SECT_FIELD:	send_to_char(ch,"@G\"");	break;
	     case SECT_HILLS:	send_to_char(ch,"@G^");		break;
	     case SECT_MOUNTAIN:	send_to_char(ch,"@y^");	break;
	     case SECT_WATER_SWIM:	send_to_char(ch,"@B:");	break;
	     case SECT_WATER_NOSWIM:	send_to_char(ch,"@b:");	break;
	     case SECT_INSIDE:	send_to_char(ch,"@W@");		break;
	     case SECT_CITY:	send_to_char(ch,"@W#");	break;
	     case (SECT_MAX+1):	send_to_char(ch,"@D?");		break;
	     default: 		send_to_char(ch,"@R*");		break;
           }
           else 
             switch(map[x][y]) {
	       case SECT_MAX:	send_to_char(ch," ");		break;
	       case SECT_FOREST:send_to_char(ch,"@");		break;
	       case SECT_FIELD:	send_to_char(ch,"\"");		break;
	       case SECT_HILLS:	send_to_char(ch,"^");		break;
	       case SECT_MOUNTAIN:	send_to_char(ch,"^");	break;
	       case SECT_WATER_SWIM:	send_to_char(ch,":");	break;
	       case SECT_WATER_NOSWIM:	send_to_char(ch,":");	break;
	       case SECT_INSIDE:	send_to_char(ch,"@");	break;
	       case SECT_CITY:		send_to_char(ch,"#");	break;
	       case (SECT_MAX+1):	send_to_char(ch,"?");	break;
	       default: 		send_to_char(ch,"*");	break;
 	     }
    }
    if (x == min) {
      if (!strcmp(world[ch->in_room].name, "The Wilderness") ||
          !strcmp(world[ch->in_room].name, "An unfinished room"))
         get_room_name(ch, world[ch->in_room].sector_type);
      else {
         sprintf(buf," ");
         send_to_char(ch, buf);
      }
      
      if (GET_LEVEL(ch) >= LVL_IMMORT) {
         sprintf(buf," @c[@RRoom @Y%d@c]@n", world[ch->in_room].number);
         send_to_char(ch, buf);
      }
    }
/* I removed the room descriptions from the ascii map, the map is descriptive enough
** I think - Edward. Just remove the comments if you want them back.
    else {
        start = str_pos;
        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';
        if (x == min + 1) send_to_char("  ", ch);
        send_to_char("   &c", ch);
        send_to_char(line, ch);
        send_to_char("&n",ch);
    }
*/
    send_to_char(ch,"\n\r"); 
  }
  send_to_char(ch,"\n\r");  /* puts a line between contents/people */
  return;
}

/* This is the main map function, do_map(ch, " ") is good to use */
/* do_map(ch "number") is for immortals to see the world map     */

/* Edward: If you play with some of the values here you can make the normal
** map people see larger or smaller. size = URANGE(9, size, MAX_MAP), the 9
** is the map size shown by default. Also look for: ShowMap (ch, min, max+1);
** and change the size of min and max and see what you like.
*/
void do_map( struct char_data *ch, char *argument )
{
  int size, center, x, y, min, max;
  char arg1[10];
  one_argument( argument, arg1 );
  size = atoi(arg1);
  size = MAPS(10,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 */
  MapArea(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 	*/
				     /* switch default will print out the *	*/

  if ( (GET_LEVEL(ch) < LVL_IMMORT)||(IS_NPC(ch)) ) {
/*     if ( !IS_SET(world[ch->in_room].room_flags, ROOM_WILDERNESS) ) {
       send_to_char(ch, "&CYou can not do that here&n.\n\r");return;}*/
       if ( IS_DARK(ch->in_room) ) {
          send_to_char(ch, "&bThe wilderness is pitch black at night... &n\n\r");
          return;
       }
       else {
         ShowRoom(ch,MAX_MAP/2-3,MAX_MAP/2+3);
         return;
       }
    }
    /* mortals not in city, enter or inside will always get a ShowRoom */
    if (GET_LEVEL(ch) >= LVL_IMMORT) {
       if (arg1[0] == '\0') 
          ShowRoom (ch, min, max+1); 
       else 
          ShowMap (ch, min, max+1); 
       return;
   }
   send_to_char(ch,"@CHuh?&n\n\r");
   return;
}