clan/
class/
data/
doc/ideas/
doc/mobprogs/
gods/
log/
player/
time/
/*
 *  The unique portions SunderMud code as well as the integration efforts
 *  for code from other sources is based on the efforts of:
 * 
 *  Lotherius (elfren@aros.net)
 *  
 *  This code can only be used under the terms of the DikuMud, Merc, 
 *  and ROM licenses. The same requirements apply to the changes that
 *  have been made.
 *
 * All other copyrights remain in place and in force.
*/

/*
*  act_clan.c - added by Zeran to support clans.
*  All functions related to clans belong in this file
*  for easy reference and modification.
*/ 

#include "everything.h"

/*command functions needed*/
DECLARE_DO_FUN (do_who);
/*Globals*/
struct clan_proto *clans[MAX_CLANS];

/*clan command functions*/       
void clan_review 	(CHAR_DATA *ch);
void clan_list 		(CHAR_DATA *ch);
void clan_accept 	(CHAR_DATA *ch, char *arg);
void clan_promote 	(CHAR_DATA *ch, char *arg);
void clan_donate  	(CHAR_DATA *ch, char *arg);
void clan_demote  	(CHAR_DATA *ch, char *arg);
void clan_quit	  	(CHAR_DATA *ch);
void do_clan_tell  	(CHAR_DATA *ch, char *argument); 


/*local functions*/

void do_clan_tell (CHAR_DATA *ch, char *argument) /*sloppy code format
					   stolen from do_auction*/
{
    char buf[MAX_STRING_LENGTH];
    DESCRIPTOR_DATA *d;
	
	if (ch->pcdata->clan_num == -1)
		{
		send_to_char ("You do not belong to any clan.\n\r",ch);
		send_to_char ("Once you join a clan, you can use 'clan tell'\n\r",ch);
		return;	
		}

    if (argument[0] == '\0' )
    {
      if (IS_SET(ch->comm,COMM_NOCLANTELL))
      {
	send_to_char("Clan channel is now ON.\n\r",ch);
	REMOVE_BIT(ch->comm,COMM_NOCLANTELL);
      }
      else
      {
	send_to_char("Clan channel is now OFF.\n\r",ch);
	SET_BIT(ch->comm,COMM_NOCLANTELL);
      }
    }
    else  
    {
	if (IS_SET(ch->comm,COMM_QUIET))
	{
	  send_to_char("You must turn off quiet mode first.\n\r",ch);
	  return;
	}

	if (IS_SET(ch->comm,COMM_NOCHANNELS))
	{
	  send_to_char("The gods have revoked your channel priviliges.\n\r",ch);
	  return;
    }

      sprintf( buf, "{RYou tell your clan '%s'{x\n\r", argument );
      send_to_char( buf, ch );
      for ( d = descriptor_list; d != NULL; d = d->next )
      {
	CHAR_DATA *victim;

	victim = d->original ? d->original : d->character;

	if ( d->connected == CON_PLAYING &&
	     d->character != ch &&
	     !IS_SET(victim->comm,COMM_NOCLANTELL) &&
	     !IS_SET(victim->comm,COMM_QUIET) &&
		 d->character->pcdata->clan_num == ch->pcdata->clan_num)
	{
	    act_new("{R$n tells the clan '$t'{x",
		    ch,argument,d->character,TO_VICT,POS_DEAD);
 	}
      }
    }
}

/* Big clan function parser */
void do_clan (CHAR_DATA *ch, char *argument)
	{
	char message[MAX_INPUT_LENGTH];
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	
	argument=one_argument(argument, arg1);
	sprintf(message, argument);
	argument=one_argument(argument, arg2);
	
	if (arg1[0]=='\0') /*no argument, kick out list of clan commands*/
		{	
		send_to_char ("\n\rClan commands:\n\r",ch);
		send_to_char ("---- --------\n\r",ch);
		send_to_char ("clan review\n\r",ch);
		send_to_char ("clan quit\n\r",ch);     
		send_to_char ("clan accept  [player]\n\r",ch);
		send_to_char ("clan promote [player]\n\r",ch);
		send_to_char ("clan demote  [player]\n\r",ch);
		send_to_char ("clan list\n\r",ch);
		send_to_char ("clan donate  [integer]\n\r",ch);
		send_to_char ("clan tell    [message string]\n\r",ch);
		return;
		}
	
	if 		(!str_cmp(arg1, "review")) clan_review(ch);
	else if	(!str_cmp(arg1, "list"  )) clan_list(ch);
	else if (!str_cmp(arg1, "quit"  )) clan_quit(ch);
	else if (!str_cmp(arg1, "accept")) clan_accept(ch,arg2);
	else if (!str_cmp(arg1, "promote")) clan_promote(ch, arg2);
	else if (!str_cmp(arg1, "demote")) clan_demote(ch, arg2);
	else if (!str_cmp(arg1, "donate")) clan_donate(ch,arg2);
	else if (!str_cmp(arg1, "tell"))   do_clan_tell(ch,message);
	else if (!str_cmp(arg1, "who"))    do_who(ch, "clan");
	else
		send_to_char ("No such clan command...\n\r",ch);
	return;
	} 
	
