rasputin/bin/
rasputin/cnf/
rasputin/doc/cwg/
rasputin/lib/
rasputin/lib/etc/
rasputin/lib/etc/boards/
rasputin/lib/house/
rasputin/lib/misc/
rasputin/lib/plralias/A-E/
rasputin/lib/plralias/F-J/
rasputin/lib/plralias/K-O/
rasputin/lib/plralias/P-T/
rasputin/lib/plralias/U-Z/
rasputin/lib/plralias/ZZZ/
rasputin/lib/plrfiles/
rasputin/lib/plrfiles/A-E/
rasputin/lib/plrfiles/F-J/
rasputin/lib/plrfiles/K-O/
rasputin/lib/plrfiles/P-T/
rasputin/lib/plrfiles/U-Z/
rasputin/lib/plrfiles/ZZZ/
rasputin/lib/plrobjs/
rasputin/lib/plrobjs/A-E/
rasputin/lib/plrobjs/F-J/
rasputin/lib/plrobjs/K-O/
rasputin/lib/plrobjs/P-T/
rasputin/lib/plrobjs/U-Z/
rasputin/lib/plrobjs/ZZZ/
rasputin/lib/plrvars/A-E/
rasputin/lib/plrvars/F-J/
rasputin/lib/plrvars/K-O/
rasputin/lib/plrvars/P-T/
rasputin/lib/plrvars/U-Z/
rasputin/lib/plrvars/ZZZ/
rasputin/lib/world/gld/
rasputin/lib/world/trg/
rasputin/src/
rasputin/src/doc/
/*****************************************************************************
** FEATS.C                                                                  **
** Source code for the Gates of Krynn Feats System.                         **
** Initial code by Paladine (Stephen Squires)                               **
** Created Thursday, September 5, 2002                                      **
**                                                                          **
*****************************************************************************/

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

CVSHEADER("$CVSHeader: cwg/rasputin/src/feats.c,v 1.14 2004/12/30 04:34:48 fnord Exp $");

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

/* Local Functions */
void assign_feats(void);
void feato(int featnum, char *name, int in_game, int can_learn, int can_stack);
void list_feats_known(struct char_data *ch); 
void list_feats_available(struct char_data *ch); 
void list_feats_complete(struct char_data *ch); 
int compare_feats(const void *x, const void *y);
void sort_feats(void);	
int find_feat_num(char *name);

/* Global Variables and Structures */
struct feat_info feat_list[NUM_FEATS_DEFINED];
int feat_sort_info[MAX_FEATS + 1];
char buf3[MAX_STRING_LENGTH];
char buf4[MAX_STRING_LENGTH];

/* External variables and structures */
extern int spell_sort_info[SKILL_TABLE_SIZE+1];
extern struct spell_info_type spell_info[];

/* External functions*/
int count_metamagic_feats(struct char_data *ch);

void feato(int featnum, char *name, int in_game, int can_learn, int can_stack)
{
  feat_list[featnum].name = name;
  feat_list[featnum].in_game = in_game;
  feat_list[featnum].can_learn = can_learn;
  feat_list[featnum].can_stack = can_stack;
}

void free_feats(void)
{
  /* Nothing to do right now */
}

