/*  These are some simple handy things to have with no real ownership value.
 *  They're so basic most anyone could/should have something similar somewhere.
 */

/* outputs race.lst when called */
void write_race_list( )
{
    int i;
    FILE *fpout;
    char filename[256];

    sprintf( filename, "%s%s", RACEDIR, RACE_LIST );
    fpout = fopen( filename, "w" );
    if ( !fpout )
    {
	bug( "FATAL: cannot open race.lst for writing!\n\r", 0 );
 	return;
    }	  
    for ( i = 0; i < MAX_PC_RACE; i++ )
	fprintf( fpout, "%s%s.race\n", RACEDIR, race_table[i]->race_name );
    fprintf( fpout, "$\n" );
    fclose( fpout );
}

/* saves all races at once */

void save_races()
{
    int x;

    for ( x = 0; x < MAX_RACE; x++ )
      write_race_file( x );
}

/* Simple function to see if a file exists, probably the same dozens have/use just converted
to simple macro-esque form. */

bool exists_file( char *filen )
{
	struct stat fst;

	if( stat(filen, &fst) == -1 )
		return FALSE;
	else
		return TRUE;
}

/* Checks to see if a player exists, much smaller than the large fst garbage every
single time you need to look for a player by name) */

bool exists_player( char *name )
{
 char filename[ MAX_STRING_LENGTH ];

 sprintf( filename, "%s%c/%s", PLAYER_DIR, tolower(name[0]), capitalize( name ) );

 if (exists_file(filename))
  return TRUE;
 
 return FALSE;
}

/* Just a tiny little function to add to filename settings to make sure a malicious
or angry imm cant use commands like aset filename, setdeity filename, etc to overwrite
vital/important files with garbage.

example of use:

    if ( !str_cmp( arg2, "filename" ) )
    {
	if ( !is_local( argument))
	{
	    send_to_char( "Local Directory Only.\n\r", ch );
	    return;
	}

There's probably better ways to do this, but it works.
*/

bool is_local( char *what )
{

    what = strlower(what);

    if (strstr( what, "../" ))
     return FALSE;

    return TRUE;
}

/* creates a numericly sequence date timestamp, useful for filenames */

char *timestamp()
{
   static char buf[MAX_STRING_LENGTH];
   struct tm *t = localtime(&current_time);

   sprintf( buf, "%04d-%02d-%02d", t->tm_year+1900, t->tm_mon+1,  t->tm_mday );
   return buf;
}

/* Sick of thousands of gender checks? 3 simple functions to give the right one
with only 1 little line instead of 6 in every spot, shortens whois nicely */

char *hesheit( CHAR_DATA *ch)
{
 switch(ch->sex)
 {
  default:
   return "It";
  case 1:
   return "He";
  case 2:
   return "She";
 }
 return "it";
}

char *himherit( CHAR_DATA *ch)
{
 switch(ch->sex)
 {
  default:
   return "It";
  case 1:
   return "Him";
  case 2:
   return "Her";
 }
 return "It";
}

char *hishersits( CHAR_DATA *ch)
{
 switch(ch->sex)
 {
  default:
   return "Its";
  case 1:
   return "His";
  case 2:
   return "Hers";
 }
 return "Its";
}

