6D/
6D/area/
6D/boards/
6D/city/
6D/color/
6D/corpses/
6D/councils/
6D/htowns/
6D/news/
6D/specials/
6D/src/specials/
6D/src/trades/
#include "h/mud.h"
#include "h/files.h"
#include "h/languages.h"
#include "h/key.h"
#ifndef WIN32
#include <unistd.h>
#endif

int                     get_risflag(char *flag);
int                     get_langflag(char *flag);
int                     get_langnum(char *flag);
int                     get_defenseflag(char *flag);
int                     get_attackflag(char *flag);

extern bool             load_race_file(const char *fname);
void                    write_race_file(int ra);
int                     MAX_PC_RACE;

RACE_TYPE              *race_table[MAX_RACE];

const char             *const npc_race[MAX_NPC_RACE] = {
  "human", "elf", "dwarf", "halfling", "pixie", "ogre", // 5 with human zero
  "orc", "troll", "shade", "goblin", "drow", "gnome", // 11
  "centaur", "dragon", "vampire", "celestial", "demon", "mindflayer", // 17

/* Above this line should be all player races */
  "ant", "ape", "baboon", "bat", "bear",  // 22
  "bee", "beetle", "boar", "bugbear", "cat", "dog", // 28
  "plant", "ferret", "fly", "gargoyle", "gelatin", "ghoul", // 34
  "gnoll", "r29", "golem", "gorgon", "harpy", // 39
  "hobgoblin", "kobold", "locust", "lycanthrope", "minotaur", // 44
  "mold", "mule", "neanderthal", "ooze", "r43", "rat",  // 50
  "rustmonster", "shadow", "shapeshifter", "shrew", "shrieker", "skeleton", // 56
  "slime", "snake", "spider", "stirge", "thoul", "troglodyte",  // 62
  "undead", "wight", "wolf", "worm", "zombie", "bovine",  // 68
  "canine", "feline", "porcine", "mammal", "rodent", "avis",  // 74
  "reptile", "amphibian", "fish", "crustacean", "insect", "spirit", // 80
  "magical", "horse", "animal", "humanoid", "monster", "god", // 86
  "avian", "badger", "beaver", "wolverine", "lion"  // 92
};

char                   *const raceflags[] = {
  (char *)"advanced"
};

int                     get_raceflag(char *flag);

void free_all_races(void)
{
  int                     hash, loopa;

  for(hash = 0; hash < MAX_RACE; hash++)
  {
    for(loopa = 0; loopa < MAX_WHERE_NAME; loopa++)
      if(race_table[hash]->where_name[loopa])
        STRFREE(race_table[hash]->where_name[loopa]);
    DISPOSE(race_table[hash]);
  }
}

/*
 * Create an instance of a new race.   -Shaddai
 */
bool create_new_race(int race, char *argument)
{
  int                     i = 0;

  if(!VLD_STR(argument))
    return FALSE;
  if(race >= MAX_RACE || race_table[race] == NULL)
    return FALSE;
  for(i = 0; i <= MAX_WHERE_NAME; i++)
    race_table[race]->where_name[i] = STRALLOC(where_name[i]);
  argument[0] = UPPER(argument[0]);
  snprintf(race_table[race]->race_name, 16, "%-.16s", argument);
  race_table[race]->sdbonus = 0;
  race_table[race]->base_str = 0;
  race_table[race]->base_dex = 0;
  race_table[race]->base_wis = 0;
  race_table[race]->base_int = 0;
  race_table[race]->base_con = 0;
  race_table[race]->base_cha = 0;
  race_table[race]->base_lck = 0;
  race_table[race]->hit = 0;
  race_table[race]->mana = 0;
  xCLEAR_BITS(race_table[race]->affected);
  race_table[race]->resist = 0;
  race_table[race]->suscept = 0;
  race_table[race]->language = 0;
  race_table[race]->alignment = 0;
  race_table[race]->minalign = 0;
  race_table[race]->maxalign = 0;
  race_table[race]->ac_plus = 0;
  race_table[race]->exp_multiplier = 0;
  xCLEAR_BITS(race_table[race]->attacks);
  xCLEAR_BITS(race_table[race]->defenses);
  race_table[race]->height = 0;
  race_table[race]->weight = 0;
  race_table[race]->hunger_mod = 0;
  race_table[race]->thirst_mod = 0;
  race_table[race]->mana_regen = 0;
  race_table[race]->hp_regen = 0;
  race_table[race]->race_recall = 0;
  return TRUE;
}

