ackmud/area/boards/
ackmud/area/imc/
ackmud/npcs/a/
ackmud/npcs/c/
ackmud/npcs/d/
ackmud/npcs/e/
ackmud/npcs/f/
ackmud/npcs/h/
ackmud/npcs/i/
ackmud/npcs/k/
ackmud/npcs/l/
ackmud/npcs/n/
ackmud/npcs/o/
ackmud/npcs/p/
ackmud/npcs/r/
ackmud/npcs/s/
ackmud/npcs/w/
ackmud/player/c/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *       _/          _/_/_/     _/    _/     _/    ACK! MUD is modified    *
 *      _/_/        _/          _/  _/       _/    Merc2.0/2.1/2.2 code    *
 *     _/  _/      _/           _/_/         _/    (c)Stephen Zepp 1998    *
 *    _/_/_/_/      _/          _/  _/             Version #: 4.3          *
 *   _/      _/      _/_/_/     _/    _/     _/                            *
 *                                                                         *
 *                        http://ackmud.nuc.net/                           *
 *                        zenithar@ackmud.nuc.net                          *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ack.h"
#ifndef DEC_MAGIC_H
#include "magic.h"
#endif

/*
 * This file should contain:
 *	o advanced damage engine
 */


struct sp_dam_str_type sp_dam_str [] =

{
/* NONE      */ { REALM_NONE, "@@g", "@@g", "@@W", "", "%s%s%s", 
                 "blast", "BLAST", "blasts", "BLASTS" },

/* Fire      */ { REALM_FIRE, "@@R", "@@W", "@@y", "@@2", "%s<%s^%s>", 
                 "burn", "INCINERATE", "burns", "INCINERATES" },
/* Shock     */ { REALM_SHOCK, "@@l", "@@W", "@@y", "@@1", "%s~%s-%s~", 
                 "shock", "FRY", "shocks", "FRIES" }, 
/* light     */ { REALM_LIGHT, "@@W", "@@y", "@@c", "@@7", "%s*%s*%s*", 
                 "zap", "ZAP", "zaps", "ZAPS" }, 
/* gas       */ { REALM_GAS, "@@W", "@@y", "@@c", "@@7", "%s(%sO%s)", 
                 "choke", "ENVELOP", "chokes", "ENVELOPS" }, 
/* poison    */ { REALM_POISON, "@@e", "@@r", "@@e", "@@4", "%s{%s^%s}", 
                 "weaken", "POISON", "weakens", "POISONS" }, 
/* cold      */ { REALM_COLD, "@@l", "@@W", "@@y", "@@1", "%s[%s~%s]", 
                 "chill", "FREEZE", "chills", "FREEZES" }, 
/* sound     */ { REALM_SOUND, "@@l", "@@W", "@@y", "@@1", "%s~%s\\/%s~", 
                 "blast", "BLAST", "blasts", "BLASTS" }, 
/* acid      */ { REALM_ACID, "@@G", "@@W", "@@r", "@@3", "%s-%sX%s-", 
                 "etch", "DISSOLVE", "etches", "DISSOLVES" }, 
/* drain     */ { REALM_DRAIN, "@@d", "@@R@@i", "@@2@@e", "@@R@@i", "%s>%s-%s<", 
                 "taint", "DRAIN", "taints", "DRAINS" }, 
/* impact    */ { REALM_IMPACT, "@@b", "@@W", "@@y", "@@4", "%s.%s^%s.", 
                 "strike", "SLAM", "strikes", "SLAMS" }, 
/* mind      */ { REALM_MIND, "@@m", "@@W", "@@p", "@@5", "%s/%sV%s\\", 
                 "zap", "BLAST", "zaps", "BLASTS" }, 
/* holy      */ { REALM_HOLY, "@@l", "@@W", "@@y", "@@1", "%s~%s\\/%s~", 
                 "holy", "HOLY", "holies", "HOLIES" }
 };

