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/
/* ************************************************************************
 *   File: Guild.c                                                         *
 *  Usage: GuildMaster's: loading files, assigning spec_procs, and handling*
 *                        practicing.                                      *
 *                                                                         *
 * Based on shop.c.  As such, the CircleMud License applies                *
 * Written by Jason Goodwin.   jgoodwin@expert.cc.purdue.edu               *
 ************************************************************************ */


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

CVSHEADER("$CVSHeader: cwg/rasputin/src/guild.c,v 1.25 2005/01/03 18:01:09 fnord Exp $");

#include "structs.h"
#include "utils.h"

#include "comm.h"
#include "constants.h"
#include "db.h"
#include "shop.h"
#include "guild.h"
#include "handler.h"
#include "interpreter.h"
#include "spells.h"
#include "screen.h"
#include "gengld.h"
#include "feats.h"


/* extern variables */
extern struct spell_info_type spell_info[];
extern struct time_info_data time_info;
extern const char *trade_letters[];
extern int cmd_say, cmd_tell;
extern const char *class_names[];

/* extern function prototypes */
ACMD(do_tell);
ACMD(do_say);
int level_exp(int level);
void gain_level(struct char_data *ch, int whichclass);
int feat_is_available(struct char_data *ch, int featnum, int iarg, char *sarg);
int find_feat_num(char *name);

/* Local variables */
struct guild_data *guild_index;
int spell_sort_info[SKILL_TABLE_SIZE + 1];
int top_guild = -1;
char *guild_customer_string(int guild_nr, int detailed);

const char *how_good(int percent)
{
  if (percent < 0)
    return " error)";
  if (percent == 0)
    return "(@Mnot@n)";
  if (percent <= 10)
    return "(@rawful@n)";
  if (percent <= 20)
    return "(@Rbad@n)";
  if (percent <= 40)
    return "(@ypoor@n)";
  if (percent <= 55)
    return "(@Yaverage@n)";
  if (percent <= 70)
    return "(@gfair@n)";
  if (percent <= 80)
    return "(@Ggood@n)";
  if (percent <= 85)
    return "(@bgreat@n)";
  if (percent <= 100)
    return "(@Bsuperb@n)";

  return "(@rinate@n)";
}

const char *prac_types[] = {
  "spell",
  "skill"
};


int compare_spells(const void *x, const void *y)
{
  int	a = *(const int *)x,
	b = *(const int *)y;

  return strcmp(spell_info[a].name, spell_info[b].name);
}


int print_skills_by_type(struct char_data *ch, char *buf, int maxsz, int sktype)
{
  size_t len = 0;
  int i, t, known, nlen;
  char buf2[READ_SIZE];

  for (i = 1; i <= SKILL_TABLE_SIZE; i++) { 
    t = spell_info[i].skilltype;

    if (t != sktype)
      continue;

    if ((t & SKTYPE_SKILL) || (t & SKTYPE_SPELL)) {
      for (nlen = 0, known = 0; nlen < NUM_CLASSES; nlen++)
	if (spell_info[i].can_learn_skill[nlen] > known)
	  known = spell_info[i].can_learn_skill[nlen];
    } else {
      known = 0;
    }

    if (known) {
      if (t & SKTYPE_LANG) {
	nlen = snprintf(buf + len, maxsz - len, "%-20s  (%s)\r\n",
                        spell_info[i].name, GET_SKILL_BASE(ch, i) ? "known" : "unknown");
      } else if (t & SKTYPE_SKILL) {
        if (GET_SKILL_BONUS(ch, i))
          snprintf(buf2, sizeof(buf2), " (base %d + bonus %d)", GET_SKILL_BASE(ch, i),
                   GET_SKILL_BONUS(ch, i));
        else
          buf2[0] = 0;
	nlen = snprintf(buf + len, maxsz - len, "%-20s  %d%s\r\n",
                        spell_info[i].name, GET_SKILL(ch, i), buf2);
      }
      else
	nlen = snprintf(buf + len, maxsz - len, "%-20s  unknown type\r\n",
                        spell_info[i].name);
      if (len + nlen >= maxsz || nlen < 0)
        break;
      len += nlen;
    }
  }

  return len;
}

void list_skills(struct char_data *ch)
{
  const char *overflow = "\r\n**OVERFLOW**\r\n";
  size_t len = 0;
  char buf2[MAX_STRING_LENGTH];

  len = snprintf(buf2, sizeof(buf2), "You have %d practice session%s remaining.\r\n", GET_PRACTICES(ch, GET_CLASS(ch)), GET_PRACTICES(ch, GET_CLASS(ch)) == 1 ? "" : "s");

  len += snprintf(buf2 + len, sizeof(buf2) - len, "\r\nYou know the following skills:\r\n");

  len += print_skills_by_type(ch, buf2 + len, sizeof(buf2) - len, SKTYPE_SKILL);

  if (CONFIG_ENABLE_LANGUAGES) {
    len += snprintf(buf2 + len, sizeof(buf2) - len, "\r\nand the following languages:\r\n");
    len += print_skills_by_type(ch, buf2 + len, sizeof(buf2) - len, SKTYPE_SKILL | SKTYPE_LANG);
  }

  if (len >= sizeof(buf2))
    strcpy(buf2 + sizeof(buf2) - strlen(overflow) - 1, overflow); /* strcpy: OK */

  page_string(ch->desc, buf2, TRUE);
}


int is_guild_open(struct char_data *keeper, int guild_nr, int msg)
{
  char buf[200];
  *buf = 0;

  if (GM_OPEN(guild_nr) > time_info.hours &&
    GM_CLOSE(guild_nr) < time_info.hours)
  strlcpy(buf, MSG_TRAINER_NOT_OPEN, sizeof(buf));

  if (!*buf)
    return (TRUE);
  if (msg)
    do_say(keeper, buf, cmd_tell, 0);

  return (FALSE);
}


