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


bool        can_die         ( char_data* );
void        death_cry       ( char_data* );
obj_data*   make_corpse     ( char_data*, content_array* );
void        raw_kill        ( char_data* );
void        loot_corpse     ( obj_data*, char_data*, char_data* );
void        register_death  ( char_data*, char_data*, char* );


/*
 *   HAS LIVE-SAVING?
 */ 


bool can_die( char_data* victim )
{
  obj_data*    obj;
  room_data*  room;

  if( victim->species != NULL )
    return TRUE;

  if( ( room = Room( victim->array->where ) ) != NULL
    && is_set( &room->room_flags, RFLAG_ARENA ) ) {
    send( *victim->array, "In a flash of light %s disappears.\n\r", victim );
    victim->hit = 1;
    update_pos( victim );
    victim->From( );
    victim->To( get_temple( victim ) );
    dismount( victim );
    victim->position = POS_RESTING;
    return FALSE;
    }  

  if( victim->shdata->level >= LEVEL_BUILDER ) {
    fsend_seen( victim, "The body of %s slowly fades out of existence.",
      victim );
    fsend( *victim->array,
      "A swirling mist appears and %s slowly reforms.", victim );
    send( victim, "You find yourself alive again.\n\r" );
    victim->hit = victim->max_hit;
    update_max_move( victim );
    update_pos( victim );
    return FALSE;
    }   

  for( int i = 0 ; ; i++ ) {
    if( i >= victim->affected ) {
      for( int j = 0; ; j++ ) {
        if( j >= victim->wearing )
          return TRUE;
        obj = (obj_data*) victim->wearing[j];
        if( is_set( obj->pIndexData->affect_flags, AFF_LIFE_SAVING ) )
          break;
        }
      fsend( *victim->array,
        "%s that %s was wearing starts to glow a deep purple!",
        obj, victim );
      fsend_seen( victim, "The body of %s slowly disappears!", victim );
      obj->Extract( 1 ); 
      break;
      } 
    if( victim->affected[i]->type == AFF_LIFE_SAVING
      && number_range( 0, 100 ) > 60-2*victim->affected[i]->level ) {
      send_seen( victim,
        "%s disappears in an explosion of light and energy.\n\r", victim );
      break;
      }
    }  

  victim->From( );

  remove_affect( victim );
  remove_leech( victim );

  rejuvenate( victim );

  victim->To( get_temple( victim ) );
  dismount( victim );
  victim->position = POS_RESTING;

  send_seen( victim, "%s slowly materializes.\n\rFrom %s appearance\
 %s obviously came close to death.\n\r",
    victim, victim->His_Her( ), victim->He_She( ) );
  send( victim, "You wake up confused and dazed, but seem alive despite\
 your memories.\n\r" );

  return FALSE;
}


bool die_forever( char_data* ch )
{
  if( ch->Type( ) == MOB_DATA ) 
    return TRUE;

  return FALSE;
}


/*
 *   DEATH HANDLER
 */


void death( char_data* victim, char_data* ch, char* dt )
{
  char               tmp  [ TWO_LINES ];
  obj_data*       corpse;
  content_array*   where  = victim->array;
  char_data*         rch;
  bool           survive;
 
  remove_bit( &victim->status, STAT_BERSERK );

  if( ch == NULL ) 
    for( int i = 0; i < *where; i++ ) 
      if( ( rch = character( where->list[i] ) ) != NULL 
        && includes( rch->aggressive, victim ) ) {
        ch = rch;
        break;
        }

  stop_fight( victim );
  clear_queue( victim );

  if( !can_die( victim ) )
    return;
 
  disburse_exp( victim );
  register_death( victim, ch, dt );

  clear_queue( victim );
  death_cry( victim );

  if( survive = !die_forever( victim ) )
    raw_kill( victim );

  corpse = make_corpse( victim, where );
  loot_corpse( corpse, ch, victim );

  if( survive ) 
    return;

  if( mob( victim ) != NULL ) {
    victim->Extract( );
    return;
    }

  sprintf( tmp, "%s's soul is taken by death.", victim->Name( ) );
  info( tmp, LEVEL_BUILDER, tmp, IFLAG_DEATHS, 1, victim );

  clear_screen( victim );
  reset_screen( victim );

  send( victim, "Death is surprisingly peaceful.\n\r" );
  send( victim, "Good night.\n\r" );

  purge( player( victim ) );
}