void clan_review (CHAR_DATA *ch)  /*Only clan members get a review*/
				  /*In the future, nonmembers will get*/
				  /* an abbreviated review */
	{
	char buf[80];
	int cnum;
	struct leader *tmp;
	
	buf[0]='\0';
	
	cnum=ch->pcdata->clan_num;
	
	if (cnum==-1)
		{
		send_to_char ("You do not belong to any clan.\n\r",ch);
		return;
		}
	else if (!valid_clan(cnum)) 
		{
		sprintf (buf, "%s's clan_num [%d] is invalid.\n\r", ch->name, cnum);
		log_string(buf);
		send_to_char ("Your clan number is invalid, inform the IMP asap.\n\r",ch);
		return;
		}
		
	send_to_char ("\n\r{gCLAN REVIEW:{x\n\r", ch);
	send_to_char ("____ ______\n\r", ch);
	sprintf(buf, "Clan {Y%s{x\n\r", clans[cnum]->name);
	send_to_char (buf, ch);
	
	send_to_char ("Clan rulers are: \n\r",ch);
	tmp=clans[cnum]->chiefs;
	if (tmp==NULL)
		{
		send_to_char ("None\n\r", ch);
		}
	else 
		for (;tmp!=NULL;tmp=tmp->next)
			{
			sprintf(buf, "{c%s{x\n\r", tmp->name);
			send_to_char (buf, ch);
			}
	
	sprintf (buf, "Membership: {r%d{x players.\n\r", clans[cnum]->num_members);
	send_to_char (buf, ch);
	
	sprintf (buf, "Bank funds: {Y%d{x gold coins.\n\r", clans[cnum]->bank);
	send_to_char (buf, ch);
	
	return;
	}

void clan_list (CHAR_DATA *ch) /*All players get list*/       
	{
	int count=0;
	char buf[80];
	
	send_to_char("\n\r{YClan listing{W:\n\r", ch);
	send_to_char("{B____ _______\n\r",ch);

	while (clans[count]!=NULL)
		{
		sprintf(buf, "{W[{Y%d{W]  %s{x\n\r",count,clans[count]->name);
		send_to_char(buf, ch);
		count++;
		}			
	}	

void clan_accept (CHAR_DATA *ch, char *arg)
	{
	CHAR_DATA *victim;
	char messbuf[128];
	int num=-1;
	
	if (ch->pcdata->clan_num==-1)
		{
		send_to_char ("You do not belong to a clan.\n\r",ch);
		return;
		}
	
	if (ch->pcdata->clan_rank < MIN_ACCEPT_RANK)
		{
		send_to_char ("You cannot accept new members, your clan rank is too low.\n\r",ch);
		return;
		}
	
	if (arg[0]=='\0') 
		{
		send_to_char ("Accept whom?\n\r",ch);
		return;
		}
	
	if (((victim = get_char_world (ch, arg)) == NULL)
		 || (victim->in_room != ch->in_room) 
		 || IS_NPC(victim))
		{
		send_to_char ("That player isn't here.\n\r",ch);
		return;
		}

	/*ok, checks done, accept new member!*/
	send_to_char ("Done. *cheer*, your clan is growing!\n\r",ch);
	sprintf (messbuf, "%s has accepted you into clan %s !\n\r",ch->name, ch->pcdata->clan->name);
	send_to_char (messbuf, victim);
	/* Zeran - notify message */
	notify_message (victim, NOTIFY_CLANACCEPT, TO_CLAN, ch->pcdata->clan->name); 
	
	/*set victims clan info*/
	num = ch->pcdata->clan_num;
	victim->pcdata->clan_num = num; /*clan number*/
	strcpy (victim->pcdata->clan_name, clans[num]->name); /*clan_name*/
	victim->pcdata->clan = clans[num]; /*pointer to clan*/
	victim->pcdata->clan_rank=1; /*minimum member rank*/
	ch->pcdata->clan->num_members++; /*increment member count*/
	fwrite_clans();
	return;
	}