int is_guild_ok_char(struct char_data * keeper, struct char_data * ch, int guild_nr)
{
	char buf[200];

	if (!(CAN_SEE(keeper, ch))) {
		do_say(keeper, MSG_TRAINER_NO_SEE_CH, cmd_say, 0);
		return (FALSE);
	}

	
	if (GET_LEVEL(ch) < GM_MINLVL(guild_nr)) {
				snprintf(buf, sizeof(buf), "%s %s", 
					GET_NAME(ch), MSG_TRAINER_MINLVL);
		do_tell(keeper, buf, cmd_tell, 0); 
		return (FALSE);
	}


	if ((IS_GOOD(ch) && NOTRAIN_GOOD(guild_nr)) ||
		 (IS_EVIL(ch) && NOTRAIN_EVIL(guild_nr)) ||
		 (IS_NEUTRAL(ch) && NOTRAIN_NEUTRAL(guild_nr))) {
		snprintf(buf, sizeof(buf), "%s %s", 
					GET_NAME(ch), MSG_TRAINER_DISLIKE_ALIGN);
		do_tell(keeper, buf, cmd_tell, 0);
		return (FALSE);
	}

	if (IS_NPC(ch))
		return (FALSE);

	if ((IS_WIZARD(ch) && NOTRAIN_WIZARD(guild_nr)) ||
		(IS_CLERIC(ch) && NOTRAIN_CLERIC(guild_nr)) ||
		(IS_ROGUE(ch) && NOTRAIN_ROGUE(guild_nr)) ||
		(IS_FIGHTER(ch) && NOTRAIN_FIGHTER(guild_nr))) {
		snprintf(buf, sizeof(buf), "%s %s", 
					GET_NAME(ch), MSG_TRAINER_DISLIKE_CLASS);
		do_tell(keeper, buf, cmd_tell, 0);
		return (FALSE);
	}

	if ((!IS_WIZARD(ch) && TRAIN_WIZARD(guild_nr)) ||
	    (!IS_CLERIC(ch) && TRAIN_CLERIC(guild_nr)) ||
	    (!IS_ROGUE(ch) && TRAIN_ROGUE(guild_nr)) ||
	    (!IS_MONK(ch) && TRAIN_MONK(guild_nr)) ||
	    (!IS_PALADIN(ch) && TRAIN_PALADIN(guild_nr)) ||
	    (!IS_FIGHTER(ch) && TRAIN_FIGHTER(guild_nr))) {
		snprintf(buf, sizeof(buf), "%s %s", 
					GET_NAME(ch), MSG_TRAINER_DISLIKE_CLASS);
		do_tell(keeper, buf, cmd_tell, 0);
		return (FALSE);
	}

	if ((IS_HUMAN(ch) && NOTRAIN_HUMAN(guild_nr)) ||
		 (IS_ELF(ch)   && NOTRAIN_ELF(guild_nr)) ||
		 (IS_GNOME(ch) && NOTRAIN_GNOME(guild_nr)) ||
		 (IS_DWARF(ch) && NOTRAIN_DWARF(guild_nr)) ||
		 (IS_HALF_ELF(ch) && NOTRAIN_HALF_ELF(guild_nr)) ||
		 (IS_HALFLING(ch) && NOTRAIN_HALFLING(guild_nr)) ||
		 (IS_DROW_ELF(ch) && NOTRAIN_DROW_ELF(guild_nr)) ||
 		 (IS_ANIMAL(ch) && NOTRAIN_ANIMAL(guild_nr)) ||
		 (IS_CONSTRUCT(ch) && NOTRAIN_CONSTRUCT(guild_nr)) ||
		 (IS_DEMON(ch) && NOTRAIN_DEMON(guild_nr)) ||
 		 (IS_DRAGON(ch) && NOTRAIN_DRAGON(guild_nr)) ||
 		 (IS_FISH(ch) && NOTRAIN_FISH(guild_nr)) ||
 		 (IS_GIANT(ch) && NOTRAIN_GIANT(guild_nr)) ||
 		 (IS_GOBLIN(ch) && NOTRAIN_GOBLIN(guild_nr)) ||
 		 (IS_INSECT(ch) && NOTRAIN_INSECT(guild_nr)) ||
 		 (IS_ORC(ch) && NOTRAIN_ORC(guild_nr)) ||
 		 (IS_SNAKE(ch) && NOTRAIN_SNAKE(guild_nr)) ||
		 (IS_TROLL(ch) && NOTRAIN_TROLL(guild_nr)) ||
 		 (IS_HALF_ORC(ch) && NOTRAIN_HALF_ORC(guild_nr)) ||
 		 (IS_MINOTAUR(ch) && NOTRAIN_MINOTAUR(guild_nr)) ||
 		 (IS_KOBOLD(ch) && NOTRAIN_KOBOLD(guild_nr)) ||
		 (IS_MINDFLAYER(ch) && NOTRAIN_MINDFLAYER(guild_nr))) {
		snprintf(buf, sizeof(buf), "%s %s", 
					GET_NAME(ch), MSG_TRAINER_DISLIKE_RACE);
		do_tell(keeper, buf, cmd_tell, 0);
		return (FALSE);
	}
	return (TRUE);
}


int is_guild_ok(struct char_data * keeper, struct char_data * ch, int guild_nr)
{
	if (is_guild_open(keeper, guild_nr, TRUE))
		return (is_guild_ok_char(keeper, ch, guild_nr));

	return (FALSE);
}


int does_guild_know(int guild_nr, int i)
{
  return ((int)(guild_index[guild_nr].skills[i]));
}


void sort_spells(void)
{
  int a;

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

  qsort(&spell_sort_info[1], SKILL_TABLE_SIZE, sizeof(int), compare_spells);
}


/* this and list skills should probally be combined.  perhaps in the
 * next release?  */
