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"


/*
 *   LOCAL FUNCTIONS
 */


const char*   get_attack     ( char_data*, obj_data* );

bool    absorb_armor      ( char_data*, char_data*, const char*, int&,
                            const char*& );
bool    absorb_bracers    ( char_data*, char_data*, int&, int, const char* );
bool    absorb_shield     ( char_data*, char_data*, const char*, int& ); 
bool    can_defend        ( char_data*, char_data* );
bool    block_shield      ( char_data*, char_data*, const char* );
void    damage_modifiers  ( char_data*, char_data*, obj_data*, int& );
bool    damage_weapon     ( char_data*, obj_data*& );
bool    dodge             ( char_data*, char_data*, int& );
bool    tumble            ( char_data*, char_data*, int& );
bool    fire_shield       ( char_data*, char_data* );
bool    thorn_shield      ( char_data*, char_data* );
bool    ion_shield        ( char_data*, char_data* );
bool    flaming_weapon    ( char_data*, char_data*, obj_data* );
bool    misses_blindly    ( char_data*, char_data*, int&, const char* );
bool    parry             ( char_data*, char_data*, int& );
bool    counter_attack    ( char_data*, char_data*, int& );
bool    guard             ( char_data*, char_data*, int& );
bool    shadow_dance      ( char_data*, char_data*, const char* );
bool    switch_victim     ( char_data*, char_data* );
bool    trip              ( char_data*, char_data*, obj_data* );
int     damage_armor      ( char_data*, int );
int     backstab_damage   ( char_data* );
int     charge_damage     ( char_data* );
void    act_spam_notvict  ( char*, char_data*, obj_data*, char_data* );
void    confused_char     ( char_data* );
void    critical_hit      ( char_data*, char_data*, obj_data*, int& );
bool    is_blocked        ( char_data*, char_data*, obj_data*, char* );
void    leap_message      ( char_data*, char_data* );
void    modify_roll       ( char_data*, char_data*, obj_data*, int& );
void    power_strike      ( char_data*, char_data*, obj_data*, int& );
void    stun              ( char_data*, char_data*, const char* );
void    trigger_hit       ( char_data*, char_data*, obj_data* );
void    player_multi      ( char_data*, char_data* );
void    barkskin          ( char_data*, int& );
void    invulnerable      ( char_data*, int& );
void    protgood          ( char_data*, char_data*, int& );
void    protevil          ( char_data*, char_data*, int& );


/*
 *   LOCAL CONSTANTS
 */


const char* dam_loc_name [] = { "light", "finger", "finger", "neck", "neck",
  "body", "head", "leg", "feet", "hand", "arm", "shield", "about",
  "waist", "left wrist", "right wrist", "wield", "hold" };

const char* weapon_attack [MAX_WEAPON] = { "punch", "pierce", "slash",
  "bash", "swing", "slash", "pound", "whip", "chop", "missile weapon",
  "pierce" };


/*
 *   EXTERNAL SUPPORT ROUTINES
 */



int initiative( char_data* )
{
  return number_range( 5,30 );
}


int response( char_data* )
{
  return number_range( 5,30 );
}


char_data* opponent( char_data* ch )
{
  char_data* rch;

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

  for( int i = 0; i < *ch->array; i++ ) 
    if( ( rch = character( ch->array->list[i] ) ) != NULL 
      && rch->fighting == ch )
      return rch;

  return NULL;
} 


char_data* has_enemy( char_data* ch )
{
  char_data* rch;

  if( ch->fighting != NULL )
    return ch->fighting;

  for( int i = 0; i < *ch->array; i++ ) 
    if( ( rch = character( ch->array->list[i] ) ) != NULL 
      && rch->position > POS_SLEEPING 
      && includes( rch->aggressive, ch ) )
      return rch;

  if( ch->cast != NULL
    && spell_table[ ch->cast->spell ].type == STYPE_OFFENSIVE )
    return (char_data*) ch->cast->target;

  return NULL;
}
 

/*
 *   TOP LEVEL ROUND HANDLER
 */


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

  if( victim->fighting == ch ) {
    send( ch, "You counterattack %s!!\r\n", victim );

    if( ch->Seen( victim ) )
      send( victim, "%s%s counterattacks you!!%s\r\n",
        bold_v( victim ), ch, normal( victim ) );

    for( int i = 0; i < *victim->array; i++ ) 
      if( ( rch = character( victim->array->list[i] ) ) != NULL 
        && rch != victim && rch != ch && ch->Seen( rch )
        && rch->link != NULL ) 
        send( rch, "%s%s counterattacks %s!!%s\r\n",
          damage_color( rch, ch, victim ), ch, victim, normal( rch ) );
    }
  else {
    send( ch, "You leap to attack %s!!\r\n", victim );
    if( ch->Seen( victim ) )
      send( victim, "%s%s leaps to attack you!!%s\r\n",
        bold_v( victim ), ch, normal( victim ) );

    for( int i = 0; i < *victim->array; i++ ) 
      if( ( rch = character( victim->array->list[i] ) ) != NULL 
        && rch != victim && rch != ch && ch->Seen( rch )
        && rch->link != NULL ) 
        send( rch, "%s%s leaps to attack %s!!%s\r\n",
          damage_color( rch, ch, victim ), ch, victim, normal( rch ) );
    }
}


