tfe-1.0/area/
tfe-1.0/files/
tfe-1.0/logs/
tfe-1.0/logs/immortal/
tfe-1.0/logs/mob/
tfe-1.0/logs/object/
tfe-1.0/logs/player/
tfe-1.0/logs/room/
tfe-1.0/notes/clans/
tfe-1.0/player/
tfe-1.0/prev/
tfe-1.0/prev/area/
tfe-1.0/prev/player/
tfe-1.0/prev/rooms/
tfe-1.0/rooms/
tfe-1.0/src-gc/
tfe-1.0/src-msvc/
tfe-1.0/src-unix/
tfe-1.0/www/
tfe-1.0/www/html/
#include "define.h"
#include "struct.h"


#define RECOG_INTRODUCE       16
#define RECOG_RECOGNIZE       17
#define RECOG_BEFRIEND        18
#define RECOG_FILTER          19
#define RECOG_CONSENT         20


bool in_character = TRUE;


/*
 *   CLASS KNOWN_DATA
 */


Recognize_Data :: Recognize_Data( int i )
{
  record_new( sizeof( recognize_data ), MEM_RECOGNIZE );
  record_new( i*sizeof( int ), -MEM_RECOGNIZE );

  size = i;
  list = new int[i];
};


Recognize_Data :: ~Recognize_Data( )
{
  record_delete( sizeof( recognize_data ), MEM_RECOGNIZE );
  record_delete( size*sizeof( int ), -MEM_RECOGNIZE );

  delete [] list;
};


/*
 *   LOCAL FUNCTIONS
 */


bool  display               ( char_data*, int, const char* );
bool  is_recognize_set      ( recognize_data*, int, int );
bool  remove_recognize_bit  ( recognize_data*&, int, int );
void  set_recognize_bit     ( char_data*, int, int );

void  sort                  ( recognize_data* );
void  insert                ( recognize_data*&, int, int );


/*
 *   SEARCH ROUTINES
 */


void sort( recognize_data* recognize )
{
  int*   list;
  int    size;
  int       i;
  bool  found;

  if( recognize == NULL )
    return;

  list = recognize->list;
  size = recognize->size;

  found = TRUE;
  for( ; found; ) { 
    found = FALSE;
    for( i = 0; i < size-1; i++ ) {
      if( ( list[i] & 0xffff ) > ( list[i+1] & 0xffff ) ) {
        swap( list[i], list[i+1] );
        found = TRUE;
        }
      }
    }
}


void insert( recognize_data*& recognize, int value, int pos )
{
  if( recognize == NULL ) {
    recognize = new recognize_data( 1 );
    recognize->list[0] = value;
    return;
    }

  insert( recognize->list, recognize->size, value, pos );
  record_new( sizeof( int ), -MEM_RECOGNIZE );
}


void remove( recognize_data*& recognize, int pos )
{
  if( pos < 0 )
    return;

  record_delete( sizeof( int ), -MEM_RECOGNIZE );

  if( recognize->size == 1 ) {
    delete recognize;   
    recognize = NULL;
    return;
    }

  remove( recognize->list, recognize->size, pos );
}  


int search( recognize_data* recognize, int ident )
{
  int element;
  int min; 
  int max;
  int value;

  if( recognize == NULL )
    return -1;

  min = 0;
  max = recognize->size-1;

  for( ; ; ) {
    if( max < min )
      return -min-1;

    element  = (max+min)/2;
    value    = ( recognize->list[element] & 0xffff );

    if( ident == value )
      break;

    if( ident > value )
      min = element+1;
    else 
      max = element-1;
    }

  return element;
}

  
/*
 *   ALTERING KNOWLEDGE ROUTINES
 */


bool is_recognize_set( recognize_data* recognize, int ident, int bit )
{
  int pos;

  pos = search( recognize, ident );

  return( pos >= 0 && IS_SET( recognize->list[pos], bit ) );
}


bool remove_recognize_bit( recognize_data*& recognize, int ident, int bit )
{
  int pos;

  pos = search( recognize, ident );
 
  if( pos >= 0 && is_set( &recognize->list[pos], bit ) ) {
    remove_bit( &recognize->list[pos], bit );
    if( ( recognize->list[pos] & 0xffff0000 ) == 0 )
      remove( recognize, pos );
    return TRUE;
    }

  return FALSE;
} 