void what_does_guild_know(int guild_nr, struct char_data * ch)
{
  const char *overflow = "\r\n**OVERFLOW**\r\n";
  char buf2[MAX_STRING_LENGTH];
  int i, sortpos, canknow, j;
  size_t nlen = 0, len = 0;

  len = snprintf(buf2, sizeof(buf2), "You have %d practice session%s remaining.\r\n", GET_PRACTICES(ch, GET_CLASS(ch)), GET_PRACTICES(ch, GET_CLASS(ch)) == 1 ? "" : "s"); // ???

  nlen = snprintf(buf2 + len, sizeof(buf2) - len, "I can teach you the following skills:\r\n");
  len += nlen;
  
  /* Need to check if trainer can train doesnt do it now ??? */
  for (sortpos = 0; sortpos < SKILL_TABLE_SIZE; sortpos++) {
    i = sortpos; /* spell_sort_info[sortpos]; */
    if (does_guild_know(guild_nr, i) && skill_type(i) == SKTYPE_SKILL) {
      //if (GET_LEVEL(ch) >= spell_info[i].min_level[(int)GET_CLASS(ch)]) {
        for (canknow = 0, j = 0; j < NUM_CLASSES; j++) 
	  if (spell_info[i].can_learn_skill[j] > canknow)
	    canknow = spell_info[i].can_learn_skill[j];
        canknow = highest_skill_value(GET_LEVEL(ch), canknow);
        if (GET_SKILL_BASE(ch, i) < canknow) {
          nlen = snprintf(buf2 + len, sizeof(buf2) - len, "@g%-20s %d@n\r\n", spell_info[i].name, GET_SKILL_BASE(ch, i));
          if (len + nlen >= sizeof(buf2) || nlen < 0)
            break;
          len += nlen;
        } else {
          nlen = snprintf(buf2 + len, sizeof(buf2) - len, "@r%-20s %d@n\r\n", spell_info[i].name, GET_SKILL_BASE(ch, i));
          if (len + nlen >= sizeof(buf2) || nlen < 0)
            break;
          len += nlen;
        }
      //}
    }
  }

  if (CONFIG_ENABLE_LANGUAGES) {
  len += snprintf(buf2 + len, sizeof(buf2) - len, "\r\nand the following languages:\r\n");

  for (sortpos = 0; sortpos < SKILL_TABLE_SIZE; sortpos++) {
    i = sortpos; /* spell_sort_info[sortpos]; */
    if (does_guild_know(guild_nr, i) && IS_SET(skill_type(i), SKTYPE_LANG)) {
      //if (GET_LEVEL(ch) >= spell_info[i].min_level[(int) GET_CLASS(ch)]) {
        for (canknow = 0, j = 0; j < NUM_CLASSES; j++)
	  if (spell_info[i].can_learn_skill[j] > canknow)
	    canknow = spell_info[i].can_learn_skill[j];
        canknow = highest_skill_value(GET_LEVEL(ch), canknow);
        if (GET_SKILL_BASE(ch, i) < canknow) {
          nlen = snprintf(buf2 + len, sizeof(buf2) - len, "%-20s %s\r\n", spell_info[i].name, GET_SKILL_BASE(ch, i) ? "known" : "unknown");
          if (len + nlen >= sizeof(buf2) || nlen < 0)
            break;
          len += nlen;
        }
      //}
    }
  }
  }
  if (len >= sizeof(buf2))
    strcpy(buf2 + sizeof(buf2) - strlen(overflow) - 1, overflow); /* strcpy: OK */

  page_string(ch->desc, buf2, TRUE);
}


void handle_practice(struct char_data *keeper, int guild_nr, struct char_data *ch, char *argument)
{
  int skill_num, learntype, pointcost, highest, i;
  char buf[MAX_STRING_LENGTH];

  skip_spaces(&argument);

  if (!*argument) {
    what_does_guild_know(guild_nr, ch);
    return;
  }

  if (GET_PRACTICES(ch, GET_CLASS(ch)) <= 0) {
    send_to_char(ch, "You do not seem to be able to practice now.\r\n");
    return;
  }

  skill_num = find_skill_num(argument);

  /****  Does the GM know the skill the player wants to learn?  ****/
  if (!(does_guild_know(guild_nr, skill_num))) {
    snprintf(buf, sizeof(buf), guild_index[guild_nr].no_such_skill, GET_NAME(ch));
    do_tell(keeper, buf, cmd_tell, 0);
    return;
  }

  /**** Can the player learn the skill if the GM knows it?  ****/ 
  if (IS_SET(spell_info[skill_num].skilltype, SKTYPE_SKILL)) {
    for (learntype = 0, i = 0; i < NUM_CLASSES; i++)
      if (spell_info[skill_num].can_learn_skill[i] > learntype)
        learntype = spell_info[skill_num].can_learn_skill[i];
    switch (learntype) {
    case SKLEARN_CANT:
      send_to_char(ch, "You cannot learn that.\r\n");
      return;
    case SKLEARN_CROSSCLASS:
      highest = highest_skill_value(GET_LEVEL(ch), SKLEARN_CROSSCLASS);
      break;
    case SKLEARN_CLASS:
      highest = highest_skill_value(GET_LEVEL(ch), learntype);
      break;
    default:
      log("Unknown SKLEARN type for skill %d in practice", skill_num);
      send_to_char(ch, "You can't learn that.\r\n");
      return;
    }
    if (spell_info[skill_num].can_learn_skill[GET_CLASS(ch)] == SKLEARN_CLASS)
      pointcost = 1;
    else
      pointcost = 2;
    if (GET_PRACTICES(ch, GET_CLASS(ch)) >= pointcost) {
      if (GET_SKILL_BASE(ch, skill_num) >= highest) {
        send_to_char(ch, "You cannot increase that skill again until you progress further.\r\n");
        return;
      } else {
        send_to_char(ch, "You practice for a while...\r\n");
        SET_SKILL(ch, skill_num, GET_SKILL_BASE(ch, skill_num) + 1);
        GET_PRACTICES(ch, GET_CLASS(ch)) -= pointcost;
      }
    } else {
      send_to_char(ch, "You need %d skill point%s to increase your skill.\r\n",
             pointcost, (pointcost == 1) ? "" : "s");
    }
  } else {
    send_to_char(ch, "You can't learn that.\r\n");
  }
}