/*
 * Load in all the race files.
 */
void load_races()
{
  FILE                   *fpList;
  const char             *filename;
  char                    racelist[256];
  int                     i;

  MAX_PC_RACE = 0;
  /*
   * Pre-init the race_table with blank races
   */
  for(i = 0; i < MAX_RACE; i++)
    race_table[i] = NULL;

  snprintf(racelist, 256, "%s%s", RACEDIR, RACE_LIST);
  if((fpList = FileOpen(racelist, "r")) == NULL)
  {
    perror(racelist);
    exit(1);
  }

  for(;;)
  {
    filename = feof(fpList) ? "$" : fread_word(fpList);
    if(filename[0] == '$')
      break;

    if(!load_race_file(filename))
    {
      bug("Cannot load race file: %s", filename);
    }
    else
      MAX_PC_RACE++;
  }
  for(i = 0; i < MAX_RACE; i++)
  {
    if(race_table[i] == NULL)
    {
      CREATE(race_table[i], struct race_type, 1);

      snprintf(race_table[i]->race_name, 16, "%s", "unused");
    }
  }
  FileClose(fpList);
  return;
}

void write_race_file(int ra)
{
  FILE                   *fpout;
  char                    filename[MIL];
  struct race_type       *race = race_table[ra];
  int                     i;
  int                     x, y;

  if(!race->race_name)
  {
    bug("Race %d has null name, not writing .race file.", ra);
    return;
  }

  snprintf(filename, MIL, "%s%s.race", RACEDIR, race->race_name);
  if((fpout = FileOpen(filename, "w+")) == NULL)
  {
    bug("Cannot open: %s for writing", filename);
    return;
  }

  if(VLD_STR(race->race_name))
    fprintf(fpout, "Name        %s~\n", race->race_name);
  fprintf(fpout, "Race        %d\n", ra);
  fprintf(fpout, "SDbonus     %d\n", race->sdbonus);
  fprintf(fpout, "Base_Str    %d\n", race->base_str);
  fprintf(fpout, "Base_Dex    %d\n", race->base_dex);
  fprintf(fpout, "Base_Wis    %d\n", race->base_wis);
  fprintf(fpout, "Base_Int    %d\n", race->base_int);
  fprintf(fpout, "Base_Con    %d\n", race->base_con);
  fprintf(fpout, "Base_Cha    %d\n", race->base_cha);
  fprintf(fpout, "Base_Lck    %d\n", race->base_lck);
  fprintf(fpout, "Hit         %d\n", race->hit);
  fprintf(fpout, "Mana        %d\n", race->mana);
  fprintf(fpout, "Affected    %s\n", print_bitvector(&race->affected));
  fprintf(fpout, "Resist      %d\n", race->resist);
  fprintf(fpout, "Suscept     %d\n", race->suscept);
  fprintf(fpout, "Language    %d\n", race->language);
  fprintf(fpout, "Align       %d\n", race->alignment);
  fprintf(fpout, "Min_Align   %d\n", race->minalign);
  fprintf(fpout, "Max_Align   %d\n", race->maxalign);
  fprintf(fpout, "AC_Plus     %d\n", race->ac_plus);
  fprintf(fpout, "Exp_Mult    %d\n", race->exp_multiplier);
  if(!xIS_EMPTY(race->attacks))
    fprintf(fpout, "Attacks     %s\n", print_bitvector(&race->attacks));
  if(!xIS_EMPTY(race->defenses))
    fprintf(fpout, "Defenses    %s\n", print_bitvector(&race->defenses));
  fprintf(fpout, "Height      %d\n", race->height);
  fprintf(fpout, "Weight      %d\n", race->weight);
  fprintf(fpout, "Flags	      %s\n", print_bitvector(&race->flags));
  fprintf(fpout, "Hunger_Mod  %d\n", race->hunger_mod);
  fprintf(fpout, "Thirst_mod  %d\n", race->thirst_mod);
  fprintf(fpout, "Mana_Regen  %d\n", race->mana_regen);
  fprintf(fpout, "HP_Regen    %d\n", race->hp_regen);
  fprintf(fpout, "Race_Recall %d\n", race->race_recall);
  for(i = 0; i < MAX_WHERE_NAME; i++)
    fprintf(fpout, "WhereName  %s~\n", race->where_name[i]);

  for(x = 0; x < top_sn; x++)
  {
    if(!skill_table[x]->name || skill_table[x]->name[0] == '\0')
      break;
    if((y = skill_table[x]->race_level[ra]) < LEVEL_IMMORTAL)
      fprintf(fpout, "Skill '%s' %d %d\n", skill_table[x]->name, y, skill_table[x]->race_adept[ra]);
  }
  fprintf(fpout, "End\n");
  FileClose(fpout);
}

