FlCodebase3.1/
FlCodebase3.1/bounty/
FlCodebase3.1/challenge/
FlCodebase3.1/clans/
FlCodebase3.1/gods/
FlCodebase3.1/mobprogs/
FlCodebase3.1/player/
FlCodebase3.1/savemud/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  * 
 *                                                                         *
 *      ROM 2.4 is copyright 1993-1998 Russ Taylor                         *
 *      ROM has been brought to you by the ROM consortium                  *
 *          Russ Taylor (rtaylor@hypercube.org)                            *
 *          Gabrielle Taylor (gtaylor@hypercube.org)                       *
 *          Brian Moore (zump@rom.org)                                     *
 *      By using this code, you have agreed to follow the terms of the     *
 *      ROM license, in the file Rom24/doc/rom.license                     *
 *                                                                         *
 * Code Adapted and Improved by Abandoned Realms Mud                       *
 * and Aabahran: The Forsaken Lands Mud by Virigoth                        *
 *                                                                         *
 * Continued Production of this code is available at www.flcodebase.com    *
 ***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <memory.h>
#include "merc.h"
#include "clan.h"

/***************************************************************/
/*Following are army orientanted routines for Forsaken Lands  */
/*mud created by Virigoth circa Apr 2004.  Copyrighted for Forsaken*/
/*Lands mud Apr 04, 2004.  Do not use or copy without explicit */
/*permission of author. (Voytek Plawny aka Virigoth)	       */
/***************************************************************/

/* GLOBALS */
static CLAN_DATA clan_list[MAX_CLANS];

/* PROTOTYPES */
char* ClanFixName( char* name );

/* PRIVATE */
//zero the clan list
void Reset(){
  memset( clan_list, 0, sizeof( CLAN_DATA ) * MAX_CLANS);
}

//convert a clan name to handle, 0 on not found
int ClanNameToHandle( char* name ){
  int clan;

  for ( clan = 0; clan < MAX_CLANS; clan++){
    if (IS_NULLSTR(clan_list[clan].name) || str_cmp(name, clan_list[clan].name))
      continue;
    else
      return ( clan + 1);
  }
  return 0;
}

//convert handle to name, NULL on not found
char* ClanHandleToName( int handle ){
  static char* nul = "";

  if (handle < 1 || handle > MAX_CLANS || IS_NULLSTR(clan_list[handle - 1].name))
    return nul;
  else
    return clan_list[handle - 1].name;
}

//returns clan data based on handle
CLAN_DATA* GetClanData( int handle ){
  if (handle < 1 || handle > MAX_CLANS)
    return NULL;
  return ( &clan_list[handle - 1]);
}

 
int ClanInsertMember( int handle, CLAN_MEMBER* pCmd ){
  CLAN_DATA* pClan = GetClanData( handle );
  CLAN_MEMBER* prev, *new;

  if (pClan == NULL || pCmd == NULL){
    return 0;
  }
  else if ( (new = GetClanMember( handle, pCmd->name)) != NULL){
    return handle;
  }
  /* search for the end of the member list */
  for (prev = &pClan->members; prev->next; prev = prev->next);
  
  /* attach the new member */
  new = alloc_mem( sizeof( *new ));
  

  memset( new, 0, sizeof( *new ));
  new->name		= str_dup( pCmd->name );
  new->class		= pCmd->class;
  new->race		= pCmd->race;
  new->level		= pCmd->level;
  new->rank		= pCmd->rank;
  new->pts		= pCmd->pts;
  new->last_logon	= pCmd->last_logon;
  new->joined		= pCmd->joined;
  new->allowed		= pCmd->allowed;

  new->next = NULL;
  prev->next = new;

  
  pClan->max++;
  return handle;
}

//adds a member to a clan
int ClanAddMember( int handle, CHAR_DATA* ch){
  CLAN_MEMBER tmp;

  if (handle < 1 || handle > MAX_CLANS || ch == NULL)
    return 0;

  tmp.name		= ch->name;
  tmp.class		= ch->class;
  tmp.race		= ch->race;
  tmp.level		= ch->race;
  tmp.rank		= 0;
  tmp.last_logon	= ch->logoff;
  tmp.joined		= mud_data.current_time;
  tmp.allowed		= 0;
  tmp.pts		= ch->pcdata->clan_points + mud_data.mudport == TEST_PORT ? 1 : 0;

  return (ClanInsertMember( handle, &tmp ));
}