void handle_train(struct char_data *keeper, int guild_nr, struct char_data *ch, char *argument)
{
  skip_spaces(&argument);
  if (!argument || !*argument)
    send_to_char(ch, "Training sessions remaining: %d\r\n"
                 "Stats: strength constitution dexterity intelligence wisdom charisma\r\n",
                 GET_TRAINS(ch));
  else if (!GET_TRAINS(ch))
    send_to_char(ch, "You have no ability training sessions.\r\n");
  else if (!strncasecmp("strength", argument, strlen(argument))) {
    send_to_char(ch, CONFIG_OK);
    ch->real_abils.str += 1;
    GET_TRAINS(ch) -= 1;
  } else if (!strncasecmp("constitution", argument, strlen(argument))) {
    send_to_char(ch, CONFIG_OK);
    ch->real_abils.con += 1;
    /* Give them retroactive hit points for constitution */
    if (! (ch->real_abils.con % 2))
      GET_MAX_HIT(ch) += GET_LEVEL(ch);
    GET_TRAINS(ch) -= 1;
  } else if (!strncasecmp("dexterity", argument, strlen(argument))) {
    send_to_char(ch, CONFIG_OK);
    ch->real_abils.dex += 1;
    GET_TRAINS(ch) -= 1;
  } else if (!strncasecmp("intelligence", argument, strlen(argument))) {
    send_to_char(ch, CONFIG_OK);
    ch->real_abils.intel += 1;
    /* Give extra skill practice, but only for this level */
    if (! (ch->real_abils.intel % 2))
      GET_PRACTICES(ch, GET_CLASS(ch)) += 1;
    GET_TRAINS(ch) -= 1;
  } else if (!strncasecmp("wisdom", argument, strlen(argument))) {
    send_to_char(ch, CONFIG_OK);
    ch->real_abils.wis += 1;
    GET_TRAINS(ch) -= 1;
  } else if (!strncasecmp("charisma", argument, strlen(argument))) {
    send_to_char(ch, CONFIG_OK);
    ch->real_abils.cha += 1;
    GET_TRAINS(ch) -= 1;
  } else
    send_to_char(ch, "Stats: strength constitution dexterity intelligence wisdom charisma\r\n");
  affect_total(ch);
  return;
}


void handle_gain(struct char_data *keeper, int guild_nr, struct char_data *ch, char *argument)
{
  int whichclass, i;

  skip_spaces(&argument);
  if (CONFIG_ALLOW_MULTICLASS) {
    if (!*argument) {
      send_to_char(ch, "You must specify a class you want to train.\r\n"
                   "You are eligible for these classes:\r\n");
      for (i = 0; i < NUM_CLASSES; i++) {
        if (class_ok_general(ch, i))
          send_to_char(ch, "  %s\r\n", pc_class_types[i]);
      }
      return;
    }
    if ((whichclass = search_block(argument, class_names, FALSE)) < 0) {
      send_to_char(ch, "That is not a class.\r\n");
      return;
    }
  } else {
    whichclass = GET_CLASS(ch);
  }
  if (! class_ok_general(ch, whichclass)) {
    send_to_char(ch, "You cannot progress in that class.\r\n");
    return;
  }
  if (GET_LEVEL(ch) < CONFIG_LEVEL_CAP - 1 &&
	GET_EXP(ch) >= level_exp(GET_LEVEL(ch) + 1)) {
    gain_level(ch, whichclass);
  } else {
    send_to_char(ch, "You are not yet ready for further advancement.\r\n");
  }
  return;
}