void clan_promote (CHAR_DATA *ch, char *arg)
	{
	CHAR_DATA *victim;
	int num=-1;
	
	if (ch->pcdata->clan_num==-1)
		{
		send_to_char ("You do not belong to a clan.\n\r",ch);
		return;
		}
	
	if (ch->pcdata->clan_rank < MIN_ADVANCE_RANK)
		{
		send_to_char ("You cannot promote members, your clan rank is too low.\n\r",ch);
		return;
		}
	
	if (arg[0]=='\0') 
		{
		send_to_char ("Promote whom?\n\r",ch);
		return;
		}
	
	if (((victim = get_char_world (ch, arg)) == NULL)
		 || (victim->in_room != ch->in_room) 
		 || IS_NPC(victim))
		{
		send_to_char ("That player isn't here.\n\r",ch);
		return;
		}
	
	num=victim->pcdata->clan_num;
	if (num != ch->pcdata->clan_num)
		{
		send_to_char ("That player is not a member of your clan.\n\r",ch);
		return;
		}

	if (victim->pcdata->clan_rank >= ch->pcdata->clan_rank)
		{
		send_to_char ("You can not promote that player any higher.\n\r",ch);
		return;
		}
	
	if (((++victim->pcdata->clan_rank) == MAX_RANK) && (victim->pcdata->clan->num_leaders == MAX_LEADER))
		{
		send_to_char ("Promoting that player will exceed the maximum number\n\r",ch);
		send_to_char ("of leaders allowed in your clan...promotion cancelled.\n\r",ch);
		victim->pcdata->clan_rank--;
		return;
		}

	/*checks done, advance rank*/
	send_to_char ("{cCongratulations{x, you have been promoted to a higher clan rank!\n\r",victim);
	send_to_char ("Done.\n\r",ch);
	/* Zeran - notify message */
	{
	char rankbuf[24];
	clan_rank_name(victim, rankbuf);
	notify_message (victim, NOTIFY_CLANPROMOTE, TO_CLAN, rankbuf);
	}
	/*check to see if new leader added, if so, update clan struct info*/
	if (victim->pcdata->clan_rank == MAX_RANK)
		{
		struct leader *tmp;
		
		victim->pcdata->clan->num_leaders++;	/*increment leader count*/
		tmp=clans[num]->chiefs; /*assumption: one leader exists already*/
		for (;tmp->next!=NULL;tmp=tmp->next); /*find end of leaders list*/
		tmp->next=(struct leader *)alloc_perm(sizeof(struct leader));
		strcpy (tmp->next->name, victim->name);
		tmp->next->next=NULL;
		fwrite_clans();
		}
	}  

void clan_demote (CHAR_DATA *ch, char *arg)
	{
	CHAR_DATA *victim;
	int num=-1;
	
	if (ch->pcdata->clan_num==-1)
		{
		send_to_char ("You do not belong to a clan.\n\r",ch);
		return;
		}
	
	if (ch->pcdata->clan_rank < MAX_RANK)
		{
		send_to_char ("Only clan rulers can demote a clan member.\n\r",ch);
		return;
		}
	
	if (arg[0]=='\0') 
		{
		send_to_char ("Demote whom?\n\r",ch);
		return;
		}
	
	if (((victim = get_char_world (ch, arg)) == NULL)
		 || (victim->in_room != ch->in_room) 
		 || IS_NPC(victim))
		{
		send_to_char ("That player isn't here.\n\r",ch);
		return;
		}
	
	num=victim->pcdata->clan_num;
	if (num != ch->pcdata->clan_num)
		{
		send_to_char ("That player is not a member of your clan.\n\r",ch);
		return;
		}

	if (victim->pcdata->clan_rank == MAX_RANK)
		{
		send_to_char ("Clan rulers cannot be demoted except by the IMP.\n\r",ch);
		return;
		}
	
	if (victim->pcdata->clan_rank == 1)
		{
		send_to_char ("That player is already at the lowest clan rank.\n\r",ch);
		return;
		}

	/*checks done, reduce rank*/
	send_to_char ("Oh no, you have been demoted to a lower clan rank!\n\r",victim);
	send_to_char ("Done.\n\r",ch);
	victim->pcdata->clan_rank--;
	}