void sp_death_message( CHAR_DATA *ch, CHAR_DATA *victim, int realm )
{
   /* Used to display assorted death messages, based on dt 
    * max_dt == number of entries in attack table in dam_message,
    * so we know if kill was unarmed, armed, or through spells or skills.
    * Stephen
    */
    
   char  buf1[MAX_STRING_LENGTH];
   char  buf2[MAX_STRING_LENGTH];
   char  buf3[MAX_STRING_LENGTH];
   int   vnum;
   int   looper;
 /*   For debugging purposes  
   sprintf( buf, "dt: %d max_dt: %d\n\r", dt, max_dt );
   notify( buf, 1 );  */
   
   vnum = 0;	/* Used to load up body parts.... eewwwwww! */
   
   for ( looper = 1; looper < 32; looper++ )
   {
     if ( IS_SET( realm, ( 1 << looper )  ) )  
       break;
   }
   switch( looper +1 )
   {
   default: /* bad realm, use non-specific */
         sprintf( buf1, "$n destroy $N!"   );
         sprintf( buf2, "You destroy $N!"   );
         sprintf( buf3, "$n destroys you." );
         break;      
   case RE_FIRE:	
   {
     if ( HAS_BODY( victim ) )
     {
      switch( number_range( 0, 4 ) )
      {
      case 0:
         sprintf( buf1, "$n cremates $N's body to a crisp!"   );
         sprintf( buf2, "You cremate $N's body to a crispy @@eRED@@N cinder!"   );
         sprintf( buf3, "$n cremates your remains." );
         break;
      case 1:
         sprintf( buf1, "$n fries $N's guts; smoke envelops $S corpse!"   );
         sprintf( buf2, "You fry $N's guts; smoke bites your eyes!"    );
         sprintf( buf3, "$n slowly fries your entrails; smoke covers your remains!" );
         break;
      case 2:
         sprintf( buf1, "$n leaves gigantic burns on $N's remains. Blood and pus spray out wildly!" );
         sprintf( buf2, "You leave gigantic burns on $N's remains. Blood and pus spray out wildly!" );
         sprintf( buf3, "$n leaves gigantic burns on your body. Blood and pus spray out wildly!" );
         break;
      case 3:
         sprintf( buf1, "$n burns $N's skin off, leaving a bloody mess!" );
         sprintf( buf2, "You burn $N's skin off, leaving a bloody mess!" );
         sprintf( buf3, "$n burns your skin off, leaving a bloody mess!" );
         break;
      case 4:
         sprintf( buf1, "$n leaves $N burning in flames. Blood spills all over the floor!" );
         sprintf( buf2, "You leave $N burning in flames. Blood spills all over the floor!"  );
         sprintf( buf3, "$n leaves you burning in flames. Your skin breaks and blood spills on the floor!" );
         break;
      }
    
     }
     else
     {
        sprintf( buf1, "$n sets $N aura on fire!"   );
         sprintf( buf2, "You set $N on fire!"   );
         sprintf( buf3, "$n sets you on fire!" );
         break;
     }
     break;
   }
   case RE_SHOCK:	
   {
     if ( HAS_BODY( victim ) )
     {
        switch( number_range( 0, 2 ) )
        {
        case 0:
         sprintf( buf1, "$n electrifies $N's to a crisp."   );
         sprintf( buf2, "You electrify $N's body to a crisp!"   );
         sprintf( buf3, "$n electrifies your remains" );
         break;
        case 1:
         sprintf( buf1, "$n fries $N. Smoke envelops $S corpse!"   );
         sprintf( buf2, "You fry $N. Smoke bites your eyes!"    );
         sprintf( buf3, "$n sends electricity through your body. You feel your skin burn." );
         break;
        case 2:
         sprintf( buf1, "$n lightning shocks $N's body and $S eye balls fall out!" );
         sprintf( buf2, "You send lightning through $N's body and $S eye balls fall out!" );
         sprintf( buf3, "$n sends lightning though your body. Your eye sockets pop and your eye balls fall out!" );
         break;
        }
     }
     else
     {
         sprintf( buf1, "$n electricutes $N."   );
         sprintf( buf2, "You electricute $N."   );
         sprintf( buf3, "$n electricutes you." );
         break;
     }
     break;
   }
   case RE_LIGHT:	
   {
     if ( HAS_BODY( victim ) )
     { 
         sprintf( buf1, "$n makes $N's corpse glow with unholy light!"   );
         sprintf( buf2, "You penetrate $N's body with light!"   );
         sprintf( buf3, "$n penetrates your remains with light!" );
         break;
     }
     else
     {
         sprintf( buf1, "$n makes $N glow with unholy light!"   );
         sprintf( buf2, "You penetrate $N with light!"   );
         sprintf( buf3, "$n penetrates you with light!" );
         break;
     }
     break;
   }
   case RE_GAS:	
   {
     if ( HAS_BODY( victim ) )
     {
         sprintf( buf1, "$n gasses $N and watches $M choke."   );
         sprintf( buf2, "You gas $N and watch $M die."   );
         sprintf( buf3, "$n gasses you and watches you die." );
         break;
     }
     else
     {
         sprintf( buf1, "$n gasses $N and watches $M choke."   );
         sprintf( buf2, "You gas $N and watch $M die."   );
         sprintf( buf3, "$n gasses you and watches you die." );
         break;
     }
     break;
   }
   case RE_POISON:	
   {
     if ( HAS_BODY( victim ) )
     {
       switch( number_range( 0,1 ) )
       {
        case 0:
         sprintf( buf1, "$n poisons $N ;$S body begins to twist in agony!"   );
         sprintf( buf2, "You poison $N and watch $S body begin twisting in agony!"   );
         sprintf( buf3, "$n poisons you -- you twist in agony." );
         break;
        
        case 1:
         sprintf( buf1, "$n sends a poisonous cloud into $N ;$S mouth starts dripping with blood!"   );
         sprintf( buf2, "You send a poisonous cloud into $N ;$S mouth starts dripping with blood!"   );
         sprintf( buf3, "$n bursts your lungs with his poisonous cloud, blood begins flowing from inside." );
         break;
       }
 
   }
     else
     {
         sprintf( buf1, "$n poisons $N ;$S soul begins to twist in agony!"   );
         sprintf( buf2, "You poison $N and watch $S soul begin twisting in agony!"   );
         sprintf( buf3, "$n poisons you -- you twist in agony." );
         break;
     }
     break;
   }
   case RE_COLD:	
   {
     if ( HAS_BODY( victim ) )
     {
       switch( number_range( 0,0 ) )
       {
        case 0:
         sprintf( buf1, "$n turns $N into a block of ice."   );
         sprintf( buf2, "You turn $N into a block of ice."   );
         sprintf( buf3, "$n turns you into ice!!" );
         break;   
       }
     }
     else
     {
         sprintf( buf1, "$n freezes $N to death!"   );
         sprintf( buf2, "You freeze $N to death!"   );
         sprintf( buf3, "$n freezes you to death!" );
         break;   
     }
     break;
   }
   case RE_SOUND:	
   {
     if ( HAS_BODY( victim ) )
     {
         sprintf( buf1, "$n explodes $N's remains with deafening sound!"   );
         sprintf( buf2, "You explode $N's remains with deafening sound!"   );
         sprintf( buf3, "$n explodes your remains with deafening sound!" );
         break;   
     }
     else
     {
         sprintf( buf1, "$n shatters $N with deafening sound!"   );
         sprintf( buf2, "You shatter $N with deafening sound!"   );
         sprintf( buf3, "$n shatters you with deafening sound!" );
         break;   
     }
     break;
   }
   case RE_ACID:	
   {
     if ( HAS_BODY( victim ) )
     {
       switch( number_range( 0, 1 ) )
       {
         case 0:
           sprintf( buf1, "$n sprays acid on $N; $S flesh falls apart!"   );
           sprintf( buf2, "You spray acid on $N; $S flesh falls apart!"   );
           sprintf( buf3, "$n sprays acid on you. Your flesh falls apart!" );
           break;  
         case 1:
           sprintf( buf1, "$n dissolves $N's corpse into mushy paste."   );
           sprintf( buf2, "You dissolve $N's corpse into mushy paste."   );
           sprintf( buf3, "$n dissolves you into mushy paste!" );
         break; 
       }
     }
     else
     {
         sprintf( buf1, "$n etches $N to death!"   );
         sprintf( buf2, "You etch $N to death!"   );
         sprintf( buf3, "$n etches you to death!" );
         break;   
     }
     break;
   }
   case RE_DRAIN:	
   {
     if ( HAS_BODY( victim ) )
     {
         sprintf( buf1, "$n drains $N of $S life energy."   );
         sprintf( buf2, "You drains $N of $S life energy."  );
         sprintf( buf3, "$n drains you of your life energy."  );
         break;   
     }
     else
     {
         sprintf( buf1, "$n darkens $N soul!"  );
         sprintf( buf2, "You darken $N soul!"   );
         sprintf( buf3, "$n darkens your soul!" );
         break;   
     }
     break;
   }
   case RE_IMPACT:	
   {
     if ( HAS_BODY( victim ) )
     {
         sprintf( buf1, "$n smashes $N's body into messy flesh."   );
         sprintf( buf2, "You smash $N into messy flesh."   );
         sprintf( buf3, "$n smashes you into messy flesh!" );
         break;   
     }
     else
     {
         sprintf( buf1, "$n crushes $N to death!"   );
         sprintf( buf2, "You crush $N to death!"   );
         sprintf( buf3, "$n crushes you to death!" );
         break;   
     }
     break;
   }
   case RE_MIND:	
   {
     if ( HAS_MIND( victim ) )
     {
         sprintf( buf1, "$n blasts $N with psionic power!"   );
         sprintf( buf2, "You blast $N with psionic power!"   );
         sprintf( buf3, "$n blasts you with psionic power!" );
         break;   
     }
     else
     {
         sprintf( buf1, "$n blasts $N with psionic power!"   );
         sprintf( buf2, "You blast $N with psionic power!"   );
         sprintf( buf3, "$n blasts you with psionic power!" );
         break;   
     }
     break;
   }
   case RE_HOLY:	
   {
     if ( HAS_MIND( victim ) )
     {
         sprintf( buf1, "$n steals $N's soul with divine power!"   );
         sprintf( buf2, "You steal $N's soul with divine power!"   );
         sprintf( buf3, "$n steals your soul with divine power!" );
         break;   
     }
     else
     {
         sprintf( buf1, "$n steals $N's soul with divine power!"   );
         sprintf( buf2, "You steal $N's soul with divine power!"   );
         sprintf( buf3, "$n steals your soul with divine power!" );
         break;  
     }
     break;
   }
   }  /* end switch */

   act( buf1, ch, NULL, victim, TO_NOTVICT );
   act( buf2, ch, NULL, victim, TO_CHAR );
   act( buf3, ch, NULL, victim, TO_VICT );

    /* Load up object, if needed. */
    if ( vnum != 0 )
    {
	char buf[MAX_STRING_LENGTH];
	OBJ_DATA *obj;
	char *name;

	name            = IS_NPC(ch) ? ch->short_descr : ch->name;
	obj             = create_object( get_obj_index( vnum ), 0 );
	obj->timer      = number_range( 4, 7 );

	sprintf( buf, obj->short_descr, name );
	free_string( obj->short_descr );
	obj->short_descr = str_dup( buf );

	sprintf( buf, obj->description, name );
	free_string( obj->description );
	obj->description = str_dup( buf );

	obj_to_room( obj, ch->in_room );
    }



   return;
}	