//removes a given member from a clan
bool ClanRemMember( int handle, char* name ){
  CLAN_DATA* pClan = GetClanData( handle );
  CLAN_MEMBER* prev, *tmp = NULL;

  if (pClan == NULL || IS_NULLSTR( name )){
    return FALSE;
  }

  /* search members untill we find target name */
  for (prev = &pClan->members; prev->next; prev = prev->next){
    if (!str_cmp(prev->next->name, name)){
      tmp = prev->next;
      break;
    }
  }

  if (tmp == NULL){
    bug("clan.c>ClanRemMember: name not found.", 0);
    return FALSE;
  }

  /* unlink the member */
  prev->next = tmp->next;

  /* free strings */
  free_string( tmp->name );

  /* free the member */
  free_mem( tmp, sizeof( *tmp ));

  pClan->max--;
  return TRUE;
}

//adds a clan to the list of clans, returns handle
int ClanAdd( CLAN_DATA* pClan){
  int handle;

  if (pClan == NULL || IS_NULLSTR(pClan->name))
    return 0;
  else if ( (handle = ClanNameToHandle( pClan->name )) > 0){
    return (handle);
  }
  else{
    /* try to find an empty spot */
    for (handle = 0; handle < MAX_CLANS; handle++){
      if (IS_NULLSTR(clan_list[handle].name)){
	memcpy(&clan_list[handle], pClan, sizeof( *pClan ));
	clan_list[handle].name	= str_dup( pClan->name );
	return (handle + 1);
      }
    }
    return 0;
  }
}

//removes a clan from the list
bool ClanRem( int handle ){
  CLAN_DATA* pClan = GetClanData( handle );
  char path[MIL];

  if (pClan == NULL){
    bug("clan.c>ClanRem: Could not find clan %d", handle );
    return FALSE;
  }

  /* free members */
  while (pClan->members.next)
    ClanRemMember( handle, pClan->members.next->name );

  /* unlink save file */
  sprintf( path, "%s%s", CLAN_DIR, ClanFixName( pClan->name ) );
  unlink( path );
  /* free strings */
  free_string( pClan->name );
  pClan->name = NULL;
  pClan->max = 0;

  return TRUE;
}

//lists all the clans loaded
void ListClans( CHAR_DATA* ch ){
  int clan;

  for (clan = 0; clan < MAX_CLANS; clan++){
    if (IS_NULLSTR(clan_list[clan].name))
      continue;
    sendf(ch, "%-25.25s (%-3d)\n\r", clan_list[clan].name, clan_list[clan].max );
  }
}

//returns a string with clan data for one member
char* PrintMemberData( CLAN_MEMBER* pCmd, bool fImm ){
  static char out[MIL];

  out[0] = 0;

  /* IMM info */
  if (fImm){
    if (pCmd == NULL){
      sprintf( out, 
	       "Name             Race      Class       Rank     Lvl  Sen Log  Pts    \n\r"\
	       "----------------------------------------------------------------------");
    }
    else{
      sprintf( out, 
	       "%-15.15s %-10.10s %-10.10s %-10.10s  %-2d  %-3ld %-3ld %-3d",
	       pCmd->name,
	       pc_race_table[pCmd->race].name,
	       class_table[pCmd->class].name,
	       clanr_table[pCmd->rank][1],
	       pCmd->level,
	       (mud_data.current_time - pCmd->joined) / 86400,
	       (mud_data.current_time - pCmd->last_logon) / 86400,
	       pCmd->pts);
    }
  }
  /* NORMAL */
  else{
    if (pCmd == NULL){
      sprintf( out, 
	       "Name           Rank     Lvl   Days Ago\n\r"\
	       "----------------------------------------");
    }
    else{
      sprintf( out, 
	       "%-15.15s %-10.10s %-2d     %-3ld",
	       pCmd->name,
	       clanr_table[pCmd->rank][1],
	       pCmd->level,
	       (mud_data.current_time - pCmd->last_logon) / 86400);
      
    }
  }
  return ( out );
}

//lists members of a given clan
//types are: seniority, rank, pts (default)
void ListMembers( CHAR_DATA* ch, int handle, bool fImm, char* type ){
  CLAN_DATA* pClan;
  CLAN_MEMBER* pCmd;

  const int max_search	= 128;
  const int max_show	= 16;
  CLAN_MEMBER* members[max_search];
  int max_member = 0, i, j;

  bool fRank = FALSE, fSen = FALSE;

  if ( (pClan = GetClanData( handle )) == NULL)
    return;

  for (pCmd = pClan->members.next; pCmd; pCmd = pCmd->next){
    if ((mud_data.current_time - pCmd->last_logon) > MAX_INACTIVE)
      continue;
    /* Viri: Lets see for now if this pruning is really necessary
       else if (pCmd->rank < RANK_ELDER && pCmd->pts < 1)
      continue;
    */
    if (max_member < max_search)
      members[max_member++] = pCmd;
  }

  if (!str_prefix(type, "rank"))
    fRank = TRUE;
  if (!str_prefix(type, "seniority"))
    fSen = TRUE;
  
  /* sort */
  if (fRank){
    for (i = 0; i < max_member; i++){
      pCmd = members[i];
      for (j = i; j > 0 && members[j - 1]->rank < pCmd->rank; j--){
	members[j] = members[j - 1];
      }
      members[j] = pCmd;
    }
  }
  else if (fSen){
    for (i = 0; i < max_member; i++){
      pCmd = members[i];
      for (j = i; j > 0 && members[j - 1]->joined > pCmd->joined; j--){
	members[j] = members[j - 1];
      }
      members[j] = pCmd;
    }
  }
  else{
    for (i = 0; i < max_member; i++){
      pCmd = members[i];
      for (j = i; j > 0 && members[j - 1]->pts < pCmd->pts; j--){
	members[j] = members[j - 1];
      }
      members[j] = pCmd;
    }
  }

  /* show */
  sendf( ch, "%s\n\r", PrintMemberData( NULL, fImm ) );
  for (i = 0; i < max_member && i < max_show; i++){
    sendf( ch, "%s\n\r", PrintMemberData( members[i], fImm ) );
  }
}