bool jump_feet( char_data* ch )
{
  if( ch->position != POS_RESTING && ch->position != POS_MEDITATING ) 
    return FALSE;

  send( ch, "You quickly jump to your feet.\r\n" );
  send_seen( ch, "%s jumps to %s feet.\r\n",
    ch, ch->His_Her( ) );

  ch->position = POS_STANDING;

  return TRUE;
} 


/*
 *   PLAYER FIGHT ROUTINES
 */


int player_round( char_data* ch, char_data* victim )
{
  int attack_skills [] = { SKILL_SECOND, SKILL_THIRD,
    SKILL_FOURTH, SKILL_FIFTH, SKILL_OFFHAND_ATTACK };

  obj_data*      wield  = NULL;
  obj_data*  secondary  = NULL;
  obj_data*     shield  = NULL;
  obj_data*       left;
  obj_data*      right;
  int            skill;
  int             rate;
  int           weight;
  int                i;

  if( is_set( ch->pcdata->pfile->flags, PLR_PARRY ) )
    return 25;

  if( ( left = ch->Wearing( WEAR_HELD_L ) ) != NULL ) {
    if( left->pIndexData->item_type == ITEM_WEAPON )
      secondary = left;
    else if( left->pIndexData->item_type == ITEM_ARMOR )
      shield = left;
    }

  if( ( right = ch->Wearing( WEAR_HELD_R ) ) != NULL ) { 
    if( right->pIndexData->item_type == ITEM_WEAPON )
      wield = right;
    else if( right->pIndexData->item_type == ITEM_ARMOR )
      shield = right;
    }

  if( wield == NULL
    || ( number_range( 0,2 ) == 0 && secondary != NULL ) )
    wield = secondary;

  if( wield != NULL ) {
    i      = ( shield == NULL && secondary == NULL ? 3 : 2 );
    weight = max( 0, wield->Weight( 1 )-10*i*ch->Strength( ) ) ;
    skill  = WEAPON_FIRST+wield->value[3];
    }
  else {
    weight = 0;
    skill  = WEAPON_UNARMED;
    }

  if( ( i = number_range( -1, 4 ) ) == -1 )
    ch->improve_skill( skill );
  else
    ch->improve_skill( attack_skills[i] );

  attack( ch, victim, get_attack( ch, wield ), wield, -1, ATT_PHYSICAL );

  skill = ch->shdata->skill[ skill ];
  rate  = 0;  

  for( i = 0; i < ( secondary == NULL ? 3 : 4 ); i++ )
    rate += ch->shdata->skill[ attack_skills[i] ]; 

  rate = 10+rate/2;
  rate = (320+weight/5-5*skill-5*ch->Dexterity( ))/rate;
  rate = number_range( rate/2, 3*rate/2 );
  
  return rate;
}


/*
 *   SPECIES FIGHT ROUTINES
 */


int mob_round( char_data* ch, char_data* victim )
{
  ch->shown     = 1;
  victim->shown = 1;

  if( switch_victim( ch, victim ) )
    return 16;

  var_mob    = ch;
  var_room   = ch->in_room;
  var_ch     = victim;
  var_victim = victim;

  execute( ch->species->attack );

  return 32;
}


bool switch_victim( char_data* ch, char_data* victim )
{
  char_data* rch;

  if( victim->pcdata == NULL
    || !is_set( victim->pcdata->pfile->flags, PLR_PARRY ) 
    || number_range( 0, 4 ) != 0 )
    return FALSE;

  for( int i = 0; ; i++ ) { 
    if( i >= *ch->array )
      return FALSE;
    if( ( rch = character( ch->array->list[i] ) ) != NULL 
      && rch != victim && rch->fighting == ch ) 
      break;
    }

  ch->fighting = rch;

  fsend( victim, "%s stops attacking you and leaps to attack %s.", ch, rch );
  fsend( rch, "%s stops attacking %s and leaps to attack you.", ch, victim );
  fsend_seen( ch, "%s stops attacking %s and leaps to attack %s.",
    ch, victim, rch );

  return TRUE;
}


void add_round( species_data* species, int delay )
{
  if( number_range( 0,32 ) > delay )
    return;

  if( species->exp > 1e8 || species->rounds++ > 1e8 
    || species->damage > 1e8 || species->damage_taken > 1e8 ) {
    species->rounds          /= 2;
    species->damage          /= 2;
    species->damage_taken    /= 2;
    species->shdata->deaths  /= 2;
    species->shdata->kills   /= 2;
    species->exp             /= 2;
    species->special         /= 2;
    }
}


/*
 *   DAMAGE AND ATTACK NAME ROUTINES
 */


const char* get_attack( char_data* ch, obj_data* wield )
{
  int skill [] = { SKILL_DEMON_SLASH, SKILL_DRAGON_STRIKE, SKILL_EAGLE_CLAW,
    SKILL_BEAR_GRASP, SKILL_LOCUST_KICK, SKILL_TIGER_PAW };

  int  weapon;
  int       i;

  weapon = ( wield == NULL ? 0 : wield->value[3] );

  if( ch->species != NULL || weapon != 0 ) 
    return weapon_attack[weapon];

  if( ch->shdata->skill[ SKILL_TIGER_PAW ] != 0 ) 
    for( i = 0; i < 6; i++ ) {  
      if( number_range( 0, 63-9*i ) < ch->shdata->skill[ skill[i] ] ) {
        ch->improve_skill( skill[i] );
        return skill_table[ skill[i] ].name;
        }
      }

  if( wield == NULL && ch->shdata->race == RACE_LIZARD
    && ch->Wearing( WEAR_HANDS ) == NULL )
    return "claw";

  return "punch";
}