void assign_feats(void)
{

  int i;

  // Initialize the list of feats.

  for (i = 0; i <= NUM_FEATS_DEFINED; i++) {
    feat_list[i].name = "Unused Feat";
    feat_list[i].in_game = FALSE;
    feat_list[i].can_learn = FALSE;
    feat_list[i].can_stack = FALSE;
  }

// Below are the various feat initializations.
// First parameter is the feat number, defined in feats.h
// Second parameter is the displayed name of the feat and argument used to train it
// Third parameter defines whether or not the feat is in the game or not, and thus can be learned and displayed
// Fourth parameter defines whether or not the feat can be learned through a trainer or whether it is
// a feat given automatically to certain classes or races.

feato(FEAT_ALERTNESS, "alertness", TRUE, TRUE, FALSE); 
feato(FEAT_ARMOR_PROFICIENCY_HEAVY, "heavy armor proficiency", TRUE, TRUE, FALSE); 
feato(FEAT_ARMOR_PROFICIENCY_LIGHT, "light armor proficiency", TRUE, TRUE, FALSE); 
feato(FEAT_ARMOR_PROFICIENCY_MEDIUM, "medium armor proficiency", TRUE, TRUE, FALSE); 
feato(FEAT_BLIND_FIGHT, "blind fighting", TRUE, TRUE, FALSE); 
feato(FEAT_BREW_POTION, "brew potion", TRUE, TRUE, FALSE); 
feato(FEAT_CLEAVE, "cleave", TRUE, TRUE, FALSE);
feato(FEAT_COMBAT_CASTING, "combat casting", TRUE, TRUE, FALSE); 
feato(FEAT_COMBAT_REFLEXES, "combat reflexes", TRUE, TRUE, FALSE);
feato(FEAT_CRAFT_MAGICAL_ARMS_AND_ARMOR, "craft magical arms and armor", TRUE, TRUE, FALSE); 
feato(FEAT_CRAFT_ROD, "craft rod", TRUE, TRUE, FALSE);
feato(FEAT_CRAFT_STAFF, "craft staff", TRUE, TRUE, FALSE); 
feato(FEAT_CRAFT_WAND, "craft wand", TRUE, TRUE, FALSE); 
feato(FEAT_CRAFT_WONDEROUS_ITEM, "craft wonderous item", FALSE, TRUE, FALSE); 
feato(FEAT_DEFLECT_ARROWS, "deflect arrows", FALSE, FALSE, FALSE); 
feato(FEAT_DODGE, "dodge", TRUE, TRUE, FALSE); 
feato(FEAT_EMPOWER_SPELL, "empower spell", TRUE, TRUE, FALSE); 
feato(FEAT_ENDURANCE, "endurance", TRUE, TRUE, FALSE);
feato(FEAT_ENLARGE_SPELL, "enlarge spell", FALSE, FALSE, FALSE);
feato(FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD, "weapon proficiency - bastard sword", FALSE, TRUE, FALSE);
feato(FEAT_EXTEND_SPELL, "extend spell", TRUE, TRUE, FALSE);
feato(FEAT_EXTRA_TURNING, "extra turning", TRUE, TRUE, FALSE);
feato(FEAT_FAR_SHOT, "far shot", FALSE, FALSE, FALSE);
feato(FEAT_FORGE_RING, "forge ring", TRUE, TRUE, FALSE);
feato(FEAT_GREAT_CLEAVE, "great cleave", FALSE, FALSE, FALSE);
feato(FEAT_GREAT_FORTITUDE, "great fortitude", TRUE, TRUE, FALSE);
feato(FEAT_HEIGHTEN_SPELL, "heighten spell", TRUE, TRUE, FALSE);
feato(FEAT_IMPROVED_BULL_RUSH, "improved bull rush", FALSE, FALSE, FALSE);
feato(FEAT_IMPROVED_CRITICAL, "improved critical", TRUE, TRUE, TRUE);
feato(FEAT_IMPROVED_DISARM, "improved disarm", TRUE, TRUE, FALSE);
feato(FEAT_IMPROVED_INITIATIVE, "improved initiative", TRUE, TRUE, FALSE);
feato(FEAT_IMPROVED_TRIP, "improved trip", TRUE, TRUE, FALSE);
feato(FEAT_IMPROVED_TWO_WEAPON_FIGHTING, "improved two weapon fighting", TRUE, TRUE, FALSE);
feato(FEAT_IMPROVED_UNARMED_STRIKE, "improved unarmed strike", FALSE, FALSE, FALSE);
feato(FEAT_IRON_WILL, "iron will", TRUE, TRUE, FALSE);
feato(FEAT_LEADERSHIP, "leadership", FALSE, FALSE, FALSE);
feato(FEAT_LIGHTNING_REFLEXES, "lightning reflexes", TRUE, TRUE, FALSE);
feato(FEAT_MARTIAL_WEAPON_PROFICIENCY, "martial weapon proficiency", TRUE, TRUE, FALSE);
feato(FEAT_MAXIMIZE_SPELL, "maximize spell", TRUE, TRUE, FALSE);
feato(FEAT_MOBILITY, "mobility", TRUE, TRUE, FALSE);
feato(FEAT_MOUNTED_ARCHERY, "mounted archery", FALSE, FALSE, FALSE);
feato(FEAT_MOUNTED_COMBAT, "mounted combat", FALSE, FALSE, FALSE);
feato(FEAT_POINT_BLANK_SHOT, "point blank shot", FALSE, FALSE, FALSE);
feato(FEAT_POWER_ATTACK, "power attack", TRUE, TRUE, FALSE);
feato(FEAT_PRECISE_SHOT, "precise shot", FALSE, FALSE, FALSE);
feato(FEAT_QUICK_DRAW, "quick draw", FALSE, FALSE, FALSE);
feato(FEAT_QUICKEN_SPELL, "quicken spell", TRUE, TRUE, FALSE);
feato(FEAT_RAPID_SHOT, "rapid shot", FALSE, FALSE, FALSE);
feato(FEAT_RIDE_BY_ATTACK, "ride by attack", FALSE, FALSE, FALSE);
feato(FEAT_RUN, "run", FALSE, FALSE, FALSE);
feato(FEAT_SCRIBE_SCROLL, "scribe scroll", TRUE, TRUE, FALSE);
feato(FEAT_SHOT_ON_THE_RUN, "shot on the run", FALSE, FALSE, FALSE);
feato(FEAT_SILENT_SPELL, "silent spell", TRUE, TRUE, FALSE);
feato(FEAT_SIMPLE_WEAPON_PROFICIENCY, "simple weapon proficiency", TRUE, TRUE, FALSE);
feato(FEAT_SKILL_FOCUS, "skill focus", TRUE, TRUE, TRUE);
feato(FEAT_SPELL_FOCUS, "spell focus", TRUE, TRUE, TRUE);
feato(FEAT_SPELL_MASTERY, "spell mastery", TRUE, TRUE, TRUE);
feato(FEAT_SPELL_PENETRATION, "spell penetration", TRUE, TRUE, FALSE);
feato(FEAT_SPIRITED_CHARGE, "spirited charge", FALSE, FALSE, FALSE);
feato(FEAT_SPRING_ATTACK, "spring attack", FALSE, FALSE, FALSE);
feato(FEAT_STILL_SPELL, "still spell", TRUE, TRUE, FALSE);
feato(FEAT_STUNNING_FIST, "stunning fist", TRUE, TRUE, FALSE);
feato(FEAT_SUNDER, "sunder", TRUE, TRUE, FALSE);
feato(FEAT_TOUGHNESS, "toughness", TRUE, TRUE, TRUE);
feato(FEAT_TRACK, "track", TRUE, TRUE, FALSE);
feato(FEAT_TRAMPLE, "trample", FALSE, FALSE, FALSE);
feato(FEAT_TWO_WEAPON_FIGHTING, "two weapon fighting", TRUE, TRUE, FALSE);
feato(FEAT_WEAPON_FINESSE, "weapon finesse", TRUE, TRUE, TRUE);
feato(FEAT_WEAPON_FOCUS, "weapon focus", TRUE, TRUE, TRUE);
feato(FEAT_WEAPON_SPECIALIZATION, "weapon specialization", TRUE, TRUE, TRUE);
feato(FEAT_WHIRLWIND_ATTACK, "whirlwind attack", TRUE, TRUE, FALSE);
feato(FEAT_WEAPON_PROFICIENCY_DRUID, "weapon proficiency - druids", FALSE, FALSE, FALSE);
feato(FEAT_WEAPON_PROFICIENCY_ROGUE, "weapon proficiency - rogues", FALSE, FALSE, FALSE);
feato(FEAT_WEAPON_PROFICIENCY_MONK, "weapon proficiency - monks", FALSE, FALSE, FALSE);
feato(FEAT_WEAPON_PROFICIENCY_WIZARD, "weapon proficiency - wizards", FALSE, FALSE, FALSE);
feato(FEAT_WEAPON_PROFICIENCY_ELF, "weapon proficiency - elves", FALSE, FALSE, FALSE);
feato(FEAT_ARMOR_PROFICIENCY_SHIELD, "shield armor proficiency", TRUE, FALSE, FALSE); 
feato(FEAT_SNEAK_ATTACK, "sneak attack", TRUE, FALSE, TRUE);
feato(FEAT_EVASION, "evasion", TRUE, FALSE, FALSE);
feato(FEAT_IMPROVED_EVASION, "improved evasion", TRUE, FALSE, FALSE);
feato(FEAT_ACROBATIC, "acrobatic", TRUE, TRUE, FALSE);
feato(FEAT_AGILE, "agile", TRUE, TRUE, FALSE);
feato(FEAT_ALERTNESS, "alertness", TRUE, TRUE, FALSE);
feato(FEAT_ANIMAL_AFFINITY, "animal affinity", TRUE, TRUE, FALSE);
feato(FEAT_ATHLETIC, "athletic", TRUE, TRUE, FALSE);
feato(FEAT_AUGMENT_SUMMONING, "augment summoning", FALSE, FALSE, FALSE);
feato(FEAT_COMBAT_EXPERTISE, "combat expertise", FALSE, FALSE, FALSE);
feato(FEAT_DECEITFUL, "deceitful", TRUE, TRUE, FALSE);
feato(FEAT_DEFT_HANDS, "deft hands", TRUE, TRUE, FALSE);
feato(FEAT_DIEHARD, "diehard", FALSE, FALSE, FALSE);
feato(FEAT_DILIGENT, "diligent", TRUE, TRUE, FALSE);
feato(FEAT_ESCHEW_MATERIALS, "eschew materials", FALSE, FALSE, FALSE);
feato(FEAT_EXOTIC_WEAPON_PROFICIENCY, "exotic weapon proficiency", FALSE, FALSE, FALSE);
feato(FEAT_GREATER_SPELL_FOCUS, "greater spell focus", FALSE, FALSE, TRUE);
feato(FEAT_GREATER_SPELL_PENETRATION, "greater spell penetration", FALSE, FALSE, FALSE);
feato(FEAT_GREATER_TWO_WEAPON_FIGHTING, "greater two weapon fighting", FALSE, FALSE, FALSE);
feato(FEAT_GREATER_WEAPON_FOCUS, "greater weapon focus", TRUE, TRUE, TRUE);
feato(FEAT_GREATER_WEAPON_SPECIALIZATION, "greater weapon specialization", TRUE, TRUE, TRUE);
feato(FEAT_IMPROVED_COUNTERSPELL, "improved counterspell", FALSE, FALSE, FALSE);
feato(FEAT_IMPROVED_FAMILIAR, "improved familiar", FALSE, FALSE, FALSE);
feato(FEAT_IMPROVED_FEINT, "improved feint", FALSE, FALSE, FALSE);
feato(FEAT_IMPROVED_GRAPPLE, "improved grapple", FALSE, FALSE, FALSE);
feato(FEAT_IMPROVED_OVERRUN, "improved overrun", FALSE, FALSE, FALSE);
feato(FEAT_IMPROVED_PRECISE_SHOT, "improved precise shot", FALSE, FALSE, FALSE);
feato(FEAT_IMPROVED_SHIELD_BASH, "improved shield bash", FALSE, FALSE, FALSE);
feato(FEAT_IMPROVED_SUNDER, "improved sunder", FALSE, FALSE, FALSE);
feato(FEAT_IMPROVED_TURNING, "improved turning", FALSE, FALSE, FALSE);
feato(FEAT_INVESTIGATOR, "investigator", TRUE, TRUE, FALSE);
feato(FEAT_MAGICAL_APTITUDE, "magical aptitude", TRUE, TRUE, FALSE);
feato(FEAT_MANYSHOT, "manyshot", FALSE, FALSE, FALSE);
feato(FEAT_NATURAL_SPELL, "natural spell", FALSE, FALSE, FALSE);
feato(FEAT_NEGOTIATOR, "negotiator", TRUE, TRUE, FALSE);
feato(FEAT_NIMBLE_FINGERS, "nimble fingers", TRUE, TRUE, FALSE);
feato(FEAT_PERSUASIVE, "persuasive", TRUE, TRUE, FALSE);
feato(FEAT_RAPID_RELOAD, "rapid reload", FALSE, FALSE, FALSE);
feato(FEAT_SELF_SUFFICIENT, "self sufficient", TRUE, TRUE, FALSE);
feato(FEAT_STEALTHY, "stealthy", TRUE, TRUE, FALSE);
feato(FEAT_ARMOR_PROFICIENCY_TOWER_SHIELD, "tower shield armor proficiency", FALSE, FALSE, FALSE);
feato(FEAT_TWO_WEAPON_DEFENSE, "two weapon defense", FALSE, FALSE, FALSE);
feato(FEAT_WIDEN_SPELL, "widen spell", FALSE, FALSE, FALSE);
}