void raw_kill( char_data* victim )
{
  affect_data    affect;
 
  victim->From( );

  remove_affect( victim );
  remove_leech( victim );

  victim->position  = POS_RESTING;
  victim->hit       = max( 1, victim->hit  );
  victim->mana      = max( 1, victim->mana );
  victim->move      = max( 1, victim->move );

  affect.type      = AFF_DEATH;
  affect.duration  = 20;
  affect.level     = 10;
  affect.leech     = NULL;

  add_affect( victim, &affect );
  delete_list( victim->prepare );
  update_maxes( victim );

  victim->To( get_room_index( ROOM_DEATH, FALSE ) );

  dismount( victim );
  clear_enemies( victim );

  write( player( victim ) );
}


void register_death( char_data* victim, char_data* ch, char* dt )
{
  char          tmp1  [ TWO_LINES ];
  char          tmp2  [ TWO_LINES ];
  mprog_data*  mprog;
  int            exp;

  if( victim->species != NULL ) {
    if( is_set( &victim->status, STAT_PET ) && victim->leader != NULL
      && victim->leader->pcdata != NULL ) {
      sprintf( tmp1, "%s killed by %s at %s. (Pet)",
        victim->Name( ), ch == NULL ? dt : ch->Name( ),
        victim->array->where->Location( ) );
      player_log( victim->leader, tmp1 );
      }
    for( mprog = victim->species->mprog; mprog != NULL;
      mprog = mprog->next ) 
      if( mprog->trigger == MPROG_TRIGGER_DEATH ) {
        var_mob  = victim;
        var_ch   = ch;
        var_room = Room( victim->array->where );
        execute( mprog );
        }
    return;
    }

  sprintf( tmp1, "%s killed by %s.", victim->Name( ),
    ch == NULL ? dt : ch->Name( ) );
  sprintf( tmp2, "%s killed by %s at %s.", victim->Name( ),
    ch == NULL ? dt : ch->Name( ), victim->array->where->Location( ) );
  info( tmp1, LEVEL_APPRENTICE, tmp2, IFLAG_DEATHS, 1, victim );

  exp = death_exp( victim, ch );
  add_exp( victim, -exp, "You lose %d exp for dying.\n\r" );

  sprintf( tmp1, "Killed by %s at %s.",
    ch == NULL ? dt : ch->real_name( ), victim->array->where->Location( ) );
  player_log( victim, tmp1 );
      
  if( ch != NULL && ch->pcdata != NULL ) {
    sprintf( tmp1, "Pkilled %s at %s.",
      victim->real_name( ), victim->array->where->Location( ) );
    player_log( ch, tmp1 );
    }
}


/* 
 *   DEATH CRY
 */


void death_message( char_data* victim )
{
  char          tmp1  [ ONE_LINE ];
  char          tmp2  [ ONE_LINE ];
  char_data*     rch;
  const char*   name;

  for( int i = 0; i < *victim->array; i++ ) {
    if( ( rch = character( victim->array->list[i] ) ) == NULL
      || rch->link == NULL || rch == victim || !victim->Seen( rch ) ) 
      continue;
    name = victim->Name( rch );
    send( rch, bold_red_v( rch ) );
    if( victim->species != NULL
      && is_set( &victim->species->act_flags, ACT_MELT ) ) {
      sprintf( tmp1, "  +-- %%%ds --+\n\r", strlen( name )+11 );
      sprintf( tmp2, tmp1, "" );
      sprintf( tmp1, "      %s SHATTERS!!\n\r", name );
      }
    else {
      sprintf( tmp1, "  +-- %%%ds --+\n\r", strlen( name )+10 );
      sprintf( tmp2, tmp1, "" );
      sprintf( tmp1, "      %s is DEAD!!\n\r", name );
      }
    tmp1[6] = toupper( tmp1[6] );
    send( rch, tmp2 );
    send( rch, tmp1 );
    send( rch, tmp2 );        
    send( rch, normal( rch ) );
    }

  send( victim, "You have been KILLED!!\n\r" );
}