int get_damage( char_data* ch, obj_data* wield, char letter )
{
  int damage;

  if( wield != NULL ) {
    damage  = roll_dice( wield->value[1], wield->value[2] );
    }
  else {
    damage = roll_dice( 1, letter == 'c' ? 6 : 4 );
    }

  if( ch->species == NULL && ( wield == NULL || wield->value[3] == 0 ) ) {
    damage += ch->shdata->skill[SKILL_PUNCH]/3;
    switch( letter ) {
      case 't' : damage = roll_dice( 2, 6  );      break;
      case 'l' : damage = roll_dice( 2, 8  );      break;
      case 'b' : damage = roll_dice( 2, 10 );      break;
      case 'e' : damage = roll_dice( 2, 12 );      break;
      case 'd' : damage = roll_dice( 2, 14 );      break;
      case '*' : damage = roll_dice( 2, 16 );      break;
      }   
    }

  return damage;
}


void damage_modifiers( char_data* ch, char_data* victim, obj_data* wield,
  int& damage )
{

  damage += (int) ch->Damroll( wield );
  
  if( ch->move > 0 && is_set( &ch->status, STAT_BERSERK ) ) {
    ch->move--;
    damage += 2+ch->shdata->skill[ SKILL_BERSERK ]/3;
    if( number_range( 1, 4 ) == 4 ) {
      if( ch->shdata->skill[ SKILL_FRENZY ] > 0 ) {
        ch->improve_skill( SKILL_FRENZY );
        damage += ch->shdata->skill[ SKILL_FRENZY ]/2;
        send( ch, "You attack with FRENZY!!\r\n" );
        send_seen( ch, "%s attacks with FRENZY!!\r\n",
          ch );
        }
      }
    }
  
  if( victim->position == POS_RESTING )
    damage = 3*damage/2;
  else if( victim->position <= POS_SLEEPING )
    damage *= 4;

  return;
}


float char_data :: Hitroll( obj_data* obj )
{
  float x;

  x = hitroll+float( Dexterity( ) )/3-3; 

  if( species == NULL
    && shdata->skill[SKILL_BLIND_FIGHTING] > 0 ) {
     x = x + 1+ float( shdata->skill[SKILL_BLIND_FIGHTING])/3 ;
     improve_skill( SKILL_BLIND_FIGHTING );
    }

  if( obj == NULL || obj->pIndexData->item_type != ITEM_WEAPON )
    return x;

  if( obj->value[3] == WEAPON_AXE-WEAPON_UNARMED 
    && is_set( affected_by, AFF_AXE_PROF ) )
    x++;

  if( obj->value[3] == WEAPON_SWORD-WEAPON_UNARMED 
    && is_set( affected_by, AFF_SWORD_PROF ) )
    x++;

  x += obj->value[0];

  return x;
}


float char_data :: Damroll( obj_data* obj )
{
  float x;

  x = damroll+float( Strength( ) )/3-4;

  if( obj == NULL || obj->pIndexData->item_type != ITEM_WEAPON )
    return x;

  if( obj->value[3] == WEAPON_AXE-WEAPON_UNARMED 
    && is_set( affected_by, AFF_AXE_PROF ) )
    x++;

  if( obj->value[3] == WEAPON_SWORD-WEAPON_UNARMED 
    && is_set( affected_by, AFF_SWORD_PROF ) )
    x++;

  x += obj->value[0];

  return x;
}


/*
 *   MAIN BATTLE ROUTINES
 */