// The follwing function is used to check if the character satisfies the various prerequisite(s) (if any)
// of a feat in order to learn it.

int feat_is_available(struct char_data *ch, int featnum, int iarg, char *sarg)
{
  if (featnum > NUM_FEATS_DEFINED)
    return FALSE;

  if (HAS_FEAT(ch, featnum) && !feat_list[featnum].can_stack)
    return FALSE;

  switch (featnum) {

  case FEAT_ARMOR_PROFICIENCY_HEAVY:
    if (HAS_FEAT(ch, FEAT_ARMOR_PROFICIENCY_MEDIUM))
      return TRUE;
    return FALSE;

  case FEAT_ARMOR_PROFICIENCY_MEDIUM:
    if (HAS_FEAT(ch, FEAT_ARMOR_PROFICIENCY_LIGHT))
      return TRUE;
    return FALSE;

  case FEAT_DODGE:
    if (GET_DEX(ch) >= 13)
      return TRUE;
    return FALSE;

  case FEAT_MOBILITY:
    if (HAS_FEAT(ch, FEAT_DODGE))
      return TRUE;
    return FALSE;

  case FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD:
    if (GET_BAB(ch) >= 1)
      return TRUE;
    return FALSE;

  case FEAT_IMPROVED_DISARM:
    return TRUE;

  case FEAT_IMPROVED_TRIP:
    return TRUE;

  case FEAT_WHIRLWIND_ATTACK:
    return TRUE;

  case FEAT_STUNNING_FIST:
    return TRUE;
  
  case FEAT_POWER_ATTACK:
    if (GET_STR(ch) >= 13)
      return TRUE;
    return FALSE;

  case FEAT_CLEAVE:
    if (HAS_FEAT(ch, FEAT_POWER_ATTACK))
      return TRUE;
    return FALSE;

  case FEAT_SUNDER:
    if (HAS_FEAT(ch, FEAT_POWER_ATTACK))
      return TRUE;
    return FALSE;

  case FEAT_TWO_WEAPON_FIGHTING:
    if (GET_DEX(ch) >= 15)
      return TRUE;
    return FALSE;

  case FEAT_IMPROVED_TWO_WEAPON_FIGHTING:
    if (GET_DEX(ch) >= 17 && HAS_FEAT(ch, FEAT_TWO_WEAPON_FIGHTING) && GET_BAB(ch) >= 6)
      return TRUE;
    return FALSE;

  case FEAT_IMPROVED_CRITICAL:
    if (GET_BAB(ch) < 8)
      return FALSE;
    if (!iarg || is_proficient_with_weapon(ch, iarg))
      return TRUE;
    return FALSE;

  case FEAT_WEAPON_FINESSE:
  case FEAT_WEAPON_FOCUS:
    if (GET_BAB(ch) < 1)
      return FALSE;
    if (!iarg || is_proficient_with_weapon(ch, iarg))
      return TRUE;
    return FALSE;

  case FEAT_WEAPON_SPECIALIZATION:
    if (GET_CLASS_RANKS(ch, CLASS_FIGHTER) < 4)
      return FALSE;
    if (!iarg || is_proficient_with_weapon(ch, iarg))
      return TRUE;
    return FALSE;

  case FEAT_GREATER_WEAPON_FOCUS:
    if (GET_CLASS_RANKS(ch, CLASS_FIGHTER) < 8)
      return FALSE;
    if (!iarg)
      return TRUE;
    if (is_proficient_with_weapon(ch, iarg) && HAS_COMBAT_FEAT(ch, CFEAT_WEAPON_FOCUS, iarg))
      return TRUE;
    return FALSE;

  case FEAT_GREATER_WEAPON_SPECIALIZATION:
    if (GET_CLASS_RANKS(ch, CLASS_FIGHTER) < 12)
      return FALSE;
    if (!iarg)
      return TRUE;
    if (is_proficient_with_weapon(ch, iarg) &&
        HAS_COMBAT_FEAT(ch, CFEAT_GREATER_WEAPON_FOCUS, iarg) &&
        HAS_COMBAT_FEAT(ch, CFEAT_WEAPON_SPECIALIZATION, iarg) &&
        HAS_COMBAT_FEAT(ch, CFEAT_WEAPON_FOCUS, iarg))
      return TRUE;
    return FALSE;

  case FEAT_SPELL_FOCUS:
    if (GET_CLASS_RANKS(ch, CLASS_WIZARD))
      return TRUE;
    return FALSE;

  case FEAT_SPELL_PENETRATION:
    if (GET_LEVEL(ch))
      return TRUE;
    return FALSE;

  case FEAT_BREW_POTION:
    if (GET_LEVEL(ch) >= 3)
      return TRUE;
    return FALSE;

  case FEAT_CRAFT_MAGICAL_ARMS_AND_ARMOR:
    if (GET_LEVEL(ch) >= 5)
      return TRUE;
    return FALSE;

  case FEAT_CRAFT_ROD:
    if (GET_LEVEL(ch) >= 9)
      return TRUE;
    return FALSE;

  case FEAT_CRAFT_STAFF:
    if (GET_LEVEL(ch) >= 12)
      return TRUE;
    return FALSE;

  case FEAT_CRAFT_WAND:
    if (GET_LEVEL(ch) >= 5)
      return TRUE;
    return FALSE;

  case FEAT_FORGE_RING:
    if (GET_LEVEL(ch) >= 5)
      return TRUE;
    return FALSE;

  case FEAT_SCRIBE_SCROLL:
    if (GET_LEVEL(ch) >= 1)
      return TRUE;
    return FALSE;

  case FEAT_EMPOWER_SPELL:
    if (GET_CLASS_RANKS(ch, CLASS_WIZARD))
      return TRUE;
    return FALSE;

  case FEAT_EXTEND_SPELL:
    if (GET_CLASS_RANKS(ch, CLASS_WIZARD))
      return TRUE;
    return FALSE;

  case FEAT_HEIGHTEN_SPELL:
    if (GET_CLASS_RANKS(ch, CLASS_WIZARD))
      return TRUE;
    return FALSE;

  case FEAT_MAXIMIZE_SPELL:
    if (GET_CLASS_RANKS(ch, CLASS_WIZARD))
      return TRUE;
    return FALSE;

  case FEAT_QUICKEN_SPELL:
    if (GET_CLASS_RANKS(ch, CLASS_WIZARD))
      return TRUE;
    return FALSE;

  case FEAT_SILENT_SPELL:
    if (GET_CLASS_RANKS(ch, CLASS_WIZARD))
      return TRUE;
    return FALSE;

  case FEAT_STILL_SPELL:
    if (GET_CLASS_RANKS(ch, CLASS_WIZARD))
      return TRUE;
    return FALSE;

  case FEAT_EXTRA_TURNING:
    if (GET_CLASS_RANKS(ch, CLASS_CLERIC))
      return TRUE;
    return FALSE;

  case FEAT_SPELL_MASTERY:
    if (GET_CLASS_RANKS(ch, CLASS_WIZARD))
      return TRUE;
    return FALSE;

  default:
    return TRUE;

  }
}