void handle_learn(struct char_data *keeper, int guild_nr, struct char_data *ch, char *argument)
{
  int feat_num, subval, sftype, subfeat;
  char *ptr, buf[MAX_STRING_LENGTH];

  if (!*argument) {
    send_to_char(ch, "Which feat would you like to learn?\r\n");
    return;
  }

  if (GET_FEAT_POINTS(ch) < 1) {
    send_to_char(ch, "You can't learn any new feats right now.\r\n");
    return;
  }

  ptr = strchr(argument, ':');
  if (ptr)
    *ptr = 0;
  feat_num = find_feat_num(argument);
  if (ptr)
    *ptr = ':';

  if (HAS_FEAT(ch, feat_num) && !feat_list[feat_num].can_stack) {
    send_to_char(ch, "You already know the %s feat.\r\n", feat_list[feat_num].name);
    return;
  }

  if (!feat_is_available(ch, feat_num, 0, NULL) || !feat_list[feat_num].in_game || !feat_list[feat_num].can_learn) {
    send_to_char(ch, "The %s feat is not available to you at this time.\r\n", argument);
    return;
  }

  sftype = 2;
  switch (feat_num) {
  case FEAT_GREATER_WEAPON_SPECIALIZATION:
  case FEAT_GREATER_WEAPON_FOCUS:
  case FEAT_WEAPON_SPECIALIZATION:
  case FEAT_WEAPON_FOCUS:
  case FEAT_WEAPON_FINESSE:
  case FEAT_IMPROVED_CRITICAL:
    sftype = 1;
  case FEAT_SPELL_FOCUS:
  case FEAT_GREATER_SPELL_FOCUS:
    subfeat = feat_to_subfeat(feat_num);
    if (subfeat == -1) {
      log("guild: Unconfigured subfeat '%s', check feat_to_subfeat()", feat_list[feat_num].name);
      send_to_char(ch, "That feat is not yet ready for use.\r\n");
      return;
    }
    if (!ptr || !*ptr) {
      if (sftype == 2)
        ptr = "spell school";
      else
        ptr = "weapon type";
      subfeat = snprintf(buf, sizeof(buf),
                         "No ':' found. You must specify a %s to improve. Example:\r\n"
                         " learn %s: %s\r\nAvailable %s:\r\n", ptr,
                         feat_list[feat_num].name,
                         (sftype == 2) ? spell_schools[0] : weapon_type[0], ptr);
      for (subval = 1; subval <= (sftype == 2 ? NUM_SCHOOLS : MAX_WEAPON_TYPES); subval++) {
        if (sftype == 2)
          ptr = (char *)spell_schools[subval];
        else
          ptr = (char *)weapon_type[subval];
        subfeat += snprintf(buf + subfeat, sizeof(buf) - subfeat, "  %s\r\n", ptr);
      }
      page_string(ch->desc, buf, TRUE);
      return;
    }
    if (*ptr == ':') ptr++;
    skip_spaces(&ptr);
    if (!ptr || !*ptr) {
      if (sftype == 2)
        ptr = "spell school";
      else
        ptr = "weapon type";
      subfeat = snprintf(buf, sizeof(buf),
                         "No %s found. You must specify a %s to improve.\r\n\r\nExample:\r\n"
                         " learn %s: %s\r\n\r\nAvailable %s:\r\n", ptr, ptr,
                         feat_list[feat_num].name,
                         (sftype == 2) ? spell_schools[0] : weapon_type[0], ptr);
      for (subval = 1; subval <= (sftype == 2 ? NUM_SCHOOLS : MAX_WEAPON_TYPES); subval++) {
        if (sftype == 2)
          ptr = (char *)spell_schools[subval];
        else
          ptr = (char *)weapon_type[subval];
        subfeat += snprintf(buf + subfeat, sizeof(buf) - subfeat, "  %s\r\n", ptr);
      }
      page_string(ch->desc, buf, TRUE);
      return;
    }
    subval = search_block(ptr, (sftype == 2) ? spell_schools : weapon_type, FALSE);
    if (subval == -1) {
      log("bad subval: %s", ptr);
      if (sftype == 2)
        ptr = "spell school";
      else
        ptr = "weapon type";
      subfeat = snprintf(buf, sizeof(buf),
                         "That is not a known %s. Available %s:\r\n",
                         ptr, ptr);
      for (subval = 1; subval <= (sftype == 2 ? NUM_SCHOOLS : MAX_WEAPON_TYPES); subval++) {
        if (sftype == 2)
          ptr = (char *)spell_schools[subval];
        else
          ptr = (char *)weapon_type[subval];
        subfeat += snprintf(buf + subfeat, sizeof(buf) - subfeat, "  %s\r\n", ptr);
      }
      page_string(ch->desc, buf, TRUE);
      return;
    }
    if (!feat_is_available(ch, feat_num, subval, NULL)) {
      send_to_char(ch, "You do not satisfy the prerequisites for that feat.\r\n");
      return;
    }
    if (sftype == 1) {
      if (HAS_COMBAT_FEAT(ch, subfeat, subval)) {
        send_to_char(ch, "You already have that weapon feat.\r\n");
        return;
      }
      SET_COMBAT_FEAT(ch, subfeat, subval);
    } else if (sftype == 2) {
      if (HAS_SCHOOL_FEAT(ch, subfeat, subval)) {
        send_to_char(ch, "You already have that spell school feat.\r\n");
        return;
      }
      SET_SCHOOL_FEAT(ch, subfeat, subval);
    } else {
      log("unknown feat subtype %d in subfeat code", sftype);
      send_to_char(ch, "That feat is not yet ready for use.\r\n");
      return;
    }
    SET_FEAT(ch, feat_num, HAS_FEAT(ch, feat_num) + 1);
    break;
  case FEAT_GREAT_FORTITUDE:
    SET_FEAT(ch, feat_num, 1);
    GET_SAVE_MOD(ch, SAVING_FORTITUDE) += 2;
    break;
  case FEAT_IRON_WILL:
    SET_FEAT(ch, feat_num, 1);
    GET_SAVE_MOD(ch, SAVING_WILL) += 2;
    break;
  case FEAT_LIGHTNING_REFLEXES:
    SET_FEAT(ch, feat_num, 1);
    GET_SAVE_MOD(ch, SAVING_REFLEX) += 2;
    break;
  case FEAT_TOUGHNESS:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    GET_MAX_HIT(ch) += 3;
    break;
  case FEAT_SKILL_FOCUS:
    if (!ptr || !*ptr) {
      send_to_char(ch, "You must specify a skill to improve. Syntax:\r\n  learn skill focus: skill\r\n");
      return;
    }
    if (*ptr == ':') ptr++;
    skip_spaces(&ptr);
    if (!ptr || !*ptr) {
      send_to_char(ch, "You must specify a skill to improve. Syntax:\r\n  learn skill focus: skill\r\n");
      return;
    }
    subval = find_skill_num(ptr);
    if (subval < 0) {
      send_to_char(ch, "I don't recognize that skill.\r\n");
      return;
    }
    SET_SKILL_BONUS(ch, subval, GET_SKILL_BONUS(ch, subval) + 3);
    SET_FEAT(ch, feat_num, HAS_FEAT(ch, feat_num) + 1);
    break;
  case FEAT_SPELL_MASTERY:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    GET_SPELL_MASTERY_POINTS(ch) += MAX(1, ability_mod_value(GET_INT(ch)));
    break;
  case FEAT_ACROBATIC:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_JUMP, GET_SKILL_BONUS(ch, SKILL_JUMP) + 2);
    SET_SKILL_BONUS(ch, SKILL_TUMBLE, GET_SKILL_BONUS(ch, SKILL_TUMBLE) + 2);
    break;
  case FEAT_AGILE:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_BALANCE, GET_SKILL_BONUS(ch, SKILL_BALANCE) + 2);
    SET_SKILL_BONUS(ch, SKILL_ESCAPE_ARTIST, GET_SKILL_BONUS(ch, SKILL_ESCAPE_ARTIST) + 2);
    break;
  case FEAT_ALERTNESS:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_LISTEN, GET_SKILL_BONUS(ch, SKILL_LISTEN) + 2);
    SET_SKILL_BONUS(ch, SKILL_SPOT, GET_SKILL_BONUS(ch, SKILL_SPOT) + 2);
    break;
  case FEAT_ANIMAL_AFFINITY:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_HANDLE_ANIMAL, GET_SKILL_BONUS(ch, SKILL_HANDLE_ANIMAL) + 2);
    SET_SKILL_BONUS(ch, SKILL_RIDE, GET_SKILL_BONUS(ch, SKILL_RIDE) + 2);
    break;
  case FEAT_ATHLETIC:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_CLIMB, GET_SKILL_BONUS(ch, SKILL_CLIMB) + 2);
    SET_SKILL_BONUS(ch, SKILL_SWIM, GET_SKILL_BONUS(ch, SKILL_SWIM) + 2);
    break;
  case FEAT_DECEITFUL:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_DISGUISE, GET_SKILL_BONUS(ch, SKILL_DISGUISE) + 2);
    SET_SKILL_BONUS(ch, SKILL_FORGERY, GET_SKILL_BONUS(ch, SKILL_FORGERY) + 2);
    break;
  case FEAT_DEFT_HANDS:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_SLEIGHT_OF_HAND, GET_SKILL_BONUS(ch, SKILL_SLEIGHT_OF_HAND) + 2);
    SET_SKILL_BONUS(ch, SKILL_USE_ROPE, GET_SKILL_BONUS(ch, SKILL_USE_ROPE) + 2);
    break;
  case FEAT_DILIGENT:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_APPRAISE, GET_SKILL_BONUS(ch, SKILL_APPRAISE) + 2);
    SET_SKILL_BONUS(ch, SKILL_DECIPHER_SCRIPT, GET_SKILL_BONUS(ch, SKILL_DECIPHER_SCRIPT) + 2);
    break;
  case FEAT_INVESTIGATOR:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_GATHER_INFORMATION, GET_SKILL_BONUS(ch, SKILL_GATHER_INFORMATION) + 2);
    SET_SKILL_BONUS(ch, SKILL_SEARCH, GET_SKILL_BONUS(ch, SKILL_SEARCH) + 2);
    break;
  case FEAT_MAGICAL_APTITUDE:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_SPELLCRAFT, GET_SKILL_BONUS(ch, SKILL_SPELLCRAFT) + 2);
    SET_SKILL_BONUS(ch, SKILL_USE_MAGIC_DEVICE, GET_SKILL_BONUS(ch, SKILL_USE_MAGIC_DEVICE) + 2);
    break;
  case FEAT_NEGOTIATOR:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_DIPLOMACY, GET_SKILL_BONUS(ch, SKILL_DIPLOMACY) + 2);
    SET_SKILL_BONUS(ch, SKILL_SENSE_MOTIVE, GET_SKILL_BONUS(ch, SKILL_SENSE_MOTIVE) + 2);
    break;
  case FEAT_NIMBLE_FINGERS:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_DISABLE_DEVICE, GET_SKILL_BONUS(ch, SKILL_DISABLE_DEVICE) + 2);
    SET_SKILL_BONUS(ch, SKILL_OPEN_LOCK, GET_SKILL_BONUS(ch, SKILL_OPEN_LOCK) + 2);
    break;
  case FEAT_PERSUASIVE:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_BLUFF, GET_SKILL_BONUS(ch, SKILL_BLUFF) + 2);
    SET_SKILL_BONUS(ch, SKILL_INTIMIDATE, GET_SKILL_BONUS(ch, SKILL_INTIMIDATE) + 2);
    break;
  case FEAT_SELF_SUFFICIENT:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_HEAL, GET_SKILL_BONUS(ch, SKILL_HEAL) + 2);
    SET_SKILL_BONUS(ch, SKILL_SURVIVAL, GET_SKILL_BONUS(ch, SKILL_SURVIVAL) + 2);
    break;
  case FEAT_STEALTHY:
    subval = HAS_FEAT(ch, feat_num) + 1;
    SET_FEAT(ch, feat_num, subval);
    SET_SKILL_BONUS(ch, SKILL_HIDE, GET_SKILL_BONUS(ch, SKILL_HIDE) + 2);
    SET_SKILL_BONUS(ch, SKILL_MOVE_SILENTLY, GET_SKILL_BONUS(ch, SKILL_MOVE_SILENTLY) + 2);
    break;
  default:
    SET_FEAT(ch, feat_num, TRUE);
    break;
  }
  save_char(ch);

  GET_FEAT_POINTS(ch)--;
  send_to_char(ch, "Your training has given you the %s feat!\r\n", feat_list[feat_num].name);

  return;
}