void death_cry( char_data* ch )
{
  room_data*  room;
  char*        msg;
 
  if( ( room = Room( ch->array->where ) ) == NULL )
    return;

  msg = ch->species ? "You hear something's death cry.\n\r"
    : "You hear someone's death cry.\n\r";

  for( int i = 0; i < room->exits; i++ ) 
    send( room->exits[i]->to_room->contents, msg );

  if( is_set( &ch->status, STAT_FAMILIAR ) && ch->leader != NULL )  
    send( ch->leader, "You sense your familiars death!\n\r" );
}


/*
 *   CORPSE ROUTINES
 */


const char* fragments_msg =
  "The fragments from %s quickly melt, leaving %s %s.";   


obj_data* make_corpse( char_data* ch, content_array* where )
{
  obj_data*          corpse;
  obj_data*             obj;
  obj_clss_data*   obj_clss;
  thing_data*         thing;

  /* GHOSTS */

  if( ch->species != NULL && is_set( &ch->species->act_flags, ACT_GHOST ) ) {
    for( int i = ch->wearing-1; i >= 0; i-- ) {
      thing = ch->wearing[i]->From( ch->wearing[i]->number );
      thing->To( &ch->contents ); 
      }
    send_publ( ch, &ch->contents, "fades out of existence", "dropping" );
    for( int i = ch->contents.size-1; i >= 0; i-- ) {
      thing = ch->contents[i]->From( ch->contents[i]->number );
      thing->To( where );
      }
    return NULL;
    }

  /*
  if( ch->species != NULL && is_set( &ch->species->act_flags, ACT_MELT ) ) {
    if( ( obj = ch->contents ) == NULL ) {
      fsend_room( room, fragments_msg, ch, "nothing", "behind" );
      }
    else if( obj->next_content == NULL ) {
      fsend_room( room, fragments_msg, ch, obj,
        "lying on the ground" );
      }
    else {
      fsend_room( room, fragments_msg, ch, "several items",
        "on the ground" );
      }
    for( ; obj != NULL; obj = ch->contents ) {
      obj = remove( obj, obj->number );
      put_obj( obj, room );
      }
    return NULL;
    }
  */

  /* CREATE CORPSE */

  if( ch->species != NULL ) {
    if( ( obj_clss = get_obj_index( ch->species->corpse ) ) == NULL ) 
      return NULL;
    corpse = create( obj_clss );
    if( obj_clss->item_type == ITEM_CORPSE )
      corpse->value[1] = ch->species->vnum;
    }
  else {
    corpse           = create( get_obj_index( OBJ_CORPSE_PC ) );
    corpse->value[1] = ch->pcdata->pfile->ident;
    }

  /* WEIGHT */

  if( corpse->pIndexData->item_type == ITEM_CORPSE
    && corpse->pIndexData->weight == 0 )
    corpse->weight = ch->Empty_Weight( );

  /* NAME CORPSE */ 

  if( !strncmp( corpse->pIndexData->singular, "corpse of", 9 ) ) {
    char* tmp = static_string( );

    if( ch->descr->name != empty_string ) {
      sprintf( tmp, "corpse of %s", ch->descr->name );
      corpse->singular = alloc_string( tmp, MEM_OBJECT );
      sprintf( tmp, "%s corpses", ch->descr->name );
      corpse->plural = alloc_string( tmp, MEM_OBJECT );
      }
    else {
      sprintf( tmp, "corpse of %s", ch->Name( NULL ) );
      corpse->singular = alloc_string( tmp, MEM_OBJECT );
      sprintf( tmp, "%s corpses", seperate( ch->descr->singular, TRUE ) );
      corpse->plural = alloc_string( tmp, MEM_OBJECT );
      }
    }
 
  /* TRANSFER ITEMS TO CORPSE */

  for( int i = ch->wearing-1; i >= 0; i-- ) {
    if( ch->species != NULL || number_range( 0,10 ) == 0 ) {
      obj = (obj_data*) ch->wearing[i];
      obj->From( obj->number );
      obj->To( corpse );
      }
    }

  for( int i = ch->contents-1; i >= 0; i-- ) {
    if( ( obj = object( ch->contents[i] ) ) != NULL
      && ( ch->species != NULL || number_range( 0,10 ) == 0 ) ) {
      obj = (obj_data*) obj->From( obj->number );
      obj->To( corpse );
      }
    }

  corpse->To( where );

  return corpse;
}


