Пример #1
0
/* 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';

	/*
	 * Show exits 
	 */
	if ( xIS_SET( ch->act, PLR_AUTOEXIT ) )
		snprintf( buf, MAX_STRING_LENGTH * 2, "%s%s", color_str( AT_EXITS, ch ), get_exits( ch ) );
	else
		mudstrlcpy( buf, "", MAX_STRING_LENGTH * 2 );

	/*
	 * Top of map frame 
	 */
	mudstrlcat( buf, "&z+-----------+&w ", MAX_STRING_LENGTH * 2 );
	if ( !alldesc )
	{
		pos = get_line( p, 63 );
		if ( pos > 0 )
		{
			mudstrlcat( buf, color_str( AT_RMDESC, ch ), MAX_STRING_LENGTH * 2 );
			strncat( buf, p, pos );
			p += pos;
		}
		else
		{
			mudstrlcat( buf, color_str( AT_RMDESC, ch ), MAX_STRING_LENGTH * 2 );
			mudstrlcat( buf, p, MAX_STRING_LENGTH * 2 );
			alldesc = TRUE;
		}
	}
	mudstrlcat( buf, "\r\n", MAX_STRING_LENGTH * 2 );

	/*
	 * Write out the main map area with text 
	 */
	for ( y = 0; y <= MAPY; ++y )
	{
		mudstrlcat( buf, "&z|&D", MAX_STRING_LENGTH * 2 );

		for ( x = 0; x <= MAPX; ++x )
		{
			switch ( dmap[x][y].tegn )
			{
				case '-':
				case '|':
				case '\\':
				case '/':
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "&O%c&d", dmap[x][y].tegn );
					break;

				case '@':	// Character is standing here
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "&R%c&d", dmap[x][y].tegn );
					break;

				case 'O':	// Indoors
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "&w%c&d", dmap[x][y].tegn );
					break;

				case '=':
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "&B%c&d", dmap[x][y].tegn );
					break;

				case '~':
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "&C%c&d", dmap[x][y].tegn );
					break;

				case '+':
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "&Y%c&d", dmap[x][y].tegn );
					break;

				case '*':
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "&g%c&d", dmap[x][y].tegn );
					break;

				case 'X':
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "&R%c&d", dmap[x][y].tegn );
					break;

				case ':':
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "&Y%c&d", dmap[x][y].tegn );
					break;

				default:	// Empty space
					snprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH * 2 ) - strlen( buf ), "%c", dmap[x][y].tegn );
					break;
			}
		}
		mudstrlcat( buf, "&z|&D ", MAX_STRING_LENGTH * 2 );

		/*
		 * Add the text, if necessary 
		 */
		if ( !alldesc )
		{
			pos = get_line( p, 63 );
			char col[10], c[2];

			strcpy( c, whatColor( text, p ) );
			if ( c[0] == '\0' )
				mudstrlcpy( col, color_str( AT_RMDESC, ch ), 10 );
			else
				snprintf( col, 10, "%s", c );

			if ( pos > 0 )
			{
				mudstrlcat( buf, col, MAX_STRING_LENGTH * 2 );
				strncat( buf, p, pos );
				p += pos;
			}
			else
			{
				mudstrlcat( buf, col, MAX_STRING_LENGTH * 2 );
				mudstrlcat( buf, p, MAX_STRING_LENGTH * 2 );
				alldesc = TRUE;
			}
		}
		mudstrlcat( buf, "\r\n", MAX_STRING_LENGTH * 2 );
	}

	/*
	 * Finish off map area 
	 */
	mudstrlcat( buf, "&z+-----------+&D ", MAX_STRING_LENGTH * 2 );
	if ( !alldesc )
	{
		char col[10], c[2];

		pos = get_line( p, 63 );

		strcpy( c, whatColor( text, p ) );
		if ( c[0] == '\0' )
			mudstrlcpy( col, color_str( AT_RMDESC, ch ), 10 );
		else
			snprintf( col, 10, "%s", c );

		if ( pos > 0 )
		{
			mudstrlcat( buf, col, MAX_STRING_LENGTH * 2 );
			strncat( buf, p, pos );
			p += pos;
			mudstrlcat( buf, "\r\n", MAX_STRING_LENGTH * 2 );
		}
		else
		{
			mudstrlcat( buf, col, MAX_STRING_LENGTH * 2 );
			mudstrlcat( buf, p, MAX_STRING_LENGTH * 2 );
			alldesc = TRUE;
		}
	}

	/*
	 * Deal with any leftover text 
	 */
	if ( !alldesc )
	{
		char col[10], c[2];

		do
		{
			/*
			 * Note the number - no map to detract from width 
			 */
			pos = get_line( p, 78 );

			strcpy( c, whatColor( text, p ) );
			if ( c[0] == '\0' )
				mudstrlcpy( col, color_str( AT_RMDESC, ch ), 10 );
			else
				snprintf( col, 10, "%s", c );

			if ( pos > 0 )
			{
				mudstrlcat( buf, col, MAX_STRING_LENGTH * 2 );
				strncat( buf, p, pos );
				p += pos;
				mudstrlcat( buf, "\r\n", MAX_STRING_LENGTH * 2 );
			}
			else
			{
				mudstrlcat( buf, col, MAX_STRING_LENGTH * 2 );
				mudstrlcat( buf, p, MAX_STRING_LENGTH * 2 );
				alldesc = TRUE;
			}
		}
		while ( !alldesc );
	}
	mudstrlcat( buf, "&D\r\n", MAX_STRING_LENGTH * 2 );
	send_to_char( buf, ch );
}
Пример #2
0
void do_list( CHAR_DATA *ch, char *argument )
{
    if ( IS_SET(ch->in_room->room_flags, ROOM_PET_SHOP) )
    {
	ROOM_INDEX_DATA *pRoomIndexNext;
	CHAR_DATA *pet;
	bool found;

	pRoomIndexNext = get_room_index( ch->in_room->vnum + 1 );
	if ( !pRoomIndexNext )
	{
	    bug( "Do_list: bad pet shop at vnum %d.", ch->in_room->vnum );
	    send_to_char( "You can't do that here.\n\r", ch );
	    return;
	}

	found = FALSE;
	for ( pet = pRoomIndexNext->first_person; pet; pet = pet->next_in_room )
	{
	    if ( IS_SET(pet->act, ACT_PET) && IS_NPC(pet) )
	    {
		if ( !found )
		{
		    found = TRUE;
		    send_to_char( "Pets for sale:\n\r", ch );
		}
		ch_printf( ch, "[%2d] %8d - %s\n\r",
			pet->top_level,
			10 * pet->top_level * pet->top_level,
			pet->short_descr );
	    }
	}
	if ( !found )
	    send_to_char( "Sorry, we're out of pets right now.\n\r", ch );
	return;
    }
    else
    {
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *keeper;
	OBJ_DATA *obj;
	int cost;
	int oref = 0;
	bool found;

	one_argument( argument, arg );

	if ( ( keeper = find_keeper( ch ) ) == NULL )
	    return;

	found = FALSE;
	for ( obj = keeper->last_carrying; obj; obj = obj->prev_content )
	{
	    if ( obj->wear_loc == WEAR_NONE
	    &&   can_see_obj( ch, obj ) )
	    {
	       oref++;
	       if ( ( cost = get_cost( ch, keeper, obj, TRUE ) ) > 0
	       && ( arg[0] == '\0' || nifty_is_name( arg, obj->name ) ) )
	       {
	       	if (keeper->home != NULL)
		  cost = obj->cost;
		if ( !found )
		{
		    found = TRUE;
		    ch_printf( ch, "%s[Price] {ref} Item\n\r", color_str( AT_LIST, ch) );
		}
		ch_printf( ch, "%s[%5d] {%3d} %s%s%s.\n\r",
		    color_str(AT_LIST, ch), cost, oref, capitalize( obj->short_descr ), color_str(AT_LIST, ch),
		    IS_SET(obj->extra_flags, ITEM_HUTT_SIZE) ? " (hutt size)" :
		    ( IS_SET(obj->extra_flags, ITEM_LARGE_SIZE) ? " (large)" :
		    ( IS_SET(obj->extra_flags, ITEM_HUMAN_SIZE) ? " (medium)" :
		    ( IS_SET(obj->extra_flags, ITEM_SMALL_SIZE) ? " (small)" :
		    "" ) ) ) );
	       }
	    }
	}

	if ( !found )
	{
	    if ( arg[0] == '\0' )
		send_to_char( "You can't buy anything here.\n\r", ch );
	    else
		send_to_char( "You can't buy that here.\n\r", ch );
	}
	return;
    }
}
Пример #3
0
/*
 * Quixadhal - I rewrote this from scratch.  It now returns the number of
 * characters in the SOURCE string that should be skipped, it always fills
 * the DESTINATION string with a valid translation (even if that is itself,
 * or an empty string), and the default for ANSI is FALSE, since mobs and
 * logfiles shouldn't need colour.
 *
 * NOTE:  dstlen is the length of your pre-allocated buffer that you passed
 * in.  It must be at least 3 bytes, but should be long enough to hold the
 * longest translation sequence (probably around 16-32).
 *
 * NOTE:  vislen is the "visible" length of the translation token.  This is
 * used by color_strlen to properly figure the visual length of a string.
 * If you need the number of bytes (such as for output buffering), use the
 * normal strlen function.
 */
