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 <stdlib.h>
#include "define.h"
#include "struct.h"


bool can_assist( char_data* ch, char_data* victim )
{
  if( ch == NULL || victim == NULL || ch->species != NULL )
    return TRUE;

  if( ch->pcdata->clss != CLSS_CLERIC
    && ch->pcdata->clss != CLSS_PALADIN )
    return TRUE;

  if( abs( ch->shdata->alignment%3-victim->shdata->alignment%3 ) != 2 )
    return TRUE;

  send( ch, "You feel the energy drain from you, but for some reason the\
 spirits refuse\n\ryour request.\n\r" );

  return FALSE;
}


/*
 *   HEALING SPELLS
 */


void heal_victim( char_data* ch, char_data* victim, int hp )
{
  const char *heal_message[] = {
    "You were not wounded so were not healed.\n\r",
    "$n was not wounded so was not healed.",

    "You are completely healed.\n\r",
    "$n is completely healed.",

    "Most of your wounds are gone.\n\r",
    "Most of $n's wounds disappear.",

    "Your wounds feel quite a bit better.\n\r",
    "$n looks quite a bit less injured.",

    "You are slightly healed.\n\r",
    "$n looks a little bit better."
    };

  int damage = victim->max_hit-victim->hit;
  int i;

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

  victim->hit = min( victim->max_hit, victim->hit+hp );

  i = ( damage <= hp ? ( damage <= 0 ? 0 : 1 ) : ( 2*damage < 3*hp
    ? 2 : ( damage < 3*hp ? 3 : 4 ) ) );
 
  send( victim, heal_message[2*i] );
  act_notchar( heal_message[2*i+1], victim );

  update_pos( victim );
  update_max_move( victim );

  return;
}


bool spell_cure_light( char_data* ch, char_data* victim, void*,
  int level, int )
{
  heal_victim( ch, victim, spell_damage( SPELL_CURE_LIGHT, level ) );

  return TRUE;
}


bool spell_cure_serious( char_data* ch, char_data* victim, void*,
  int level, int )
{
  heal_victim( ch, victim, spell_damage( SPELL_CURE_SERIOUS, level ) );

  return TRUE;
}


bool spell_group_serious( char_data* ch, char_data*, void*,
  int level, int )
{
  char_data* gch;

  for( int i = 0; i < *ch->array; i++ ) 
    if( ( gch = player( ch->array->list[i] ) ) != NULL
      && is_same_group( gch, ch ) )
      heal_victim( ch, gch, spell_damage( SPELL_GROUP_SERIOUS, level ) );

  return TRUE;
}


bool spell_cure_critical( char_data* ch, char_data* victim, void*,
  int level, int )
{
  heal_victim( ch, victim, spell_damage( SPELL_CURE_CRITICAL, level ) );

  return TRUE;
}



bool spell_group_critical( char_data* ch, char_data*, void*,
  int level, int )
{
  char_data* gch;

  for( int i = 0; i < *ch->array; i++ ) 
    if( ( gch = player( ch->array->list[i] ) ) != NULL
      && is_same_group( gch, ch ) )
      heal_victim( ch, gch, spell_damage( SPELL_GROUP_CRITICAL, level ) );

  return TRUE;

}

bool spell_heal( char_data* ch, char_data* victim, void*,
  int level, int )
{
  heal_victim( ch, victim, spell_damage( SPELL_HEAL, level ) );

  return TRUE;
}

bool spell_restoration( char_data* ch, char_data* victim, void*,
  int level, int )
{
  heal_victim( ch, victim, spell_damage( SPELL_RESTORATION, level ) );

  return TRUE;
}


/*
 *   REMOVE CURSE
 */


