#include "ctype.h"
#include "dirent.h"
#include "sys/types.h"
#include "stdio.h"
#include "stdlib.h"
#include "syslog.h"
#include "unistd.h"
#include "define.h"
#include "struct.h"
clan_data** clan_list = NULL;
int max_clan = 0;
void rename_clan ( clan_data*, char* );
void create_clan ( pfile_data*, char* );
bool good_clan_name ( char_data*, char* );
void display ( char_data*, clan_data* );
void extract ( clan_data* );
bool edit_clan ( char_data*, clan_data*, bool = FALSE );
void expell ( char_data*, clan_data*, pfile_data* );
const char* clan_flags [ MAX_CLAN_FLAGS ] = { "Approved", "Exist.Known",
"Members.Known" };
inline bool knows( char_data* ch, clan_data* clan )
{
return( ch->pcdata->pfile->clan == clan
|| ( is_set( clan->flags, CLAN_APPROVED )
&& is_set( clan->flags, CLAN_KNOWN ) )
|| has_permission( ch, PERM_CLANS ) );
}
/*
* CLAN ROUTINES
*/
clan_data* find_clan( char_data* ch, char* argument )
{
clan_data* clan;
int i;
for( i = 0; i < max_clan; i++ )
if( knows( ch, clan = clan_list[i] )
&& ( fmatches( argument, clan->name )
|| fmatches( argument, clan->abbrev ) ) )
return clan;
send( ch, "No such clan exists.\n\r" );
return NULL;
}
bool edit_clan( char_data* ch, clan_data* clan, bool msg )
{
title_data* title;
if( clan == NULL ) {
if( msg )
send( ch, "You are not in a clan so editing it makes no sense.\n\r" );
return FALSE;
}
if( !has_permission( ch, PERM_CLANS ) ) {
if( is_set( clan->flags, CLAN_APPROVED ) ) {
if( msg )
send( ch, "After the clan is approved it may not be edited.\n\r" );
return FALSE;
}
if( ( title = get_title( ch->pcdata->pfile ) ) == NULL
|| !is_set( title->flags, TITLE_EDIT_CHARTER ) ) {
if( msg )
send( ch, "You don't have permission to edit the clan.\n\r" );
return FALSE;
}
}
return TRUE;
}
inline void clan_options( char_data* ch, clan_data* clan,
char* argument )
{
const char* response;
#define types 5
if( clan == NULL ) {
send( ch,
"You cannot edit or view options for a clan you are not in.\n\r" );
return;
}
const char* title [types] = {
"*Options", "*Races", "*Classes",
"*Alignments", "*Sexes" };
int max [types] = {
MAX_CLAN_FLAGS, MAX_PLYR_RACE, MAX_CLSS, MAX_ENTRY_ALIGNMENT, 2 };
const char** name1 [types] = {
&clan_flags[0], &race_table[0].name, &clss_table[0].name,
&alignment_table[0].name, &sex_name[ SEX_MALE ] };
const char** name2 [types] = {
&clan_flags[1], &race_table[1].name, &clss_table[1].name,
&alignment_table[1].name, &sex_name[ SEX_FEMALE ] };
int* flag_value [types] = { clan->flags, &clan->races, &clan->classes,
&clan->alignments, &clan->sexes };
int can_edit [types] = { 1, -1, -1, -1, -1 };
int not_edit [types] = { 1, 1, 1, 1, 1 };
response = flag_handler( title, name1, name2, flag_value, max,
edit_clan( ch, clan ) ? can_edit : not_edit,
has_permission( ch, PERM_CLANS ) ? (const char*) NULL
: "You do not have permission to alter that flag.\n\r",
ch, argument, types );
clan->modified = TRUE;
#undef types
return;
}
inline void clan_titles( char_data* ch, clan_data* clan, char* argument )
{
title_data* title;
int i;
if( clan == NULL ) {
send( ch, "Since you aren't in a clan the T option is meaningless.\n\r" );
return;
}
if( *argument == '\0' ) {
page_underlined( ch, "%-20s %s\n\r", "Title", "Character" );
for( i = 0; i < clan->titles.size; i++ ) {
title = clan->titles.list[i];
page( ch, "%-20s %s\n\r", title->name,
title->pfile == NULL ? "Noone" : title->pfile->name );
}
return;
}
send( ch, "Editting of titles is not yet enabled.\n\r" );
return;
}
inline void create_clan( pfile_data* pfile, char* name )
{
*name = toupper( *name );
clan_data* clan = new clan_data( name );
title_data* title = new title_data( "Founder", pfile );
add_member( clan, pfile );
insert( clan->titles.list, clan->titles.size, title, 0 );
set_bit( title->flags, TITLE_SET_FLAGS );
set_bit( title->flags, TITLE_EDIT_CHARTER );
set_bit( title->flags, TITLE_RECRUIT );
set_bit( title->flags, TITLE_REMOVE_NOTES );
set_bit( &clan->classes, pfile->clss );
set_bit( &clan->races, pfile->race );
save_clans( clan );
save_notes( clan );
return;
}
const char* create_msg = "Summoning a scribe daemon you request that the\
paperwork be drawn up to form a clan by the name of '%s'. He politely\
nods his head, scribbles a few lines on the back of an envelope, hands you\
the envelope, and then informs you that your bank account will be deducted\
2000 sp for services rendered.";
void do_clans( char_data* ch, char* argument )
{
player_data* pc;
clan_data* clan;
title_data* title;
pfile_data* pfile;
int flags;
int i;
if( is_mob( ch ) )
return;
pc = player( ch );
clan = ch->pcdata->pfile->clan;
if( !get_flags( ch, argument, &flags, "fotcna", "Clans" ) )
return;
if( exact_match( argument, "expell" ) ) {
if( ( title = get_title( ch->pcdata->pfile ) ) == NULL
|| !is_set( title->flags, TITLE_RECRUIT ) ) {
send( ch, "You don't have permission to expell clan members.\n\r" );
return;
}
if( *argument == '\0' ) {
send( ch, "Who do you wish to expell from the clan?\n\r" );
return;
}
if( ( pfile = find_pfile( argument, ch ) ) != NULL )
expell( ch, clan, pfile );
return;
}
if( has_permission( ch, PERM_CLANS )
&& exact_match( argument, "delete" ) ) {
if( *argument == '\0' ) {
send( ch, "Which clan do you wish to delete?\n\r" );
}
else if( ( clan = find_clan( ch, argument ) ) != NULL ) {
extract( clan );
send( ch, "Clan deleted.\n\r" );
}
return;
}
if( is_set( &flags, 0 ) ) {
if( pc->pcdata->pfile->clan != NULL ) {
send( ch, "You cannot form a clan if already a member of one.\n\r" );
return;
}
if( pc->shdata->level < 20 ) {
send( ch, "You must be at least 15th level to form a clan.\n\r" );
return;
}
if( pc->bank < 20000 ) {
send( ch, "There is a 2000 sp charge, withdrawn from bank, for forming\
a clan and you lack\n\rsufficent funds.\n\r" );
return;
}
if( *argument == '\0' ) {
send( ch, "What name do you wish for the clan?\n\r" );
return;
}
if( good_clan_name( ch, argument ) ) {
create_clan( ch->pcdata->pfile, argument );
pc->bank -= 20000;
fsend( ch, create_msg, argument );
}
return;
}
if( is_set( &flags, 2 ) ) {
clan_titles( ch, clan, argument );
return;
}
if( is_set( &flags, 1 ) ) {
clan_options( ch, clan, argument );
return;
}
if( is_set( &flags, 4 ) ) {
if( !edit_clan( ch, clan, TRUE ) )
return;
if( *argument == '\0' ) {
send( ch, "What do you want to set the name of the clan to?\n\r" );
return;
}
free_string( clan->name, MEM_CLAN );
clan->name = alloc_string( argument, MEM_CLAN );
send( ch, "Name of clan set to %s.\n\r", argument );
return;
}
if( is_set( &flags, 5 ) ) {
if( !edit_clan( ch, clan, TRUE ) )
return;
if( *argument == '\0' ) {
send( ch, "What do you want to set the abbrev for the clan to?\n\r" );
return;
}
if( !good_clan_name( ch, argument ) )
return;
rename_clan( clan, argument );
send( ch, "Clan abbrev changed to %s.\n\r", argument );
return;
}
if( is_set( &flags, 3 ) ) {
if( !edit_clan( ch, clan, TRUE ) )
return;
clan->modified = TRUE;
clan->charter = edit_string( ch, argument,
clan->charter, MEM_CLAN );
return;
}
if( *argument == '\0' ) {
page_underlined( ch, "Abrv %-50s Members\n\r", "Clan" );
for( i = 0; i < max_clan; i++ )
if( knows( ch, clan = clan_list[i] ) )
page( ch, "%4s %-50s %s\n\r", clan->abbrev, clan->name,
knows_members( ch, clan ) ? number_word( clan->members.size )
: "???" );
return;
}
if( ( clan = find_clan( ch, argument ) ) != NULL )
display( ch, clan );
}
/*
* CLAN EDITTING
*/
void display_edit( char_data* ch, clan_data* clan )
{
title_data** list = clan->titles.list;
char* flags = "FCRN";
char* tmp = static_string( );
char* letter;
int i, j;
send( ch, " Name: %s\n\r", clan->name );
send( ch, " Abbrev: %s\n\r\n\r", clan->abbrev );
send_underlined( ch,
"Nmbr Title Holder Flags\n\r" );
for( i = 0; i < clan->titles.size; i++ ) {
letter = tmp;
for( j = 0; j < MAX_TITLE; j++ )
if( is_set( list[i]->flags, j ) )
*letter++ = flags[j];
*letter = '\0';
send( ch, "%-6d%-20s%-20s%s\n\r",
i+1, list[i]->name, list[i]->pfile == NULL ? "noone"
: list[i]->pfile->name, tmp );
}
return;
}
void do_cedit( char_data* ch, char* argument )
{
clan_data* clan;
title_data* title;
pfile_data* pfile;
int i;
if( ( clan = ch->pcdata->pfile->clan ) == NULL ) {
send( ch, "Cedit operates on the clan you are in and you\
aren't in a clan.\n\r" );
return;
}
if( *argument == '\0' ) {
display_edit( ch, clan );
return;
}
if( matches( argument, "new" ) ) {
if( *argument == '\0' ) {
send( ch, "What should the new title be called?\n\r" );
return;
}
if( clan->titles.size > 5 ) {
send( ch, "A clan is restricted to 5 titles.\n\r" );
return;
}
insert( clan->titles.list, clan->titles.size,
new title_data( argument, NULL ), clan->titles.size );
send( ch, "New title %s added.\n\r", argument );
return;
}
if( matches( argument, "delete" ) ) {
if( *argument == '\0' ) {
send( ch, "Which title do you wish to delete?\n\r" );
return;
}
if( ( i = atoi( argument ) ) < 1 || i > clan->titles.size ) {
send( ch, "No such title exists.\n\r" );
return;
}
title = clan->titles.list[--i];
send( ch, "Title '%s' removed.\n\r", title->name );
remove( clan->titles.list, clan->titles.size, i );
delete title;
return;
}
if( number_arg( argument, i ) ) {
if( i < 1 || i > clan->titles.size ) {
send( ch, "No such title exists.\n\r" );
return;
}
title = clan->titles.list[--i];
set_flags( ch, argument, title->flags, "FCRN" );
if( matches( argument, "title" ) ) {
set_string( ch, argument, title->name, "title", MEM_CLAN );
return;
}
if( matches( argument, "holder" ) ) {
if( ( pfile = find_pfile( argument, ch ) ) != NULL ) {
if( pfile->clan != clan ) {
fsend( ch, "%s isn't a member of %s.\n\r",
pfile->name, clan->name );
}
else {
title->pfile = pfile;
send( ch, "%s set to %s.\n\r", title->name, title->pfile->name );
}
}
return;
}
}
send( ch, "Unknown syntax - see help cedit.\n\r" );
return;
}
/*
* ALLEGIANCE ROUTINES
*/
inline bool can_join( char_data* ch, clan_data* clan )
{
const char* word;
int i;
if( has_permission( ch, PERM_CLANS ) )
return TRUE;
if( !is_set( clan->flags, CLAN_APPROVED ) ) {
fsend( ch, "%s has not been approved so may not accept members.",
name( clan ) );
return FALSE;
}
if( ch->shdata->level < clan->min_level ) {
fsend( ch, "To join %s you must be at least level %d.",
name( clan ), clan->min_level );
return FALSE;
}
#define types 4
const char** name1 [types] = {
&race_table[0].name, &clss_table[0].name,
&alignment_table[0].name, &sex_name[ SEX_MALE ] };
const char** name2 [types] = {
&race_table[1].name, &clss_table[1].name,
&alignment_table[1].name, &sex_name[ SEX_FEMALE ] };
int* flag_value [types] = {
&clan->races, &clan->classes,
&clan->alignments, &clan->sexes };
int player_value [types] = {
ch->shdata->race, ch->pcdata->clss, ch->shdata->alignment,
ch->sex-SEX_MALE };
for( i = 0; i < types; i++ ) {
if( !is_set( flag_value[i], player_value[i] ) ) {
word = *(name1[i]+player_value[i]*(name2[i]-name1[i]));
fsend( ch, "As %s %s you would not be allowed to join %s.\n\r",
isvowel( *word ) ? "an" : "a", word, name( clan ) );
return FALSE;
}
}
#undef types
return TRUE;
}
void do_allegiance( char_data* ch, char* argument )
{
char_data* victim;
player_data* pc;
clan_data* clan;
title_data* title;
if( is_mob( ch ) )
return;
pc = player( ch );
clan = ch->pcdata->pfile->clan;
if( *argument == '\0' ) {
if( clan == NULL ) {
send( ch, "Swear allegiance to whom?\n\r" );
}
else {
fsend( ch, "You have sworn allegiance to %s.\n\r", name( clan ) );
send( ch, "Switch your allegiance to whom?\n\r" );
}
return;
}
if( !strcasecmp( argument, "none" ) ) {
if( clan == NULL ) {
send( ch, "You have sworn allegiance to noone already.\n\r" );
}
else {
fsend( ch, "You revoke your allegiance to %s.\n\r", name( clan ) );
remove_member( pc );
remove_member( pc->pcdata->pfile );
}
return;
}
if( clan != NULL ) {
fsend( ch, "You must first revoke your allegiance to %s.", name( clan ) );
return;
}
if( ( victim = one_player( ch, argument, "swear allegiance to",
ch->array ) ) == NULL )
return;
if( ch == victim ) {
send( ch, "Allegiance to yourself is assumed.\n\r" );
return;
}
clan = victim->pcdata->pfile->clan;
if( clan == NULL || ( !knows_members( ch, clan )
&& !victim->Befriended( ch ) ) ) {
send( ch, "They are not a member of any clan.\n\r" );
return;
}
if( !can_join( ch, clan ) )
return;
if( !consenting( victim, ch ) ) {
fsend( ch, "Swearing allegiance to %s, who has not consented to\
you joining %s clan is pointless.", victim, victim->His_Her( ) );
return;
}
title = get_title( victim->pcdata->pfile );
if( title == NULL
|| !is_set( title->flags, TITLE_RECRUIT ) ) {
send( ch, "%s is not permitted to recruit members.\n\r", victim );
return;
}
add_member( clan, ch->pcdata->pfile );
save_clans( clan );
fsend( ch, "You kneel down and swear allegiance to %s.", name( clan ) );
fsend( *victim->array,
"%s kneels down and swears allegiance to %s.", ch, name( clan ) );
return;
}
/*
* INTERNAL ROUTINES
*/
bool good_clan_name( char_data* ch, char* name )
{
int i;
if( strlen( name ) != 4 ) {
send( ch,
"Clan abbreviation must be exactly 4 letters.\n\r" );
return FALSE;
}
for( i = 0; i < 4; i++ )
if( !isalpha( name[i] ) ) {
send( ch, "The clan name may only contain letters.\n\r" );
return FALSE;
}
for( i = 0; i < max_clan; i++ )
if( !strncasecmp( name, clan_list[i]->name, 4 ) ) {
send( ch, "There is already a clan using that abbreviation.\n\r" );
return FALSE;
}
return TRUE;
}
title_data* get_title( pfile_data* pfile )
{
clan_data* clan = pfile->clan;
int i;
if( clan == NULL )
return NULL;
for( i = 0; i < clan->titles.size; i++ )
if( clan->titles.list[i]->pfile == pfile )
return clan->titles.list[i];
return NULL;
}
/*
* ADDING/REMOVING MEMBERS
*/
void add_member( clan_data* clan, pfile_data* pfile )
{
if( pfile->clan != NULL ) {
bug( "Add_Member: Character is already in a clan." );
return;
}
clan->members += pfile;
pfile->clan = clan;
}
void remove_member( player_data* player )
{
if( player->noteboard == NOTE_CLAN )
player->noteboard = NOTE_GENERAL;
if( player->note_edit != NULL
&& player->note_edit->noteboard == NOTE_CLAN )
player->note_edit = NULL;
return;
}
void remove_member( pfile_data* pfile )
{
clan_data* clan;
int i;
if( ( clan = pfile->clan ) == NULL )
return;
clan->members -= pfile;
for( i = 0; i < clan->titles.size; i++ )
if( clan->titles.list[i]->pfile == pfile )
clan->titles.list[i]->pfile = NULL;
pfile->clan = NULL;
if( is_empty( clan->members ) ) {
extract( clan );
return;
}
save_clans( clan );
return;
}
void extract( clan_data* clan )
{
player_data* pc;
int i;
for( i = 0; i < max_clan; i++ )
if( clan_list[i] == clan )
break;
if( i == max_clan ) {
bug( "Extract( Clan ): Non-existent clan!?" );
return;
}
remove( clan_list, max_clan, i );
for( i = 0; i < player_list; i++ ) {
pc = player_list[i];
if( pc->Is_Valid( )
&& pc->pcdata->pfile->clan == clan )
remove_member( pc );
}
for( i = 0; i < clan->members; i ++ )
clan->members[i]->clan = NULL;
delete_file( CLAN_DIR, clan->abbrev );
delete_file( CLAN_NOTE_DIR, clan->abbrev );
delete clan;
}
void expell( char_data* ch, clan_data* clan, pfile_data* pfile )
{
char* tmp = static_string( );
player_data* pc;
if( pfile->clan != clan ) {
send( ch, "%s already isn't in your clan.\n\r", pfile->name );
return;
}
if( ch->pcdata->pfile == pfile ) {
send( ch, "You can't expell yourself - use allegiance none.\n\r" );
return;
}
for( int i = 0; i < player_list; i++ ) {
pc = player_list[i];
if( pc->Is_Valid( )
&& pc->pcdata->pfile == pfile ) {
send( pc, ">> %s has expelled you from your clan. <<\n\r", ch );
remove_member( pc );
break;
}
}
remove_member( pfile );
send( ch, "%s expelled.\n\r", pfile->name );
sprintf( tmp, "%s has been expelled from the clan by %s.",
pfile->name, ch->descr->name );
info( tmp, 1, tmp, IFLAG_CLANS, 3, ch, clan );
return;
}
/*
* DISK ROUTINES
*/
void rename_clan( clan_data* clan, char* new_name )
{
rename_file( CLAN_DIR, clan->abbrev, CLAN_DIR, new_name );
rename_file( CLAN_NOTE_DIR, clan->abbrev, CLAN_NOTE_DIR, new_name );
free_string( clan->abbrev, MEM_CLAN );
clan->abbrev = alloc_string( new_name, MEM_CLAN );
return;
}
void save_clans( clan_data* clan )
{
FILE* fp;
pfile_data* pfile;
title_array* titles;
if( clan == NULL ) {
for( int i = 0; i < max_clan; i++ )
save_clans( clan_list[i] );
return;
}
clan->modified = FALSE;
if( ( fp = open_file( CLAN_DIR, clan->abbrev, "w" ) ) == NULL )
return;
fprintf( fp, "#CLAN\n\n" );
fprintf( fp, "%s~\n", clan->name );
fprintf( fp, "%s~\n", clan->charter );
fprintf( fp, "%d %d\n", clan->flags[0], clan->flags[1] );
fprintf( fp, "%d %d %d %d %d\n",
clan->min_level, clan->races, clan->classes,
clan->alignments, clan->sexes );
fprintf( fp, "%d\n", clan->date );
titles = &clan->titles;
fprintf( fp, "%d %d\n\n", titles->size, clan->members.size );
for( int i = 0; i < titles->size; i++ ) {
pfile = titles->list[i]->pfile;
fprintf( fp, "%s~\n", titles->list[i]->name );
fprintf( fp, "%d %d %d\n", pfile == NULL ? -1 : pfile->ident,
titles->list[i]->flags[0], titles->list[i]->flags[1] );
}
for( int i = 0; i < clan->members; i++ )
fprintf( fp, "%d\n", clan->members[i]->ident );
fclose( fp );
}
void load_clans( void )
{
FILE* fp;
DIR* dirp;
struct dirent* dp;
clan_data* clan;
title_array* titles;
pfile_data* pfile;
int i;
int length;
echo( "Loading Clans ...\n\r" );
clan_list = NULL;
max_clan = 0;
dirp = opendir( CLAN_DIR );
for( dp = readdir( dirp ); dp != NULL; dp = readdir( dirp ) ) {
if( !strcmp( dp->d_name, "." ) || !strcmp( dp->d_name, ".." ) )
continue;
fp = open_file( CLAN_DIR, dp->d_name, "r" );
if( strcmp( fread_word( fp ), "#CLAN" ) )
panic( "Load_Clans: Missing header." );
clan = new clan_data( dp->d_name );
clan->name = fread_string( fp, MEM_CLAN );
clan->charter = fread_string( fp, MEM_CLAN );
clan->flags[0] = fread_number( fp );
clan->flags[1] = fread_number( fp );
clan->min_level = fread_number( fp );
clan->races = fread_number( fp );
clan->classes = fread_number( fp );
clan->alignments = fread_number( fp );
clan->sexes = fread_number( fp );
clan->date = fread_number( fp );
titles = &clan->titles;
titles->size = fread_number( fp );
titles->list = new title_data* [ titles->size ];
length = fread_number( fp );
for( i = 0; i < titles->size; i++ ) {
titles->list[i] = new title_data;
titles->list[i]->name = fread_string( fp, MEM_CLAN );
titles->list[i]->pfile = get_pfile( fread_number( fp ) );
titles->list[i]->flags[0] = fread_number( fp );
titles->list[i]->flags[1] = fread_number( fp );
}
for( i = 0; i < length; i++ )
if( ( pfile = get_pfile( fread_number( fp ) ) ) != NULL )
add_member( clan, pfile );
fclose( fp );
load_notes( clan );
}
closedir( dirp );
}
/*
* DISPLAY ROUTINES
*/
void display( char_data* ch, clan_data* clan )
{
char tmp [ 3*MAX_STRING_LENGTH ];
pfile_data* pfile;
int i, j;
page( ch, scroll_line[0] );
page_centered( ch, name( clan ) );
page( ch, scroll_line[0] );
page( ch, "\n\r" );
if( knows_members( ch, clan ) ) {
page_title( ch, "Leaders" );
for( i = 0; i < clan->titles.size; i++ ) {
pfile = clan->titles.list[i]->pfile;
page( ch, "%38s :: %s\n\r", clan->titles.list[i]->name,
pfile == NULL ? "Noone" : pfile->name );
}
page( ch, "\n\r" );
page_title( ch, "Members" );
for( i = j = 0; i < clan->members.size; i++ )
page( ch, "%18s%s", clan->members.list[i]->name,
(j++)%4 != 3 ? "" : "\n\r" );
page( ch, "\n\r%s", j%4 != 0 ? "\n\r" : "" );
}
page_title( ch, "Charter" );
convert_to_ansi( ch, clan->charter, tmp );
page( ch, tmp );
}