bool load_race_file(const char *fname)
{
  char                    buf[MSL];
  const char             *word;
  char                   *race_name = NULL;
  bool                    fMatch;
  struct race_type       *race;
  int                     ra = -1;
  FILE                   *fp;
  int                     i, wear = 0;

  snprintf(buf, MSL, "%s%s", RACEDIR, fname);
//  snprintf(buf, MSL, "%s", fname);
  if((fp = FileOpen(buf, "r")) == NULL)
  {
    perror(buf);
    return FALSE;
  }

  CREATE(race, struct race_type, 1);
  for(i = 0; i < MAX_WHERE_NAME; i++)
    race->where_name[i] = STRALLOC(where_name[i]);

  for(;;)
  {
    word = feof(fp) ? "End" : fread_word(fp);
    fMatch = FALSE;

    switch (UPPER(word[0]))
    {
      case '*':
        fMatch = TRUE;
        fread_to_eol(fp);
        break;

      case 'A':
        KEY("Align", race->alignment, fread_number(fp));
        KEY("AC_Plus", race->ac_plus, fread_number(fp));
        KEY("Affected", race->affected, fread_bitvector(fp));
        KEY("Attacks", race->attacks, fread_bitvector(fp));
        break;

      case 'B':
        KEY("Base_Dex", race->base_dex, fread_number(fp));
        KEY("Base_Int", race->base_int, fread_number(fp));
        KEY("Base_Lck", race->base_lck, fread_number(fp));
        KEY("Base_Con", race->base_con, fread_number(fp));
        KEY("Base_Cha", race->base_cha, fread_number(fp));
        KEY("Base_Wis", race->base_wis, fread_number(fp));
        KEY("Base_Str", race->base_str, fread_number(fp));
        break;

      case 'D':
        KEY("Defenses", race->defenses, fread_bitvector(fp));
        break;

      case 'E':
        if(!str_cmp(word, "End"))
        {
          FileClose(fp);
          if(ra < 0 || ra >= MAX_RACE)
          {
            bug("Load_race_file: Race (%s) bad/not found (%d)", race->race_name ? race->race_name : race_name ? race_name : "name not found", ra);
            if(race_name)
              STRFREE(race_name);
            DISPOSE(race);
            return FALSE;
          }
          race_table[ra] = race;
          if(race_name)
            STRFREE(race_name);
          return TRUE;
        }
        KEY("Exp_Mult", race->exp_multiplier, fread_number(fp));
        break;

      case 'F':
        KEY("Flags", race->flags, fread_bitvector(fp));
        break;

      case 'H':
        KEY("Height", race->height, fread_number(fp));
        KEY("Hit", race->hit, fread_number(fp));
        KEY("HP_Regen", race->hp_regen, fread_number(fp));
        KEY("Hunger_Mod", race->hunger_mod, fread_number(fp));
        break;

      case 'L':
        KEY("Language", race->language, fread_number(fp));
        break;

      case 'M':
        KEY("Mana", race->mana, fread_number(fp));
        KEY("Mana_Regen", race->mana_regen, fread_number(fp));
        KEY("Min_Align", race->minalign, fread_number(fp));
        KEY("Max_Align", race->maxalign, fread_number(fp));
        break;

      case 'N':
        KEY("Name", race_name, fread_string(fp));
        break;

      case 'R':
        KEY("Race", ra, fread_number(fp));
        KEY("Race_Recall", race->race_recall, fread_number(fp));
        KEY("Resist", race->resist, fread_number(fp));
        break;

      case 'S':
        KEY("SDbonus", race->sdbonus, fread_number(fp));
        KEY("Suscept", race->suscept, fread_number(fp));
        if(!str_cmp(word, "Skill"))
        {
          int                     sn, lev, adp;

          word = fread_word(fp);
          lev = fread_number(fp);
          adp = fread_number(fp);
          sn = skill_lookup(word);
          if(ra < 0 || ra >= MAX_RACE)
            bug("load_race_file: Skill %s -- race bad/not found (%d)", word, ra);
          else if(!IS_VALID_SN(sn))
            bug("load_race_file: Skill %s unknown", word);
          else
          {
            skill_table[sn]->race_level[ra] = lev;
            skill_table[sn]->race_adept[ra] = adp;
          }
          fMatch = TRUE;
          break;
        }
        break;

      case 'T':
        KEY("Thirst_Mod", race->thirst_mod, fread_number(fp));
        break;

      case 'W':
        KEY("Weight", race->weight, fread_number(fp));
        if(!str_cmp(word, "WhereName"))
        {
          if(ra < 0 || ra >= MAX_RACE)
          {
            bug("load_race_file: Title -- race bad/not found (%d)", ra);
            fread_flagstring(fp);
            fread_flagstring(fp);
          }
          else if(wear < MAX_WHERE_NAME)
          {
            if(VLD_STR(race->where_name[wear]))
              STRFREE(race->where_name[wear]);
            race->where_name[wear] = fread_string(fp);
            ++wear;
          }
          else
            bug("%s", "load_race_file: Too many where_names");
          fMatch = TRUE;
          break;
        }
        break;
    }

    if(race_name != NULL)
      snprintf(race->race_name, 16, "%-.16s", race_name);

    if(!fMatch)
    {
      bug("load_race_file: no match: %s", word);
      fread_to_eol(fp);
    }
  }
  return FALSE;
}