int is_proficient_with_armor(const struct char_data *ch, int armor_type)
{
  switch (armor_type) {
    case ARMOR_TYPE_LIGHT:
      if (HAS_FEAT(ch, FEAT_ARMOR_PROFICIENCY_LIGHT))
        return TRUE;
    break;
    case ARMOR_TYPE_MEDIUM:
      if (HAS_FEAT(ch, FEAT_ARMOR_PROFICIENCY_MEDIUM))
        return TRUE;
    break;
    case ARMOR_TYPE_HEAVY:
      if (HAS_FEAT(ch, FEAT_ARMOR_PROFICIENCY_HEAVY))
        return TRUE;
    break;
    case ARMOR_TYPE_SHIELD:
      if (HAS_FEAT(ch, FEAT_ARMOR_PROFICIENCY_SHIELD))
        return TRUE;
    break;
  }
  return FALSE;
}

int is_proficient_with_weapon(const struct char_data *ch, int weapon_type)
{
  switch (weapon_type) {
  case WEAPON_TYPE_UNARMED:
    return 1;
  case WEAPON_TYPE_DAGGER:
  case WEAPON_TYPE_MACE:
  case WEAPON_TYPE_SICKLE:
  case WEAPON_TYPE_SPEAR:
  case WEAPON_TYPE_STAFF:
  case WEAPON_TYPE_CROSSBOW:
  case WEAPON_TYPE_SLING:
  case WEAPON_TYPE_THROWN:
  case WEAPON_TYPE_CLUB:
    if (HAS_FEAT(ch, FEAT_SIMPLE_WEAPON_PROFICIENCY))
      return TRUE;
    break;
  case WEAPON_TYPE_SHORTBOW:
  case WEAPON_TYPE_LONGBOW:
  case WEAPON_TYPE_HAMMER:
  case WEAPON_TYPE_LANCE:
  case WEAPON_TYPE_FLAIL:
  case WEAPON_TYPE_LONGSWORD:
  case WEAPON_TYPE_SHORTSWORD:
  case WEAPON_TYPE_GREATSWORD:
  case WEAPON_TYPE_RAPIER:
  case WEAPON_TYPE_SCIMITAR:
  case WEAPON_TYPE_POLEARM:
  case WEAPON_TYPE_BASTARD_SWORD:
  case WEAPON_TYPE_AXE:
    if (HAS_FEAT(ch, FEAT_MARTIAL_WEAPON_PROFICIENCY))
      return TRUE;
    break;
  default:
    return FALSE;
    break;
  }
  return FALSE;
}
  