//fixes a clan name to be ok for a filename
char* ClanFixName( char* name ){
  static char out[MIL];
  char* ptr = out;

  *ptr = 0;

  while (*name ){
    switch( *name ){
    default:	
      if (isalpha( *name ))
	*ptr = *name;		
      else
	*ptr = '_';
      break;

    case ' ':	*ptr = '_';		break;
    }
    ptr++;
    name++;
  }
  *ptr = 0;
  return out;
}
      

//writes a single clan's data to file
void fWriteClan( FILE *fp, CLAN_DATA* pClan ){
  CLAN_MEMBER* pCmd;

  //start the file off with the name
  fprintf( fp, "CLAN %s~\n", pClan->name );

  for (pCmd = pClan->members.next; pCmd; pCmd = pCmd->next){
    fprintf( fp, 
	     "MEMBER %s~\n"\
	     "RACE %d CLASS %d LEVEL %d\n"\
	     "RANK %d PTS %d\n"\
	     "JOIN %ld LAST %ld ALLOWED %ld\n"\
	     "MEMBER_END\n",
	     pCmd->name,
	     pCmd->race, pCmd->class, pCmd->level,
	     pCmd->rank, pCmd->pts,
	     pCmd->joined, pCmd->last_logon, pCmd->allowed);
  }
  fprintf( fp, "END\n\n");
}

//reads a single clan's data and loads the clan
void fReadClan( FILE* fp ){
  CLAN_DATA clan;
  CLAN_MEMBER member;
  char* word;
  int handle;
  bool fMatch;

  if ( (word = fread_word( fp )) == NULL){
    bug("clan.c>fReadClan: Error accessing file.\n\r", 0);
    return;
  }
  else if (str_cmp(word, "CLAN")){
    bug("can.c>fReadClan: Expected CLAN not found.", 0);
    return;
  }
  memset( &clan, 0, sizeof( CLAN_DATA ));
  //get name first
  clan.name	= fread_string( fp );
  if ( (handle = ClanAdd( &clan )) < 1){
    bug("clan.c>fReadClan: Could not get a handle for clan.", 0);
    return;
  }

  //reset the name data for use
  memset( &member, 0, sizeof( CLAN_MEMBER ));

  for (;;){
    fMatch = FALSE;

    if (feof( fp) || (word = fread_word( fp )) == NULL)
      word = "END";

    switch( UPPER(word[0])){
    case 'A':
      KEY( "ALLOWED",	member.allowed,		fread_number( fp ));
      break;
    case 'C':
      KEY( "CLASS",	member.class,		fread_number( fp ));
      break;
    case 'E':
      if (!str_cmp(word, "END")){
	fMatch = TRUE;
	return;
      }
      break;
    case 'J':
      KEY( "JOIN",	member.joined,		fread_number( fp ));
      break;
    case 'L':
      KEY( "LEVEL",	member.level,		fread_number( fp ));
      KEY( "LAST",	member.last_logon,		fread_number( fp ));
      break;
    case 'M':
      KEYS( "MEMBER",	member.name,		fread_string( fp ));
      if (!str_cmp(word, "MEMBER_END")){
	if (ClanInsertMember( handle, &member) < 1){
	  nlogf("[*****] BUG: clan.c>fReadClan: Could not insert member %s", member.name);
	  continue;
	}
	fMatch = TRUE;
	break;
      }
      break;
    case 'P':
      KEY( "PTS",	member.pts,		fread_number( fp ));
      break;
    case 'R':
      KEY( "RACE",	member.race,		fread_number( fp ));
      KEY( "RANK",	member.rank,		fread_number( fp ));
      break;
    }
    if (!fMatch){
      nlogf("[*****] BUG: clan.c>fReadClan: Can't match \"%s\"", word);
    }
  }
}
      

  

  