void do_races(CHAR_DATA *ch, char *argument)
{
  int                     iRace = 0;
  int                     counter = 0;

  if(!IS_IMMORTAL(ch))
    counter = 1;
  send_to_pager("\r\n", ch);
  for(iRace = 0; iRace < MAX_PC_RACE; iRace++)
  {
    if(!IS_IMMORTAL(ch) && !VLD_STR(race_table[iRace]->race_name))
      continue;
    pager_printf(ch, "&g[&G%2d&g]&W %-10s", counter, race_table[iRace]->race_name);
    if(IS_IMMORTAL(ch))
      pager_printf(ch, "%-1s &gMultiplier:&W %-5d &gHit: &W%-3d &gMana: &W%-3d", "", race_table[iRace]->exp_multiplier, race_table[iRace]->hit, race_table[iRace]->mana);
    pager_printf(ch, "\r\n");
    counter++;
  }
  return;
}

void update_racelist(void)
{
  char                    racelist[256];
  int                     i;
  FILE                   *fpList;

  snprintf(racelist, 256, "%s%s", RACEDIR, RACE_LIST);
  if((fpList = FileOpen(racelist, "w")) == NULL)
  {
    bug("%s", "Error opening racelist.");
    return;
  }
  for(i = 0; i < MAX_PC_RACE; i++)
    fprintf(fpList, "%s.race\n", race_table[i]->race_name);
  fprintf(fpList, "%s", "$\n");
  FileClose(fpList);
  return;
}