bool attack( char_data* ch, char_data* victim, const char* dt,
  obj_data* wield, int damage, int modifier, int type )
{
  int              roll;
  bool           active;
  bool         backstab;
  bool           charge;
  const char*  loc_name;

  if( ch->position < POS_FIGHTING )
    return FALSE;

  roll  = number_range( -250, 250 );
  roll += modifier;

  modify_roll( ch, victim, wield, roll );

  active   = can_defend( victim, ch );
  backstab = !strcmp( dt, "backstab" );
  charge = !strcmp( dt, "charge" );

  if( ( !backstab && !charge ) && type == ATT_PHYSICAL
    && misses_blindly( ch, victim, roll, dt ) )
    return FALSE;

  if( active && dodge( ch, victim, roll ) )
    return FALSE;

  if( active && tumble( ch, victim, roll ) )
    return FALSE;

  if( type == ATT_PHYSICAL ) {
    if( fire_shield( ch, victim )
    || ( ion_shield( ch, victim ) ) 
    || ( thorn_shield( ch, victim ) )  )
      return FALSE;

    if( damage_weapon( ch, wield )
      || ( active && !backstab && !charge && ( parry( ch, victim, roll ) 
      || ( active && !backstab && !charge && ( guard( ch, victim, roll )
      || block_shield( ch, victim, dt )
      || trip( ch, victim, wield ) ) ) ) ) )
      return FALSE;
    }

  if( active && ( !backstab && !charge  )
    && shadow_dance( ch, victim, dt ) )
    return FALSE;

  if( damage == -1 ) {
    damage = get_damage( ch, wield, dt[0] );
    if( backstab )
      damage *= backstab_damage( ch );
    if( charge )
      damage *= charge_damage(ch);
    }

  damage_modifiers( ch, victim, wield, damage );
  damage = max( 1, damage );

  if( victim->species != NULL && victim->hit > 0
    && !is_set( &victim->status, STAT_PET ) )
    victim->species->damage_taken += min( victim->hit, damage );
  if( ch->species != NULL )
    ch->species->damage += damage/2;

  switch( type ) {
    case ATT_PHYSICAL:
      critical_hit( ch, victim, wield, damage );
      power_strike( ch, victim, wield, damage );
      barkskin( victim, damage );
      invulnerable( victim, damage );
      protgood( victim, ch, damage );
      protevil( victim, ch, damage );
      if( absorb_shield( victim, ch, dt, damage )
        || absorb_armor( victim, ch, dt, damage, loc_name ) )
        return FALSE; 
      dam_local( victim, ch, damage, dt, loc_name );
      if( !inflict( victim, ch, damage, "" ) 
        && !flaming_weapon( ch, victim, wield ) ) { 
        stun( ch, victim, dt ); 
        trigger_hit( ch, victim, wield );
        }
      break;

    case ATT_ACID:
      damage_acid( victim, ch, damage, dt );
      break;

    case ATT_COLD:
      damage_cold( victim, ch, damage, dt );
      break;

    case ATT_SHOCK:
      damage_shock( victim, ch, damage, dt );
      break;

    case ATT_FIRE:
      damage_fire( victim, ch, damage, dt );
      break;

    default:
      bug( "Attack: Impossible attack type." );
      break;
    }

  if( ch->species != NULL )
    ch->species->damage -= damage/2;
  
  return( damage > 0 );
}


void modify_roll( char_data* ch, char_data* victim, obj_data* wield,
  int& roll )
{
  int weapon = ( wield == NULL ?  0 : wield->value[3] );

  roll -= victim->mod_armor;
  roll += ch->shdata->level + 5 * (int) ch->Hitroll( wield );
  roll += ( ch->species == NULL
    ? 8*ch->get_skill( WEAPON_UNARMED+weapon ) : 80 );

  if( victim->position != POS_FIGHTING )
    roll += 50;
 
  if( victim->position <= POS_SLEEPING )
    roll += 100;

  return;
}


bool can_defend( char_data* victim, char_data* ch )
{
  if(  victim->position < POS_FIGHTING
    || is_set( victim->affected_by, AFF_ENTANGLED )
    || !ch->Seen( victim ) )
    return FALSE;

  return TRUE;
}


/*
 *   WEAPON ROUTINES
 */


bool damage_weapon( char_data* ch, obj_data*& wield )
{
  if( wield == NULL
    || number_range( 0, 15-4*wield->rust ) > (!is_set( wield->extra_flags, OFLAG_SANCT ) ? 0 : 1)
    || number_range( 1,4+wield->value[0] ) > 4
    || --wield->condition > 0 )
    return FALSE;

  send( ch, "%s you are wielding shatters into pieces.\r\n", wield );
  send_seen( ch, "%s which %s is wielding shatters into pieces.\r\n",
    wield, ch );

  wield->Extract( );
  wield = NULL;

  return TRUE;
}


void trigger_hit( char_data* ch, char_data* victim, obj_data* wield )
{
  oprog_data* oprog;

  if( wield == NULL || ch->fighting != victim )
    return;

  for( oprog = wield->pIndexData->oprog; oprog != NULL;
    oprog = oprog->next ) {
    if( oprog->trigger == OPROG_TRIGGER_HIT ) { 
      var_ch     = ch;
      var_victim = victim;
      var_obj    = wield;    
      var_room   = ch->in_room;
      execute( oprog );
      }
    }

  return;
}


bool flaming_weapon( char_data*, char_data*, obj_data* wield )
{
  if( wield == NULL || !is_set( wield->extra_flags, OFLAG_FLAMING ) )
    return FALSE;

  return FALSE;
}


/* 
 *   ARMOR ROUTINES
 */