SPECIAL(guild)
{
  char arg[MAX_INPUT_LENGTH];
  int guild_nr, i;
  struct char_data *keeper = (struct char_data *) me;
  struct {
    const char *cmd;
    void (*func)(struct char_data *, int, struct char_data *, char *);
  } guild_cmd_tab[] = {
    { "practice",	handle_practice },
    { "gain",		handle_gain },
    { "train",		handle_train },
    { "learn",		handle_learn },
    { NULL,		NULL }
  };

  for (guild_nr = 0; guild_nr <= top_guild; guild_nr++)
    if (GM_TRAINER(guild_nr) == keeper->nr)
      break;

  if (guild_nr > top_guild)
    return (FALSE);

  if (GM_FUNC(guild_nr))
    if ((GM_FUNC(guild_nr)) (ch, me, cmd, arg))
      return (TRUE);

  /*** Is the GM able to train?    ****/
  if (!AWAKE(keeper))
    return (FALSE);

  for (i = 0; guild_cmd_tab[i].cmd; i++)
    if (CMD_IS(guild_cmd_tab[i].cmd))
      break;

  if (!guild_cmd_tab[i].cmd)
    return (FALSE);

  if (!(is_guild_ok(keeper, ch, guild_nr)))
    return (TRUE);

  (guild_cmd_tab[i].func)(keeper, guild_nr, ch, argument);

  return (TRUE);
}