void set_recognize_bit( char_data* ch, int ident, int bit )
{
  recognize_data*  recognize  = ch->pcdata->recognize;
  int                    pos; 
    
  pos = search( recognize, ident );

  if( pos >= 0 ) {
    set_bit( &recognize->list[pos], bit );
    return;
    }

  set_bit( &ident, bit );
  insert( ch->pcdata->recognize, ident, -pos-1 );

  return;
} 


/*
 *   LOGIN ROUTINE
 */


void reconcile_recognize( char_data* ch )
{
  recognize_data*    recog_ch;
  recognize_data*  recog_vict;
  player_data*         victim;
  int                  pos_ch;
  int                pos_vict;
  int                 flag_ch;
  int               flag_vict;
  int                       i;

  if( ( recog_ch = ch->pcdata->recognize ) != NULL ) {
    for( i = recog_ch->size-1; i >= 0; i-- ) 
      if( get_pfile( recog_ch->list[i] & 0xffff ) == NULL ) 
        remove( recog_ch, i );
    sort( recog_ch );
    }

  for( i = 0; i < player_list; i++ ) {
    victim = player_list[i];

    if( !victim->Is_Valid( ) || victim == ch )
      continue;

    recog_vict  = victim->pcdata->recognize;
    pos_ch      = search( recog_ch, victim->pcdata->pfile->ident );
    pos_vict    = search( recog_vict, ch->pcdata->pfile->ident );

    flag_ch     = ( pos_ch >= 0 ? recog_ch->list[pos_ch] : 0 );
    flag_vict   = ( pos_vict >= 0 ? recog_vict->list[pos_vict] : 0 );

    if( ( is_set( &flag_ch, RECOG_RECOGNIZE )
      != is_set( &flag_vict, RECOG_INTRODUCE ) )
      || ( is_set( &flag_vict, RECOG_RECOGNIZE )
      != is_set( &flag_ch, RECOG_INTRODUCE ) ) ) {
      remove( recog_ch, pos_ch );
      remove( victim->pcdata->recognize, pos_vict );
      }
    }

  ch->pcdata->recognize = recog_ch;
}


/*
 *   DISPLAY LIST WITH BIT SET
 */


bool display( char_data* ch, int bit, const char* title )
{
  recognize_data*  recognize  = ch->pcdata->recognize;
  pfile_data*          pfile;
  int                   i, j;
  bool                 found  = FALSE;

  if( recognize == NULL )
    return FALSE;

  for( i = j = 0; i < recognize->size; i++ ) {
    if( ( pfile = get_pfile( recognize->list[i] & 0xffff ) ) == NULL
      || !is_set( &recognize->list[i], bit ) )
      continue;
    if( !found ) { 
      page( ch, "%s:\r\n", title );
      found = TRUE;
      }
    page( ch, "%17s%s", pfile->name, ++j%4 == 0 ? "\r\n" : "" );
    }  

  if( j%4 != 0 )
    page( ch, "\r\n" );
  
  return found;
}


pfile_data* remove_name( recognize_data*& recognize, char* name, int bit )
{
  pfile_data* pfile;

  if( ( pfile = find_pfile( name ) ) != NULL
    && remove_recognize_bit( recognize, pfile->ident, bit ) )
    return pfile;

  return NULL;
}


/*
 *   INTRODUCTION FUNCTIONS
 */


bool char_data :: Recognizes( char_data *victim )
{
  if( pcdata == NULL )
    return FALSE;

  if( victim->species != NULL ) {
    if( victim->descr == victim->species->descr || victim->leader != this
      || victim->descr->singular[0] == '\0' )
      return FALSE;
    return TRUE;
    }

  if( victim == this || shdata->level >= LEVEL_APPRENTICE
    || victim->shdata->level >= LEVEL_APPRENTICE ) 
    return TRUE;

  return is_recognize_set( pcdata->recognize,
    victim->pcdata->pfile->ident, RECOG_RECOGNIZE );
}