void loot_corpse( obj_data* corpse, char_data* ch, char_data* victim )
{
  if( ch == NULL || ch->pcdata == NULL
    || victim->species == NULL || corpse == NULL ) 
    return;

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

  if( level == 0 )
    return;

  if( level == 1 ) {
    send_priv( ch, &corpse->contents, "contains", corpse ); 
    return;
    }

  /*
  for( obj = corpse->contents; obj != NULL; obj = next ) {
    next = obj->next_content;
    if( obj->pIndexData->item_type == ITEM_MONEY ) {
      for( i = 0; i < MAX_COIN; i++ )
        if( obj->pIndexData->vnum == coin_vnum[i] )
          amount += obj->number*coin_value[i];
      }
    else {
      if( !is_set( ch->pcdata->pfile->flags, PLR_AUTO_LOOT ) ) 
        continue;
      }
    obj->next_list = get;
    get            = obj;
    obj->selected  = obj->number;
    }

  get_obj( ch, get, corpse );

  if( is_set( ch->pcdata->pfile->flags, PLR_AUTO_SPLIT ) ) 
    split_money( ch, amount, FALSE );
  */
}


/*
 *   SLAY ROUTINE
 */


void do_slay( char_data* ch, char* argument )
{
  char_data*  victim;
    
  if( ch->shdata->level < LEVEL_BUILDER ) {
    send( ch, "To prevent abuse you are unable to use slay in\
 mortal form.\n\r" );
    return;
    }

  if( *argument == '\0' ) {
    send( ch, "Slay whom?\n\r" );
    return;
    }

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

  if( ch == victim ) {
    send( ch, "Suicide is a mortal sin.\n\r" );
    return;
    }
    
  if( victim->species == NULL
    && ( get_trust( victim ) >= get_trust( ch )
    || !has_permission( ch, PERM_PLAYERS ) ) ) {
    send( ch, "You failed.\n\r" );
    return;
    }

  send( ch, "You slay %s in cold blood!\n\r", victim );
  send( victim, "%s slays you in cold blood!\n\r", ch );
  send( *ch->array, "%s slays %s in cold blood!\n\r", ch, victim );

  make_corpse( victim, ch->array );

  if( victim->species == NULL ) 
    raw_kill( victim );
  else
    victim->Extract( );
}


/*
 *   EXTRACTION ROUTINES
 */


void dereference( char_data* wch, char_data* ch )
{
  player_data*   pc;
  wizard_data*  imm;

  if( !wch->Is_Valid( ) )
    return;

  if( wch->cast != NULL && wch->cast->target == ch ) 
    disrupt_spell( wch );

  wch->seen_by  -= ch;
  wch->known_by -= ch;

  if( wch->reply == ch ) {
    if( is_set( &wch->status, STAT_REPLY_LOCK ) ) {
      send( wch, "%s has quit - reply lock removed.\n\r", ch );
      remove_bit( &wch->status, STAT_REPLY_LOCK );
      }
    wch->reply = NULL;
    }

  if( ( imm = wizard( wch ) ) != NULL
    && imm->player_edit == ch ) {
    send( imm, "The player you were editing just quit.\n\r" );
    imm->player_edit = NULL;
    }

  if( ( pc = player( wch ) ) != NULL
    && pc->familiar == ch )
    pc->familiar = NULL;
} 