/* INTERFACE */ 
void LoadClans(){
  FILE* fp;
  DIR *directory;		//Directory
  struct dirent *dir_ent;	//Directory entry
  struct stat Stat;		//File statistics
  char path[MIL];		//Current file name

  Reset();

  /* Open dir, get first entry */  
  if ( (directory = opendir(CLAN_DIR)) == NULL){
    bug("clan.c>LoadClans: Could not access CLAN_DIR", 0);
    return;
  }
  else if ( (dir_ent = readdir(directory)) == NULL){
    bug("clan.c>LoadClans: Could not access first directory entry.", 0);
    closedir( directory );
    return;
  }

  fclose( fpReserve );

  while( dir_ent != NULL){
    sprintf( path, "%s%s", CLAN_DIR, dir_ent->d_name );

    if ( -1 == stat( path, &Stat)){
      dir_ent = readdir( directory );
      continue;
    }
    else if(!S_ISREG(Stat.st_mode)){
      dir_ent = readdir( directory );
      continue;
    }
    nlogf("Loading clan %s", dir_ent->d_name );
    if ( (fp = fopen( path, "r")) == NULL){
      perror( path );
      dir_ent = readdir( directory );
      continue;
    }
    fReadClan( fp );
    fclose( fp );
    dir_ent = readdir( directory );
  }
  closedir( directory );

  fpReserve = fopen( NULL_FILE, "r" );
}

//saves a single clan
void ClanSave( int handle ){
  CLAN_DATA* pClan = GetClanData( handle );
  FILE* fp;
  char path[MIL], buf[MIL];

  if (pClan == NULL){
    bug("clan.c>ClanSave: Could not get pointer to clan %d", handle );
    return;
  }

  sprintf( path, "%s%s", CLAN_DIR, CLAN_TMP_FILE );

  if ( (fp = fopen( path, "w")) == NULL){
    perror( path );
    return;
  }
  fWriteClan( fp, pClan );
  fclose( fp );

  sprintf( buf, "%s%s", CLAN_DIR, ClanFixName( pClan->name ));
  rename( path, buf );
}

void SaveClans(){
  int clan;

  fclose( fpReserve );
  for ( clan = 0; clan < MAX_CLANS; clan++){
    if (!IS_NULLSTR(clan_list[clan].name))
      ClanSave( clan + 1 );
  }
  fpReserve = fopen( NULL_FILE, "r" );
}

