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 <sys/types.h>
#include <stdio.h>
#include <syslog.h>
#include "define.h"
#include "struct.h"


bool  trigger_attack    ( char_data*, char_data* );
void  end_berserk       ( char_data* );


/* 
 *   CAN_KILL ROUTINES
 */


bool in_sanctuary( char_data* ch, bool msg )
{    
  room_data* room  = Room( ch->array->where ); 

  if( room != NULL && is_set( &room->room_flags, RFLAG_SAFE ) ) {
    if( msg ) 
      send( ch, "You are in a sanctuary.\n\r" );
    return TRUE;
    }

  return FALSE;
}


bool can_pkill( char_data* ch, char_data* victim, bool msg )
{
  room_data* room  = Room( ch->array->where ); 

  if( room != NULL ) {
    if( is_set( &room->room_flags, RFLAG_ARENA ) )
      return TRUE;
    if( is_set( &room->room_flags, RFLAG_NO_PKILL ) ) {
      if( msg )
        send( ch, "You can't kill players here.\n\r" );
      return FALSE; 
      }
    }

  if( victim == NULL )
    return TRUE;

  if( ch->shdata->race <= RACE_LIZARD 
    && victim->shdata->race <= RACE_LIZARD ) {
    if( msg ) {
      const char* race = plyr_race_table[ victim->shdata->race ].name; 
      send( ch, "You would never kill a%s %s.\n\r",
        isvowel( *race ) ? "n" : "", race );
      }
    return FALSE;
    }

  return TRUE;
}


bool can_kill( char_data* ch, char_data* victim, bool msg )
{
  program_data*   program;

  if( ch->fighting == victim || victim->fighting == ch )
    return TRUE;
  
  if( ( msg && !trigger_attack( ch, victim ) )
    || in_sanctuary( ch ) )
    return FALSE; 

  if( is_set( victim->affected_by, AFF_SANCTUARY ) ) {
    send( ch, "You cannot attack this particular mob.\n\r" );
    return FALSE;
    }

  if( victim->species != NULL
    && ( program = victim->species->attack ) == NULL ) {
    compile( program );
    if( program->binary == NULL ) {
      if( msg ) {
        send( ch,
          "That mob has no attack program - please contact a god.\n\r" );
        bug( "No attack prog: %d.", victim->species->vnum );
        }
      return FALSE;
      } 
    }  

  if( ch->pcdata == NULL ) {
    if( ch->leader == NULL || !is_set( &ch->status, STAT_PET ) )
      return TRUE;
    ch = ch->leader;
    }

  if( ch->shdata->level >= LEVEL_APPRENTICE )
    return TRUE;

  if( victim->pcdata != NULL
    && !can_pkill( ch, victim, msg ) ) 
    return FALSE;

  if( victim->species != NULL && victim->leader != NULL 
    && is_set( &victim->status, STAT_PET ) ) {
    if( ch == victim->leader ) {
      if( msg )
        fsend( ch, "You may not attack your own pet.", victim );
      return FALSE;
      }
    if( !can_pkill( ch, victim->leader, FALSE ) ) {
      if( msg ) 
        fsend( ch, "%s belongs to another player and attacking it is\
 forbidden.\n\r", victim );
      return FALSE;
      }
    }

  if( victim->shdata->level >= LEVEL_APPRENTICE ) {
    send( ch, "Attacking an immortal would be sure death.\n\r" );
    return FALSE;
    }

  return TRUE;
}


bool trigger_attack( char_data* ch, char_data* victim )
{
  action_data*  action;
  mprog_data*    mprog;

  if( IS_NPC( victim ) ) {
    for( mprog = victim->species->mprog; mprog != NULL; mprog = mprog->next )
      if( mprog->trigger == MPROG_TRIGGER_ATTACK ) {
        var_ch = ch;
        var_mob = victim; 
        var_room = ch->in_room;
        if( !execute( mprog ) || ch->in_room == NULL
          || ch->in_room != victim->in_room )   
          return FALSE;
        }
    }

  for( action = ch->in_room->action; action != NULL; action = action->next )
    if( action->trigger == TRIGGER_ATTACK ) {
      var_ch = ch;
      var_victim = victim; 
      var_room = ch->in_room;
      if( !execute( action ) || ch->in_room == NULL
        || ch->in_room != victim->in_room )
        return FALSE;
      }

  return TRUE;
}


/*
 *   AGGRESSIVE ROUTINES
 */