/* 
 * assumes a base damage, after initial save checks.
 * will modify damage as it sees fit for weaknesses and strengths.
 *
 */





    
void sp_dam_message( OBJ_DATA * obj, CHAR_DATA *ch, CHAR_DATA *victim, int dam, int realm, int dt )
{

    char buf1[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH], buf3[MAX_STRING_LENGTH];
    const char *attack;
    char punct;
    int rtype, dam_range;
    bool dead = FALSE;
    char symbuf[MSL];
    char catsymbuf[MSL];
    char outercol[MSL];
    char innercol[MSL];
    bool stress = FALSE;

    if ( dam >= victim->hit )
       dead = TRUE; 
    if ( sysdata.shownumbers == TRUE )
    {        
      sprintf( testerbuf, " @@l(@@W%i@@l)@@N", dam );
    }
    else
      sprintf( testerbuf, "%s", "" );
      
    for (rtype=0;
         rtype < MAX_REALM;
         rtype++)
    {
      if ( sp_dam_str[rtype].realm == realm )
        break;
    }
    if ( rtype == MAX_REALM )
     rtype = 0;



/* notes:
  2000+ stress color    
  1000+ normal color
  0+ no backcolor
  500+ stress verb
  0+ normal verb
  each 50 is a symbol 
*/

   if ( dam > 2000 )
   {
     dam_range = dam - 2000;
   }
   else if ( dam > 1000 )
   {
     dam_range = dam -1000;
   }
   else
   {
     dam_range = dam;
   }
   dam_range /= 2;
   if ( dam_range > 250 )
   {
     stress = TRUE;
     dam_range -= 250;
   }
    punct   = (!stress) ? '.' : '!';
    sprintf( outercol, "%s%s",
        ( dam > 250 ? sp_dam_str[rtype].backcol : "" ),
        ( dam > 250 ? sp_dam_str[rtype].invertcol : sp_dam_str[rtype].basecol ) );
    sprintf( innercol, "%s%s",
        ( dam > 250 ? sp_dam_str[rtype].backcol : "" ),
        ( dam > 500 ? sp_dam_str[rtype].stresscol : 
          ( dam > 250 ? sp_dam_str[rtype].invertcol : sp_dam_str[rtype].basecol ) ) ); 

   catsymbuf[0] = '\0';
   sprintf( symbuf, "%s", " " );
   for( ; dam_range > 0; dam_range -= 50 )
   {
     sprintf( catsymbuf, sp_dam_str[rtype].formatter, outercol, innercol, outercol );
     safe_strcat( MSL, symbuf, catsymbuf );
   }
   safe_strcat( MSL, symbuf, " " );



	if ( dt >= 0 && dt < MAX_SKILL )
	    attack      = skill_table[dt].noun_damage;
	else
	{
	    bug( "Dam_message: bad dt %d.", dt );
	    rtype  = 0;
	    attack  = "!!!!!";
	}
  if ( obj == NULL )
  {	
	   sprintf( buf1, "%s$n %s%s%s@@N $N %swith $s %s%c@@N%s",
        sp_dam_str[rtype].basecol,
        symbuf, 
        ( stress ? sp_dam_str[rtype].vp_stress : sp_dam_str[rtype].vp ),
        symbuf,
        sp_dam_str[rtype].basecol, 
        attack,
        punct,
        testerbuf );
	   sprintf( buf2, "%sYou %s%s%s@@N $N %swith your %s%c@@N%s",
        sp_dam_str[rtype].basecol,
        symbuf,
        ( stress ? sp_dam_str[rtype].vs_stress : sp_dam_str[rtype].vs ),
        symbuf,
        sp_dam_str[rtype].basecol,
        attack,
        punct,
        testerbuf );
/*	   if ( *str == '\'' )
	    sprintf( buf3, "%s$n %s%s your%s%s $s %s%c@@N",col,col, vp,col, str+2, attack, punct);
	   else
*/
	    sprintf( buf3, "%s$n %s%s%s %syou with $s %s%c@@N%s",
      sp_dam_str[rtype].basecol, 
      symbuf,
      ( stress ? sp_dam_str[rtype].vp_stress : sp_dam_str[rtype].vp ),
      symbuf, 
      sp_dam_str[rtype].basecol,
      attack,
      punct,
      testerbuf );
  }
  else if ( obj != NULL )
  {	
	   sprintf( buf1, "%s$p %s%s%s@@N $N %swith a %s%c@@N",
        sp_dam_str[rtype].basecol,
        symbuf, 
        ( stress ? sp_dam_str[rtype].vp_stress : sp_dam_str[rtype].vp ),
        symbuf,
        sp_dam_str[rtype].basecol, 
        attack,
        punct );
#if 0
	   sprintf( buf2, "%sYou %s%s%s@@N $N %swith your %s%c@@N%s",
        sp_dam_str[rtype].basecol,
        symbuf,
        ( stress ? sp_dam_str[rtype].vs_stress : sp_dam_str[rtype].vs ),
        symbuf,
        sp_dam_str[rtype].basecol,
        attack,
        punct,
        testerbuf );
#endif
/*	   if ( *str == '\'' )
	    sprintf( buf3, "%s$n %s%s your%s%s $s %s%c@@N",col,col, vp,col, str+2, attack, punct);
	   else
*/
	    sprintf( buf3, "%s$p %s%s%s %syou with $s %s%c@@N",
      sp_dam_str[rtype].basecol, 
      symbuf,
      ( stress ? sp_dam_str[rtype].vp_stress : sp_dam_str[rtype].vp ),
      symbuf, 
      sp_dam_str[rtype].basecol,
      attack,
      punct );
  }
  else 
  {
    sprintf( log_buf, "%s", "Error in casting spell , sp_dam called with NULL obj and ch.");
    monitor_chan( log_buf, MONITOR_DEBUG );
    return;
  }
    if ( obj == NULL ) 
    {
      act( buf1, ch, NULL, victim, TO_NOTVICT );
    }
    else
    {
      act( buf1, NULL, (void *) obj, victim, TO_NOTVICT );
    }
    if ( !IS_NPC( ch ) && IS_SET( ch->pcdata->pflags, PFLAG_BLIND_PLAYER ) )
    {
      if ( dam < victim->max_hit/ 30 )
        act( "You glance $K", ch, NULL, victim, TO_CHAR );
      else if ( dam < victim->max_hit/ 20 )
        act( "You hit $K", ch, NULL, victim, TO_CHAR );
      else if ( dam < victim->max_hit / 10 )
        act( "You nail $K", ch, NULL, victim, TO_CHAR );
      else
        act( "You thwack $K", ch, NULL, victim, TO_CHAR );
    }
    else if ( obj == NULL )
    {
      act( buf2, ch, NULL, victim, TO_CHAR );
    }
    if ( !IS_NPC( victim ) && IS_SET( victim->pcdata->pflags, PFLAG_BLIND_PLAYER ) )
    {
      if ( dam < victim->max_hit/ 30 )
        act( "$k glances you", ch, NULL, victim, TO_VICT );
      else if ( dam < victim->max_hit/ 20 )
        act( "$k hits you", ch, NULL, victim, TO_VICT );
      else if ( dam < victim->max_hit / 10 )
        act( "$k nails you", ch, NULL, victim, TO_VICT );
      else
        act( "$k thwacks you", ch, NULL, victim, TO_VICT );
    }
    else if ( obj == NULL )
    {
      act( buf3, ch, NULL, victim, TO_VICT );
    }
    else 
    {
      act( buf3, NULL, (void *) obj, victim, TO_VICT );
    }
    if ( dead )
    {
        sp_death_message( ch, victim, realm );
    }
    return;
}