bool absorb_armor( char_data* victim, char_data* ch, const char* dt,
  int& damage, const char*& loc_name )
{
  char      tmp  [ TWO_LINES ];
  int      roll;
  int  absorbed;
  int         i;
  int       loc;

  roll = number_range( 0, 1000 );

  if( victim->species == NULL
    || is_set( &victim->species->act_flags, ACT_HUMANOID ) ) {

         if( roll < 450 )  loc = WEAR_BODY;
    else if( roll < 600 )  loc = WEAR_HEAD;
    else if( roll < 700 )  loc = WEAR_LEGS;
    else if( roll < 750 )  loc = WEAR_FEET;
    else if( roll < 850 )  loc = WEAR_HANDS;
    else if( roll < 990 )  loc = WEAR_ARMS;
    else if( roll < 1000 ) loc = WEAR_FINGER_L;
    else                   loc = WEAR_FINGER_R;

    absorbed  = damage_armor( victim, loc );
    damage   -= absorbed;

    if( damage <= 0 ) {
      send( victim, "Your %s armor absorbs %s's %s.\r\n",
        dam_loc_name[loc], ch->Name( victim ), dt );
      send( ch, "%s's %s armor absorbs your %s.\r\n",
        victim->Name( ch ), dam_loc_name[loc], dt );
      send( *ch->array, "%s's %s armor absorbs %s's %s.\r\n",
        victim, dam_loc_name[loc], ch, dt );
      return TRUE;
      }

    if( absorb_bracers( victim, ch, damage, absorbed, dt ) )
      return TRUE;

    loc_name = dam_loc_name[loc];

    return FALSE;
    }
    
  for( i = 0; i < MAX_ARMOR-1; i++ ) 
    if( roll < victim->species->chance[i] )
       break;

  damage -= number_range( 0, victim->species->armor[i] );

  if( damage > 0 ) {
    loc_name = victim->species->part_name[i];
    return FALSE;
    }

  if( *victim->species->part_name[i] != '\0' ) {
    sprintf( tmp, "Your %s absorbs %s's attack.\r\n",
      victim->species->part_name[i], ch->Name( victim ) );
    spam_char( victim, tmp );
    sprintf( tmp, "You %s %s's %s inflicting no damage.\r\n",
      dt, victim->Name( ch ), victim->species->part_name[i] );
    spam_char( ch, tmp );
    sprintf( tmp, "%%s's %s absorbs %%s's %s.\r\n",
      victim->species->part_name[i], dt );
    spam_room( tmp, victim, ch );
    }
  else {
    spam_char( victim, "Your armor absorbs %s's attack.\r\n", ch );
    sprintf( tmp, "You %s %s inflicting no damage.\r\n",
      dt, victim->Name( ch ) );
    spam_char( ch, tmp );
    spam_room( "%s's armor absorbs %s's attack.\r\n", victim, ch );
    }

  return TRUE;
}


int damage_armor( char_data* ch, int loc )
{
  obj_data*     armor;
  int        absorbed  = 0;

  for( int i = ch->wearing-1; i >= 0; i-- ) {
    if( ( armor = object( ch->wearing[i] ) ) != NULL
      && armor->position == loc ) {
      if( armor->pIndexData->item_type == ITEM_ARMOR )
        absorbed += number_range( 0, armor_class( armor ) );
      if( number_range( 0, 15-4*armor->rust ) <= (!is_set( armor->extra_flags, OFLAG_SANCT ) ? 0 : 1)
        && number_range( 1,4+armor->value[0] ) <= 4
        && --armor->condition < 0 ) {
        send( ch, "%s you are wearing shatters into pieces.\r\n", armor );
        send_seen( ch, "%s which %s is wearing shatters into pieces.\r\n",
          armor, ch );
        armor->Extract( );
        }
      }
    }

  return absorbed;
}


/*
 *   ATTACK ROUTINES
 */


void critical_hit( char_data* ch, char_data* victim, obj_data* wield,
  int& damage )
{
  int  weapon;

  if( ch->species != NULL
    || ch->shdata->skill[SKILL_CRITICAL_HIT] == 0 )
    return;

  weapon = ( wield == NULL ? 0 : wield->value[3] );

  if( number_range( 1,50 ) > ch->get_skill( WEAPON_UNARMED+weapon ) )
    return; 

  if( ch->shdata->skill[SKILL_DEATH_STRIKE] != 0     
    && number_range( 0, 30 ) < ch->get_skill( SKILL_DEATH_STRIKE ) ) {
    send( ch, "You call upon the SHADOWS to DESTROY %s!\r\n", victim );
    send( victim, "%s calls upon the SHADOWS to DESTROY you!\r\n", ch );
    send( *ch->array, "%s calls upon the SHADOWS to DESTROY %s!\r\n",
      ch, victim );
    ch->improve_skill( SKILL_DEATH_STRIKE );
    damage *= 8;
    }
  else if( number_range( 0, 20 ) < ch->get_skill( SKILL_CRITICAL_HIT ) ) {
    send( ch, "You CRITICALLY hit %s!\r\n", victim );
    send( victim, "%s CRITICALLY hits you!\r\n", ch );
    send( *ch->array, "%s CRITICALLY hits %s!\r\n", ch, victim );
    ch->improve_skill( SKILL_CRITICAL_HIT );
    damage *= 5;
    }
}


void power_strike( char_data* ch, char_data* victim, obj_data* wield,
  int& damage )
{
  int weapon;


  if( ch->species != NULL
    || ch->shdata->skill[SKILL_POWER_STRIKE] == 0 )
    return;

  weapon = ( wield == NULL ? 0 : wield->value[3] );
  
  if( number_range( 1,75 ) > ch->get_skill( WEAPON_UNARMED+weapon ) )
    return;

  if( number_range( 0, 25 ) < ch->get_skill( SKILL_POWER_STRIKE ) ) {
    send(ch, "Your POWER STRIKE hits %s!\r\n", victim );
    send( victim, "%s hits you with a POWER STRIKE!\r\n", ch );
    send( *ch->array, "%s hits %s with a POWER STRIKE!\r\n", ch, victim );
    ch->improve_skill( SKILL_POWER_STRIKE );
    damage *= 3;
    }
}