/* commands:
   clan list			//clan member only
   clan list clans		//imm only
   clan create <clan>		//imm only
   clan delete <clan>		//imp only
   clan draft  <victim>		//clan leader only
   clan draft  <victim> <clan>	//imm/mob only
   clan remove <victim>		//clan leader only
   clan remove <victim> <clan>	//imm/mob only
   clan prom <victim>		//elder only
   clan prom <victim> <clan>	//imm/mob only
   clan demo <victim>		//elder only
   clan demo <victim> <clan>	//imm/mob only
*/
void do_clan( CHAR_DATA* ch, char* argument ){
  int handle;
  char arg1[MIL], arg2[MIL], buf[MIL];
  
  argument = one_argument( argument, arg1 );

  if (IS_NULLSTR(arg1)){
    send_to_char("Common clan commands are: draft, remove, prom, demo.\n\r", ch);
    return;
  }

  /* CREATE */
  if (!str_prefix( arg1, "create")){
    CLAN_DATA clan;

    memset(&clan, 0, sizeof( clan ));

    if (!IS_IMMORTAL(ch)){
      send_to_char("You cannot create clans.\n\r", ch);
      return;
    }
    else if (IS_NULLSTR(argument)){
      send_to_char( "Create what clan?\n\r", ch);
      return;
    }
    
    sprintf( buf, "%s", argument );
    buf[0] = UPPER(buf[0]);
    clan.name = buf;

    if ( (handle = ClanNameToHandle( buf )) > 0){
      send_to_char("That clan already exists.\n\r", ch);
      return;
    }
    else if ( (handle = ClanAdd( &clan )) < 0){
      send_to_char("Error adding clan.\n\r", ch);
      return;
    }
    else
      sendf( ch, "Clan \"%s\" created.\n\r", ClanHandleToName( handle ));
    ClanSave( handle );
    return;
  }
  /* DELETE */
  if (!str_prefix( arg1, "delete")){

    if (get_trust(ch) < CREATOR){
      sendf( ch, "Requires level %d trust\n\r", CREATOR);
      return;
    }
    else if (IS_NULLSTR(argument)){
      send_to_char( "Delete what clan?\n\r", ch);
      return;
    }
    else if ( (handle = ClanNameToHandle( argument )) < 1){
      send_to_char("That clan doesn't exists.\n\r", ch);
      return;
    }
    else if ( !ClanRem( handle ) ){
      send_to_char("Error deleting clan.\n\r", ch);
      return;
    }
    else{
      send_to_char("Removed.\n\r", ch);
    }
    return;
  }
  /* LIST */
  if (!str_prefix( arg1, "list")){
    /* IMMORTAL LIST */
    if (IS_IMMORTAL(ch)){
      if (IS_NULLSTR(argument)){
	if (GET_CLAN(ch) < 1){
	  send_to_char( "List which clan?\n\r", ch);
	  return;
	}
	else
	  handle = GET_CLAN(ch);
      }
      if (!str_cmp(argument, "clans")){
	ListClans(ch);
	return;
      }
      else if ( (handle = ClanNameToHandle( argument )) < 1){
	send_to_char("No such clan.\n\r", ch);
	return;
      }
      argument = one_argument( argument, arg1);
      ListMembers( ch, handle, TRUE, "Pts");
      return;
    }
    /* MORTAL LIST */
    else if ( (handle = GET_CLAN(ch)) < 1){
      send_to_char("You do not belong to a clan.\n\r", ch );
      return;
    }
    else if (!CLAN_ELDER(ch)){
      send_to_char("You lack the privilige.\n\r", ch);
      return;
    }
    ListMembers( ch, handle, FALSE, "Pts");
    return;    
  }
  /* RANKS */
  else if (!str_prefix( arg1, "rank")){
    /* IMMORTAL LIST */
    if (IS_IMMORTAL(ch)){
      if (IS_NULLSTR(argument)){
	if (GET_CLAN(ch) < 1){
	  send_to_char( "List which clan?\n\r", ch);
	  return;
	}
	else
	  handle = GET_CLAN(ch);
      }
      if ( (handle = ClanNameToHandle( argument )) < 1){
	send_to_char("No such clan.\n\r", ch);
	return;
      }
      argument = one_argument( argument, arg1);
      ListMembers( ch, handle, TRUE, "Rank");
      return;
    }
    /* MORTAL LIST */
    else if ( (handle = GET_CLAN(ch)) < 1){
      send_to_char("You do not belong to a clan.\n\r", ch );
      return;
    }
    else if (!CLAN_ELDER(ch)){
      send_to_char("You lack the privilige.\n\r", ch);
      return;
    }
    ListMembers( ch, handle, FALSE, "Rank");
    return;    
  }
  /* SENIOR */
  else if (!str_prefix( arg1, "senior")){
    /* IMMORTAL LIST */
    if (IS_IMMORTAL(ch)){
      if (IS_NULLSTR(argument)){
	if (GET_CLAN(ch) < 1){
	  send_to_char( "List which clan?\n\r", ch);
	  return;
	}
	else
	  handle = GET_CLAN(ch);
      }
      if ( (handle = ClanNameToHandle( argument )) < 1){
	send_to_char("No such clan.\n\r", ch);
	return;
      }
      argument = one_argument( argument, arg1);
      ListMembers( ch, handle, TRUE, "Senior");
      return;
    }
    /* MORTAL LIST */
    else if ( (handle = GET_CLAN(ch)) < 1){
      send_to_char("You do not belong to a clan.\n\r", ch );
      return;
    }
    else if (!CLAN_ELDER(ch)){
      send_to_char("You lack the privilige.\n\r", ch);
      return;
    }
    ListMembers( ch, handle, FALSE, "Senior");
    return;    
  }
  /* DRAFT */
  else if (!str_prefix( arg1, "draft")){
    CHAR_DATA* victim;

    argument = one_argument( argument, arg2);

    if ( IS_NULLSTR(arg2)){
      send_to_char("Draft whom?\n\r", ch);
      return;
    }
    else if ((victim = get_char_room( ch, NULL, arg2)) == NULL){
      send_to_char("They aren't here.\n\r", ch);
      return;
    }
    else if (IS_NPC(victim)){
      send_to_char("Not on mobs.\n\r", ch);
      return;
    }

    /* IMMORTAL/NPC */
    if (IS_IMMORTAL(ch) || (IS_NPC(ch) && get_trust(ch) >= IMPLEMENTOR)){
      if (IS_NULLSTR(argument)){
	if ( (handle = GET_CLAN(ch)) < 1){
	  send_to_char("Draft them into which clan?\n\r", ch);
	  return;
	}
	
      }
      if ( (handle = ClanNameToHandle( argument)) < 1){
	send_to_char("That clan does not exist.\n\r", ch);
	return;
      }
    }
    /* MORTAL */
    else if ( (handle = GET_CLAN(ch)) < 1){
      send_to_char("You do not belong to a clan.\n\r", ch);
      return;
    }
    else if (!CLAN_ELDER(ch)){
      send_to_char("You lack the privilige.\n\r", ch);
      return;
    }
    else if (victim->master != ch && !IS_IMMORTAL(ch)){
      send_to_char("They are not following you.\n\r", ch);
      return;
    }
    if (HAS_CLAN(victim)){
      int cur = GET_CLAN(victim);
      ClanRemMember( cur, victim->name);
      ClanSave( cur );
    }
    if ( (victim->pcdata->clan_handle = ClanAddMember( handle, victim )) < 1){
      send_to_char("Error removing member.\n\r", ch);
      return;
    }
    ClanSave( handle );
    act("$n is now a member of $t.", victim, ClanHandleToName( GET_CLAN(victim)), NULL, TO_ROOM);
    sendf( victim, "You are now a member of %s.\n\r", ClanHandleToName( GET_CLAN(victim)) );
    return;
  }
  /* REMOVE */
  else if (!str_prefix( arg1, "remove")){
    CHAR_DATA* victim;

    argument = one_argument( argument, arg2);

    if ( IS_NULLSTR(arg2)){
      send_to_char("Remove whom?\n\r", ch);
      return;
    }

    /* IMMORTAL/NPC */
    if (IS_IMMORTAL(ch)){
      if (IS_NULLSTR(argument)){
	if ( (handle = GET_CLAN(ch)) < 1){
	  send_to_char("Remove them from which clan?\n\r", ch);
	  return;
	}
      }
      if ( (handle = ClanNameToHandle( argument)) < 1){
	send_to_char("That clan does not exist.\n\r", ch);
	return;
      }
    }
    /* MORTAL */
    else if ( (handle = GET_CLAN(ch)) < 1){
      send_to_char("You do not belong to a clan.\n\r", ch);
      return;
    }
    else if (!CLAN_LEADER(ch)){
      send_to_char("You lack the privilige.\n\r", ch);
      return;
    }
    if (!ClanRemMember( handle, arg2)){
      send_to_char("No such member in the clan.\n\r", ch);
      return;
    }
    if ( (victim = get_char( arg2 )) != NULL && !IS_NPC(victim)){
      victim->pcdata->clan_handle = 0;
      send_to_char("You have been removed from your clan.\n\r", victim);
    }
    ClanSave( handle );
    send_to_char("Removed.\n\r", ch);
    return;
  }
  /* PROMOTE */
  else if (!str_prefix( arg1, "promote")){
    CLAN_MEMBER* pCmd = NULL;

    argument = one_argument( argument, arg2);

    if ( IS_NULLSTR(arg2)){
      send_to_char("Promote whom?\n\r", ch);
      return;
    }

    /* IMMORTAL/NPC */
    if (IS_IMMORTAL(ch)){
      if (IS_NULLSTR(argument)){
	if ( (handle = GET_CLAN(ch)) < 1){
	  send_to_char("Promote them in which clan?\n\r", ch);
	  return;
	}
      }
      else if ( (handle = ClanNameToHandle( argument)) < 1){
	send_to_char("That clan does not exist.\n\r", ch);
	return;
      }
      if ( (pCmd = GetClanMember(handle, arg2)) == NULL){
	send_to_char("No such member in that clan.\n\r", ch);
	return;
      }
    }
    /* MORTAL */
    else {
      if ( (handle = GET_CLAN(ch)) < 1){
	send_to_char("You do not belong to a clan.\n\r", ch);
	return;
      }
      else if (!CLAN_ELDER(ch)){
	send_to_char("You lack the privilige.\n\r", ch);
	return;
      }
      else if ( (pCmd = GetClanMember( handle, arg2)) == NULL){
	send_to_char("They are not part of your clan.\n\r", ch);
	return;
      }
      else if (pCmd->rank + 1 >= ch->pcdata->clan_rank){
	send_to_char("You cannot promote them any further.\n\r", ch);
	return;
      }
    }
    if (pCmd){
      CHAR_DATA* vch = get_char( pCmd->name );
      if (pCmd->rank >= RANK_LEADER){
	send_to_char("They cannot be promoted further.\n\r", ch);
	pCmd->rank = RANK_LEADER;
      }
      else{
	pCmd->rank++;
	sendf(ch, "Promoted to %s.\n\r", clanr_table[pCmd->rank][1]);
      }
      if (vch && !IS_NPC(vch)){
	SynchClanData( vch );
	send_to_char("You have been promoted in within your clan!\n\r", vch);
      }
    }
    ClanSave( handle );
    return;
  }
  /* DEMOTE */
  else if (!str_prefix( arg1, "demote")){
    CLAN_MEMBER* pCmd = NULL;

    argument = one_argument( argument, arg2);

    if ( IS_NULLSTR(arg2)){
      send_to_char("Demote whom?\n\r", ch);
      return;
    }

    /* IMMORTAL/NPC */
    if (IS_IMMORTAL(ch)){
      if (IS_NULLSTR(argument)){
	if ( (handle = GET_CLAN(ch)) < 1){
	  send_to_char("Demote them in which clan?\n\r", ch);
	  return;
	}
      }
      else if ( (handle = ClanNameToHandle( argument)) < 1){
	send_to_char("That clan does not exist.\n\r", ch);
	return;
      }
      if ( (pCmd = GetClanMember(handle, arg2)) == NULL){
	send_to_char("No such member in that clan.\n\r", ch);
	return;
      }
    }
    /* MORTAL */
    else{
      if ( (handle = GET_CLAN(ch)) < 1){
      send_to_char("You do not belong to a clan.\n\r", ch);
      return;
      }
      else if (!CLAN_LEADER(ch)){
	send_to_char("You lack the privilige.\n\r", ch);
	return;
      }
      else if ( (pCmd = GetClanMember( handle, arg2)) == NULL){
	send_to_char("They are not part of your clan.\n\r", ch);
	return;
      }
      else if (pCmd->rank >= ch->pcdata->clan_rank){
	send_to_char("You cannot demote them.\n\r", ch);
	return;
      }
    }
    if (pCmd){
      CHAR_DATA* vch = get_char( pCmd->name );
      if (pCmd->rank <= RANK_NEWBIE){
	send_to_char("They cannot be demoted further.\n\r", ch);
	pCmd->rank = RANK_NEWBIE;
      }
      else{
	pCmd->rank--;
	sendf(ch, "Demoted to %s.\n\r", clanr_table[pCmd->rank][1]);
      }
      if (vch && !IS_NPC(vch)){
	SynchClanData( vch );
	send_to_char("You have been demoted in within your clan!\n\r", vch);
      }
    }
    ClanSave( handle );
    return;
  }
  /* ALLOW */
  else if (!str_prefix( arg1, "allow")){
    CABAL_DATA* pCab;
    CLAN_MEMBER* pCmd = NULL;
    CHAR_DATA* victim;

    argument = one_argument( argument, arg2);

    if (!IS_IMMORTAL(ch)){
      send_to_char("You are not an Immortal.\n\r", ch);
      return;
    }
    else if ( IS_NULLSTR(arg2)){
      send_to_char("Allow whom to apply to their clan's cabal?\n\r", ch);
      return;
    }
    if (IS_NULLSTR(argument)){
      if ( (handle = GET_CLAN(ch)) < 1){
	send_to_char("Allow them in which clan?\n\r", ch);
	return;
      }
    }
    else if ( (handle = ClanNameToHandle( argument)) < 1){
      send_to_char("That clan does not exist.\n\r", ch);
      return;
    }
    //min member check
    for (pCab = cabal_list; pCab; pCab = pCab->next){
      if (pCab->clan == handle && pCab->cur_member >= pCab->max_member){
	send_to_char("The cabal is at max. capacity.\n\r", ch);
	return;
      }
    }
    if ( (pCmd = GetClanMember(handle, arg2)) == NULL){
      send_to_char("No such member in that clan.\n\r", ch);
      return;
    }
    pCmd->allowed = mud_data.current_time;
    if ( (victim = get_char( pCmd->name)) != NULL){
      send_to_char("`@You have seven days to apply to your clan's cabal.``\n\r", victim);
    }
    else{
      DESCRIPTOR_DATA* d;
      if ( (d = bring(ch->in_room, pCmd->name)) != NULL){
	d->character->pcdata->roomnum *= -1;
	SET_BIT(d->character->pcdata->messages, MSG_CABAL_ALLOW);
	purge(d->character );
      }
    }
    send_to_char("They have been allowed to vote for next 7 days.\n\r", ch);
    ClanSave( handle );
    return;
  }
  else
    do_clan( ch, "");
}