int colorcode( const char *src, char *dst, DESCRIPTOR_DATA * d, int dstlen, int *vislen )
{
   CHAR_DATA *ch = NULL;
   bool ansi = FALSE;
   const char *sympos = NULL;

   /*
    * No descriptor, assume ANSI conversion can't be done. 
    */
   if( !d )
      ansi = FALSE;
   /*
    * But, if we have one, check for a PC and set accordingly. If no PC, assume ANSI can be done. For color logins. 
    */
   else
   {
      ch = d->original ? d->original : d->character;

      if( ch )
         ansi = ( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_ANSI ) );
      else
         ansi = TRUE;
   }

   if( !dst )
      return 0;   /* HEY, I said at least 3 BYTES! */

   dst[0] = '\0'; /* Initialize the the default NOTHING */

   /*
    * Move along, nothing to see here 
    */
   if( !src || !*src )
      return 0;

   switch ( *src )
   {
      case '&':  /* NORMAL, Foreground colour */
         switch ( src[1] )
         {
            case '&':  /* Escaped self, return one of us */
               dst[0] = src[0];
               dst[1] = '\0';
               if( vislen )
                  *vislen = 1;
               return 2;

            case 'Z':  /* Random Ansi Foreground */
               if( ansi )
                  mudstrlcpy( dst, random_ansi( 1 ), dstlen );
               break;

            case '[':  /* Symbolic color name */
               if( ( sympos = strchr( src + 2, ']' ) ) )
               {
                  register int subcnt = 0;
                  unsigned int sublen = 0;

                  sublen = sympos - src - 2;
                  for( subcnt = 0; subcnt < MAX_COLORS; subcnt++ )
                  {
                     if( !strncmp( src + 2, pc_displays[subcnt], sublen ) )
                     {
                        if( strlen( pc_displays[subcnt] ) == sublen )
                        {
                           /*
                            * These can only be used with a logged in char 
                            */
                           if( ansi && ch )
                              mudstrlcpy( dst, color_str( subcnt, ch ), dstlen );
                           if( vislen )
                              *vislen = 0;
                           return sublen + 3;
                        }
                     }
                  }
               }  /* found matching ] */

               /*
                * Unknown symbolic name, return just the sequence  
                */
               dst[0] = src[0];
               dst[1] = src[1];
               dst[2] = '\0';
               if( vislen )
                  *vislen = 2;
               return 2;

            case 'i':  /* Italic text */
            case 'I':
               if( ansi )
                  mudstrlcpy( dst, ANSI_ITALIC, dstlen );
               break;

            case 'v':  /* Reverse colors */
            case 'V':
               if( ansi )
                  mudstrlcpy( dst, ANSI_REVERSE, dstlen );
               break;

            case 'u':  /* Underline */
            case 'U':
               if( ansi )
                  mudstrlcpy( dst, ANSI_UNDERLINE, dstlen );
               break;

            case 's':  /* Strikeover */
            case 'S':
               if( ansi )
                  mudstrlcpy( dst, ANSI_STRIKEOUT, dstlen );
               break;

            case 'd':  /* Player's client default color */
               if( ansi )
                  mudstrlcpy( dst, ANSI_RESET, dstlen );
               break;

            case 'D':  /* Reset to custom color for whatever is being displayed */
               if( ansi )
               {
                  /*
                   * Yes, this reset here is quite necessary to cancel out other things 
                   */
                  mudstrlcpy( dst, ANSI_RESET, dstlen );
                  if( ch && ch->desc )
                     mudstrlcat( dst, color_str( ch->desc->pagecolor, ch ), dstlen );
               }
               break;

            case 'x':  /* Black */
               if( ansi )
                  mudstrlcpy( dst, ANSI_BLACK, dstlen );
               break;

            case 'O':  /* Orange/Brown */
               if( ansi )
                  mudstrlcpy( dst, ANSI_ORANGE, dstlen );
               break;

            case 'c':  /* Cyan */
               if( ansi )
                  mudstrlcpy( dst, ANSI_CYAN, dstlen );
               break;

            case 'z':  /* Dark Grey */
               if( ansi )
                  mudstrlcpy( dst, ANSI_DGREY, dstlen );
               break;

            case 'g':  /* Dark Green */
               if( ansi )
                  mudstrlcpy( dst, ANSI_DGREEN, dstlen );
               break;

            case 'G':  /* Light Green */
               if( ansi )
                  mudstrlcpy( dst, ANSI_GREEN, dstlen );
               break;

            case 'P':  /* Pink/Light Purple */
               if( ansi )
                  mudstrlcpy( dst, ANSI_PINK, dstlen );
               break;

            case 'r':  /* Dark Red */
               if( ansi )
                  mudstrlcpy( dst, ANSI_DRED, dstlen );
               break;

            case 'b':  /* Dark Blue */
               if( ansi )
                  mudstrlcpy( dst, ANSI_DBLUE, dstlen );
               break;

            case 'w':  /* Grey */
               if( ansi )
                  mudstrlcpy( dst, ANSI_GREY, dstlen );
               break;

            case 'Y':  /* Yellow */
               if( ansi )
                  mudstrlcpy( dst, ANSI_YELLOW, dstlen );
               break;

            case 'C':  /* Light Blue */
               if( ansi )
                  mudstrlcpy( dst, ANSI_LBLUE, dstlen );
               break;

            case 'p':  /* Purple */
               if( ansi )
                  mudstrlcpy( dst, ANSI_PURPLE, dstlen );
               break;

            case 'R':  /* Red */
               if( ansi )
                  mudstrlcpy( dst, ANSI_RED, dstlen );
               break;

            case 'B':  /* Blue */
               if( ansi )
                  mudstrlcpy( dst, ANSI_BLUE, dstlen );
               break;

            case 'W':  /* White */
               if( ansi )
                  mudstrlcpy( dst, ANSI_WHITE, dstlen );
               break;

            default:   /* Unknown sequence, return all the chars */
               dst[0] = src[0];
               dst[1] = src[1];
               dst[2] = '\0';
               if( vislen )
                  *vislen = 2;
               return 2;
         }
         break;

      case '^':  /* BACKGROUND colour */
         switch ( src[1] )
         {
            case '^':  /* Escaped self, return one of us */
               dst[0] = src[0];
               dst[1] = '\0';
               if( vislen )
                  *vislen = 1;
               return 2;

            case 'Z':  /* Random Ansi Background */
               if( ansi )
                  mudstrlcpy( dst, random_ansi( 3 ), dstlen );
               break;

            case 'x':  /* Black */
               if( ansi )
                  mudstrlcpy( dst, BACK_BLACK, dstlen );
               break;

            case 'r':  /* Dark Red */
               if( ansi )
                  mudstrlcpy( dst, BACK_DRED, dstlen );
               break;

            case 'g':  /* Dark Green */
               if( ansi )
                  mudstrlcpy( dst, BACK_DGREEN, dstlen );
               break;

            case 'O':  /* Orange/Brown */
               if( ansi )
                  mudstrlcpy( dst, BACK_ORANGE, dstlen );
               break;

            case 'b':  /* Dark Blue */
               if( ansi )
                  mudstrlcpy( dst, BACK_DBLUE, dstlen );
               break;

            case 'p':  /* Purple */
               if( ansi )
                  mudstrlcpy( dst, BACK_PURPLE, dstlen );
               break;

            case 'c':  /* Cyan */
               if( ansi )
                  mudstrlcpy( dst, BACK_CYAN, dstlen );
               break;

            case 'w':  /* Grey */
               if( ansi )
                  mudstrlcpy( dst, BACK_GREY, dstlen );
               break;

            case 'z':  /* Dark Grey */
               if( ansi )
                  mudstrlcpy( dst, BACK_DGREY, dstlen );
               break;

            case 'R':  /* Red */
               if( ansi )
                  mudstrlcpy( dst, BACK_RED, dstlen );
               break;

            case 'G':  /* Green */
               if( ansi )
                  mudstrlcpy( dst, BACK_GREEN, dstlen );
               break;

            case 'Y':  /* Yellow */
               if( ansi )
                  mudstrlcpy( dst, BACK_YELLOW, dstlen );
               break;

            case 'B':  /* Blue */
               if( ansi )
                  mudstrlcpy( dst, BACK_BLUE, dstlen );
               break;

            case 'P':  /* Pink */
               if( ansi )
                  mudstrlcpy( dst, BACK_PINK, dstlen );
               break;

            case 'C':  /* Light Blue */
               if( ansi )
                  mudstrlcpy( dst, BACK_LBLUE, dstlen );
               break;

            case 'W':  /* White */
               if( ansi )
                  mudstrlcpy( dst, BACK_WHITE, dstlen );
               break;

            default:   /* Unknown sequence, return all the chars */
               dst[0] = src[0];
               dst[1] = src[1];
               dst[2] = '\0';
               if( vislen )
                  *vislen = 2;
               return 2;
         }
         break;

      case '}':  /* BLINK Foreground colour */
         switch ( src[1] )
         {
            case '}':  /* Escaped self, return one of us */
               dst[0] = src[0];
               dst[1] = '\0';
               if( vislen )
                  *vislen = 1;
               return 2;

            case 'Z':  /* Random Ansi Blink */
               if( ansi )
                  mudstrlcpy( dst, random_ansi( 2 ), dstlen );
               break;

            case 'x':  /* Black */
               if( ansi )
                  mudstrlcpy( dst, BLINK_BLACK, dstlen );
               break;

            case 'O':  /* Orange/Brown */
               if( ansi )
                  mudstrlcpy( dst, BLINK_ORANGE, dstlen );
               break;

            case 'c':  /* Cyan */
               if( ansi )
                  mudstrlcpy( dst, BLINK_CYAN, dstlen );
               break;

            case 'z':  /* Dark Grey */
               if( ansi )
                  mudstrlcpy( dst, BLINK_DGREY, dstlen );
               break;

            case 'g':  /* Dark Green */
               if( ansi )
                  mudstrlcpy( dst, BLINK_DGREEN, dstlen );
               break;

            case 'G':  /* Light Green */
               if( ansi )
                  mudstrlcpy( dst, BLINK_GREEN, dstlen );
               break;

            case 'P':  /* Pink/Light Purple */
               if( ansi )
                  mudstrlcpy( dst, BLINK_PINK, dstlen );
               break;

            case 'r':  /* Dark Red */
               if( ansi )
                  mudstrlcpy( dst, BLINK_DRED, dstlen );
               break;

            case 'b':  /* Dark Blue */
               if( ansi )
                  mudstrlcpy( dst, BLINK_DBLUE, dstlen );
               break;

            case 'w':  /* Grey */
               if( ansi )
                  mudstrlcpy( dst, BLINK_GREY, dstlen );
               break;

            case 'Y':  /* Yellow */
               if( ansi )
                  mudstrlcpy( dst, BLINK_YELLOW, dstlen );
               break;

            case 'C':  /* Light Blue */
               if( ansi )
                  mudstrlcpy( dst, BLINK_LBLUE, dstlen );
               break;

            case 'p':  /* Purple */
               if( ansi )
                  mudstrlcpy( dst, BLINK_PURPLE, dstlen );
               break;

            case 'R':  /* Red */
               if( ansi )
                  mudstrlcpy( dst, BLINK_RED, dstlen );
               break;

            case 'B':  /* Blue */
               if( ansi )
                  mudstrlcpy( dst, BLINK_BLUE, dstlen );
               break;

            case 'W':  /* White */
               if( ansi )
                  mudstrlcpy( dst, BLINK_WHITE, dstlen );
               break;

            default:   /* Unknown sequence, return all the chars */
               dst[0] = src[0];
               dst[1] = src[1];
               dst[2] = '\0';
               if( vislen )
                  *vislen = 2;
               return 2;
         }
         break;

      default:   /* Just a normal character */
         dst[0] = *src;
         dst[1] = '\0';
         if( vislen )
            *vislen = 1;
         return 1;
   }
   if( vislen )
      *vislen = 0;
   return 2;
}
Пример #4
0
static void print_entry_long(int * widths, struct tfile * file) {
	const char * ansi_color_str = color_str(&file->statbuf);

	/* file permissions */
	if (S_ISLNK(file->statbuf.st_mode))       { printf("l"); }
	else if (S_ISCHR(file->statbuf.st_mode))  { printf("c"); }
	else if (S_ISBLK(file->statbuf.st_mode))  { printf("b"); }
	else if (S_ISDIR(file->statbuf.st_mode))  { printf("d"); }
	else { printf("-"); }
	printf( (file->statbuf.st_mode & S_IRUSR) ? "r" : "-");
	printf( (file->statbuf.st_mode & S_IWUSR) ? "w" : "-");
	if (file->statbuf.st_mode & S_ISUID) {
		printf("s");
	} else {
		printf( (file->statbuf.st_mode & S_IXUSR) ? "x" : "-");
	}
	printf( (file->statbuf.st_mode & S_IRGRP) ? "r" : "-");
	printf( (file->statbuf.st_mode & S_IWGRP) ? "w" : "-");
	printf( (file->statbuf.st_mode & S_IXGRP) ? "x" : "-");
	printf( (file->statbuf.st_mode & S_IROTH) ? "r" : "-");
	printf( (file->statbuf.st_mode & S_IWOTH) ? "w" : "-");
	printf( (file->statbuf.st_mode & S_IXOTH) ? "x" : "-");

	printf( " %*d ", widths[0], file->statbuf.st_nlink); /* number of links, not supported */

	char tmp[100];
	print_username(tmp, file->statbuf.st_uid);
	printf("%-*s ", widths[1], tmp);
	print_username(tmp, file->statbuf.st_gid);
	printf("%-*s ", widths[2], tmp);

	if (human_readable) {
		print_human_readable_size(tmp, file->statbuf.st_size);
		printf("%*s ", widths[3], tmp);
	} else {
		printf("%*d ", widths[3], (int)file->statbuf.st_size);
	}

	char time_buf[80];
	struct tm * timeinfo = localtime((time_t*)&file->statbuf.st_mtime);
	if (timeinfo->tm_year == this_year) {
		strftime(time_buf, 80, "%b %d %H:%M", timeinfo);
	} else {
		strftime(time_buf, 80, "%b %d  %Y", timeinfo);
	}
	printf("%s ", time_buf);

	/* Print the file name */
	if (stdout_is_tty) {
		printf("\033[%sm%s\033[0m", ansi_color_str, file->name);
		if (S_ISLNK(file->statbuf.st_mode)) {
			const char * s = color_str(&file->statbufl);
			printf(" -> \033[%sm%s\033[0m", s, file->link);
		}
	} else {
		printf("%s", file->name);
		if (S_ISLNK(file->statbuf.st_mode)) {
			printf(" -> %s", file->link);
		}
	}

	printf("\n");
}
Пример #5
0
static int
process(char *filename,RUBBLE_PILE *rp,BOOLEAN sim_units,double *time)
{
	enum {next,mass,radius,density,pos,vel,orient,spin,color,agg_id,par_id};

	SSIO ssio;
	SSHEAD h;
	int i,choice;

	assert(rp != NULL);

	*time = 0.0;

	if (ssioOpen(filename,&ssio,SSIO_READ)) {
		(void) fprintf(stderr,"Unable to open \"%s\"\n",filename);
		return 1;
		}

	if (ssioHead(&ssio,&h) || h.n_data < 0) {
		(void) fprintf(stderr,"Corrupt header\n");
		(void) ssioClose(&ssio);
		return 1;
		}

	if (h.n_data == 0) {
		(void) fprintf(stderr,"No data found!");
		(void) ssioClose(&ssio);
		return 1;
		}

	switch(h.iMagicNumber) {
	case SSIO_MAGIC_STANDARD:
		break;
	case SSIO_MAGIC_REDUCED:
		(void) fprintf(stderr,"Reduced ss format not supported.\n");
		ssioClose(&ssio);
		return 1;
	default:
		(void) fprintf(stderr,"Unrecognized ss file magic number (%i).\n",h.iMagicNumber);
		ssioClose(&ssio);
		return 1;
		}

	rp->n_particles = h.n_data;
	*time = h.time;
	(void) printf("Number of particles = %i (time %g)\n",rp->n_particles,*time);
	rpuMalloc(rp);

	for (i=0;i<rp->n_particles;i++)
		if (ssioData(&ssio,&rp->data[i])) {
			(void) fprintf(stderr,"Corrupt data\n");
			(void) ssioClose(&ssio);
			return 1;
			}

	(void) ssioClose(&ssio);

	while (/*CONSTCOND*/1) {

		rpuAnalyze(rp);

		(void) printf("%i. Total mass = ",mass);
		if (sim_units) (void) printf("%g M_sun",rp->mass);
		else (void) printf("%g kg",rp->mass*M_SCALE);
		(void) printf("\n");

		(void) printf("%i. Bulk radius = ",radius);
		if (sim_units) (void) printf("%g AU",rp->radius);
		else (void) printf("%g km",rp->radius*0.001*L_SCALE);
		(void) printf("\n");

		(void) printf("   [Bulk semi-axes: ");
		if (sim_units) (void) printf("%g %g %g AU",
									 rp->axis_len[rp->axis_ord[X]],
									 rp->axis_len[rp->axis_ord[Y]],
									 rp->axis_len[rp->axis_ord[Z]]);
		else (void) printf("%g %g %g km",
						   rp->axis_len[rp->axis_ord[X]]*0.001*L_SCALE,
						   rp->axis_len[rp->axis_ord[Y]]*0.001*L_SCALE,
						   rp->axis_len[rp->axis_ord[Z]]*0.001*L_SCALE);
		(void) printf("]\n");

		(void) printf("%i. Bulk density = ",density);
		if (sim_units) (void) printf("%g M_sun/AU^3",rp->density);
		else (void) printf("%g g/cc",rp->density*0.001*D_SCALE);
		(void) printf("\n");

		(void) printf("%i. Centre-of-mass position = ",pos);
		if (sim_units) (void) printf("%g %g %g AU",rp->pos[X],rp->pos[Y],
									 rp->pos[Z]);
		else (void) printf("%.2f %.2f %.2f km",rp->pos[X]*0.001*L_SCALE,
						   rp->pos[Y]*0.001*L_SCALE,rp->pos[Z]*0.001*L_SCALE);
		(void) printf("\n");

		(void) printf("%i. Centre-of-mass velocity = ",vel);
		if (sim_units) (void) printf("%g %g %g x 30 km/s",rp->vel[X],rp->vel[Y],
									 rp->vel[Z]);
		else (void) printf("%.2f %.2f %.2f m/s",rp->vel[X]*V_SCALE,
						   rp->vel[Y]*V_SCALE,rp->vel[Z]*V_SCALE);
		(void) printf("\n");

		(void) printf("%i. Orientation: a1 = %6.3f %6.3f %6.3f\n",orient,
					  rp->axes[rp->axis_ord[X]][X],
					  rp->axes[rp->axis_ord[X]][Y],
					  rp->axes[rp->axis_ord[X]][Z]);
		(void) printf("                a2 = %6.3f %6.3f %6.3f\n",
					  rp->axes[rp->axis_ord[Y]][X],
					  rp->axes[rp->axis_ord[Y]][Y],
					  rp->axes[rp->axis_ord[Y]][Z]);
		(void) printf("                a3 = %6.3f %6.3f %6.3f\n",
					  rp->axes[rp->axis_ord[Z]][X],
					  rp->axes[rp->axis_ord[Z]][Y],
					  rp->axes[rp->axis_ord[Z]][Z]);

		(void) printf("%i. Spin = ",spin);
		if (sim_units) (void) printf("%g %g %g x 2pi rad/yr",
									 rp->spin[X],rp->spin[Y],rp->spin[Z]);
		else {
			double scale = 3600/(TWO_PI*T_SCALE),w;
			(void) printf("%.2f %.2f %.2f 1/h (",rp->spin[X]*scale,
						  rp->spin[Y]*scale,rp->spin[Z]*scale);
			w = MAG(rp->spin);
			if (w) (void) printf("period %g h",1/(w*scale));
			else (void) printf("no spin");
			(void) printf(")");
			}
		(void) printf("\n");

		(void) printf("   [Ang mom = ");
		if (sim_units) (void) printf("%g %g %g (sys units)",rp->ang_mom[X],
									 rp->ang_mom[Y],rp->ang_mom[Z]);
		else {
			double scale = M_SCALE*SQ(L_SCALE)/T_SCALE;
			(void) printf("%.5e %.5e %.5e N m/s",rp->ang_mom[X]*scale,
						  rp->ang_mom[Y]*scale,rp->ang_mom[Z]*scale);
			}
		(void) printf("]\n");

		(void) printf("   [Effective spin = ");
		if (sim_units) (void) printf("%g x 2pi rad/yr",rp->eff_spin);
		else {
			double scale = 3600/(TWO_PI*T_SCALE);
			(void) printf("%.2f 1/h (",rp->eff_spin*scale);
			if (rp->eff_spin) printf("period %g h",1/(rp->eff_spin*scale));
			else (void) printf("no spin");
			(void) printf(")");
			}
		(void) printf("]\n");

		(void) printf("   [Rotation index = %.2f (",rp->rot_idx);
		if (rp->eff_spin == 0.0) (void) printf("undefined");
		else if (rp->rot_idx == 1.0) (void) printf("unif rot about max moment");
		else if (rp->rot_idx < 1.0 && rp->rot_idx > 0.0) (void) printf("SAM");
		else if (rp->rot_idx == 0.0) (void) printf("unif rot about mid moment");
		else if (rp->rot_idx < 0.0 && rp->rot_idx > -1.0) (void) printf("LAM");
		else if (rp->rot_idx == -1.0) (void) printf("unif rot about min moment");
		else assert(0);
		(void) printf(")]\n");

		(void) printf("%i. Color = %i (%s)\n",color,(int) rp->color,
					  color_str(rp->color));

		(void) printf("%i. Aggregate ID = ",agg_id);
		if (rp->agg_id < 0)
			(void) printf("N/A");
		else
			(void) printf("%i",(int) rp->agg_id);
		(void) printf("\n");

		(void) printf("%i. Particle ID\n",par_id);

		do {
			(void) printf("Enter number to change (or 0 to continue): ");
			(void) scanf("%i",&choice);
			(void) getchar();
			} while (choice < next || choice > par_id);
		
		if (choice == next) return 0;

		switch(choice) {
		case mass:
			{
			double f;
			BOOLEAN const_den = get_yn("Keep bulk density constant","n"),proceed=TRUE;
			do {
				(void) printf("Enter mass scaling factor (-ve ==> abs val): ");
				(void) scanf("%lf",&f);
				if (f == 0.0) {
					getchar();
					proceed = get_yn("WARNING: This will set all particle masses to zero...continue","n");
					}
				} while (!proceed);
			if (f < 0) {
				if (!sim_units) f /= M_SCALE;
				f = -f/rp->mass;
				}
			rpuScaleMass(rp,f);
			if (const_den) rpuScaleRadius(rp,pow(f,1.0/3),FALSE);
			break;
			}
		case radius:
			{
			double f;
			BOOLEAN just_particles = get_yn("Just scale particles","n"),const_den = FALSE;
			if (!just_particles)
				const_den = get_yn("Keep bulk density constant","n");
			do {
				(void) printf("Enter radius scaling factor "
							  "(-ve ==> abs val): ");
				(void) scanf("%lf",&f);
				} while (f == 0);
			getchar();
			if (f < 0) {
				if (!sim_units) f *= 1000/L_SCALE;
				if (!just_particles)
					f = -f/rp->radius;
				}
			rpuScaleRadius(rp,f,just_particles);
			if (just_particles)
				rpuCalcRadius(rp); /* because outer edge may have changed */
			if (const_den) rpuScaleMass(rp,CUBE(f));
			break;
			}
		case density:
			{
			double f;
			BOOLEAN const_radius = get_yn("Keep radius constant","y");
			do {
				(void) printf("Enter density scaling factor (-ve ==> abs val): ");
				(void) scanf("%lf",&f);
				} while (f == 0);
			getchar();
			if (f < 0) {
				if (!sim_units) f *= 1000/D_SCALE;
				f = -f/rp->density;
				}
			if (const_radius) rpuScaleMass(rp,f);
			else rpuScaleRadius(rp,pow(f,-1.0/3),FALSE);
			break;
			}
		case pos:
		    {
			BOOLEAN absolute = get_yn("Specify absolute position","y");
			if (absolute) {
				SCALE_VEC(rp->pos,-1.0);
				rpuApplyPos(rp); /* reset COM to (0,0,0) first */
				(void) printf("Enter new position [x y z in ");
				}
			else
				(void) printf("Enter position offset [x y z in ");
			if (sim_units) (void) printf("AU");
			else (void) printf("km");
			(void) printf("]: ");
			(void) scanf("%lf%lf%lf",&rp->pos[X],&rp->pos[Y],&rp->pos[Z]);
			(void) getchar();
			if (!sim_units) NORM_VEC(rp->pos,0.001*L_SCALE);
			rpuApplyPos(rp);
			break;
			}
		case vel:
		    {
			BOOLEAN absolute = get_yn("Specify absolute velocity","y");
			if (absolute) {
				SCALE_VEC(rp->vel,-1.0);
				rpuApplyVel(rp);
				(void) printf("Enter new velocity [vx vy vz in ");
				}
			else
				(void) printf("Enter velocity offset [vx vy vz in ");
			if (sim_units) (void) printf("units of 30 km/s");
			else (void) printf("m/s");
			(void) printf("]: ");
			(void) scanf("%lf%lf%lf",&rp->vel[X],&rp->vel[Y],&rp->vel[Z]);
			(void) getchar();
			if (!sim_units) NORM_VEC(rp->vel,V_SCALE);
			rpuApplyVel(rp);
			break;
			}
		case orient:
			{
			enum {x=1,y,z};
			MATRIX rot;
			double angle;
			BOOLEAN align,body,rndm;
			int choice;
			align = get_yn("Align body axes with coordinate axes","n");
			if (align) {
				MATRIX m;
				COPY_VEC(rp->axes[MAJOR(rp)],m[X]);
				COPY_VEC(rp->axes[INTER(rp)],m[Y]);
				COPY_VEC(rp->axes[MINOR(rp)],m[Z]);
				rpuRotate(rp,m,FALSE);
				break;
				}
			body = get_yn("Use body axes","n");
			(void) printf("%i. Rotate about %s axis\n",x,body?"major":"x");
			(void) printf("%i. Rotate about %s axis\n",y,body?"intermediate":"y");
			(void) printf("%i. Rotate about %s axis\n",z,body?"minor":"z");
			do {
				(void) printf("Enter choice: ");
				(void) scanf("%i",&choice);
				} while (choice < x || choice > z);
			--choice; /* to conform with X,Y,Z macros */
			(void) getchar();
			rndm = get_yn("Use random angle","n");
			if (rndm) angle = TWO_PI*rand()/RAND_MAX;
			else {
				(void) printf("Enter rotation angle in ");
				if (sim_units) (void) printf("radians");
				else (void) printf("degrees");
				(void) printf(" (-ve=clockwise): ");
				(void) scanf("%lf",&angle);
				(void) getchar();
				if (!sim_units) angle *= DEG_TO_RAD;
				}
			UNIT_MAT(rot);
			if (body) choice = rp->axis_ord[choice];
			switch (choice) {
			case X:
				rot[Y][Y] = cos(angle); rot[Y][Z] = -sin(angle);
				rot[Z][Y] = -rot[Y][Z]; rot[Z][Z] = rot[Y][Y];
				break;
			case Y:
				rot[X][X] = cos(angle); rot[X][Z] = sin(angle);
				rot[Z][X] = -rot[X][Z]; rot[Z][Z] = rot[X][X];
				break;
			case Z:
				rot[X][X] = cos(angle); rot[X][Y] = -sin(angle);
				rot[Y][X] = -rot[X][Y]; rot[Y][Y] = rot[X][X];
				break;
			default:
				assert(0);
				}
			rpuRotate(rp,rot,body);
			break;
			}
		case spin:
		    {
			VECTOR old_spin,d;
			double w_max = 2*PI/sqrt(3*PI/rp->density);
			BOOLEAN incr_only,ang_mom,body;
			COPY_VEC(rp->spin,old_spin); /* needed for spin increment */
			/*DEBUG following only removes net spin---it does not
			  ensure that every particle has wxr_i = 0 and w_i = 0*/
			SCALE_VEC(rp->spin,-1.0);
			rpuAddSpin(rp,FALSE); /* remove current spin */
			(void) printf("Classical breakup limit for measured density = ");
			if (sim_units) (void) printf("%g x 2pi rad/yr",w_max);
			else (void) printf("%g 1/h (P_min = %g h)",
							   3600*w_max/(TWO_PI*T_SCALE),
							   TWO_PI*T_SCALE/(3600*w_max));
			(void) printf("\n");
			incr_only = get_yn("Specify increment only, instead of absolute value","n");
			if (incr_only)
				ang_mom = get_yn("Specify angular momentum increment","n");
			else
				ang_mom = get_yn("Specify angular momentum","n");
			if (ang_mom) {
				if (incr_only)
					(void) printf("Enter angular momentum increment [dlx dly dlz in ");
				else
					(void) printf("Enter new angular momentum [lx ly lz in ");
				if (sim_units) (void) printf("sys units");
				else (void) printf("N m/s");
				(void) printf("]: ");
				(void) scanf("%lf%lf%lf",&d[X],&d[Y],&d[Z]);				
				(void) getchar();
				if (!sim_units)
					SCALE_VEC(d,T_SCALE/(SQ(L_SCALE)*M_SCALE));
				if (incr_only) {
					ADD_VEC(rp->ang_mom,d,rp->ang_mom);
					}
				else {
					COPY_VEC(d,rp->ang_mom);
					}
				rpuAddAngMom(rp);
				if (MAG(rp->spin) > w_max)
					(void) printf("WARNING: exceeds classical breakup limit\n");
				break;
				}
			body = get_yn("Use body axes","n");
			if (incr_only)
				(void) printf("Enter spin increment [dwx dwy dwz in ");
			else
				(void) printf("Enter new spin [wx wy wz in ");
			if (sim_units) (void) printf("units of 2pi rad/yr");
			else (void) printf("1/h");
			(void) printf("]: ");
			(void) scanf("%lf%lf%lf",&d[X],&d[Y],&d[Z]);
			(void) getchar();
			if (!sim_units) SCALE_VEC(d,TWO_PI*T_SCALE/3600);
			if (incr_only) {
				ADD_VEC(old_spin,d,rp->spin);
				}
			else {
				COPY_VEC(d,rp->spin);
				}
			if (MAG(rp->spin) > w_max)
				(void) printf("WARNING: exceeds classical breakup limit\n");
			rpuAddSpin(rp,body);
			break;
			}
		case color:
			{
			BOOLEAN invalid_color;
			int c;
			(void) printf("Color scheme:\n");
			for (i=BLACK;i<FIRST_GRAY;i++)
				(void) printf("%2i. %s\n",i,color_str(i));
			do {
				invalid_color = FALSE;
				(void) printf("Enter new color: ");
				(void) scanf("%i",&c);
				(void) getchar();
				if (c >= NUM_COLORS) { /* allow negative colors */
					(void) printf("Invalid color\n");
					invalid_color = TRUE;
					continue;
					}
				if (c == BLACK || c == FIRST_GRAY)
					(void) printf("WARNING: Particles may be invisible!\n");
				} while (invalid_color);
			rp->color = c;
			rpuApplyColor(rp);
			break;
			}
		case agg_id:
			{
			do {
				(void) printf("Enter new aggregate ID (or -1 to reset): ");
				(void) scanf("%i",&rp->agg_id);
				(void) getchar();
				if (rp->agg_id < -1)
					(void) printf("Invalid ID\n");
				else
					rpuApplyAggID(rp);
				} while(rp->agg_id < -1);
			break;
			}
		case par_id:
			{
			SSDATA *p,*pmax;
			VECTOR r;
			double lng,lat,dmax,d;
			int c;
			(void) printf("Enter angular coordinates [lng lat in deg]: ");
			(void) scanf("%lf%lf",&lng,&lat);
			(void) getchar();
			lng *= DEG_TO_RAD;
			lat *= DEG_TO_RAD;
			SET_VEC(r,cos(lng)*cos(lat),sin(lng)*cos(lat),sin(lat));
			dmax = 0.0;
			pmax = NULL;
			for (i=0;i<rp->n_particles;i++) {
				p = &rp->data[i];
				/* projected distance along vector minus distance perpendicular
				   to vector favors particles closest to vector */
				d = DOT(p->pos,r) - sqrt(MAG_SQ(p->pos) - SQ(DOT(p->pos,r)));
				if (d > dmax) {
					dmax = d;
					pmax = p;
				}
			}
			if (!pmax) {
				(void) printf("No particle found.\n");
				continue;
			}
			(void) printf("Found particle (original index %i, color %i [%s])\n",
						  pmax->org_idx,pmax->color,color_str(pmax->color));
			while (/*CONSTCOND*/1) {
				(void) printf("Enter new color: ");
				(void) scanf("%i",&c);
				(void) getchar();
				if (c >= NUM_COLORS) { /* allow negative colors */
					(void) printf("Invalid color\n");
					goto invalid;
					}
				if (c == BLACK || c == RED || c == YELLOW || c == MAGENTA ||
					c == CYAN || c == KHAKI || c == FIRST_GRAY) {
					(void) printf("Color %i is reserved\n",c);
					goto invalid;
					}
				break;
			invalid:
				(void) printf("Color scheme:\n");
				for (i=BLACK;i<FIRST_GRAY;i++)
					(void) printf("%2i. %s\n",i,color_str(i));
				}; /* while */
			pmax->color = c;
			break;
			}
		default:
			assert(0);
			}
		}
	}