void do_introduce( char_data *ch, char *argument )
{
  char_data*  victim;

  if( is_confused_pet( ch ) ) 
    return;

  if( *argument == '\0' ) {
    send( ch, "Who do you want to introduce yourself to?\r\n" );
    return;
    }

  if( ( victim = one_character( ch, argument, "introduce",
    ch->array ) ) == NULL )
    return;

  if( ch == victim ) {
    send( ch, "You unfortunately already recognize yourself.\r\n" );
    return;
    }

  if( victim->fighting != NULL ) {
    send( ch,
      "They are too busy fighting for you to introduce yourself.\r\n" );
    return;
    }

  if( victim->position < POS_RESTING ) {
    send( ch, "They aren't in a good state for introductions.\r\n" );
    return;
    }

  if( victim->species != NULL ) {
    send( ch, "Introducing yourself to npcs will do nothing useful.\r\n" );
    return;
    }

  if( !associate( ch, victim ) ) 
    return;

  if( victim->Recognizes( ch ) ) {
    send( ch, "%s already recognizes you.\r\n", victim );
    return;
    }

  if( !ch->Seen( victim ) ) {
    send( ch, "%s cannot see you.\r\n", victim );
    return;
    }

  if( !can_talk( ch, "introduce yourself" ) ) 
    return;

  leave_shadows( ch );
  leave_camouflage( ch );

  if( skill_language( victim, ch->pcdata->speaking ) == 0 ) {
    fsend( ch, "You attempt to introduce yourself to %s, but %s\
 does not seem to understand a word you are saying.\r\n",
      victim, victim->He_She( ) );
    return;
    }

  fsend( ch, "You introduce yourself to %s.\r\n", victim );
  fsend( victim, "%s greets you and introduces %sself as '%s'.\r\n",
    ch, ch->Him_Her( ), ch->descr->name );
  fsend_seen( ch, "%s introduces %sself to %s.\r\n",
    ch, ch->Him_Her( ), victim );

  set_recognize_bit( victim, ch->pcdata->pfile->ident, RECOG_RECOGNIZE ); 
  set_recognize_bit( ch, victim->pcdata->pfile->ident, RECOG_INTRODUCE );
}


/*
 *   BEFRIEND FUNCTIONS
 */


bool Char_Data :: Befriended( pfile_data* pfile )
{
  if( pcdata == NULL )
    return FALSE; 

  return is_recognize_set( pcdata->recognize,
    pfile->ident, RECOG_BEFRIEND );
}


bool Char_Data :: Befriended( char_data* ch )
{
  if( pcdata == NULL || ch->pcdata == NULL )
    return FALSE;
 
  return is_recognize_set( pcdata->recognize,
    ch->pcdata->pfile->ident, RECOG_BEFRIEND );
}


void do_befriend( char_data* ch, char* argument )
{
  char                   tmp  [ MAX_INPUT_LENGTH ];
  char_data*          victim;
  pfile_data*          pfile;
 
  if( is_confused_pet( ch ) ) 
    return;

  if( argument[0] == '\0' ) {
    if( !display( ch, RECOG_BEFRIEND, "Befriend List" ) )
      send( "You have befriended no one.\r\n", ch );
    return;
    }

  if( ( pfile = remove_name( ch->pcdata->recognize, argument,
    RECOG_BEFRIEND ) ) != NULL ) {
    sprintf( tmp, "You no longer consider %s a friend.\r\n", pfile->name );
    send( tmp, ch );
    return; 
    }
        
  if( ( victim = one_character( ch, argument, "befriend",
    ch->array ) ) == NULL )
    return;

  if( ch == victim ) {
    send( ch, "Befriending yourself is a waste of time.\r\n" );
    return;
    }

  if( IS_NPC( victim ) ) {
    send( ch, "Befriending npcs will do nothing useful.\r\n" );
    return;
    }

  if( !ch->Recognizes( victim ) ) {
    fsend( ch, "You cannot befriend %s without first knowing %s name.",
      victim, victim->His_Her( ) );
    return;
    }

  if( !victim->Recognizes( ch ) ) {
    fsend( ch, 
      "You cannot befriend %s until you have introduced yourself to %s.",
      victim, victim->Him_Her( ) );
    return;
    }

  if( ch->Befriended( victim ) ) {
    send( ch, "You already think %s is your friend.\r\n", victim );
    return;
    }

  send( ch, "You now consider %s a friend.\r\n", victim );

  set_recognize_bit( ch, victim->pcdata->pfile->ident, RECOG_BEFRIEND );

  return;
}


/*
 *   IGNORE ROUTINES
 */