void clan_donate (CHAR_DATA *ch, char *arg)
	{
	int amount;	
	
	if (ch->pcdata->clan_num == -1) /*not in clan*/
		{
		send_to_char ("You are not a member of a clan.\n\r",ch);
		return;
		}
	
	if (arg[0]=='\0')	
		{
		send_to_char ("You must specify an amount of gold.\n\r",ch);
		return;
		}

	amount=atoi(arg);
	if (amount < 1)
		{
		send_to_char ("You must donate a positive number of gold coins.\n\r",ch);
		return;
		}

	if (amount > ch->gold)
		{
		send_to_char ("You do not have that much gold to donate.\n\r",ch);
		return;
		}
	
	if (amount >= (0.75*ch->gold)) /*very generous*/
		{
		send_to_char ("Your clan greatly appreciates your large donation.\n\r",ch);
		if ((amount >= 10000) && (number_percent() <= 10))
				{
				int bonus;
				char messybuf[80];
				bonus = 25 + number_percent()*75/100;
				sprintf (messybuf, "Role playing bonus for clan involvement: %d xp.\n\r", bonus);
				send_to_char (messybuf, ch);
				ch->exp += bonus;
				}
		}
	else
		{
		send_to_char ("You make a donation to your clan.\n\r",ch);
		}
	
	ch->gold -= amount;
	ch->pcdata->clan->bank += amount;
	return;
	fwrite_clans();
	}

void clan_quit (CHAR_DATA *ch)
	{
	if (ch->pcdata->clan_num == -1)
		{
		send_to_char ("You are not a member of any clan.\n\r",ch);
		return;
		}
	
	if (ch->pcdata->clan_rank == MAX_RANK) /*rulers can't quit!*/
		{
		send_to_char ("Clan rulers cannot simply do 'clan quit', please talk to the IMP.\n\r",ch);
		return;
		}
	
	if (!ch->pcdata->clan_quit)	
		{
		send_to_char ("Are you sure you want to quit your clan?\n\r",ch);
		send_to_char ("Do 'clan quit' again to verify and quit your clan.\n\r",ch);
		ch->pcdata->clan_quit=TRUE;
		return;
		}
	
	send_to_char ("'clan quit' verified and complete.\n\r",ch);
	/* Zeran - notify message */
	notify_message (ch, NOTIFY_CLANQUIT, TO_CLAN, ch->pcdata->clan->name);
	
	/*reset player's clan fields*/
	ch->pcdata->clan_num = -1;
	ch->pcdata->clan_rank = -1;
	ch->pcdata->clan = NULL;
	ch->pcdata->clan_quit = FALSE;
	sprintf (ch->pcdata->clan_name, "none");
	fwrite_clans();
	}	

void boot_clans (void)
	{
	FILE *clan_file;	
	int count=0;	
	bool done=FALSE;
	
	if ( ( clan_file = fopen( CLAN_FILE, "r" ) ) == NULL )
		{
		   perror (CLAN_FILE);
		   exit(1);
		}
	   	while ((!done) && (count<MAX_CLANS))
	    {
		char *word;
		
		if (fread_letter(clan_file) != '#')
			{
			bug ("boot_clan:  Missing #.", 0);
			exit (1);
			}

		word = fread_word( clan_file );

	    if ( word[0] == '$' ) 
			{
			done = TRUE;
			/* log_string ("clan:  Got ending $"); */
			}
		
		else if ( !str_cmp( word, "NAME"     ) ) 
			{
			word = fread_string( clan_file );
			if (strlen(word) > 40)
				{
				bug ("boot_clan:  Clan name too long.", 0);
				exit (1);
				}
			clans[count]=(struct clan_proto *)alloc_perm(sizeof(struct clan_proto));
			clans[count]->chiefs=NULL;
			clans[count]->number=count;
			strcpy (clans[count]->name, word);
			/* log_string (clans[count]->name); */
			}
					
		else if ( !str_cmp( word, "LEADER"    ) ) 
			{
			struct leader *tmp;
			/* log_string ("clan:  getting leaders");*/
			clans[count]->num_leaders=0;
			for (;;)	
				{
				word = fread_string (clan_file);
				/* log_string (word); */
				if (word[0]=='@') break;
				if (strlen(word) > 40)
					{
					bug ("boot_clan:  Leader name too long.", 0);
					exit (1);
					}
				tmp = clans[count]->chiefs;
				if (clans[count]->chiefs==NULL)
					{
					clans[count]->chiefs=(struct leader *)alloc_perm(sizeof(struct leader));	
					tmp=clans[count]->chiefs;
					}
				else /*goto end of chief list*/
					{
					tmp = clans[count]->chiefs;
					for (;(tmp->next!=NULL);tmp=tmp->next);
					tmp->next = (struct leader *)alloc_perm(sizeof(struct leader));	
					tmp=tmp->next;
					}
				strcpy (tmp->name, word);
				clans[count]->num_leaders++;
				tmp->next=NULL;
				}
			tmp=clans[count]->chiefs;
			for (;(tmp!=NULL);tmp=tmp->next)
				{
				/* log_string(tmp->name); */
				}
			}
					
		else if ( !str_cmp( word, "MEMCOUNT"  ) ) 
			{	
			int number;
			number = fread_number (clan_file);
			/* log_string ("clan: getting MEMCOUNT number"); */
			if (number <=0)
				{
				bug ("boot_clan:  Bad MEMCOUNT number.", 0);
				exit (1);
				}
			clans[count]->num_members=number;
			}

        else if ( !str_cmp( word, "BANK" ) ) 
			{
			int number;
			number = fread_number(clan_file);
			/* log_string ("clan:  getting BANK number"); */
			if (number < 0)
				{
				bug ("boot_clan:  Bad BANK number.", 0);
				exit (1);
				}
			clans[count]->bank=number;
			count++; /*increment clan counter*/
			clans[count]=NULL;  /*signify end of clans*/
			}
		
		else
			{
			bug ("boot_clan:  Bad header after #.", 0);
			exit (1);
			}
		} /*end while*/
		log_string ("Finished Booting Clans");	
		fclose( clan_file );

	} /*end reading of clans*/