Пример #6
0
static void
process(SSDATA *d,int n,double *t)
{
	PROPERTIES p;
	int choice;

	enum {Next,Time,Mass,Bounds,ComPos,ComVel,AngMom,VelDsp,Color,Units,
			  Offsets,Masses,Radii,End};

	while (/*CONSTCOND*/1) {

		ss_analyze(d,n,&p);

		(void) printf("%2i. Time = %g\n",Time,*t);
		(void) printf("%2i. Total mass = %g\n",Mass,p.total_mass);
		(void) printf("%2i. Bounds: x=[%g,%g]\n"
					  "            y=[%g,%g]\n"
					  "            z=[%g,%g]\n",Bounds,
					  p.bnd_min[X],p.bnd_max[X],
					  p.bnd_min[Y],p.bnd_max[Y],
					  p.bnd_min[Z],p.bnd_max[Z]);
		(void) printf("%2i. Centre-of-mass position = %g %g %g\n",ComPos,
					  p.com_pos[X],p.com_pos[Y],p.com_pos[Z]);
		(void) printf("%2i. Centre-of-mass velocity = %g %g %g\n",ComVel,
					  p.com_vel[X],p.com_vel[Y],p.com_vel[Z]);
		(void) printf("%2i. Specific angular momentum = %g %g %g\n",AngMom,
					  p.ang_mom[X],p.ang_mom[Y],p.ang_mom[Z]);
		(void) printf("%2i. Velocity dispersion = %g %g %g\n",VelDsp,
					  p.vel_dsp[X],p.vel_dsp[Y],p.vel_dsp[Z]);
		(void) printf("%2i. Dominant color = %i (%s)\n",Color,p.color,
					  color_str(p.color));
		(void) printf("%2i. Units\n",Units);
		(void) printf("%2i. Offsets\n",Offsets);
		(void) printf("%2i. Particle masses\n",Masses);
		(void) printf("%2i. Particle radii\n",Radii);

		do {
			(void) printf("Enter number to change (or 0 to continue): ");
			(void) scanf("%i",&choice);
			} while (choice < Next || choice >= End);
		
		(void) getchar();

		if (choice == Next) return;

		switch(choice) {
		case Time:
			do {
				(void) printf("Enter new time: ");
				(void) scanf("%lf",t);
				(void) getchar();
				} while (*t < 0);
			break;
		case Mass:
			{
			double f;
			do get_scaling(&f,NegativeOK);
			while (f == 0);
			if (f < 0) f = -f/p.total_mass;
			scale_mass(d,n,f);
			break;
			}
		case Bounds:
			{
			double f,min,max;
			int i,choice;
			do {
				do {
					(void) printf("%i. Change x bounds (now [%g,%g])\n",X + 1,
								  p.bnd_min[X],p.bnd_max[X]);
					(void) printf("%i. Change y bounds (now [%g,%g])\n",Y + 1,
								  p.bnd_min[Y],p.bnd_max[Y]);
					(void) printf("%i. Change z bounds (now [%g,%g])\n",Z + 1,
								  p.bnd_min[Z],p.bnd_max[Z]);
					(void) printf("Your choice (or 0 when done): ");
					(void) scanf("%i",&choice);
					(void) getchar();
					} while (choice < 0 || choice > N_DIM);
				if (choice == 0) break;
				--choice; /* put back in range [X,Z] */
				if (p.bnd_min[choice] == p.bnd_max[choice]) {
					(void) printf("Chosen dimension is degenerate\n");
					continue;
					}
				do {
					(void) printf("Enter new bounds (min max): ");
					(void) scanf("%lf%lf",&min,&max);
					(void) getchar();
					} while (min > max);
				if (min == max &&
					get_yn("Zero velocities for this component","y"))
					for (i=0;i<n;i++)
						d[i].vel[choice] = 0;
				f = (max - min)/(p.bnd_max[choice] - p.bnd_min[choice]);
				for (i=0;i<n;i++)
					d[i].pos[choice] =
						(d[i].pos[choice] - p.bnd_min[choice])*f + min;
				p.bnd_min[choice] = min;
				p.bnd_max[choice] = max;
				} while (/*CONSTCOND*/1);
			break;
			}
		case ComPos:
			{
			VECTOR v;
			if (MAG(p.com_pos) && get_yn("Scale the magnitude","y")) {
				double f;
				get_scaling(&f,NegativeOK);
				COPY_VEC(p.com_pos,v);
				if (f < 0) f = -f/MAG(v);
				SCALE_VEC(v,f);
				}
			else get_components(v);
			adj_com_pos(d,n,&p,v);
			break;
			}
		case ComVel:
			{
			VECTOR v;
			if (MAG(p.com_vel) && get_yn("Scale the magnitude","y")) {
				double f;
				get_scaling(&f,NegativeOK);
				COPY_VEC(p.com_vel,v);
				if (f < 0) f = -f/MAG(v);
				SCALE_VEC(v,f);
				}
			else get_components(v);
			adj_com_vel(d,n,&p,v);
			break;
			}
		case AngMom:
			{
			VECTOR v;
			(void) printf("NOTE: specific angular momentum is measured with\n"
						  "respect to fixed space frame centred at (0,0,0)\n"
						  "and does not take particle spins into account\n");
			if (MAG(p.ang_mom) && get_yn("Scale the magnitude","y")) {
				double f;
				get_scaling(&f,NegativeOK);
				COPY_VEC(p.ang_mom,v);
				if (f < 0) f = -f/MAG(p.ang_mom);
				SCALE_VEC(v,f);
				}
			else if (get_yn("Scale the components","y")) {
				VECTOR u;
				int k;
				get_component_scaling(u);
				for (k=0;k<N_DIM;k++)
					v[k] = u[k]*p.ang_mom[k];
				}
			else get_components(v);
			adj_ang_mom(d,n,&p,v);
			break;
			}
		case VelDsp:
			{
			VECTOR v;
			(void) printf("NOTE: velocity dispersion is context dependent,\n"
						  "for now relative ONLY to center-of-mass velocity,\n"
						  "i.e. without considering bulk rotation or shear\n");
			if (!MAG(p.vel_dsp)) {
				(void) printf("Zero velocity dispersion -- cannot adjust\n");
				break;
				}
			if (get_yn("Scale the magnitude","y")) {
				double f;
				get_scaling(&f,NegativeOK);
				if (f < 0) f = -f/MAG(p.vel_dsp);
				SET_VEC(v,f,f,f);
				}
			else get_component_scaling(v);
			scale_vel_dsp(d,n,&p,v);
			break;
			}
		case Color:
			{
			int c;
			(void) printf("Color scheme:\n");
			for (c=BLACK;c<FIRST_GRAY;c++)
				(void) printf("%2i. %s\n",c,color_str(c));
			(void) printf("[values from %i to %i are levels of gray]\n",
						  FIRST_GRAY,LAST_GRAY);
			do {
				(void) printf("Enter new color: ");
				(void) scanf("%i",&c);
				(void) getchar();
				} while (c < 0 || c >= NUM_COLORS);
			change_color(d,n,c);
			break;
			}
		case Units:
			{
			enum {N,M,L,T,V,E};
			double f;
			int i,choice;
			(void) printf("NOTE: It is up to you to ensure dimensions are\n"
						  "internally consistent. pkdgrav assumes G == 1.\n");
			do {
				do {
					(void) printf("%i. Mass (particle masses)\n",M);
					(void) printf("%i. Length (particle radii, pos'ns)\n",L);
					(void) printf("%i. Time (time,particle spins)\n",T);
					(void) printf("%i. Velocity (particle velocities)\n",V);
					(void) printf("Select dimension to scale "
								  "(or 0 when done): ");
					(void) scanf("%i",&choice);
					(void) getchar();
					} while (choice < N || choice >= E);
				if (choice == N) break;
				switch (choice) {
				case M:
					(void) printf("M_Sun     = 1.9891e30 kg\n"
								  "M_Earth   = 5.9742e24 kg\n"
								  "M_Jupiter = 1.8992e27 kg\n"
								  "M_Saturn  = 5.6864e26 kg\n");
					get_scaling(&f,PositiveOnly);
					for (i=0;i<n;i++)
						d[i].mass *= f;
					break;
				case L:
					(void) printf("1 AU    = 1.49597892e11 m\n"
								  "R_Earth = 6.37814e6 m\n");
					get_scaling(&f,PositiveOnly);
					for (i=0;i<n;i++) {
						d[i].radius *= f;
						SCALE_VEC(d[i].pos,f);
						}
					break;
				case T:
					(void) printf("1 yr        = 3.15576e7 s\n"
								  "1 yr / 2 pi = 5.02255e6 s\n");
					get_scaling(&f,PositiveOnly);
					*t *= f;
					for (i=0;i<n;i++)
						NORM_VEC(d[i].spin,f);
					break;
				case V:
					(void) printf("V_Earth = 2.97852586e4 m/s\n");
					get_scaling(&f,PositiveOnly);
					for (i=0;i<n;i++)
						SCALE_VEC(d[i].vel,f);
					break;
				default:
					assert(0);
					}
				} while (/*CONSTCOND*/1);
			break;
			}
		case Offsets:
			{
			VECTOR v;
			int i;
			(void) printf("POSITION OFFSET (0 0 0 for none)...\n");
			get_components(v);
			for (i=0;i<n;i++)
				ADD_VEC(d[i].pos,v,d[i].pos);
			(void) printf("VELOCITY OFFSET (0 0 0 for none)...\n");
			get_components(v);
			for (i=0;i<n;i++)
				ADD_VEC(d[i].vel,v,d[i].vel);
			break;
			}
		case Masses:
			{
			double f;
			do get_scaling(&f,NegativeOK);
			while (f == 0);
			scale_masses(d,n,f);
			break;
			}
		case Radii:
			{
			double f;
			do get_scaling(&f,NegativeOK);
			while (f == 0);
			scale_radii(d,n,f);
			break;
			}
		default:
			assert(0);
			}
		}
	}