/* Identify the value of a name */
void do_namestat(CHAR_DATA *ch, char *argument)
{
    int x, a, b, c;
    sh_int str=0, dex=0, wis=0, intl=0, con=0, cha=0, lck=0, total;

    if ( strlen(argument) <  4 || ( strlen(argument) > 12 ))
    {
        ch_printf( ch, "Name too short or too long.\n\r" );
        return;
    }

    for ( x = 0; x < strlen(argument); x++ )
    {
	c = argument[x] + x;
	b = c % 14;
	a = (c % 1) + 1;
	switch (b)
	{
	   case  0:
	     str = str + a;
	     break;
	   case  1:
	     dex = dex + a;
	     break;
	   case  2:
	     wis = wis + a;
	     break;
	   case  3:
	     intl = intl + a;
	     break;
	   case  4:
	     con = con + a;
	     break;
	   case  5:
	     cha = cha + a;
	     break;
	   case  6:
	     lck = lck + a;
	     break;
	   case  7:
	     str = str - a;
	     break;
	   case  8:
	     dex = dex - a ;
	     break;
	   case  9:
	     wis = wis - a;
	     break;
	   case 10:
	     intl = intl - a;
	     break;
	   case 11:
	     con = con - a;
	     break;
	   case 12: 
	     cha = cha - a;
	     break;
	   case 13:
	     lck = lck - a;
	     break;
	}
    }
  ch_printf( ch, "&WThe Name &G%s&W returns the following stats:\n\r", argument);
  ch_printf( ch, "&WStr: %s%d\n\r", str < 0 ? "&R" : str > 0 ? "&C" : "&W", str);
  ch_printf( ch, "&WDex: %s%d\n\r", dex < 0 ? "&R" : dex > 0 ? "&C" : "&W", dex);
  ch_printf( ch, "&WWis: %s%d\n\r", wis < 0 ? "&R" : wis > 0 ? "&C" : "&W", wis);
  ch_printf( ch, "&WInt: %s%d\n\r", intl < 0 ? "&R" : intl > 0 ? "&C" : "&W", intl);
  ch_printf( ch, "&WCon: %s%d\n\r", con < 0 ? "&R" : con > 0 ? "&C" : "&W", con);
  ch_printf( ch, "&WCha: %s%d\n\r", cha < 0 ? "&R" : cha > 0 ? "&C" : "&W", cha);
  ch_printf( ch, "&WLck: %s%d\n\r", lck < 0 ? "&R" : lck > 0 ? "&C" : "&W", lck);
  total = str+dex+wis+intl+con+cha+lck;
  ch_printf( ch, "&WTotal Stats: %s%d\n\r", total < 0 ? "&R" : "&C", total);
  return;
}
/* human = 0, etc, silly to have to reference everything numerically */
int get_race_by_name( char *argument)
{
  int iRace;

  for (iRace = 0; iRace < MAX_PC_RACE; iRace++)
  {
    if (!str_cmp(argument, race_table[iRace]->race_name))
     return iRace;
  }
  return -1;
}

/* mage = 0, etc, silly to have to reference everything numerically */
int get_class_by_name( char *argument)
{
  int iClass;

  for (iClass = 0; iClass < MAX_PC_CLASS; iClass++)
  {
    if (!str_cmp(argument, class_table[iClass]->who_name))
     return iClass;
  }
  return -1;
}

/*
 * Return pointer a mob in the world by vnum without requiring a character
 * to initiate the search.
 */
CHAR_DATA *get_mob( int vnum)
{
    CHAR_DATA *wch;

    /* check the world for an exact match */
    for ( wch = first_char; wch; wch = wch->next )
	if (IS_NPC(wch) && vnum == wch->pIndexData->vnum )
		return wch;

    return NULL;
}

/* makes it much easier to determine if a player can get something and manipulate
obhects when you can simply call this to check if they should be able to instead
of repeating code dozens of places or simply not bothering */

bool can_touch( CHAR_DATA *ch, OBJ_DATA *obj )
{
  if ( IS_IMMORTAL(ch) )
   return TRUE;

  if ( ( IS_OBJ_STAT(obj, ITEM_ANTI_EVIL)    && IS_EVIL(ch)    )
  ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_GOOD)    && IS_GOOD(ch)    )
  ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_PKILL)    && CAN_PKILL(ch) && !sysdata.all_pk )
  ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_PEACEFUL)    && !CAN_PKILL(ch))
  ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch) ) )
   return FALSE;
   return TRUE;
}

/* Why repeat this code in dozens of places? */

void zap(CHAR_DATA *ch, OBJ_DATA *obj)
{
	/*
	 * Thanks to Morgenes for the bug fix here!
	 */
	if ( loading_char != ch )
	{
	   act( AT_MAGIC, "&BYou are zapped by $p&B and drop it.", ch, obj, NULL, TO_CHAR );
	   act( AT_MAGIC, "&B$n is zapped by $p&B and drops it.",  ch, obj, NULL, TO_ROOM );
	}
	if ( obj->carried_by )
	   obj_from_char( obj );
	obj_to_room( obj, ch->in_room );
	oprog_zap_trigger( ch, obj);
	if ( IS_SET(sysdata.save_flags, SV_ZAPDROP) && !char_died(ch) )
	    save_char_obj( ch );
	return;
}