bool spell_remove_curse( char_data* ch, char_data* victim, void*,
  int level, int )
{
  obj_data*   obj;
  int       count  = 0;

  if( !consenting( victim, ch, "curse removal" ) ) 
    return TRUE;

  for( int i = victim->wearing.size-1; i >= 0; i-- ) {
    if( ( obj = object( victim->wearing[i] ) ) == NULL
      || ( !is_set( obj->extra_flags, OFLAG_NODROP )
      && ( !is_set( obj->extra_flags, OFLAG_NOREMOVE ) ) ) ) 
      continue;

    if( count++ > level/5 ) 
      return TRUE;

    send( victim, "%s which you are wearing turns to dust.\n\r", 
      obj );
    send_seen( victim, "%s which %s is wearing turns to dust.\n\r",
      obj, victim );
    obj->Extract( );
    }

  for( int i = victim->contents.size-1; i >= 0; i-- ) {
    if( ( obj = object( victim->contents[i] ) ) == NULL
      || ( !is_set( obj->extra_flags, OFLAG_NODROP )
      && ( !is_set( obj->extra_flags, OFLAG_NOREMOVE ) ) ) ) 
      continue;

    if( count++ > level/5 ) 
      return TRUE;

    send( victim, "%s which you are carrying turns to dust.\n\r", obj );
    send_seen( victim, "%s which %s is carrying turns to dust.\n\r",
      obj, victim );
    obj->Extract( );
    }

  if( count == 0 ) 
    if( victim == ch ) 
      send( ch, "You weren't carrying anything cursed.\n\r" );
    else 
      send( ch, "%s wasn't carrying anything cursed.\n\r", victim );

  return TRUE;
}


/*
 *   POISON/DISEASE
 */


bool spell_cure_disease( char_data* ch, char_data* victim, void*, int, int )
{
  if( !is_set( victim->affected_by, AFF_PLAGUE ) ) {
    if( ch != victim )
      send( ch, "%s wasn't diseased.\n\r", victim );
    return TRUE;
    }

  strip_affect( victim, AFF_PLAGUE );

  if( is_set( victim->affected_by, AFF_PLAGUE ) ) {
    send( ch, "%s is still diseased!?\n\r", victim );
    send( victim, "You are still diseased!?" );
    }

  return TRUE;
}


bool spell_cure_poison( char_data* ch, char_data* victim, void*, int, int )
{
  bool is_drunk;

  is_drunk = ( victim->species == NULL &&
    ( victim->pcdata->condition[COND_ALCOHOL] > 0
    || victim->pcdata->condition[COND_DRUNK] > 0 ) );

  if( !is_drunk && !is_set( victim->affected_by, AFF_POISON ) ) {
    if( ch != victim )
      send( ch, "%s wasn't poisoned.\n\r", victim );
    return TRUE;
    }

  if( victim->pcdata != NULL ) {
    victim->pcdata->condition[ COND_ALCOHOL ] = 0;
    victim->pcdata->condition[ COND_DRUNK ]   = 0;
    }

  strip_affect( victim, AFF_POISON );

  if( is_set( victim->affected_by, AFF_POISON ) ) {
    if( ch != victim ) 
      send( ch, "%s is still poisoned!?\n\r", victim );
    send( victim, "You are still poisoned!?\n\r" );
    }

  return TRUE;
}


/*
 *   SILENCE SPELL
 */


bool spell_gift_of_tongues( char_data* ch, char_data* victim, void*,
  int level, int duration )
{
  spell_affect( ch, victim, level, duration, SPELL_GIFT_OF_TONGUES,
    AFF_TONGUES );

  return TRUE;
}



bool spell_silence( char_data* ch, char_data* victim, void*, int level, int duration )
{
  if( makes_save( victim, ch, RES_MAGIC, SPELL_SILENCE, level ) )
    return TRUE;

  spell_affect( ch, victim, level, duration, SPELL_SILENCE, AFF_SILENCE );

  return TRUE;
}


bool spell_augury( char_data* ch, char_data*, void* vo, int, int )
{
  obj_data*  obj  = (obj_data*) vo;

  if( ch == NULL || obj == NULL )
    return TRUE;

  if( !obj->Belongs( ch ) ) {
    fsend( ch, "%s glows black and you sense the true owner is %s.",
      obj, obj->owner->name );
    }
  else {
    send( ch, "Nothing happens.\n\r" );
    }

  return TRUE;
}


bool spell_true_sight( char_data* ch, char_data* victim, void*, 
  int level, int duration )
{

  spell_affect( ch, victim, level, duration, SPELL_TRUE_SIGHT,
    AFF_TRUE_SIGHT );

  return TRUE;
}