//returns clan's handle from name
int GetClanHandle( char* name ){
  return (ClanNameToHandle( name ));
}

//returns name of clan based onhandle
char* GetClanName( int handle ){
  return(ClanHandleToName( handle ));
}

//synchronizes clan and character data
void SynchClanData( CHAR_DATA* ch ){
  int handle;
  CLAN_MEMBER* pCmd;

  if ( (handle = GET_CLAN(ch)) < 1)
    return;
  else if ( (pCmd = GetClanMember( handle, ch->name)) == NULL)
    return;

  //synch
  pCmd->level		= ch->level;
  pCmd->class		= ch->class;
  pCmd->race		= ch->race;
  pCmd->last_logon	= ch->logoff;
  pCmd->pts		= ch->pcdata->clan_points;

  if (ch->pCabal){
    pCmd->rank		= UMAX(ch->pcdata->rank, pCmd->rank);
    ch->pcdata->clan_points = 0;
    pCmd->pts		= 0;
    pCmd->allowed	= 0;
  }
  ch->pcdata->clan_rank = pCmd->rank;

}
	    

//returns member data based on handle and name
CLAN_MEMBER* GetClanMember( int handle, char* name ){
  CLAN_MEMBER* pCmd;
  CLAN_DATA* pClan = GetClanData( handle );

  if (pClan == NULL || IS_NULLSTR(name))
    return NULL;
  for (pCmd = pClan->members.next; pCmd; pCmd = pCmd->next){
    if (!str_cmp(name, pCmd->name))
      return pCmd;
  }
  return NULL;
}