/* Modified by Samson to allow setting language by name - 8-6-98 */
void do_setrace(CHAR_DATA *ch, char *argument)
{
  struct race_type       *race;
  char                    buf[MSL], arg1[MIL], arg2[MIL], arg3[MIL];
  int                     value, v2, ra;

  set_char_color(AT_PLAIN, ch);

  smash_tilde(argument);
  argument = one_argument(argument, arg1);
  argument = one_argument(argument, arg2);
  if(arg1[0] == '\0' || arg2[0] == '\0')
  {
    send_to_char("Syntax: setrace <race> <field> <value>\r\n", ch);
    send_to_char("Syntax: setrace <race> create\r\n", ch);
    send_to_char("Syntax: setrace <race> save\r\n", ch);
    send_to_char("\r\nField being one of:\r\n", ch);
    send_to_char("  name strplus dexplus wisplus\r\n", ch);
    send_to_char("  intplus conplus chaplus lckplus hit\r\n", ch);
    send_to_char("  mana affected resist suscept language\r\n", ch);
    send_to_char("  attack defense alignment acplus\r\n", ch);
    send_to_char("  minalign maxalign height weight\r\n", ch);
    send_to_char("  hungermod thirstmod expmultiplier\r\n", ch);
    send_to_char("  saving_poison_death saving_wand\r\n", ch);
    send_to_char("  saving_para_petri saving_breath\r\n", ch);
    send_to_char("  saving_spell_staff\r\n", ch);
    send_to_char("  mana_regen hp_regen sdbonus\r\n", ch);
    send_to_char("  flags\r\n", ch);
    return;
  }
  if(is_number(arg1) && (ra = atoi(arg1)) >= 0 && ra < MAX_RACE)
    race = race_table[ra];
  else
  {
    race = NULL;
    for(ra = 0; ra < MAX_RACE && race_table[ra]; ra++)
    {
      if(!race_table[ra]->race_name)
        continue;

      if(!str_cmp(race_table[ra]->race_name, arg1))
      {
        race = race_table[ra];
        break;
      }
    }
  }

  if(!str_cmp(arg2, "create") && race)
  {
    send_to_char("That race already exists!\r\n", ch);
    return;
  }
  else if(!race && str_cmp(arg2, "create"))
  {
    send_to_char("No such race.\r\n", ch);
    return;
  }

  if(!str_cmp(arg2, "create"))
  {
    if(MAX_PC_RACE >= MAX_RACE)
    {
      send_to_char("You need to up MAX_RACE in mud.h and make clean.\r\n", ch);
      return;
    }
    if((create_new_race(MAX_PC_RACE, arg1)) == FALSE)
    {
      send_to_char("Couldn't create a new race.\r\n", ch);
      return;
    }
    MAX_PC_RACE++;
    update_racelist();
    ra = MAX_PC_RACE;
    write_race_file(MAX_PC_RACE);
    send_to_char("New race created.\r\n", ch);
    return;
  }

  if(!str_cmp(arg2, "save"))
  {
    write_race_file(ra);
    send_to_char("Saved.\r\n", ch);
    return;
  }

  if(!VLD_STR(argument))
  {
    send_to_char("You must specify an argument.\r\n", ch);
    return;
  }

  if(!str_cmp(arg2, "name"))
  {
    snprintf(buf, MSL, "%s%s.race", RACEDIR, race->race_name);
    snprintf(race->race_name, 16, "%-.16s", capitalize(argument));
    write_race_file(ra);
    unlink(buf);
    update_racelist();
    send_to_char("Race name set.\r\n", ch);
    return;
  }

  if(!str_cmp(arg2, "flags"))
  {
    value = get_raceflag(argument);

    if(value < 0 || value > MAX_BITS)
      ch_printf(ch, "Unknown flag: %s\r\n", argument);
    else
    {
      xTOGGLE_BIT(race->flags, value);
      send_to_char("Done.\r\n", ch);
    }

    return;
  }

  if(!str_cmp(arg2, "sdbonus"))
    race->sdbonus = (short)atoi(argument);
  else if(!str_cmp(arg2, "basestr"))
    race->base_str = (short)atoi(argument);
  else if(!str_cmp(arg2, "basedex"))
    race->base_dex = (short)atoi(argument);
  else if(!str_cmp(arg2, "basewis"))
    race->base_wis = (short)atoi(argument);
  else if(!str_cmp(arg2, "baseint"))
    race->base_int = (short)atoi(argument);
  else if(!str_cmp(arg2, "basecon"))
    race->base_con = (short)atoi(argument);
  else if(!str_cmp(arg2, "basecha"))
    race->base_cha = (short)atoi(argument);
  else if(!str_cmp(arg2, "baselck"))
    race->base_lck = (short)atoi(argument);
  else if(!str_cmp(arg2, "hit"))
    race->hit = (short)atoi(argument);
  else if(!str_cmp(arg2, "mana"))
    race->mana = (short)atoi(argument);
  else if(!str_cmp(arg2, "affected"))
  {
    if(!VLD_STR(argument))
    {
      send_to_char("Usage: setrace <race> affected <flag> [flag]...\r\n", ch);
      return;
    }
    while(VLD_STR(argument))
    {
      argument = one_argument(argument, arg3);
      value = get_aflag(arg3);
      if(value < 0 || value > MAX_BITS)
        ch_printf(ch, "Unknown flag: %s\r\n", arg3);
      else
        xTOGGLE_BIT(race->affected, value);
    }
  }
  else if(!str_cmp(arg2, "resist"))
  {
    if(!VLD_STR(argument))
    {
      send_to_char("Usage: setrace <race> resist <flag> [flag]...\r\n", ch);
      return;
    }
    while(VLD_STR(argument))
    {
      argument = one_argument(argument, arg3);
      value = get_risflag(arg3);
      if(value < 0 || value > 31)
        ch_printf(ch, "Unknown flag: %s\r\n", arg3);
      else
        TOGGLE_BIT(race->resist, 1 << value);
    }
  }
  else if(!str_cmp(arg2, "suscept"))
  {
    if(!VLD_STR(argument))
    {
      send_to_char("Usage: setrace <race> suscept <flag> [flag]...\r\n", ch);
      return;
    }
    while(VLD_STR(argument))
    {
      argument = one_argument(argument, arg3);
      value = get_risflag(arg3);
      if(value < 0 || value > 31)
        ch_printf(ch, "Unknown flag: %s\r\n", arg3);
      else
        TOGGLE_BIT(race->suscept, 1 << value);
    }
  }
  else if(!str_cmp(arg2, "language"))
  {
    argument = one_argument(argument, arg3);
    value = get_langflag(arg3);
    if(value == LANG_UNKNOWN)
    {
      ch_printf(ch, "Unknown language: %s\r\n", arg3);
      return;
    }
    else
    {
      if(!(value &= VALID_LANGS))
        ch_printf(ch, "Player races may not speak %s.\r\n", arg3);
    }
    v2 = get_langnum(arg3);
    if(v2 == -1)
      ch_printf(ch, "Unknown language: %s\r\n", arg3);
    else
      TOGGLE_BIT(race->language, 1 << v2);
  }
  else if(!str_cmp(arg2, "acplus"))
    race->ac_plus = atoi(argument);
  else if(!str_cmp(arg2, "alignment"))
    race->alignment = atoi(argument);
  else if(!str_cmp(arg2, "defense"))
  {
    if(!VLD_STR(argument))
    {
      send_to_char("Usage: setrace <race> defense <flag> [flag]...\r\n", ch);
      return;
    }
    while(VLD_STR(argument))
    {
      argument = one_argument(argument, arg3);
      value = get_defenseflag(arg3);
      if(value < 0 || value > MAX_BITS)
        ch_printf(ch, "Unknown flag: %s\r\n", arg3);
      else
        xTOGGLE_BIT(race->defenses, value);
    }
  }
  else if(!str_cmp(arg2, "attack"))
  {
    if(!VLD_STR(argument))
    {
      send_to_char("Usage: setrace <race> attack <flag> [flag]...\r\n", ch);
      return;
    }
    while(VLD_STR(argument))
    {
      argument = one_argument(argument, arg3);
      value = get_attackflag(arg3);
      if(value < 0 || value > MAX_BITS)
        ch_printf(ch, "Unknown flag: %s\r\n", arg3);
      else
        xTOGGLE_BIT(race->attacks, value);
    }
  }
  else if(!str_cmp(arg2, "minalign"))
    race->minalign = atoi(argument);
  else if(!str_cmp(arg2, "maxalign"))
    race->maxalign = atoi(argument);
  else if(!str_cmp(arg2, "height"))
    race->height = atoi(argument);
  else if(!str_cmp(arg2, "weight"))
    race->weight = atoi(argument);
  else if(!str_cmp(arg2, "thirstmod"))
    race->thirst_mod = atoi(argument);
  else if(!str_cmp(arg2, "hungermod"))
    race->hunger_mod = atoi(argument);
  else if(!str_cmp(arg2, "maxalign"))
    race->maxalign = atoi(argument);
  else if(!str_cmp(arg2, "expmultiplier"))
    race->exp_multiplier = atoi(argument);
  else if(!str_cmp(arg2, "saving_poison_death"))
    race->saving_poison_death = atoi(argument);
  else if(!str_cmp(arg2, "saving_wand"))
    race->saving_wand = atoi(argument);
  else if(!str_cmp(arg2, "saving_para_petri"))
    race->saving_para_petri = atoi(argument);
  else if(!str_cmp(arg2, "saving_breath"))
    race->saving_breath = atoi(argument);
  else if(!str_cmp(arg2, "saving_spell_staff"))
    race->saving_spell_staff = atoi(argument);
  else if(!str_cmp(arg2, "mana_regen"))
    race->mana_regen = atoi(argument);
  else if(!str_cmp(arg2, "hp_regen"))
    race->hp_regen = atoi(argument);
#ifdef NEW_RACE_STUFF
  else if(!str_cmp(arg2, "carry_weight"))
    race->acplus = atoi(argument);
  else if(!str_cmp(arg2, "carry_number"))
    race->acplus = atoi(argument);
#endif
  else
  {
    do_setrace(ch, (char *)"");
    return;
  }
  write_race_file(ra);
  ch_printf(ch, "Updated %s on race %s[%d].\r\n", arg2, (race_table[ra] && VLD_STR(race_table[ra]->race_name)) ? race_table[ra]->race_name : "(Unknown)", ra);
  return;
}