bool spell_protect_life( char_data* ch, char_data* victim, void*,
  int level, int duration )
{
  spell_affect( ch, victim, level, duration, SPELL_PROTECT_LIFE,
    AFF_LIFE_SAVING ); 

  return TRUE;
}


bool spell_sense_life( char_data* ch, char_data* victim, void*, 
  int level, int duration )
{

  spell_affect( ch, victim, level, duration, SPELL_SENSE_LIFE,
    AFF_SENSE_LIFE );

  return TRUE;

}


/*
 *   CREATION SPELLS
 */


bool spell_create_water( char_data* ch, char_data* victim, void* vo,
  int level, int duration )
{
  obj_data*         obj  = (obj_data*) vo;
  content_array*  where;
  int            liquid;
  int             metal;

  /* DIP */

  if( duration == -3 ) {
    if( ( metal = obj->metal( ) ) != 0 && number_range( 0,3 ) == 0 ) {
      if( obj->rust == 3 ) {
        send( *ch->array, "%s disintegrates into worthless pieces.\n\r", obj );
        obj->Extract( 1 );
        } 
      else {
        send( *ch->array, "%s %s.\n\r",
          obj, material_table[ metal ].rust_name );
        obj->rust++;
        }  
      }
    return FALSE;
    }      

  /* THROWING, REACTING */ 

  if( ch == NULL || victim != NULL )
    return FALSE;

  /* CAST */

  liquid = LIQ_WATER;
  where  = obj->array;

  if( number_range( 0, 100 ) < 2 ) {
    for( ; ; ) {
      if( ( liquid = number_range( 0, MAX_ENTRY_LIQUID-1 ) ) == LIQ_WATER
        || liquid_table[ liquid ].create )
        break;
      }
    }

  obj = (obj_data*) obj->From( 1 );

  obj->value[1] += 100*level;
  obj->value[2]  = liquid;
  obj->selected  = 1;

  include_empty  = FALSE;
  include_liquid = FALSE;

  if( obj->value[1] >= obj->value[0] ) {
    send( *ch->array, "%s fills to overflowing with %s.\n\r",
      obj, liquid_table[ liquid ].name );
    obj->value[1] = obj->value[0];
    }
  else {
    send( *ch->array, "%s fills partially up with %s.\n\r",
      obj, liquid_table[ liquid ].name );
    }

  include_empty  = TRUE;
  include_liquid = TRUE;

  set_bit( obj->extra_flags, OFLAG_KNOWN_LIQUID );
  obj->To( where );
  react_filled( ch, obj, liquid );

  return TRUE;    
}


/*
 *   OBJECT SPELLS
 */

bool spell_purify( char_data* ch, char_data* victim, void*, int, int )
{
  if( !is_set( victim->affected_by, AFF_SLEEP )  &&
    !is_set( victim->affected_by, AFF_SLOW ) &&
    !is_set( victim->affected_by, AFF_CURSE ) ) {
    if( ch != victim )
      send( ch, "%s is not affected by anything which can be purified.\n\r",
        victim );
    else
      send( victim, 
        "You are not affected by anything which can be purified.\n\r" );
    return TRUE;
    }

  if( is_set( victim->affected_by, AFF_SLEEP ) ) {
    if( ch != victim )
      send( ch, "%s is no longer affected by magical sleep.\n\r", victim );
    else
      send( victim, "You are no longer affected by magical sleep.\n\r" );
    strip_affect( victim, AFF_SLEEP );
    }

  if( is_set( victim->affected_by, AFF_CURSE ) ) {
    if( ch != victim )
      send( ch, "%s is no longer cursed.\n\r", victim );
    else
      send( victim, "You are no longer cursed.\n\r" );
    strip_affect( victim, AFF_CURSE );
    }

  if( is_set( victim->affected_by, AFF_SLOW ) ) {
    if( ch != victim )
      send( ch, "%s is no longer slowed.\n\r", victim );
    else
      send( victim, "You are no longer slowed.\n\r" );

    strip_affect( victim, AFF_SLOW );
    }

  return TRUE;
}