bool sp_damage( OBJ_DATA * obj, CHAR_DATA *ch, CHAR_DATA *victim, int dam, int type, int sn, bool show_msg )
{
     int  ch_strong, ch_weak, ch_race, ch_suscept, ch_resist,
          vi_strong, vi_weak, vi_race, vi_suscept, vi_resist;
     float dam_modifier = 1.0;
     bool can_reflect = TRUE;
     bool can_absorb = TRUE;

/*   char buf[MAX_STRING_LENGTH];   this is unused now -- uni */


    if (  ( victim->is_free == TRUE )  )
	return FALSE;

/*
 *  First, check caster's strengths and weaknesses.
 *
 */

    if ( IS_SET( type, NO_REFLECT ) )
    {
      REMOVE_BIT( type, NO_REFLECT );
      can_reflect = FALSE;
    }
    if ( IS_SET( type, NO_ABSORB ) )
    {
      REMOVE_BIT( type, NO_ABSORB );
      can_absorb = FALSE;
    }
  if ( obj == NULL )
  {
    if (  ( can_reflect )
       && ( skill_table[sn].target == TAR_CHAR_OFFENSIVE )
       && ( IS_AFFECTED( victim, AFF_CLOAK_REFLECTION ) )
       && ( ch != victim )
       && ( number_percent( ) < ( get_psuedo_level( victim ) - 70 ) )  )
    {
            
      act( "@@N$n's @@lc@@el@@ro@@ya@@ak@@N glows brightly as $Nn's spell hits it, and the spell is reflected@@N!!", ch, victim, NULL, TO_ROOM );
      act( "@@N$N's @@lc@@el@@ro@@ya@@ak@@N glows brightly, and reflects your spell back on you@@N!!", ch, NULL, victim, TO_CHAR );
      act( "@@NYour @@lc@@el@@ro@@ya@@ak@@N glows brightly, and reflects the spell back on $N@@N!!!", victim, NULL, ch, TO_CHAR );
     (*skill_table[sn].spell_fun) ( sn, 60, ch, (void *) ch, NULL );
     return FALSE;

    }


    else if (  ( can_reflect )
            && ( skill_table[sn].target == TAR_CHAR_OFFENSIVE )
            && ( IS_AFFECTED( victim, AFF_CLOAK_ABSORPTION ) )
            && ( ch != victim )
            && ( number_percent( ) < ( get_psuedo_level( victim ) - 55 ) )  )
    {
      int mana;
      mana = mana_cost( ch, sn );
      victim->mana = UMIN( victim->max_mana, victim->mana + mana );
      
      act( "@@N$n's @@lcloak@@N glows brightly as $N's spell hits it, then fades@@N!!", victim, NULL, ch, TO_ROOM );
      act( "@@N$N's @@lcloak@@N glows brightly, and absorbs your spell@@N!!", ch, NULL, victim, TO_CHAR );
      act( "@@NYour @@lcloak@@N glows brightly, and absorbs $N's spell@@N!!!", victim, NULL, ch, TO_CHAR );
      return FALSE;
    }  




  ch_strong = ( IS_NPC( ch ) ?
                ( (  ( ch->race > 0 )
                  && ( ch->race < MAX_RACE ) ) ?
                  race_table[ch->race].strong_realms :
                  ch->strong_magic ) :
                race_table[ch->race].strong_realms );
  ch_resist = ( IS_NPC( ch ) ?
                ( (  ( ch->race > 0 )
                  && ( ch->race < MAX_RACE ) ) ?
                  race_table[ch->race].resist_realms :
                  ch->resist ) :
                race_table[ch->race].resist_realms );
  ch_weak = ( IS_NPC( ch ) ?
                ( (  ( ch->race > 0 )
                  && ( ch->race < MAX_RACE ) ) ?
                  race_table[ch->race].weak_realms :
                  ch->weak_magic ) :
                race_table[ch->race].weak_realms );
  ch_suscept = ( IS_NPC( ch ) ?
                ( (  ( ch->race > 0 )
                  && ( ch->race < MAX_RACE ) ) ?
                  race_table[ch->race].suscept_realms :
                  ch->suscept ) :
                race_table[ch->race].suscept_realms );
  ch_race = ( IS_NPC( ch ) ?
                ( (  ( ch->race > 0 )
                  && ( ch->race < MAX_RACE ) ) ?
                  race_table[ch->race].race_flags :
                  ch->race_mods ) :
                race_table[ch->race].race_flags );

  if ( IS_SET( ch_strong, type ) )
  {
    dam_modifier += .35;
  }
  else if ( IS_SET( ch_weak, type ) )
  {
    dam_modifier -= .35;
  }

  if ( IS_SET( ch_race, RACE_MOD_STRONG_MAGIC ) )
  {
    dam_modifier += .25;
  }
  else if ( IS_SET( ch_race, RACE_MOD_WEAK_MAGIC ) )
  {
    dam_modifier -= .25;
  }
  else if ( IS_SET( ch_race, RACE_MOD_NO_MAGIC ) )
  {
    dam_modifier -= .50;
  }

  if ( ch->stance == STANCE_CASTER )
    dam_modifier += .10;
  else if  ( ch->stance == STANCE_WIZARD )
    dam_modifier += .25;
  else if ( ch->stance == STANCE_MAGI )
    dam_modifier += .30;

    if (  ( !IS_NPC( ch ) )
       && ( !IS_SET( type, REALM_MIND ) )  )
    {
      if ( ch->pcdata->learned[ gsn_potency ] > 0 )
      {
        dam_modifier +=
          ( get_curr_int( ch ) * ch->pcdata->learned[gsn_potency] /5000 );
      }

      if ( ch->pcdata->learned[ gsn_thaumatergy ] > 0 )
      {
        dam_modifier +=
          ( get_curr_int( ch ) * ch->pcdata->learned[gsn_thaumatergy] /2500 );
      }     
    }       
    if ( is_affected( ch, skill_lookup( "mystical focus" ) ) )
    {
      dam_modifier += .5;
    }
  } /* obj == NULL */
  else if ( obj->carried_by != NULL )
  {
    ch = obj->carried_by;
  }
  else
  {
    sprintf( log_buf, "Error, object %s casting spell, but not carried by anyone.",
     obj->short_descr );
    monitor_chan( log_buf, MONITOR_DEBUG );
    return FALSE;
  }
  
/* 
 *  Next, the victim
 *
 */
  vi_strong = ( IS_NPC( victim ) ?
                ( (  ( victim->race > 0 )
                  && ( victim->race < MAX_RACE ) ) ?
                  race_table[victim->race].strong_realms :
                  victim->strong_magic ) :
                race_table[victim->race].strong_realms );
  vi_resist = ( IS_NPC( victim ) ?
                ( (  ( victim->race > 0 )
                  && ( victim->race < MAX_RACE ) ) ?
                  race_table[victim->race].resist_realms :
                  victim->resist ) :
                race_table[victim->race].resist_realms );
  vi_weak = ( IS_NPC( victim ) ?
                ( (  ( victim->race > 0 )
                  && ( victim->race < MAX_RACE ) ) ?
                  race_table[victim->race].weak_realms :
                  victim->weak_magic ) :
                race_table[victim->race].weak_realms );
  vi_suscept = ( IS_NPC( victim ) ?
                ( (  ( victim->race > 0 )
                  && ( victim->race < MAX_RACE ) ) ?
                  race_table[victim->race].suscept_realms :
                  victim->suscept ) :
                race_table[victim->race].suscept_realms );
  vi_race = ( IS_NPC( victim ) ?
                ( (  ( victim->race > 0 )
                  && ( victim->race < MAX_RACE ) ) ?
                  race_table[victim->race].race_flags :
                  victim->race_mods ) :
                race_table[victim->race].race_flags );

  if ( IS_SET( vi_suscept, type ) )
  {
    dam_modifier += .45;
  }
  else if ( IS_SET( vi_resist, type ) )
  {
    dam_modifier -= .45;
  }

  else if ( IS_SET( vi_race, RACE_MOD_NO_MAGIC ) )
  {
    dam_modifier -= .25;
  }

  if ( MAGIC_STANCE( ch ) )
    dam_modifier += .15;

  if (  ( IS_SET( type, REALM_MIND ) )
     && ( !HAS_MIND( victim )  )  )
    dam_modifier = 0.0;
  else if (  (  ( IS_SET( type, REALM_IMPACT ) )
             || ( IS_SET( type, REALM_ACID ) )
             || ( IS_SET( type, REALM_GAS ) )  )
          && ( !HAS_BODY( victim ) )  )
    dam_modifier = 0.0;
 
  if (  ( IS_SET( type, REALM_POISON ) )
     && ( IS_SET( vi_race, RACE_MOD_IMMUNE_POISON ) )  )
     dam_modifier = 0.0;

  if (  ( IS_SET( type, REALM_DRAIN ) )
     && ( IS_UNDEAD( victim ) )  )
     dam_modifier = 0.0;  
       
  dam *= dam_modifier;

    /*
     * Stop up any residual loopholes.
     */
  if ( dam > 3000 )
  {
    char buf[MAX_STRING_LENGTH];
    sprintf( buf, "Spell: %d damage by %s, spell %s", dam,
    ( obj == NULL ) ?
     ( IS_NPC(ch) ? ch->short_descr : ch->name ) :
      obj->short_descr,
    skill_table[sn].name );
    log_f( buf );
/*    dam = 3000; */
  }

  if ( victim != ch )
  {
	/*
	 * Certain attacks are forbidden.
	 * Most other attacks are returned.
	 */
    if ( is_safe( ch, victim ) )
      return FALSE;
    if ( victim != ch->fighting )   
      check_killer( ch, victim );  

    if ( victim->position > POS_STUNNED )
    {
	    if ( victim->fighting == NULL )
        set_fighting( victim, ch, FALSE );
	    victim->position = POS_FIGHTING;
    }

    if ( victim->position > POS_STUNNED )
    {
	    if ( ch->fighting == NULL )
	    {
        set_fighting( ch, victim, TRUE );
	    }


	    /*
	     * If victim is charmed, ch might attack victim's master.
	     */
	    if ( IS_NPC(ch)
	    &&   IS_NPC(victim)
	    &&   IS_AFFECTED(victim, AFF_CHARM)
	    &&   victim->master != NULL
	    &&   victim->master->in_room == ch->in_room
	    &&   number_bits( 3 ) == 0 )
	    {
        stop_fighting( ch, FALSE );
        multi_hit( ch, victim->master, TYPE_UNDEFINED );
	    }
    }

	/*
	 * More charm stuff.
	 */
    if ( victim->master == ch )
	    stop_follower( victim );

	/*
	 * Inviso attacks ... not.
	 */
    if ( IS_AFFECTED(ch, AFF_INVISIBLE) )
    {
	    affect_strip( ch, gsn_invis );
	    affect_strip( ch, gsn_mass_invis );
	    REMOVE_BIT( ch->affected_by, AFF_INVISIBLE );
	    act( "$n shimmers into existence.", ch, NULL, NULL, TO_ROOM );
    }

	/*
	 * Damage modifiers.
	 */

    if ( dam < 0 )
	    dam = 0;

    if (  ( show_msg ) 
       && ( dam >= 0 )  )
	    sp_dam_message( obj, ch, victim, dam, type, sn );

  }

    /*
     * Hurt the victim.
     * Inform the victim of his new state.
     */
    victim->hit -= dam;
     if ( !IS_NPC ( victim ) )
      check_adrenaline( victim , dam );

     if ( !IS_NPC( victim ) && IS_WOLF( victim ) && ( dam > 350 )  )
       do_rage( victim, "FORCE" );

    update_pos( victim );

    if ( ( IS_NPC( victim) || !IS_VAMP( victim ) ) &&  !( deathmatch) )
    {
      switch( victim->position )
      {
        case POS_MORTAL:
           act( "$n is mortally wounded, and will die soon, if not aided.",
           victim, NULL, NULL, TO_ROOM );
           send_to_char( 
	         "You are mortally wounded, and will die soon, if not aided.\n\r",
	         victim );
          break;

        case POS_INCAP:
          act( "$n is incapacitated and will slowly die, if not aided.",
           victim, NULL, NULL, TO_ROOM );
          send_to_char(
         "You are incapacitated and will slowly die, if not aided.\n\r",
          victim );
          break;

        case POS_STUNNED:
          act( "$n is too stunned to do anything!",
            victim, NULL, NULL, TO_ROOM );
          send_to_char("You are too stunned to do anything!\n\r",
            victim );
          break;

        case POS_DEAD:
          act( "$n is DEAD!!", victim, 0, 0, TO_ROOM );
         send_to_char( "You have been KILLED!!\n\r\n\r", victim );
         break;

        default:
        if ( dam > victim->max_hit / 4 )
         send_to_char( "That really did HURT!\n\r", victim );
        if ( victim->hit < victim->max_hit / 4 )
         send_to_char( "You sure are BLEEDING!\n\r", victim );
         break;
      }
    } /* end of if statement */
    /*
     * Sleep spells and extremely wounded folks.
     */
    if ( !IS_AWAKE(victim) )
      stop_fighting( victim, FALSE );

    /*
     * Payoff for killing things.
     */
    
    
    
    if ( victim->position == POS_DEAD && ( IS_NPC( victim ) || !IS_VAMP( victim ) || ( deathmatch ) )  )
    {
      group_gain( ch, victim );

	/* Sort out kill counts..... */
    if ( !IS_NPC( ch ) )
    {
        if ( !IS_NPC( victim ) )
	        ch->pcdata->pkills++;
        else
            ch->pcdata->mkills++;
    }

    if ( !IS_NPC( victim ) )
	{
	    if ( !IS_NPC( ch ) )
	        victim->pcdata->pkilled++;
	    else
	        victim->pcdata->mkilled++;
	}
	 	
	if ( !IS_NPC(victim) || IS_SET(victim->act,ACT_INTELLIGENT))
	{


            sprintf( log_buf, "%s killed by %s at %d",
		(IS_NPC(victim) ? victim->short_descr : victim->name),
		(IS_NPC(ch) ? ch->short_descr : ch->name),
		victim->in_room->vnum );
	    log_string( log_buf );

	notify( log_buf, 82 );

	/* As level gain is no longer automatic, a dead char loses
	 * 1/2 their gained exp.  -S- 
         * Fixed my bug here too, hehe!
	 */

	    if ( victim->exp > 0 )
            {
               gain_exp( victim, ( 0 - ( victim->exp / 2 ) ) );
               victim->exp = UMAX( victim->exp, 0 );
            }
		
	}

        if ( IS_NPC(ch) )
 	   raw_kill( victim, "" );
        else
        {
          char name_buf[MAX_STRING_LENGTH];
          sprintf( name_buf, "%s", ch->name );
	    raw_kill( victim, name_buf );
        }

	if ( deathmatch && !IS_NPC( victim ) )
	   do_quit( victim, "" );
	
	if ( IS_NPC(ch) && IS_NPC(victim) && IS_SET( ch->act, ACT_INTELLIGENT ) )
	{
	   do_get( ch, "all corpse" );
	   do_sacrifice( ch, "corpse" );
	}
	
	if ( !IS_NPC(ch) && IS_NPC(victim) )
	{
	    if ( IS_SET(ch->config, CONFIG_AUTOLOOT) )
		do_get( ch, "all corpse" );
	    else
		do_look( ch, "in corpse" );

	    if ( IS_SET(ch->config, CONFIG_AUTOSAC) )
		do_sacrifice( ch, "corpse" );
	}

	return FALSE;
    }

    if ( victim == ch )
	return TRUE;

    /*
     * Take care of link dead people.
     */
    if ( !IS_NPC(victim) && victim->desc == NULL )
    {
	if ( number_range( 0, victim->wait ) == 0 )
	{
	    do_recall( victim, "" );
	    return TRUE;
	}
    }

    /*
     * Wimp out?
     */
    if ( IS_NPC(victim) && dam > 0 )
    {
	if ( ( IS_SET(victim->act, ACT_WIMPY) && number_bits( 1 ) == 0
	&&   victim->hit < victim->max_hit / 2 )
	||   ( IS_AFFECTED(victim, AFF_CHARM) && victim->master != NULL
	&&     victim->master->in_room != victim->in_room ) )
	    do_flee( victim, "" );
    }

    if ( !IS_NPC(victim)
    &&   victim->hit > 0
    &&   victim->hit <= victim->wimpy
    &&   victim->wait == 0 )
	do_flee( victim, "" );

    tail_chain( );
    return TRUE;

}