/*
 *   OFFENSIVE ROUTINES
 */


void stun( char_data* ch, char_data* victim, const char* dt )
{
  char        tmp  [ MAX_INPUT_LENGTH ];
  char_data*  rch;

  if( victim->position <= POS_STUNNED
    || victim->shdata->race == RACE_PLANT )
    return;

  if( ch->pcdata == NULL
    || ch->shdata->skill[SKILL_STUN] == 0
    || ch->get_skill( SKILL_STUN ) <= number_range( 0, 100
    +5*victim->shdata->level ) ) 
    return;

  ch->improve_skill( SKILL_STUN );

  if( victim->Seen( ch ) ) 
    send( ch, "-* Your %s momentarily STUNS %s! *-\r\n",
      dt, victim->Seen_Name( ch ) ); 

  send( victim, "%s's %s momentarily STUNS you!\r\n",
    ch->Name( victim ), dt );

  for( int i = 0; i < *ch->array; i++ ) {
    if( ( rch = character( ch->array->list[i] ) ) == NULL 
      || rch == ch || rch == victim || rch->link == NULL
      || !victim->Seen( rch ) )
      continue;
    sprintf( tmp, "%s's %s momentarily STUNS %s.\r\n",
      ch->Name( rch ), dt, victim->Seen_Name( rch ) );
    send( tmp, rch ); 
    }

  disrupt_spell( victim );
  set_delay( victim, 40 ); 
}


bool trip( char_data* ch, char_data* victim, obj_data* wield )
{

  if( victim->position < POS_FIGHTING )
    return FALSE;
 
  if( ch->species == NULL )  {
    if( ( wield != NULL &&  wield->pIndexData->value[3] != 0 )
    && ch->shdata->skill[SKILL_TRIP] == 0 ) 
    return FALSE;

    if( victim->species != NULL
      && ( !is_set( &victim->species->act_flags, ACT_HUMANOID ) ) ) {
      if( ch->shdata->skill[SKILL_TRIP] == 0 ) 
      return FALSE; }
  }
 
 
  if( victim->species != NULL
    && ( is_set( &victim->species->act_flags, ACT_GHOST ) ) )
    return FALSE;

  if( ch->species != NULL  
    && ( !is_set( &ch->species->act_flags, ACT_HUMANOID ) 
    || is_set( &ch->species->act_flags, ACT_GHOST ) ) )
    return FALSE; 

  if( ch->species == NULL ) {
    if( number_range( 0, 500 ) > 2*ch->get_skill( SKILL_TRIP ) +
      ch->get_skill( SKILL_KICK ) )
      return FALSE; }
  else
    if( number_range( 0, 200 ) > 5 )
      return FALSE;

  send( ch,
    "With a well timed kick you knock the feet out from under %s!\r\n",
    victim );
  fsend( victim, "%s delivers a sweeping kick to your feet, knocking you to\
 the ground!", ch );

  send( *ch->array, "%s kicks %s's leg, knocking %s to the ground.\r\n",
    ch, victim, victim->Him_Her( ) );

  if( ch->species == NULL &&
      ch->shdata->skill[SKILL_TRIP] > 0 )
    ch->improve_skill( SKILL_TRIP );

  disrupt_spell( victim );

  victim->position = POS_RESTING;

  return TRUE;
} 


int charge_damage( char_data* ch )
{
  int i;

  if( ch->species != NULL )
    return 5;

  ch->improve_skill( SKILL_CHARGE );

  i = 10*ch->shdata->skill[ SKILL_CHARGE ] + ch->shdata->level/2 +
    ch->Strength( );
  i = 1+i/25;
  return i;

}

int backstab_damage( char_data* ch )
{
  int i;

  if( ch->species != NULL )
    return 5;

  if( ch->shdata->skill[ SKILL_ASSASSINATE] == 0 )
    ch->improve_skill( SKILL_BACKSTAB );
  else
    ch->improve_skill( SKILL_ASSASSINATE );

  i = 10*ch->shdata->skill[ SKILL_BACKSTAB ]
    +10*ch->shdata->skill[ SKILL_ASSASSINATE ]
    +ch->shdata->level;

  i = 1+i/25;

  return i;
}


/*
 *   DEFENSIVE ROUTINES
 */


bool absorb_bracers( char_data* victim, char_data* ch, int& damage,
  int armor, const char* dt )
{
  char           tmp  [ MAX_INPUT_LENGTH ];
  obj_data*  bracers;

  if( ( bracers = victim->Wearing( WEAR_WRIST_L ) ) != NULL )
    armor -= bracers->value[2];

  if( ( bracers = victim->Wearing( WEAR_WRIST_R ) ) != NULL )
    armor -= bracers->value[2];

  if(  armor >= 0
    || ( damage -= number_range( 0, -armor ) ) > 0 )
    return FALSE;

  spam_char( victim,
    "Your bracers glow briefly and %s's %s is deflected.\r\n", 
    ch, dt );

  spam_char( ch,
    "%s's bracers glow briefly and your %s is magically deflected.\r\n",
    victim, dt );

  sprintf( tmp, "%%s's bracers glow briefly and %%s's %s is deflected.", dt );
  spam_room( tmp, victim, ch );

  return TRUE;
}