void Char_Data :: Extract( )
{
  affect_data*    affect;
  char_data*         wch;
  obj_array*       array;
  mob_data*          npc;
  player_data*        pc;
  wizard_data*       imm;

  /* REMOVE WORLD REFERENCES */

  if( !Is_Valid( ) ) {
    roach( "Extract Char: Extracting invalid character." ); 
    return;
    }

  if( species != NULL ) {
    if( link != NULL ) 
      do_return( this, "" );
    unregister_reset( this );
    }

  if( link != NULL ) {
    link->character = NULL;
    link->player    = NULL;
    link            = NULL;
    }

  if( this->array != NULL )
    From( );

  clear_queue( this );

  if( ( pc = player( this ) ) != NULL ) {
    remove( request_app, pc );
    remove( request_imm, pc );
    }

  /* CLEAR EVENTS */

  stop_events( this );
  unlink( &active );
  active.time = -1;

  /* EXTRACT OBJECTS */

  if( ( pc = player( this ) ) != NULL ) {
    array = &pc->save_list;
    for( int i = 0; i < array->size; i++ )
      if( array->list[i] != NULL )
        array->list[i]->save = NULL;
    clear( *array );
    extract( pc->locker );
    extract( pc->junked );
    }

  extract( contents );
  extract( wearing );

  /* REMOVE FOLLOWERS */

  if( leader != NULL ) {
    if( ( pc = player( leader ) ) != NULL 
      && pc->familiar == this )
      pc->familiar = NULL;
    leader->followers -= this;
    leader = NULL;
    }

  for( int i = 0; i < followers; i++ ) {
    wch         = followers[i];
    wch->leader = NULL;
    if( wch->species != NULL && is_set( &wch->status, STAT_PET ) ) {
      send_seen( wch,
        "%s goes into limbo and awaits %s master's return.\n\r",
        wch, wch->His_Her( ) );
      wch->Extract( );
      }
    }

  clear( followers );
  
  /* REMOVE REFERENCES ON OTHER PLAYERS */

  for( int i = 0; i < player_list; i++ ) 
    dereference( player_list[i], this );

  for( int i = 0; i < mob_list; i++ ) 
    dereference( mob_list[i], this );

  if( mount != NULL ) {
    mount->rider = NULL;
    mount = NULL;
    }

  if( rider != NULL ) {
    rider->mount = NULL;
    rider = NULL;
    }

  /*
   *   FREE MEMORY
   */

  remove_leech( this );

  for( int i = 0; i < affected; i++ ) {
    affect = affected[i]; 
    if( affect->leech != NULL )
      fsend( affect->leech, "Leech for %s on %s dissipated.",
        aff_char_table[affect->type].name, descr->name );
    remove_leech( affect );
    }
  clear( affected );

  extract( enemy );
  delete_list( prepare );

  clear( cmd_queue );
  clear( known_by );
  clear( seen_by );
  clear( seen_exits );

  if( species == NULL || descr != species->descr ) 
    delete descr;

  if( ( pc = player( this ) ) != NULL ) {
    delete_list( pc->alias );
    delete_list( pc->tell );
    delete_list( pc->gtell );
    delete_list( pc->ctell );
    delete_list( pc->whisper );
    delete_list( pc->chat );
    delete_list( pc->gossip );
    delete_list( pc->say );
    delete_list( pc->yell );
    delete_list( pc->shout );
    delete_list( pc->atalk );
    delete_list( pc->to );
    delete_list( pc->chant );
    }

  if( ( imm = wizard( this ) ) != NULL ) {
    delete_list( imm->build_chan );
    delete_list( imm->imm_talk   );
    delete_list( imm->god_talk   );
    delete_list( imm->avatar     );

    free_string( imm->bamfin,       MEM_WIZARD );
    free_string( imm->bamfout,      MEM_WIZARD );
    free_string( imm->level_title,  MEM_WIZARD );
    }

  if( ( npc = mob( this ) ) != NULL ) { 
    if( npc->pTrainer != NULL ) 
      npc->pTrainer->mob = NULL;
    free_string( npc->pet_name, MEM_MOBS );
    }

  if( pcdata != NULL ) {
    free_string( pcdata->title,        MEM_PLAYER );
    free_string( pcdata->buffer,       MEM_PLAYER ); 
    free_string( pcdata->tmp_short,    MEM_PLAYER );
    free_string( pcdata->tmp_keywords, MEM_PLAYER );
    free_string( pcdata->prompt,       MEM_PLAYER );

    delete pcdata->recognize; 
    delete pcdata;
    delete shdata;
    }

  pcdata   = NULL;
  shdata   = NULL;
  descr    = NULL;
  species  = NULL;
  position = POS_EXTRACTED;
  pShop    = NULL;
  reset    = NULL;
  valid    = -1;

  extracted += this;
}