/*
Zeran: set_clan_pointer was originally only meant to set a character's
clan pointer, but it has blown up to include initializations
of some other clan related fields inside each character.
*/
void set_clan_pointer (CHAR_DATA *ch)
	{ 
	char buf[80];
	int count=0;
	bool match=FALSE;
	
	ch->pcdata->clan_quit=FALSE; /*hasn't tried to quit their clan yet*/

	while ((clans[count]!=NULL) && (count<MAX_CLANS))	
		{
		if (!str_cmp(clans[count]->name, ch->pcdata->clan_name))
			{
			ch->pcdata->clan_num=count;
			match=TRUE;
			break;
			}
		/* sprintf (buf, "%d", count);
		log_string(buf); */	
		count++;
		}
	
	if (!match) 
		{
		sprintf (buf, "%s's clan name %s is invalid.",ch->name, ch->pcdata->clan_name);
		log_string (buf);
		ch->pcdata->clan_num=-1; /*no clan*/
		return;
		}

	ch->pcdata->clan=clans[count];
	if (ch->pcdata->clan_rank==-1)
		{
		log_string ("Bad rank number, resetting to rank 1");
		ch->pcdata->clan_rank=1;
		}
	/* log_string ("end of set_clan_pointer");
	log_string (ch->pcdata->clan->name); */
	return;
	}		

bool valid_clan (int number)
	{
	if ( (number < MAX_CLANS) && (number > -1) && (clans[number] != NULL) )
		return TRUE;
	else return FALSE;
	}

#define OUTFILE "../clan/clans.txt"

/* 
 * Zeran: Write out the clan file
*/

void fwrite_clans (void)
	{
	FILE *outfile;
	int count=0;
	bool done=FALSE;
	struct leader *tmp;
	
	if ((outfile=fopen(OUTFILE, "w+")) == NULL)
		{
		bug ("Failed to open clan output file.",0);
		return;
		}
	
	while ((!done)	&& (count<MAX_CLANS))
		{
		fprintf(outfile, "#NAME\n");
		fprintf(outfile, "%s~\n", clans[count]->name);
		fprintf(outfile, "#LEADER\n");
		tmp=clans[count]->chiefs;
		for(;tmp!=NULL;tmp=tmp->next)
			{
			fprintf(outfile, "%s~\n", tmp->name);
			}
		fprintf(outfile, "@~\n");
		fprintf(outfile, "#MEMCOUNT\n");
		fprintf(outfile, "%d\n", clans[count]->num_members);
		fprintf(outfile, "#BANK\n");
		fprintf(outfile, "%d\n", clans[count]->bank);
		count++;
		if (clans[count]==NULL) done=TRUE;
		}
	fprintf(outfile, "#$\n");
	fclose (outfile);
	} 	

void clan_rank_name (CHAR_DATA *ch, char *buf)
	{
	int rank=ch->pcdata->clan_rank;	
	
	if (rank==1)
		sprintf(buf, "Follower");
	else if (rank==2)
		sprintf(buf, "Disciple");
	else if (rank==3)
		sprintf(buf, "Advocate");
	else if (rank==4) 
		sprintf(buf, "OverSeer");
	else if (rank==5)
		sprintf(buf, "Ruler"); 
	else 
		sprintf(buf, "none");
	}

/* Zeran - get_clan_by_name returns a clan pointer by a clan name lookup.
           If the name isn't found, NULL is returned. */

struct clan_proto *get_clan_by_num (int num)
	{
	if (valid_clan(num))
		return clans[num];
	else
		return NULL;
	}