bool is_aggressive( char_data* ch, char_data* victim )
{
  char_data* opponent;

  if( ch == victim || ch->position <= POS_SLEEPING )
    return FALSE;

  if( ( opponent = victim->fighting ) != NULL )
    if( join_fight( opponent, victim, ch ) )
      return TRUE;

  if(  ch->pcdata != NULL
    || is_set( &victim->in_room->room_flags, RFLAG_SAFE )
    || !victim->Seen( ch ) )
    return FALSE;

  if( ch->shdata->race == RACE_PLANT
    && is_set( victim->affected_by, AFF_PROT_PLANTS ) )
    return FALSE;

  if( is_evil( victim ) )
    if( is_set( &ch->status, STAT_AGGR_EVIL )
      && is_set( ch->affected_by, AFF_DETECT_EVIL ) ) 
      return TRUE;
  else if( is_good( victim ) )
    if( is_set( &ch->status, STAT_AGGR_GOOD )
      && is_set( ch->affected_by, AFF_DETECT_GOOD ) ) 
      return TRUE;

  if( is_set( &ch->status, STAT_PET ) )
    return FALSE;

  if( victim->species == NULL ) {
    if( victim->shdata->level >= LEVEL_BUILDER )
      return FALSE;
    if( is_set( &ch->status, STAT_AGGR_ALL )
      || is_enemy( ch, victim ) )
      return TRUE;
    }

  return FALSE;
}


bool join_fight( char_data* victim, char_data* ch, char_data* rch )
{
  if( rch == ch )
    return FALSE;

  if( rch == victim )
    return TRUE;

  if( rch->pcdata != NULL ) {
    if( is_set( rch->pcdata->pfile->flags, PLR_AUTO_ASSIST ) 
      && is_same_group( rch, victim ) && !is_same_group( rch, ch )
      && can_kill( rch, ch ) )
      return TRUE;
    return FALSE;
    }
 
  if( is_set( &rch->status, STAT_PET ) ) {
    if( rch->leader == victim && ( victim->pcdata == NULL
      || is_set( victim->pcdata->pfile->flags, PLR_PET_ASSIST ) ) )
      return TRUE;
    return FALSE;
    }

  if( rch->species != NULL && victim->species != NULL 
    && is_set( &rch->species->act_flags, ACT_ASSIST_GROUP )
    && !is_set( &victim->status, STAT_PET ) ) {
    if( victim->species->nation != NATION_NONE
      && rch->species->nation == victim->species->nation )
      return TRUE;
    if( victim->species->group != GROUP_NONE
      && victim->species->group == rch->species->group )
      return TRUE;
    }

  return FALSE;
}  
 

/*
 *   START/STOP FIGHT ROUTINES
 */


void renter_combat( char_data* ch )
{ 
  char_data*  rch;

  for( int i = 0; i < *ch->array; i++ ) {
    if( ( rch = character( ch->array->list[i] ) ) == NULL 
      || rch == ch )
      continue;
 
    if( is_aggressive( ch, rch ) ) 
      ch->aggressive += rch;
    }
 
  init_attack( ch );
}


void init_attack( char_data* ch, char_data* victim )
{
  event_data* event;

  if( victim != NULL )
    ch->aggressive += victim;

  if( ch->active.time != -1 ) 
    return;

  for( int i = 0; i < ch->events.size; i++ )
    if( ch->events[i]->func == execute_leap )
      return;

  if( victim == NULL ) {
    if( is_empty( ch->aggressive ) )
      return;
    victim = ch->aggressive[0];
    }

  event          = new event_data( execute_leap, ch );
  event->pointer = (void*) victim; 

  add_queue( event, 20 );
}


void react_attack( char_data* ch, char_data* victim )
{
  char_data*     rch;

  if( victim->leader == ch )
    stop_follower( victim );

  if( ch->leader == victim )
    stop_follower( ch );

  init_attack( victim, ch );

  for( int i = 0; i < *ch->array; i++ ) {
    if( ( rch = character( ch->array->list[i] ) ) != NULL ) {
      if( join_fight( victim, ch, rch ) )
        init_attack( rch, ch );
      else if( join_fight( ch, victim, rch ) )
        init_attack( rch, victim );
      }
    }
}


void stop_fight( char_data* ch )
{
  char_data*     rch;

  remove_bit( &ch->status, STAT_BERSERK );

  ch->fighting = NULL;
  disrupt_spell( ch );
  clear( ch->aggressive );
  stop_events( ch, execute_leap );

  for( int i = 0; i < *ch->array; i++ ) {
    if( ( rch = character( ch->array->list[i] ) ) == NULL )
      continue;

    if( rch->cast != NULL && rch->cast->target == ch
      && spell_table[rch->cast->spell].type != STYPE_WORLD ) 
      disrupt_spell( rch );

    rch->aggressive -= ch;

    if( rch->fighting == ch ) 
      rch->fighting = NULL;

    for( int j = rch->events-1; j >= 0; j-- )
      if( rch->events[j]->pointer == (void*) ch ) {
        extract( rch->events[j] );
        init_attack( rch );
        }
    }
}