int compare_feats(const void *x, const void *y)
{
  int   a = *(const int *)x,
        b = *(const int *)y;
  
  return strcmp(feat_list[a].name, feat_list[b].name);
}

void sort_feats(void)
{
  int a;

  /* initialize array, avoiding reserved. */
  for (a = 1; a <= NUM_FEATS_DEFINED; a++)
    feat_sort_info[a] = a;

  qsort(&feat_sort_info[1], NUM_FEATS_DEFINED, sizeof(int), compare_feats);
}

void list_feats_known(struct char_data *ch) 
{
  int i, sortpos;
  int none_shown = TRUE;
  int temp_value;
  int added_hp = 0;
  char buf [MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];

  if (!GET_FEAT_POINTS(ch))
    strcpy(buf, "\r\nYou cannot learn any feats right now.\r\n");
  else
    sprintf(buf, "\r\nYou can learn %d feat%s right now.\r\n",
            GET_FEAT_POINTS(ch), (GET_FEAT_POINTS(ch) == 1 ? "" : "s"));

    
    // Display Headings
    sprintf(buf + strlen(buf), "\r\n");
    sprintf(buf + strlen(buf), "@WFeats Known@n\r\n");
    sprintf(buf + strlen(buf), "@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@n\r\n");
    sprintf(buf + strlen(buf), "\r\n");

  strcpy(buf2, buf);

  for (sortpos = 1; sortpos <= NUM_FEATS_DEFINED; sortpos++) {

    if (strlen(buf2) > MAX_STRING_LENGTH -32)
      break;

    i = feat_sort_info[sortpos];
    if (HAS_FEAT(ch, i)  && feat_list[i].in_game) {
      if (i == FEAT_SKILL_FOCUS) {
        sprintf(buf, "%-20s (+%d points overall)\r\n", feat_list[i].name, HAS_FEAT(ch, i) * 2);
        strcat(buf2, buf);
        none_shown = FALSE;
      }
    else if (i == FEAT_TOUGHNESS) {
      temp_value = HAS_FEAT(ch, FEAT_TOUGHNESS);
      added_hp = temp_value * 3;
      sprintf(buf, "%-20s (+%d hp)\r\n", feat_list[i].name, added_hp);
      strcat(buf2, buf);  
      none_shown = FALSE;
    } else {
        sprintf(buf, "%-20s\r\n", feat_list[i].name);
        strcat(buf2, buf);        /* The above, ^ should always be safe to do. */
        none_shown = FALSE;
      }
    }
  }

  if (none_shown) {
    sprintf(buf, "You do not know any feats at this time.\r\n");
    strcat(buf2, buf);
  }
   
  page_string(ch->desc, buf2, 1);
}