void do_showrace(CHAR_DATA *ch, char *argument)
{
  char                    arg1[MIL];
  struct race_type       *race;
  int                     ra;

  set_pager_color(AT_PLAIN, ch);
  argument = one_argument(argument, arg1);
  if(!VLD_STR(arg1))
  {
    do_races(ch, (char *)"");
    return;
  }
  if(is_number(arg1) && (ra = atoi(arg1)) >= 0 && ra < MAX_RACE)
    race = race_table[ra];
  else
  {
    race = NULL;
    for(ra = 0; ra < MAX_RACE && race_table[ra]; ra++)
      if(!str_cmp(race_table[ra]->race_name, arg1))
      {
        race = race_table[ra];
        break;
      }
  }
  if(!race)
  {
    send_to_char("No such race.\r\n", ch);
    return;
  }
  if(xIS_SET(race->flags, RACE_ADVANCED))
    ch_printf(ch, "ADVANCED RACE: %s\r\n", race->race_name);
  else
    ch_printf(ch, "RACE: %s\r\n", race->race_name);

  ch_printf(ch, "Base: Str: %-3d Dex: %-3d Wis: %-3d Int: %-3d\r\n", race->base_str, race->base_dex, race->base_wis, race->base_int);
  ch_printf(ch, "      Con: %-3d Cha: %-3d Lck: %-3d\r\n", race->base_con, race->base_cha, race->base_lck);

  ch_printf(ch, "Hit Pts:  %-3d\tMana: %-3d\tAlign: %-4d\tAC: %-d\r\n", race->hit, race->mana, race->alignment, race->ac_plus);
  ch_printf(ch, "Min Align: %d\tMax Align: %-d\t\tXP Mult: %-d%%\r\n", race->minalign, race->maxalign, race->exp_multiplier);
  ch_printf(ch, "Height: %3d in.\t\tWeight: %4d lbs.\tHungerMod: %d\tThirstMod: %d\r\n", race->height, race->weight, race->hunger_mod, race->thirst_mod);
  ch_printf(ch, "SDBonus: %d\r\n", race->sdbonus);
  send_to_char("Affected by: ", ch);
  send_to_char(!xIS_EMPTY(race->affected) ? ext_flag_string(&race->affected, a_flags) : "Nothing", ch);
  send_to_char("\r\n", ch);
  send_to_char("Resistant to: ", ch);
  send_to_char(flag_string(race->resist, ris_flags), ch);
  send_to_char("\r\n", ch);
  send_to_char("Susceptible to: ", ch);
  send_to_char(flag_string(race->suscept, ris_flags), ch);
  send_to_char("\r\n", ch);
  ch_printf(ch, "Saves: (P/D) %d (W) %d (P/P) %d (B) %d (S/S) %d\r\n", race->saving_poison_death, race->saving_wand, race->saving_para_petri, race->saving_breath, race->saving_spell_staff);
  send_to_char("Innate Attacks: ", ch);
  send_to_char(ext_flag_string(&race->attacks, attack_flags), ch);
  send_to_char("\r\n", ch);
  send_to_char("Innate Defenses: ", ch);
  send_to_char(ext_flag_string(&race->defenses, defense_flags), ch);
  send_to_char("\r\n", ch);
  ch_printf(ch, "Spoken Language: %s", flag_string(race->language, lang_names));
  send_to_char("\r\n", ch);
  ch_printf(ch, "Race flags: %s\r\n", ext_flag_string(&race->flags, raceflags));
  send_to_char("\r\n", ch);
  return;
}

int get_raceflag(char *flag)
{
  unsigned int            x;

  for(x = 0; x < (sizeof(raceflags) / sizeof(raceflags[0])); x++)
    if(!str_cmp(flag, raceflags[x]))
      return x;
  return -1;
}

/*
int get_adv_class(int race)
{
  int x;

  for(x=0;x<MAX_CLASS;x++)
    if(race_table[race] && class_table[x] && !str_cmp(race_table[race]->race_name, class_table[x]->who_name))
      return x;

  return -1;
}
*/