void CharToClan( CHAR_DATA* ch, int handle ){
  if (IS_NPC(ch))
    return;
  ch->pcdata->clan_handle = ClanAddMember( handle, ch);
}

void CharFromClan( CHAR_DATA* ch ){
  int handle;
  if ( (handle = GET_CLAN( ch )) < 1)
    return;
  else if (ClanRemMember( handle, ch->name ))
    ClanSave( handle );
}

void do_brownie( CHAR_DATA* ch, char* argument ){
  CHAR_DATA* victim;
  char name[MIL];
  int range;

  argument = one_argument( argument, name );
  range = atoi( argument );

  if (IS_NULLSTR(argument)){
    send_to_char("Give brownie points to whom and on what scale (-2 to 2)?\n\r", ch);
    return;
  }
  else if ( (victim = get_char( name )) == NULL){
    send_to_char("Character not found.\n\r", ch);
    return;
  }
  else if (IS_NPC(victim)){
    send_to_char("Not on mobs.\n\r", ch);
    return;
  }
  else if (range == 0){
    sendf( ch, "%s has %d points.  Use scale of -2 to 2 to remove or add points.\n\r", PERS2(victim), victim->pcdata->clan_points);
    return;
  }
  else if (range < -2 || range > 2){
    send_to_char("Use a scale of -2 to 52for the amount of reward.\n\r", ch);
    return;
  }

  switch (range){
  case -2:  victim->pcdata->clan_points -= 100;	break;
  case -1:  victim->pcdata->clan_points -= 50;	break;
  case  2:  victim->pcdata->clan_points += 100;	break;
  case  1:  victim->pcdata->clan_points += 50;	break;
  default:	break;
  }
  SynchClanData( victim );
  sendf( ch, "%s's clan points now at %d\n\r", PERS2(victim), victim->pcdata->clan_points);

  save_char_obj( victim );
  ClanSave( GET_CLAN(victim ));
}