void list_feats_available(struct char_data *ch) 
{
  char buf[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];
  int i, sortpos;
  int none_shown = TRUE;

  if (!GET_FEAT_POINTS(ch))
    strcpy(buf, "\r\nYou cannot learn any feats right now.\r\n");
  else
    sprintf(buf, "\r\nYou can learn %d feat%s right now.\r\n",
            GET_FEAT_POINTS(ch), (GET_FEAT_POINTS(ch) == 1 ? "" : "s"));
    
    // Display Headings
    sprintf(buf + strlen(buf), "\r\n");
    sprintf(buf + strlen(buf), "@WFeats Available to Learn@n\r\n");
    sprintf(buf + strlen(buf), "@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@n\r\n");
    sprintf(buf + strlen(buf), "\r\n");

  strcpy(buf2, buf);

  for (sortpos = 1; sortpos <= NUM_FEATS_DEFINED; sortpos++) {
    i = feat_sort_info[sortpos];
    if (strlen(buf2) >= MAX_STRING_LENGTH - 32) {
      strcat(buf2, "**OVERFLOW**\r\n"); 
      break;   
    }
    if (feat_is_available(ch, i, 0, NULL) && feat_list[i].in_game && feat_list[i].can_learn) {
      sprintf(buf, "%-20s\r\n", feat_list[i].name);
      strcat(buf2, buf);        /* The above, ^ should always be safe to do. */
      none_shown = FALSE;
    }
  }

  if (none_shown) {
    sprintf(buf, "There are no feats available for you to learn at this point.\r\n");
    strcat(buf2, buf);
  }
   
  page_string(ch->desc, buf2, 1);
}
void list_feats_complete(struct char_data *ch) 
{

	char buf[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];
  int i, sortpos;
  int none_shown = TRUE;

  if (!GET_FEAT_POINTS(ch))
    strcpy(buf, "\r\nYou cannot learn any feats right now.\r\n");
  else
    sprintf(buf, "\r\nYou can learn %d feat%s right now.\r\n",
            GET_FEAT_POINTS(ch), (GET_FEAT_POINTS(ch) == 1 ? "" : "s"));

    
    // Display Headings
    sprintf(buf + strlen(buf), "\r\n");
    sprintf(buf + strlen(buf), "@WComplete Feat List@n\r\n");
    sprintf(buf + strlen(buf), "@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@B~@R~@n\r\n");
    sprintf(buf + strlen(buf), "\r\n");

  strcpy(buf2, buf);

  for (sortpos = 1; sortpos <= NUM_FEATS_DEFINED; sortpos++) {
    i = feat_sort_info[sortpos];
    if (strlen(buf2) >= MAX_STRING_LENGTH - 32) {
      strcat(buf2, "**OVERFLOW**\r\n"); 
      break;   
    }
//	sprintf(buf, "%s : %s\r\n", feat_list[i].name, feat_list[i].in_game ? "In Game" : "Not In Game");
//	strcat(buf2, buf);
    if (feat_list[i].in_game) {
      sprintf(buf, "%-20s\r\n", feat_list[i].name);
      strcat(buf2, buf);        /* The above, ^ should always be safe to do. */
      none_shown = FALSE;
    }
  }

  if (none_shown) {
    sprintf(buf, "There are currently no feats in the game.\r\n");
    strcat(buf2, buf);
  }
   
  page_string(ch->desc, buf2, 1);
}