bool absorb_shield( char_data* victim, char_data* ch, const char* dt,
  int& damage )
{
  char tmp [ TWO_LINES ];

  if( !is_set( victim->affected_by, AFF_PROTECT ) )
    return FALSE;

  damage -= number_range( 0, 3 );

  if( damage > 0 ) 
    return FALSE;

  spam_char( victim,
    "The air crackles as %s's %s is mysteriously blocked.\r\n",
    ch, dt );

  spam_char( ch,
    "The air around %s crackles as your %s is mysteriously blocked.\r\n",
    victim, dt );

  sprintf( tmp,
    "The air crackles as %%s's %s is mysteriously blocked.\r\n", dt );
  spam_room( tmp, ch, victim );

  return TRUE;
}


bool ion_shield( char_data* ch, char_data* victim )
{
  if( IS_AFFECTED( victim, AFF_ION_SHIELD ) ) {
    damage_shock( ch, victim, roll_dice( 4,8 ), "electric spark" );
    if( ch->hit <= 0 )
      return TRUE;
    }

  return FALSE;
}


bool thorn_shield( char_data* ch, char_data* victim )
{
  if( IS_AFFECTED( victim, AFF_THORN_SHIELD ) ) {
    damage_acid( ch, victim, roll_dice( 3,6 ), "thorn shield" );
    if( ch->hit <= 0 )
      return TRUE;
    }

  return FALSE;
}


bool fire_shield( char_data* ch, char_data* victim ) 
{
  if( IS_AFFECTED( victim, AFF_FIRE_SHIELD ) ) {
    damage_fire( ch, victim, roll_dice( 2,4 ), "fire shield" );
    if( ch->hit <= 0 )
      return TRUE;
    }

  return FALSE;
}


bool block_shield( char_data* ch, char_data* victim, const char* dt )
{
  char          tmp  [ TWO_LINES ];
  obj_data*  shield;
  int          roll;

  if( ( shield = victim->Wearing( WEAR_HELD_L ) ) == NULL  
    || shield->pIndexData->item_type != ITEM_ARMOR )
    return FALSE; 

  if( ( roll = number_range( 0, 100 ) ) > 25 )
    return FALSE;

  if( roll > shield->value[1]/2+( victim->pcdata == NULL ? 7
    : victim->get_skill( SKILL_SHIELD ) ) ) 
    return FALSE;

  damage_armor( ch, WEAR_SHIELD );
  victim->improve_skill( SKILL_SHIELD ); 

  spam_char( victim, "%s's %s is blocked by your shield.\r\n", ch, dt );
  spam_char( ch, "%s blocks your %s with %s shield.\r\n", victim, dt,
    victim->His_Her( ) );
  sprintf( tmp, "%%s blocks %%s's %s with %s shield.\r\n",
    dt, victim->His_Her( ) );
  spam_room( tmp, victim, ch );

  return TRUE;
}    


bool shadow_dance( char_data* ch, char_data* victim, const char* dt )
{
  char tmp [ TWO_LINES ];

  if( victim->pcdata == NULL || number_range( 0, 35 )
    >= victim->shdata->skill[SKILL_SHADOW_DANCE] )
    return FALSE;
  
  victim->improve_skill( SKILL_SHADOW_DANCE );

  spam_char( victim, "You meld with the shadows avoiding %s's %s.\r\n",
    ch, dt );
  spam_char( ch, "%s melds with the shadows avoiding your %s.\r\n",
    victim, dt );
  sprintf( tmp, "%%s melds with the shadows avoiding %%s's %s.\r\n", dt );
  spam_room( tmp, victim, ch );
 
  return TRUE;
}


bool counter_attack( char_data* ch, char_data* victim, int& roll )
{
  return FALSE;

  /*
  if( victim->get_skill( SKILL_COUNTER_ATTACK ) < 1 )
    return FALSE;

  if( victim->species != NULL ) {
    if( victim->Wearing( WEAR_HELD_R ) != NULL )
      roll -= 25;
    }
  else
    roll -= 4*victim->get_skill( SKILL_COUNTER_ATTACK );

  if( roll >= 0 )
    return FALSE;
  
  spam_char( victim, "You counter-attack %s's attack!\r\n", ch );
  spam_char( ch, "%s counters your attack!\r\n", victim );
  spam_room( "%s counters %s's attack!\r\n", victim, ch );
  
  one_round( ch, victim );
 
  victim->improve_skill( SKILL_COUNTER_ATTACK );
  return TRUE;
  */
}


bool parry( char_data* ch, char_data* victim, int& roll )
{
  if( victim->species != NULL ) {    
    if( victim->Wearing( WEAR_HELD_R ) != NULL )
      roll -= 25; 
    }
  else
    roll -= 4*victim->get_skill( SKILL_PARRY );

  if( roll >= 0 ) 
    return FALSE;

  spam_char( victim, "You parry %s's attack.\r\n", ch );
  spam_char( ch, "%s parries your attack.\r\n", victim );
  spam_room( "%s parries %s's attack.\r\n", victim, ch );

  victim->improve_skill( SKILL_PARRY );

  return TRUE;
}