/**** This function is here just because I'm extremely paranoid.  Take
      it out if you aren't ;)  ****/
void clear_skills(int index)
{
  int i;

  for  (i = 0; i < SKILL_TABLE_SIZE; i++) 
    guild_index[index].skills[i] = 0;
}


/****  This is ripped off of read_line from shop.c.  They could be
 *  combined. But why? ****/

void read_guild_line(FILE * gm_f, char *string, void *data, char *type)
{
	char buf[MAX_STRING_LENGTH];
	
	if (!get_line(gm_f, buf) || !sscanf(buf, string, data)) {
		fprintf(stderr, "Error in guild #%d, Could not get %s\n", GM_NUM(top_guild), type);
		exit(1);
	}
}


void boot_the_guilds(FILE * gm_f, char *filename, int rec_count)
{
  char *buf, buf2[256], *p;
  int temp, val;
  int done = FALSE;

  snprintf(buf2, sizeof(buf2), "beginning of GM file %s", filename);

  buf = fread_string(gm_f, buf2);
  while (!done) {
    if (*buf == '#') {		/* New Trainer */
      sscanf(buf, "#%d\n", &temp);
      snprintf(buf2, sizeof(buf2), "GM #%d in GM file %s", temp, filename);
      free(buf);		/* Plug memory leak! */
      top_guild++;
      if (!top_guild)
	CREATE(guild_index, struct guild_data, rec_count);
      GM_NUM(top_guild) = temp;

      clear_skills(top_guild);    
      read_guild_line(gm_f, "%d", &temp, "TEMP1");
      while( temp > -1) {
	guild_index[top_guild].skills[(int)temp] = 1;
	read_guild_line(gm_f, "%d", &temp, "TEMP2");
      }
                   
      read_guild_line(gm_f, "%f", &GM_CHARGE(top_guild), "GM_CHARGE");

      guild_index[top_guild].no_such_skill = fread_string(gm_f, buf2);
      guild_index[top_guild].not_enough_gold = fread_string(gm_f, buf2);

      read_guild_line(gm_f, "%d", &GM_MINLVL(top_guild), "GM_MINLVL");
      read_guild_line(gm_f, "%d", &GM_TRAINER(top_guild), "GM_TRAINER");

      GM_TRAINER(top_guild) = real_mobile(GM_TRAINER(top_guild));
      read_guild_line(gm_f, "%d", &GM_WITH_WHO(top_guild)[0], "GM_WITH_WHO");

      read_guild_line(gm_f, "%d", &GM_OPEN(top_guild), "GM_OPEN");
      read_guild_line(gm_f, "%d", &GM_CLOSE(top_guild), "GM_CLOSE");

      GM_FUNC(top_guild) = NULL;
      CREATE(buf, char, READ_SIZE);
      get_line(gm_f, buf);
      if (buf && *buf != '#' && *buf != '$') {
	p = buf;
	for (temp = 1; temp < SW_ARRAY_MAX; temp++) {
	  if (!p || !*p)
	    break;
	  if (sscanf(p, "%d", &val) != 1) {
	    log("SYSERR: Can't parse GM_WITH_WHO line in %s: '%s'", buf2, buf);
	    break;
	  }
	  GM_WITH_WHO(top_guild)[temp] = val;
	  while (isdigit(*p) || *p == '-') {
	    p++;
	  }
	  while (*p && !(isdigit(*p) || *p == '-')) {
	    p++;
	  }
	}
	while (temp < SW_ARRAY_MAX)
	  GM_WITH_WHO(top_guild)[temp++] = 0;
	free(buf);
	buf = fread_string(gm_f, buf2);
      }
    } else {
      if (*buf == '$')		/* EOF */
	done = TRUE;
      free(buf);		/* Plug memory leak! */
    }
  }
}


void assign_the_guilds(void)
{
	int index;

	cmd_say = find_command("say");
	cmd_tell = find_command("tell");

	for (index = 0; index <= top_guild; index++) {
		if (GM_TRAINER(index) == NOBODY)
			continue;
		if (mob_index[GM_TRAINER(index)].func)
			GM_FUNC(index) = mob_index[GM_TRAINER(index)].func;
		mob_index[GM_TRAINER(index)].func = guild;
	}
}

char *guild_customer_string(int guild_nr, int detailed)
{
  int gindex = 0, flag = 0, nlen;
  size_t len = 0;
  static char buf[MAX_STRING_LENGTH];

  while (*trade_letters[gindex] != '\n' && len + 1 < sizeof(buf)) {
    if (detailed) {
      if (!IS_SET_AR(GM_WITH_WHO(guild_nr), flag)) {
	nlen = snprintf(buf + len, sizeof(buf) - len, ", %s", trade_letters[gindex]);

        if (len + nlen >= sizeof(buf) || nlen < 0)
          break;

        len += nlen;
      }
    } else {
      buf[len++] = (IS_SET_AR(GM_WITH_WHO(guild_nr), flag) ? '_' : *trade_letters[gindex]);
      buf[len] = '\0';

      if (len >= sizeof(buf))
        break;
    }

    gindex++;
    flag += 1;
  }

  buf[sizeof(buf) - 1] = '\0';
  return (buf);
}