int find_feat_num(char *name)
{  
  int index, ok;
  char *temp, *temp2;
  char first[256], first2[256];
   
  for (index = 1; index <= NUM_FEATS_DEFINED; index++) {
    if (is_abbrev(name, feat_list[index].name))
      return (index);
    
    ok = TRUE;
    /* It won't be changed, but other uses of this function elsewhere may. */
    temp = any_one_arg((char *)feat_list[index].name, first);
    temp2 = any_one_arg(name, first2);
    while (*first && *first2 && ok) {
      if (!is_abbrev(first2, first))
        ok = FALSE;
      temp = any_one_arg(temp, first);
      temp2 = any_one_arg(temp2, first2);
    }
  
    if (ok && !*first2)
      return (index);
  }
    
  return (-1);
}

ACMD(do_feats)
{
  char arg[80];

  one_argument(argument, arg);

  if (is_abbrev(arg, "known") || !*arg) {
    send_to_char(ch, "Syntax is \"feats <available | complete | known>\".\r\n");
    list_feats_known(ch);
  } else if (is_abbrev(arg, "available")) {
    list_feats_available(ch);
  } else if (is_abbrev(arg, "complete")) {
    list_feats_complete(ch);
  }
}

int feat_to_subfeat(int feat)
{
  switch (feat) {
  case FEAT_IMPROVED_CRITICAL:
    return CFEAT_IMPROVED_CRITICAL;
  case FEAT_WEAPON_FINESSE:
    return CFEAT_WEAPON_FINESSE;
  case FEAT_WEAPON_FOCUS:
    return CFEAT_WEAPON_FOCUS;
  case FEAT_WEAPON_SPECIALIZATION:
    return CFEAT_WEAPON_SPECIALIZATION;
  case FEAT_GREATER_WEAPON_FOCUS:
    return CFEAT_GREATER_WEAPON_FOCUS;
  case FEAT_GREATER_WEAPON_SPECIALIZATION:
    return CFEAT_GREATER_WEAPON_SPECIALIZATION;
  case FEAT_SPELL_FOCUS:
    return CFEAT_SPELL_FOCUS;
  case FEAT_GREATER_SPELL_FOCUS:
    return CFEAT_GREATER_SPELL_FOCUS;
  default:
    return -1;
  }
}