bool Char_Data :: Ignoring( char_data* victim )
{
  if( pcdata == NULL || victim->pcdata == NULL 
    || victim->shdata->level >= LEVEL_APPRENTICE )
    return FALSE;

  if( !is_set( pcdata->pfile->flags, PLR_APPROVED ) 
    && has_permission( victim, PERM_APPROVE ) )
    return FALSE;

  int level = level_setting( &pcdata->pfile->settings, SET_IGNORE );

  switch( level ) {
    case 0 : return FALSE;
    case 1 : return !victim->Recognizes( this );
    case 2 : return !Befriended( victim );
    }

  return TRUE;
}


bool Char_Data :: Filtering( char_data *victim )
{
  if( this == NULL || pcdata == NULL || victim->pcdata == NULL )
    return FALSE;

  return is_recognize_set( pcdata->recognize,
    victim->pcdata->pfile->ident, RECOG_FILTER );
}


void do_filter( char_data* ch, char* argument )
{
  char_data*      victim;
  pfile_data*      pfile;

  if( is_confused_pet( ch ) )
    return;

  if( *argument == '\0' ) {
    if( !display( ch, RECOG_FILTER, "Filter List" ) ) 
      send( ch, "You are filtering noone.\r\n" );
    return;
    }

  if( ( pfile = remove_name( ch->pcdata->recognize,
    argument, RECOG_FILTER ) ) != NULL ) {
    send( ch, "You will no longer filter %s.\r\n", pfile->name );
    return;
    }

  in_character = FALSE;

  if( ( victim = one_player( ch, argument, "filter",
    (thing_array*) &player_list ) ) == NULL ) 
    return;

  if( victim == ch ) {
    send( ch, 
      "Ignoring yourself might be wise, but it is also pointless.\r\n" );
    }
  else if( victim->shdata->level >= LEVEL_APPRENTICE ) {
    send( ch, "You may not filter immortals.\r\n" );
    }
  else if( ch->Filtering( victim ) ) {
    send( ch, "You are already filtering them.\r\n" );
    }
  else {
    set_recognize_bit( ch, victim->pcdata->pfile->ident, RECOG_FILTER );
    send( ch, "You are now filtering %s.\r\n", victim );
    }
}


/*
 *    ROUTINES
 */


bool consenting( char_data* victim, char_data* ch, const char* word )
{
  if( ch == victim || ch->shdata->level >= LEVEL_APPRENTICE )
    return TRUE;

  if( ch->pcdata != NULL && victim->pcdata != NULL
    && is_recognize_set( victim->pcdata->recognize,
    ch->pcdata->pfile->ident, RECOG_CONSENT ) )
    return TRUE;

  if( word != empty_string ) {
    fsend( ch, "Since %s does not automatically consent to your actions\
 the %s fails.", victim, word );
    send( victim, "You automatically disrupt %s.\r\n", word );
    } 

  return FALSE;
}


void do_consent( char_data* ch, char* argument )
{
  char_data*          victim;
  pfile_data*          pfile;

  if( is_confused_pet( ch ) )
    return;

  if( *argument == '\0' ) {
    if( !display( ch, RECOG_CONSENT, "Consent List" ) ) 
      send( ch, "You have consented noone.\r\n" );
    return;
    }

  if( ( pfile = remove_name( ch->pcdata->recognize,
    argument, RECOG_CONSENT ) ) != NULL ) {
    send( ch, "You no longer automatically consent %s.\r\n", pfile->name );
    return;
    }

  if( ( victim = one_player( ch, argument, "consent",
    ch->array, (thing_array*) &player_list ) ) == NULL )
    return;

  if( victim == ch ) {
    send( ch, "That you agree with your own actions is assumed.\r\n" );
    return;
    }

  if( !ch->Recognizes( victim ) ) {
    send( ch, "You may only consent someone whom you recognize.\r\n" );
    return;
    } 

  if( victim->pcdata == NULL ) {
    send( ch, "Consent only matters with players.\r\n" );
    return;
    }

  if( consenting( ch, victim ) ) {
    send( ch, "%s is already listed for automatic consent.\r\n", victim );
    return;
    }

  set_recognize_bit( ch, victim->pcdata->pfile->ident, RECOG_CONSENT );

  send( ch, "You now automatically consent to the actions of %s.\r\n",
    victim );
}