bool guard( char_data* ch, char_data* victim, int& roll )
{
  if( victim->species != NULL ) {
    if( victim->Wearing( WEAR_HELD_R ) != NULL )
      roll -= 30;
    }
  else
    roll -= 5*victim->get_skill( SKILL_GUARD );
  

  if( roll >= 0 )
    return FALSE;

  spam_char( victim, "You guard yourself from %s's attack.\r\n", ch );
  spam_char( ch, "%s guards from your attack.\r\n", victim );
  spam_room( "%s guards from %s's attack.\r\n", victim, ch );

  victim->improve_skill( SKILL_GUARD );

  return TRUE;
}


bool tumble( char_data* ch, char_data* victim, int& roll )
{
  int dex;

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

  if( victim->get_skill( SKILL_TUMBLE ) < 1 )
    return FALSE;

  dex = victim->Dexterity( );

  roll -= victim->get_skill( SKILL_TUMBLE)+4*dex-20;

  if( roll > 0 )
    return FALSE;

  spam_char( ch, "%s tumbles away, avoiding your attack.\r\n", victim );
  spam_char( victim, "You tumble away, avoiding %s's attack.\r\n", ch );
  spam_room( "%s tumbles away, avoiding %s's attack.\r\n", victim, ch );

  victim->improve_skill( SKILL_TUMBLE );

  return TRUE;
}


bool dodge( char_data* ch, char_data* victim, int& roll )
{
  int dex;

  dex = victim->Dexterity( ); 

  if( victim->species == NULL ) 
    roll -= 2*victim->get_skill( SKILL_DODGE )+4*dex-20; 
  else 
    roll -= 4*dex; 

  if( roll > 0 )
    return FALSE;

  spam_char( ch, "%s dodges your attack.\r\n", victim );
  spam_char( victim, "You dodge %s's attack.\r\n", ch );
  spam_room( "%s dodges %s's attack.\r\n", victim, ch );

  victim->improve_skill( SKILL_DODGE );

  return TRUE;
}


bool misses_blindly( char_data* ch, char_data* victim, int& chance,
  const char* dt )
{
  if( chance < 0 ) {
    spam_char( victim, "%s's attack misses you.\r\n", ch );
    spam_char( ch, "You miss %s.\r\n", victim );
    spam_room( "%s's attack misses %s.\r\n", ch, victim );
    return TRUE;
    }

  if( !ch->in_room->Seen( ch ) && ( chance -= 30 ) < 0 ) {
    spam_char( ch,
      "You swing wildly in the dark missing everything.\r\n" );
    spam_room( "%s swings wildly missing everything.\r\n", ch, NULL );
    return TRUE;
    }

  if( !victim->Seen( ch ) ) {
    if( ( chance -= 30 ) < 0 ) {
      spam_char( ch,
        "You swing at your unseen victim, but hit nothing.\r\n" );
      spam_char( victim,
        "%s tries to hit you, but swings in the wrong direction.\r\n", ch );
      spam_room( "%s tries to hit %s, but swings in the wrong direction.\r\n",
        ch, victim );
      return TRUE;
      }
    }
  else {
    if( is_set( victim->affected_by, AFF_DISPLACE )
      && ( chance -= 10 ) < 0 ) {
      spam_char( ch,
        "Your %s seems to hit %s, but passes through %s.\r\n",
        dt, victim, victim->Him_Her( ) );
      spam_char( victim,
        "%s's %s strikes your displaced image, doing you no harm.\r\n",
        ch, dt );
      spam_room( "%s strikes the displaced image of %s.\r\n",
        ch, victim );
      return TRUE;
      }
    }
 
  return FALSE;
}


void invulnerable( char_data* ch, int& damage )
{
  if( IS_AFFECTED( ch, AFF_INVULNERABILITY ) ) {
    if( ch->species == NULL && ch->pcdata->clss == CLSS_CLERIC )
      damage = 9*damage/10;
    else  
      damage = 8*damage/10;
  }
 
  return;
}


void barkskin( char_data* ch, int& damage )
{
  if( IS_AFFECTED( ch, AFF_BARKSKIN ) ) 
    damage = 9*damage/10;

  return;
}


void protgood( char_data* ch, char_data* victim, int& damage )
{
  if( IS_AFFECTED( ch, AFF_PROTECT_GOOD ) && is_good( victim )
    && is_evil( ch ) )
    damage = 8*damage/10;

  return;
}


void protevil( char_data* ch, char_data* victim, int& damage )
{
  if(IS_AFFECTED( ch, AFF_PROTECT_EVIL ) && is_evil( victim )
    && is_good( ch ) )
    damage = 8*damage/10;

  return;
}


/*
 *   CONFUSED CHARACTER ROUTINE
 */

   
void confused_char( char_data* ch )
{
  /*
  char *word[] = { "hop", "pout", "smile", "growl", "sulk", "drool",
    "clap", "fume" };

  char_data*  rch;
  int           i  = number_range( 0, 24 );

  if( i < 8 ) {
    interpret( ch, word[i] );
    return;
    }

  if( i < 16 ) 
    if( ( rch = rand_victim( ch ) ) != NULL && rch != ch ) {
      start_fight( ch, rch );
      multi_hit( ch, rch );
      }
      */
  return;
}