bool spell_sanctify( char_data* ch, char_data*, void *vo, int level, int )
{
  obj_data *obj = (obj_data*) vo;
  int dam;

  dam = obj->value[0]*(obj->value[1]+1);

  if( is_set( obj->extra_flags, OFLAG_SANCT ) ) {
    send( ch, "Nothing happens.\n\r" );
    return TRUE;
    }

  if( dam > 3*level ) {
    fsend( *ch->array,
      "%s glows with a pale blue light which quickly fades.", 
      obj );
    return TRUE;
    }

  fsend( *ch->array, "%s glows with a pale blue light.\n\rThis\
 slowly fades as if being absorbed into the item.", obj );

  set_bit( obj->extra_flags, OFLAG_SANCT );

  return TRUE;
};


/*
 *   PROTECTION SPELLS
 */


bool spell_armor( char_data* ch, char_data* victim, void*, int level,
  int duration )
{
  spell_affect( ch, victim, level, duration, SPELL_ARMOR, AFF_ARMOR );

  return TRUE;
}


bool spell_bless( char_data* ch, char_data* victim, void*, int level,
  int duration )
{
  spell_affect( ch, victim, level, duration, SPELL_BLESS, AFF_BLESS );

  return TRUE;
}


bool spell_protect_good( char_data* ch, char_data* victim, void*,
  int level, int duration )
{
  spell_affect( ch, victim, level, duration, SPELL_PROTECT_GOOD,
    AFF_PROTECT_GOOD );

  return TRUE;
}


bool spell_protect_evil( char_data* ch, char_data* victim, void*,
  int level, int duration )
{
  spell_affect( ch, victim, level, duration, SPELL_PROTECT_EVIL,
    AFF_PROTECT_EVIL );

  return TRUE;
}


/*
 *   WRATH
 */


bool spell_holy_wrath( char_data *ch, char_data *victim, void*, int level,
  int duration )
{
  if( ch != NULL
    && ch->shdata->alignment%3 != victim->shdata->alignment%3 ) {
    send( ch, "You are unable to incite %s into a holy rage.\n\r", victim );
    send( victim, "%s is unable to incite you into a holy rage.\n\r", ch );
    return TRUE;
    }

  spell_affect( ch, victim, level, duration, SPELL_HOLY_WRATH, AFF_WRATH );

  return TRUE;
}


/*
 *   GOLEM SPELLS
 */


bool spell_animate_clay( char_data* ch, char_data*, void*, int, int )
{
  char_data*       golem;
  species_data*  species;

  if( null_caster( ch, SPELL_ANIMATE_CLAY ) )
    return TRUE;

  for( int i = 0; i < ch->followers; i++ ) { 
    golem = ch->followers[i];
    if( is_set( &golem->status, STAT_PET ) 
      && golem->shdata->race == RACE_GOLEM ) {
      send( ch, "The incarnation fails as you can only control one golem\
 at a time.\n\r" );
      return TRUE;
      }
    }

  if( ( species = get_species( MOB_CLAY_GOLEM ) ) == NULL ) {
    bug( "Animate_Clay: NULL species." );
    return TRUE;
    }

  golem = create_mobile( species );

  golem->To( ch->array );
  add_follower( golem, ch );
  set_bit( &golem->status, STAT_PET );

  return TRUE;
}


/*
 *   DEATH
 */


bool spell_resurrect( char_data*, char_data*, void*, int, int )
{
  return TRUE;
}


/*
 *   FEAR
 */


bool spell_fear( char_data* ch, char_data* victim, void*, int level, int )
{
  /*
  if( ch == NULL ) {
    send( victim, "Tell merior she forgot about fear potions.\n\r" );
    return TRUE; 
    }
  */

  if( makes_save( victim, ch, RES_MAGIC, SPELL_FEAR, level ) ) {
    send( ch, "You are unable to make %s afraid!\n\r", victim );
    send( victim, "%s is unable to make you afraid!\n\r", ch );
    send( *ch->array, "%s is unable to make %s afraid.\n\r",
      ch, victim );
    return TRUE;
    }

  send( victim, "%s causes you to cringe in fear!\n\r", ch );
  send( *ch->array, "%s cringes in fear!\n\r", victim );
 
  disrupt_spell( victim );
  set_delay( victim, 40+level );

  return TRUE;
}