int ClanSecondsToApply( CHAR_DATA* ch ){
  int handle = GET_CLAN(ch);
  CLAN_MEMBER* pCmd;

  if (handle < 1){
    return 0;
  }
  else if ( (pCmd = GetClanMember( handle, ch->name)) == NULL){
    return 0;
  }
  else if (pCmd->allowed < 1){
    return 0;
  }
  else if (mud_data.current_time - pCmd->allowed > CLAN_APPLY_WIN){
    return 0;
  }
  else
    return (CLAN_APPLY_WIN - (mud_data.current_time - pCmd->allowed));
}

bool ClanApplicationCheck( CHAR_DATA* ch, CABAL_DATA* pCab){
  int handle = GET_CLAN(ch);
  CLAN_MEMBER* pCmd;

  if (handle < 1){
    sendf(ch, "You cannot join %s beacuse you're a member of %s.\n\r", pCab->name, GetClanName(pCab->clan));
    return FALSE;
  }
  else if ( (pCmd = GetClanMember( handle, ch->name)) == NULL){
    sendf(ch, "You cannot join %s beacuse you're a member of %s.\n\r", pCab->name, GetClanName(pCab->clan));
    return FALSE;
  }
  else if (pCmd->allowed < 1){
    sendf(ch, "%s has not allowed you to apply to %s.\n\r", pCab->immortal, pCab->name );
    return FALSE;
  }
  else if (mud_data.current_time - pCmd->allowed > CLAN_APPLY_WIN){
    sendf(ch, "You have taken over seven days to apply.  %s must allow you to do so once more.\n\r", pCab->immortal);
    return FALSE;
  }
  return TRUE;
}

void ClanEcho( int handle, char* string ){
  DESCRIPTOR_DATA* d;

  for ( d = descriptor_list; d != NULL; d = d->next ){
    if ( d->connected == CON_PLAYING 
	 && !IS_AFFECTED2(d->character, AFF_SILENCE)
	 && !IS_NPC(d->character)
	 && !is_affected(d->character,gsn_silence)
	 && GET_CLAN(d->character) == handle
	 ){
      sendf(d->character,"[`8%s``]: '`0%s``'\n\r", GetClanName(handle), string);
    }
  }
}

bool ClanRename(int handle, char* current, char* new ){
  CLAN_MEMBER* cm;
    
  if (handle < 1 || IS_NULLSTR(current) || IS_NULLSTR(new))
    return FALSE;

  if ( (cm = GetClanMember(handle, current)) == NULL)
    return FALSE;
  
  free_string(cm->name);
  cm->name = str_dup (capitalize (new));

  return TRUE;
}