/*
* 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;
}