void list_all_guilds(struct char_data *ch)
{
  const char *list_all_guilds_header =
  "Virtual   G.Master	Charge   Members\r\n"
  "-------------------------------------------------------------\r\n";
  int gm_nr, headerlen = strlen(list_all_guilds_header);
  size_t len = 0;
  char buf[MAX_STRING_LENGTH], buf1[16];

  *buf = '\0';
  for (gm_nr = 0; gm_nr <= top_guild && len < sizeof(buf); gm_nr++) {
  /* New page in page_string() mechanism, print the header again. */
    if (!(gm_nr % (PAGE_LENGTH - 2))) {
    /*
     * If we don't have enough room for the header, or all we have room left
     * for is the header, then don't add it and just quit now.
     */
    if (len + headerlen + 1 >= sizeof(buf))
      break;
    strcpy(buf + len, list_all_guilds_header);	/* strcpy: OK (length checked above) */
    len += headerlen;
    }

    if (GM_TRAINER(gm_nr) == NOBODY)
      strcpy(buf1, "<NONE>");  /* strcpy: OK (for 'buf1 >= 7') */
    else
      sprintf(buf1, "%6d", mob_index[GM_TRAINER(gm_nr)].vnum);  /* sprintf: OK (for 'buf1 >= 11', 32-bit int) */	

    len += snprintf(buf + len, sizeof(buf) - len, "%6d	%s		%5.2f	%s\r\n",
      GM_NUM(gm_nr), buf1, GM_CHARGE(gm_nr), guild_customer_string(gm_nr, FALSE));
  }

  page_string(ch->desc, buf, TRUE);
}


void list_detailed_guild(struct char_data * ch, int gm_nr)
{
  int i;
  char buf[MAX_STRING_LENGTH];
  char buf1[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];

  if (GM_TRAINER(gm_nr) < 0)
    strcpy(buf1, "<NONE>");
  else
    sprintf(buf1, "%6d   ", mob_index[GM_TRAINER(gm_nr)].vnum);

  sprintf(buf, " Guild Master: %s\r\n", buf1);
  sprintf(buf, "%s Hours: %4d to %4d,  Surcharge: %5.2f\r\n", buf,
			  GM_OPEN(gm_nr), GM_CLOSE(gm_nr), GM_CHARGE(gm_nr));
  sprintf(buf, "%s Min Level will train: %d\r\n", buf, GM_MINLVL(gm_nr));
  sprintf(buf, "%s Whom will train: %s\r\n", buf, guild_customer_string(gm_nr, TRUE));

   /* now for the REAL reason why someone would want to see a Guild :) */

  sprintf(buf, "%s The GM can teach the following:\r\n", buf);

  *buf2 = '\0';
  for (i = 0; i < SKILL_TABLE_SIZE; i++) {
    if (does_guild_know(gm_nr, i))
      sprintf(buf2, "%s %s \r\n", buf2, spell_info[i].name);
  }
 
  strcat(buf, buf2);

  page_string(ch->desc, buf, 1);
}
  

void show_guild(struct char_data * ch, char *arg)
{
  int gm_nr, gm_num;

  if (!*arg)
    list_all_guilds(ch);
  else {
    if (is_number(arg))
      gm_num = atoi(arg);
    else
      gm_num = -1;

    if (gm_num > 0) {
      for (gm_nr = 0; gm_nr <= top_guild; gm_nr++) {
      if (gm_num == GM_NUM(gm_nr))
        break; 
      }

      if (gm_num < 0 || gm_nr > top_guild) {
        send_to_char(ch, "Illegal guild master number.\n\r");
        return;
      }
      list_detailed_guild(ch, gm_nr);
    }
  }
}

/*
 * List all guilds in a zone.                              
 */                                                                           
void list_guilds(struct char_data *ch, zone_rnum rnum, guild_vnum vmin, guild_vnum vmax)
{
  int i, bottom, top, counter = 0;
  
  if (rnum != NOWHERE) {
    bottom = zone_table[rnum].bot;
    top    = zone_table[rnum].top;
  } else {
    bottom = vmin;
    top    = vmax;
  }
  
  /****************************************************************************/
  /** Store the header for the guild listing.                                **/
  /****************************************************************************/
  send_to_char (ch,
  "Index VNum    Guild Master\r\n"
  "----- ------- ---------------------------------------------\r\n");
  
  for (i = 0; i <= top_guild; i++) {
    if (GM_NUM(i) >= bottom && GM_NUM(i) <= top) {
      counter++;
      
      send_to_char(ch, "@g%4d@n) [@c%-5d@n]", counter, GM_NUM(i));

      /************************************************************************/
      /** Retrieve the list of rooms for this guild.                         **/
      /************************************************************************/

		send_to_char(ch, " @c[@y%d@c]@y %s@n", 
			(GM_TRAINER(i) == -1) ?
			  -1 : mob_index[GM_TRAINER(i)].vnum,
			(GM_TRAINER(i) == -1) ?
			  "" : mob_proto[GM_TRAINER(i)].short_descr); 
      
      send_to_char(ch, "\r\n");
    }
  }
  
  if (counter == 0)
    send_to_char(ch, "None found.\r\n");
}

void destroy_guilds(void)
{
  ssize_t cnt/*, itr*/;

  if (!guild_index)
    return;

  for (cnt = 0; cnt <= top_guild; cnt++) {
    if (guild_index[cnt].no_such_skill)
      free(guild_index[cnt].no_such_skill);
    if (guild_index[cnt].not_enough_gold)
      free(guild_index[cnt].not_enough_gold);

    /*if (guild_index[cnt].type) {
      for (itr = 0; BUY_TYPE(guild_index[cnt].type[itr]) != NOTHING; itr++)
        if (BUY_WORD(guild_index[cnt].type[itr]))
          free(BUY_WORD(guild_index[cnt].type[itr]));
      free(shop_index[cnt].type);
    } */
  }

  free(guild_index);
  guild_index = NULL;
  top_guild = -1;
}


int count_guilds(guild_vnum low, guild_vnum high)
{
  int i, j;
  
  for (i = j = 0; GM_NUM(i) <= high; i++)
    if (GM_NUM(i) >= low)
      j++;
 
  return j;
}


void levelup_parse(struct descriptor_data *d, char *arg)
{
}