/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

magic.c					Spells, the actual code of each 
					spell... arrive here from sparse.

		******** Heavily modified and expanded ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** Heavily modified and expanded ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***

  NOTE:  All spells1.c and spells2.c have been COMBINED with this magic.c
  file, in an attempt to put the spells closer together to make additions
  and alterations much easier than having to hop from file to file.
************************************************************************ */
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "comm.h"
#include "magic.h"
#include "handler.h"
#include "mudlimits.h"
#include "interpreter.h"
#include "acmd.h"
#include "db.h"
#include "fight.h"
#include "affect.h"
#include "lists.h"
#include "htown.h"
#include "global.h"
#include "darkenelf.h"

/* extern variables */
extern char *dirs[];
extern char *comm_dirs[];
extern int rev_dir[];
extern char	*item_types[];
extern char	*extra_bits[];
extern char	*extra_bits2[];
extern char	*apply_types[];
extern char	*affected_bits[];
extern char	*affected2_bits[];
extern char	*wv_bits[];

/* extern functions */
BOOL saves_spell(chdata *ch, int spell);
void weight_change_object(obdata *obj, int weight);
int check_room_affects(chdata *ch, int room);

// replace old USE_MANA macro with function, -jtrhone 8/16/98
int manause(chdata *ch, int spl)
{
  // madepts special case
  switch(GET_CLASS(ch)) {
    case CLASS_MADEPT:
    return MAX(spell_info[spl].min_usesmana, 100/MAX(1, (2+GET_LEVEL(ch) - (LEV_IMM/2))));
    break;

    default:
    break;
  }

  return MAX(spell_info[spl].min_usesmana, 100/MAX(1, (2+GET_LEVEL(ch) - get_spell_min_level(ch, spl))));
}

// the main interface to all the ASPELLS now...
void do_cast_spell(int spl, chdata *ch, char *arg, int type, chdata *victim, obdata *obj)
{
  int retval;

  if (IN_NOWHERE(ch)) return;

  if (WAITING(ch))
  {
     send_to_char("You cannot cast anything right now!\n\r",ch);
     return;
  }

  switch (type) {
   case SPELL_TYPE_SPELL:
      if (SPELL_FLAGGED(spl, S_CASTABLE))
      {
	// cant cast if room is silenced
	if (spell_affects_room(ch->in_room, SPELL_SILENCE) && spl < 230) /* regular, non-breath */
	{
	  act("This area is %Bsilenced%0!", FALSE, ch, 0, 0, TO_CHAR);
	  act("$n cannot cast $s spell because this area is %Bsilenced!%0", FALSE, ch, 0, 0, TO_ROOM);
	  return;
	}
	else
	  retval = (*spell_info[spl].spell_pointer)(ch, arg, victim, obj);

        switch(retval) {
          case SPELL_SUCCESS:
	    act("Success!", FALSE, ch, 0, 0, TO_CHAR);
            break;

          case SPELL_FAILED:
	    act("Your spell failed...", FALSE, ch, 0, 0, TO_CHAR);
            break;

          case SPELL_NORMAL:
          default:
            break;
        }
      }
      break;

   case SPELL_TYPE_POTION:
      if(SPELL_FLAGGED(spl, S_POTION))
        (*spell_info[spl].spell_pointer)(ch, arg, victim, obj);
      break;

   case SPELL_TYPE_SCROLL:
      if(SPELL_FLAGGED(spl, S_SCROLL))
      {
        if (victim)
          (*spell_info[spl].spell_pointer)(ch, arg, victim, obj);
	else
	if (obj)
          (*spell_info[spl].spell_pointer)(ch, arg, NULL, obj);
        else 
	if (!obj)
          (*spell_info[spl].spell_pointer)(ch, arg, ch, NULL);
      }
      break;

   case SPELL_TYPE_WAND:
      if(SPELL_FLAGGED(spl, S_WAND) && victim)
        (*spell_info[spl].spell_pointer)(ch, arg, victim, obj);
      break;

   case SPELL_TYPE_STAFF:
      if(SPELL_FLAGGED(spl, S_STAFF))
      for (victim = world[ch->in_room].people; victim; victim = victim->next_in_room)
	 if (victim != ch)
          (*spell_info[spl].spell_pointer)(ch, arg, victim, obj);
      break;

   default :
      log("SYSERR: unknown spell type to do_cast_spell!");
      break;
  }
}


ASPELL(spell_chain_lightning)
{
  int size_die, dam;

  if (!victim)
    return SPELL_FAILED;

/*
  Mana(ch) -= (Level(ch) * 2);
*/
  size_die = (Level(ch) / 2);
  dam = dice(size_die, 6);

  SpellDamage(ch, victim, dam, SPELL_CHAIN_LIGHTNING, FALSE);
  size_die -= 5;

  CharsInRoom(ch, victim) {
    if (!InSameGroup(ch, victim)) {
      dam = dice(size_die, 6);

      SpellDamage(ch, victim, dam, SPELL_CHAIN_LIGHTNING, FALSE);
      size_die -= 5;
    }
  }
  return SPELL_NORMAL;
}


ASPELL(spell_fireball)
{
  int size_die, dam;

/*
  Mana(ch) -= (Level(ch) * 2);
*/
  size_die = (Level(ch) / 2);
  dam = dice(size_die, 6);

  CharsInRoom(ch, victim) {
    if (!InSameGroup(ch, victim)) {
      dam = dice(size_die, 6);

      SpellDamage(ch, victim, dam, SPELL_FIREBALL, FALSE);
    }
  }
  return SPELL_NORMAL;
}


// Animate dead added per request of Mouseglove... 08/06/98 -callahan
ASPELL(spell_animate_dead)
{
  AffType af, af2;
  CharData *mob;
  ObjData *corpse, *next_corpse, *tobj, *next_obj;
  int mobnum, corpses = 0;

  if (affected_by_spell(ch, SPELL_ANIMATE_DEAD)) {
    SendChar("You are already in the process of animating the dead.\r\n", ch);
    return SPELL_FAILED;
  }

  if (MaxSummons(ch))
    return SPELL_FAILED;

  for (corpse = world[InRoom(ch)].contents; corpse; corpse = next_corpse) {
    next_corpse = corpse->next_content;

    if (CAN_SEE_OBJ(ch, corpse) && (ITEM_TYPE(corpse) == ITEM_CONTAINER) &&
        corpse->value[3]) {
      corpses++;

      if (corpses < (Level(ch) / 10)) {
        if (Mana(ch) < Level(ch)) {
          SendChar(tprintf("You haven't enough energy to animate anything%s."
                           "\r\n", (corpses > 1) ? " else" : ""),  ch);
          return SPELL_NORMAL;
        }

        if (InRange(Level(ch), 60, 75))
          mobnum = 739;
        else if (InRange(Level(ch), 55, 75))
          mobnum = 738;
        else if (InRange(Level(ch), 50, 75))
          mobnum = 737;
        else if (InRange(Level(ch), 45, 75))
          mobnum = 736;
        else if (InRange(Level(ch), 40, 75))
          mobnum = 735;
        else if (InRange(Level(ch), 35, 75))
          mobnum = 734;
        else if (InRange(Level(ch), 30, 75))
          mobnum = 733;
        else if (InRange(Level(ch), 25, 75))
          mobnum = 732;
        else if (InRange(Level(ch), 20, 75))
          mobnum = 731;
        else if (InRange(Level(ch), 15, 75))
          mobnum = 730;

        mobnum = number(730, mobnum);

        if (!(mob = read_mobile(mobnum, VIRTUAL))) {
          SendChar("Seek immortal assistance, undead non-existance error.\n\r",
                   ch);
          return SPELL_FAILED;
        }
        Mana(ch) -= Level(ch);
        SET_BIT(CHAR_FLAGS(mob), CH_SUMMONED);
        SUMMONER(mob) = GET_IDNUM(ch);

        char_to_room(mob, InRoom(ch));

        act(tprintf("$n waves $s arms over %s, chanting in dark undertones.",
                    corpse->shdesc), TRUE, ch, 0, 0, TO_ROOM);
        SendChar(tprintf("You wave your arms, and begin to animate %s.\r\n",
                         corpse->shdesc), ch);
        act("$n slowly rises from the ground.", FALSE, mob, 0, 0, TO_ROOM);
        add_follower(mob, ch);
     
        for (tobj = corpse->contains; tobj; tobj = next_obj) {
          next_obj = tobj->next_content;
          obj_from_obj(tobj);
          obj_to_char(tobj, mob);
        }

        NewAffect(&af);

        af.type = SPELL_ANIMATE_DEAD;
        af.bitvector = AFF_CHARM;
        af.duration = -1;
        affect_to_char(mob, &af);

        NewAffect(&af2);

        af2.type = SPELL_ANIMATE_DEAD;
	af2.duration = 1;
        af2.bitvector = AFF_HOLD;
        affect_to_char(mob, &af2);
  
        extract_obj(corpse);
      } else
        return SPELL_NORMAL;
    }
  }

  // If anything was animated, set spell on char to notify when animation
  // is finished. 08/10/98 -callahan
  if (corpses) {
    NewAffect(&af);

    af.type = SPELL_ANIMATE_DEAD;
    af.duration = 1;
    affect_to_char(ch, &af);
  } else {
    SendChar("You do not see anything dead around here...\r\n", ch);
    return SPELL_FAILED;
  }

  return SPELL_NORMAL;
}


ASPELL(spell_magic_missile)
{
  int dam = 0, num_missile = 0, missile_cnt = 0;
  int level = GET_LEVEL(ch);

  if (!victim) return SPELL_FAILED;

  num_missile = (level/10) + 1;
  for (missile_cnt=1; missile_cnt <= num_missile; missile_cnt++)
    dam += number(1,4);

  SpellDamage(ch, victim, dam, SPELL_MAGIC_MISSILE, FALSE);

  return SPELL_NORMAL;
}

ASPELL(spell_chill_touch)
{
  struct affected_type af;
  int dam;

  if (!victim) return SPELL_FAILED;

  dam = number(1,7) + 7;
  if (!saves_spell(victim, SPELL_CHILL_TOUCH))
  {
    af.type      = SPELL_CHILL_TOUCH;
    af.duration  = 6;
    af.modifier  = -1;
    af.location  = APPLY_STR;
    af.bitvector = 0;
    af.bitvector2 = 0;
    affect_join(victim, &af, TRUE, FALSE);
  } 
  else 
    dam >>= 1;
  damage(ch, victim, dam, SPELL_CHILL_TOUCH, FALSE);
  return SPELL_NORMAL;
}

ASPELL(spell_burning_hands)
{
  int dam;

  if (!victim)
    return SPELL_FAILED;

  dam = number(10,20);
  SpellDamage(ch, victim, dam, SPELL_BURNING_HANDS, FALSE);
  return SPELL_NORMAL;
}

ASPELL(spell_shocking_grasp)
{
  int	dam;

  if (!victim)
    return SPELL_FAILED;

  dam = number(1,10) + 25;
  SpellDamage(ch, victim, dam, SPELL_SHOCKING_GRASP, FALSE);
  return SPELL_NORMAL;
}

// Modified damage. 08/13/98 -callahan
ASPELL(spell_lightning_bolt)
{
  int	dam;

  if (!victim)
    return SPELL_FAILED;

/*
  Mana(ch) -= Level(ch);
*/
  dam = dice(Level(ch) / 2, 6);

  SpellDamage(ch, victim, dam, SPELL_LIGHTNING_BOLT, FALSE);
  return SPELL_NORMAL;
}

ASPELL(spell_colour_spray)
{
  int	dam;

  if (!victim)
    return SPELL_FAILED;

  dam = number(40,60);

  SpellDamage(ch, victim, dam, SPELL_COLOUR_SPRAY, FALSE);
  return SPELL_NORMAL;
}

ASPELL(spell_energy_drain)
{
  int	dam, xp, mana;
  int level = GET_LEVEL(ch);

  if (!victim) return SPELL_FAILED;

  if (IN_ARENA(ch) || IN_ARENA(victim))
  {
    act("You can no longer use this spell in an arena.",FALSE,ch,0,0,TO_CHAR);
    return SPELL_FAILED;
  }

  if (!saves_spell(victim, SPELL_ENERGY_DRAIN))
  {
    GET_ALIGNMENT(ch) = MAX(-1000, GET_ALIGNMENT(ch) - 200);

    if (GET_LEVEL(victim) <= 2) 
      damage(ch, victim, 100, SPELL_ENERGY_DRAIN, FALSE); 
    else 
    {
	 xp = number(level >> 1, level) * 1000;
	 gain_exp(victim, -xp);
	 dam = dice(1, 10);
	 mana = GET_MANA(victim) >> 1;
	 GET_MOVE(victim) >>= 1;
	 GET_MANA(victim) = mana;
	 GET_MANA(ch) += mana >> 1;
	 GET_HIT(ch) += dam;
	 act("Your life energy is drained!",FALSE,victim,0,0,TO_CHAR);
	 damage(ch, victim, dam, SPELL_ENERGY_DRAIN, FALSE);
    }
  } 
  else
    damage(ch, victim, 0, SPELL_ENERGY_DRAIN, FALSE); /* Miss */

  return SPELL_NORMAL;
}

// Changed from spell_fireball. 08/13/98 -callahan
ASPELL(spell_fireflash)
{
  int	dam;

  if (!victim)
    return SPELL_FAILED;

/*
  Mana(ch) -= Level(ch);
*/
  dam = dice(Level(ch) / 2, 6);

  SpellDamage(ch, victim, dam, SPELL_FIREFLASH, FALSE);
  return SPELL_NORMAL;
}


ASPELL(spell_earthquake)
{
  int	dam;
  chdata *tmp_victim, *temp;
  BOOL pc = 0;
  int level = GET_LEVEL(ch);

  if (IN_NOWHERE(ch)) return SPELL_FAILED;

  dam =  dice(1, 8) + level;

  act("The earth trembles beneath your feet!", FALSE, ch, 0, 0, TO_CHAR);
  act("$n makes the earth tremble and shiver!\n\rYou fall, and hit yourself!", FALSE, ch, 0, 0, TO_ROOM);

  if (IS_PC(ch)) 
    pc = TRUE;

  for (tmp_victim = character_list; tmp_victim; tmp_victim = temp) 
  {
    temp = tmp_victim->next;
    if (SAME_ROOM(ch, tmp_victim) && ch != tmp_victim &&
        ((pc && IS_NPC(tmp_victim)) || (!pc && IS_PC(tmp_victim))))
    {
	 if (GET_POS(tmp_victim) == POS_SLEEPING)
	   do_wake(tmp_victim, "", 0, 0);
      
      // fix NOKILL mobs taking damage here 5/29/98 -jtrhone
      // also ppl in flight or truced...
      if (!SPC_FLAGGED(tmp_victim, SPC_NOKILL) && !IS_FLYING(tmp_victim) && check_truce(ch, tmp_victim))
	 damage(ch, tmp_victim, dam, SPELL_EARTHQUAKE, FALSE);
    }
    else 
    if (world[ch->in_room].zone == world[tmp_victim->in_room].zone)
      send_to_char("The earth trembles and shivers!\n\r", tmp_victim);
  }

  return SPELL_NORMAL;
}

ASPELL(spell_dispel_evil)
{
  int	dam;
  int level = GET_LEVEL(ch);

  if (!victim) return SPELL_FAILED;

  if (IS_EVIL(ch))
     victim = ch;
  else 
  if (!IS_EVIL(victim)) 
  {
    act("$N is not evil.", FALSE, ch, 0, victim, TO_CHAR);
    return SPELL_NORMAL;
  }

  if ((GET_LEVEL(victim) <= level) || (victim == ch))
    dam = 100;
  else 
  {
    dam = dice(level, 4);
    if (saves_spell(victim, SPELL_DISPEL_EVIL))
      dam >>= 1;
  }
  damage(ch, victim, dam, SPELL_DISPEL_EVIL, FALSE);

  return SPELL_NORMAL;
}

ASPELL(spell_call_lightning)
{
  int	dam;
  int level = GET_LEVEL(ch);

  if (!victim)
    return SPELL_FAILED;

  dam = dice(MIN(level, 15), 8);

  SpellDamage(ch, victim, dam, SPELL_CALL_LIGHTNING, FALSE);
  return SPELL_NORMAL;
}

ASPELL(spell_harm)
{
  int	dam;

  if (!victim) return SPELL_FAILED;

  dam = GET_HIT(victim) - dice(1, 4);
  if (dam < 0)
    dam = 0; 
  else
  if (saves_spell(victim, SPELL_HARM))
    dam = MIN(30, dam / 3);
  damage(ch, victim, dam, SPELL_HARM, FALSE);
  return SPELL_NORMAL;
}

ASPELL(spell_armor)
{
  struct affected_type af;

  if (!victim) return SPELL_FAILED;

  if (!affected_by_spell(victim, SPELL_ARMOR) && 
      !affected_by_spell(victim, SPELL_STONE_SKIN) &&
      !affected_by_spell(victim, SPELL_BARKSKIN)) 
  {
    af.type      = SPELL_ARMOR;
    af.duration  = 24;
    af.modifier  = -GET_LEVEL(ch);
    af.location  = APPLY_AC;
    af.bitvector = 0;
    af.bitvector2 = 0;

    affect_to_char(victim, &af);
    if (ch == victim)
    {
      act("You protect yourself with a mystical armor!", FALSE, ch, 0, 0, TO_CHAR);
      act("$n protects $mself with a mystical armor!", FALSE, ch, 0, 0, TO_ROOM);
    }
    else
    {
    act("You protect $N with a mystical armor!", FALSE, ch, 0, victim, TO_CHAR);
    act("$n protects you with $s mystical armor!", FALSE, ch, 0, victim, TO_VICT);
    }
  }
  else
  {
    if (victim == ch)
      act("You are already protected!", FALSE, ch, 0, 0, TO_CHAR);
    else
      act("$N is already protected!", FALSE, ch, 0, victim, TO_CHAR);
  }
  return SPELL_NORMAL;
}

ASPELL(spell_teleport)
{
   int	to_room;

   if (ROOM_FLAGGED(ch->in_room, NO_TELEPORT))
   {
     send_to_char("Forces beyond your comprehension prevent you from teleporting.\n\r",ch);
     return SPELL_NORMAL;
   }

   do 
   {
      to_room = number(0, (top_of_world-1));
   } 
   while (ROOM_FLAGGED(to_room, PRIVATE) || ROOM_FLAGGED(to_room, NO_TELEPORT) ||
          ZONE_FLAGGED(world[to_room].zone, Z_CLOSED)    ||
          ZONE_FLAGGED(world[to_room].zone, Z_LOCKED)    ||
          ZONE_FLAGGED(world[to_room].zone, Z_TEST)      ||
          ZONE_FLAGGED(world[to_room].zone, Z_IMMORT)    ||
          (IN_ARENA(ch) != ZONE_FLAGGED(world[to_room].zone, Z_ARENA)) ||
          (MOB_FLAGGED(ch, MOB_STAY_ZONE)  && world[to_room].zone != GET_MOB_VNUM(ch) / 100) )
      ;

   act("You slowly fade out of existence.", FALSE, ch, 0, 0, TO_CHAR);
   act("$n slowly fades out of existence.", FALSE, ch, 0, 0, TO_ROOM);
   char_from_room(ch);
   char_to_room(ch, to_room);
   act("You slowly fade into existence.", FALSE, ch, 0, 0, TO_CHAR);
   act("$n slowly fades into existence.", FALSE, ch, 0, 0, TO_ROOM);
   do_look_at_room(ch, 15, 0);
   if (check_room_affects(ch, ch->in_room) == CHAR_DIED)
     return SPELL_NORMAL;
   if (check_death_trap(ch, NULL))
     return SPELL_NORMAL;

   return SPELL_NORMAL;
}

ASPELL(spell_bless)
{
  struct affected_type af;

  if (obj) 
  {
     if (GET_LEVEL(ch) < obj->min_level)
	send_to_char("That object is too powerful for you to bless.\n\r",ch);
     else
     if ( (5 * GET_LEVEL(ch) > GET_OBJ_WEIGHT(obj)) && 
          (!FIGHTING(ch)) && !OBJ_FLAGGED(obj, ITEM_EVIL)) 
     {
	 SET_BIT(OBJ_EXTRAS(obj), ITEM_BLESS);
	 act("$p briefly glows %4%Bblue%0.", FALSE, ch, obj, 0, TO_ROOM);
     }
  } 
  else 
  {
    if (!victim) return SPELL_FAILED;

    if (FIGHTING(victim))
    {
	send_to_char("You cannot be blessed while fighting!\n\r",victim);
	return SPELL_NORMAL;
    }

    if (!affected_by_spell(victim, SPELL_BLESS)) 
    {
	 af.type      = SPELL_BLESS;
	 af.duration  = 6;
	 af.modifier  = 1;
	 af.location  = APPLY_HITROLL;
	 af.bitvector = 0;
	 af.bitvector2 = 0;
	 affect_to_char(victim, &af);

	 af.location = APPLY_SV_MAGIC;
	 af.modifier = 5;                 /* Make better */
	 affect_to_char(victim, &af);
         if (ch == victim)
         {
           act("You bless yourself with the goodness of the gods!", FALSE, ch, 0, 0, TO_CHAR);
           act("$n blesses $mself!", FALSE, ch, 0, 0, TO_ROOM);
         }
         else
         {
           act("You bless $N with the goodness of the gods!", FALSE, ch, 0, victim, TO_CHAR);
           act("$n blesses you with $s mystical spell!", FALSE, ch, 0, victim, TO_VICT);
         }
    }
    else
      send_to_char("You are already affected by some type of blessing.\n\r",victim);
  }

  return SPELL_NORMAL;
}

ASPELL(spell_blindness)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;

   if (!check_mortal_combat(ch, victim))  /* then its worth a saving throw*/
     return SPELL_FAILED;

   if (saves_spell(victim, SPELL_BLINDNESS) || MOB_FLAGGED(victim, MOB_NO_BLIND)) 
   { 
     if (ch != victim)
       act("$N repels your spell.",TRUE,ch,0,victim,TO_CHAR);
     else
       act("You repel your spell...?",TRUE,ch,0,victim,TO_CHAR);
     return SPELL_NORMAL;
   }

   if (!affected_by_spell(victim, SPELL_BLINDNESS))
   {
     af.type      = SPELL_BLINDNESS;
     af.location  = APPLY_HITROLL;
     af.modifier  = -(GET_LEVEL(ch)/3);  /* Make hitroll WAY worse */
     af.duration  = 1;
     af.bitvector = AFF_BLIND;
     af.bitvector2 = 0;
     affect_to_char(victim, &af);

     af.location = APPLY_AC;
     af.modifier = + 20; /* Make AC Worse! */
     affect_to_char(victim, &af);
     act("$n seems to be blinded!", TRUE, victim, 0, 0, TO_ROOM);
     act("You have been blinded!",FALSE,victim,0,0,TO_CHAR);
   }
   else
     send_to_char("Luckily, you are already blind!\n\r",victim);

   return SPELL_NORMAL;
}

// spell knock, opens locked or jammed doors... 4/26/98 -jtrhone
ASPELL(spell_knock)
{
  int dir, other_room;
  rmdirdata *d, *back;
  char *argu = arg;

  skip_spaces(&argu);
  if (!*argu)
  {
    send_to_char("You must supply the direction...\n\r",ch);
    return SPELL_NORMAL;
  }

  dir = search_block(argu, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    send_to_char("You must supply the direction...\n\r",ch);
    return SPELL_NORMAL;
  }

  if (!(d = EXIT(ch, dir)))
  {
    act("It would be fairly difficult to do that there.",FALSE,ch,0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  if (!EXIT_ISDOOR(d))
    act("It would be fairly difficult to do that there.",FALSE,ch,0,0,TO_CHAR);
  else if (EXIT_OPEN(d))
    send_to_char("It's open!\n\r", ch);
  else if (!EXIT_LOCKED(d) && !EXIT_JAMMED(d))
    send_to_char("It's not locked or jammed!\n\r", ch);
  else if (EXIT_FLAGGED(d, EX_NOBASH) || EXIT_FLAGGED(d, EX_PICKPROOF))
    send_to_char("You fail to knock that exit.\n\r", ch);
  else
  {
    UNFLAG_EXIT(d, EX_LOCKED | EX_JAMMED);
    if (d->keyword)
    {
      act("You knock the $F open!", FALSE, ch, 0, d->keyword, TO_CHAR);
      act("$n knocks the $F open!", TRUE, ch, 0, d->keyword, TO_ROOM);
    }
    else
    {
      act("You knock it open!", FALSE, ch, 0, 0, TO_CHAR);
      act("$n knocks something open!", TRUE, ch, 0, 0, TO_ROOM);
    }

    /* now for jamming the other side, too */
    if ((other_room = d->to_room) != NOWHERE)
      if ((back = DIR(other_room, rev_dir[dir])))
        if (back->to_room == ch->in_room)
          UNFLAG_EXIT(back, EX_LOCKED | EX_JAMMED);
  }
  return SPELL_NORMAL;
}

ASPELL(spell_control_weather)
{
  char *argu = arg;
  int zone, temp;
  void stop_precip(int zone);
  void begin_precip(int zone);
  void send_zone_temp_updates(int zone);

  if (!*argu)
  {
    send_to_char("Usage: cast 'control weather' " "< wetter | drier | warmer | cooler >\n\r",ch);
    return SPELL_NORMAL;
  }

  if (INVALID_ROOM(ch->in_room) || !WEATHER_ROOM(ch->in_room))
  {
    send_to_char("You cannot control the weather from this area.\n\r",ch);
    return SPELL_NORMAL;
  }

  zone = world[ch->in_room].zone;
  skip_spaces(&argu);
  if (is_abbrev(argu, "wetter"))
  {
    if (IS_PRECIPPING(zone))
    {
      send_to_char("Your spell has no affect.\n\r",ch);
      return SPELL_NORMAL;
    }
    if (GET_LEVEL(ch) > number(1, 100))
      begin_precip(zone);
  }
  else
  if (is_abbrev(argu, "drier"))
  {
    if (!IS_PRECIPPING(zone))
    {
      send_to_char("Your spell has no affect.\n\r",ch);
      return SPELL_NORMAL;
    }
    if (GET_LEVEL(ch) > number(1, 100))
      stop_precip(zone);
  }
  else
  if (is_abbrev(argu, "warmer"))
  {
    temp = GET_LEVEL(ch) / 2 + GET_INT(ch);
    zone_table[zone].current_gtemp += temp;
    send_zone_temp_updates(zone);
  }
  else
  if (is_abbrev(argu, "cooler"))
  {
    temp = GET_LEVEL(ch) / 2 + GET_INT(ch);
    zone_table[zone].current_gtemp -= temp;
    send_zone_temp_updates(zone);
  }
  else
  {
    send_to_char("Usage: cast 'control weather' "
		 "< wetter | drier | warmer | cooler >\n\r",ch);
    return SPELL_NORMAL;
  }

  return SPELL_NORMAL;
}

ASPELL(spell_create_water)
{
  int	water;
  int level = GET_LEVEL(ch);
  void	name_to_drinkcon(obdata *obj, int type);
  void	name_from_drinkcon(obdata *obj);

  // ok, if its a canteen or fountain type...
  if ((ITEM_TYPE(obj) == ITEM_DRINKCON) || (ITEM_TYPE(obj) == ITEM_FOUNTAIN)) 
  {
    // if it doesn't have wawa in it, AND it's not empty (better both be right)
    if ((obj->value[2] != LIQ_WATER) && (obj->value[1] != 0)) 
    {
      // pull the first liquid name from it
      name_from_drinkcon(obj);

      // replace it with slime
      obj->value[2] = LIQ_SLIME;
      name_to_drinkcon(obj, LIQ_SLIME);
    } 
    else 
    {
      water = 2 * level;

      /* Calculate water it can contain, or water created */
      water = MIN(obj->value[0] - obj->value[1], water);
      if (water > 0) 
      {
         obj->value[2] = LIQ_WATER;
         obj->value[1] += water;

         weight_change_object(obj, water);
         name_from_drinkcon(obj);
         name_to_drinkcon(obj, LIQ_WATER);

         act("$p is filled.", FALSE, ch, obj, 0, TO_CHAR);
      }
    }
  } 
  else
    act("You try, but are unable to fill $p!", FALSE, ch, obj, 0, TO_CHAR);

  return SPELL_NORMAL;
}

ASPELL(spell_cure_blind)
{
  if (!victim) return SPELL_FAILED;

  if (affected_by_spell(victim, SPELL_BLINDNESS)) 
  {
     affect_from_char(victim, SPELL_BLINDNESS);
     if (ch == victim)
       act("Your vision returns!",FALSE,victim,0,0,TO_CHAR);
     else
       act("$N's vision returns!",FALSE, ch, 0, victim, TO_NOTVICT);
     return SPELL_NORMAL;
  }

  if (affected_by_spell(victim, SPELL_SPIRITLEAVES)) 
  {
     affect_from_char(victim, SPELL_SPIRITLEAVES);
     if (ch == victim)
       act("Your vision returns!",FALSE,victim,0,0,TO_CHAR);
     else
       act("$N's vision returns!",FALSE, ch, 0, victim, TO_NOTVICT);
     return SPELL_NORMAL;
  }

  if (ch == victim)
   act("You are not blind!",FALSE,victim,0,0,TO_CHAR);
  else
   act("$N is not blind!",FALSE, ch, 0, victim, TO_CHAR);

  return SPELL_NORMAL;
}

ASPELL(spell_cure_critic)
{
   int	healpoints;

   if (!victim) return SPELL_FAILED;

   healpoints = dice(4, 8) + 3;

   if ( (healpoints + GET_HIT(victim)) > GET_MAX_HIT(victim))
      GET_HIT(victim) = GET_MAX_HIT(victim);
   else
      GET_HIT(victim) += healpoints;

   if (ch != victim)
   {
     act("$n cures some of your wounds.",FALSE,ch,0,victim,TO_VICT);
     act("You cure some of $S wounds.",FALSE,ch,0,victim,TO_CHAR);
   }
   else
     act("You cure some of your wounds.",FALSE,ch,0,0,TO_CHAR);

   update_pos(victim);
   return SPELL_NORMAL;
}

ASPELL(spell_cure_light)
{
   int	healpoints;

   if (!victim) return SPELL_FAILED;

   healpoints = dice(2, 8);

   if ( (healpoints + GET_HIT(victim)) > GET_MAX_HIT(victim))
      GET_HIT(victim) = GET_MAX_HIT(victim);
   else
      GET_HIT(victim) += healpoints;

   if (ch != victim)
   {
     act("$n cures some of your wounds.",FALSE,ch,0,victim,TO_VICT);
     act("You cure some of $S wounds.",FALSE,ch,0,victim,TO_CHAR);
   }
   else
     act("You cure some of your wounds.",FALSE,ch,0,0,TO_CHAR);

   update_pos( victim );
   return SPELL_NORMAL;
}

ASPELL(spell_curse)
{
   struct affected_type af;

   if (obj) 
   {
      SET_BIT(OBJ_EXTRAS(obj), ITEM_EVIL);
      SET_BIT(OBJ_EXTRAS(obj), ITEM_NODROP);

      /* LOWER ATTACK DICE BY -1 */
      if (IS_WEAPON(obj))
      {
	 if (obj->value[2] > 1) 
	 {
	    obj->value[2]--;
	    act("$p glows red.", FALSE, ch, obj, 0, TO_CHAR);
	 } 
	 else 
	    send_to_char("Nothing happens.\n\r", ch);
      }
      else
        send_to_char("Nothing happens.\n\r", ch);
   } 
   else 
   {
      if (!victim) return SPELL_FAILED;

      if (saves_spell(victim, SPELL_CURSE))
      {
        act("$N resists your attempt!",TRUE,ch,0,victim,TO_CHAR);
	return SPELL_NORMAL;
      }

      if (!affected_by_spell(victim, SPELL_CURSE))
      {
        af.type      = SPELL_CURSE;
        af.duration  = 24 * 7;       /* 7 Days */
        af.modifier  = -1;
        af.location  = APPLY_HITROLL;
        af.bitvector = AFF_CURSE;
        af.bitvector2 = 0;
        affect_to_char(victim, &af);

        af.location = APPLY_SV_MAGIC;
        af.modifier = -30; /* Make worse */
        affect_to_char(victim, &af);

        act("$n briefly reveals a red aura!", FALSE, victim, 0, 0, TO_ROOM);
        act("You feel very uncomfortable.", FALSE, victim, 0, 0, TO_CHAR);
      }
      else
        send_to_char("Luckily, you are already cursed!\n\r",victim);
   }
   return SPELL_NORMAL;
}

ASPELL(spell_detect_evil)
{
   struct affected_type af;
   int level = GET_LEVEL(ch);

   if (!victim) return SPELL_FAILED;
   if (!affected_by_spell(victim, SPELL_DETECT_EVIL))
   {
     af.type      = SPELL_DETECT_EVIL;
     af.duration  = level * 5;
     af.modifier  = 0;
     af.location  = APPLY_NONE;
     af.bitvector = AFF_DETECT_EVIL;
     af.bitvector2 = 0;
     affect_to_char(victim, &af);
     send_to_char("You can now detect the presence of %1evil%0.\n\r",victim);
   }
   else
     send_to_char("You are already affected by detect evil.\n\r",victim);

   return SPELL_NORMAL;
}

ASPELL(spell_detect_invisibility)
{
   struct affected_type af;
   int level = GET_LEVEL(ch);

   if (!victim) return SPELL_FAILED;

   af.type      = SPELL_DETECT_INVISIBLE;
   af.duration  = level * 5;
   af.modifier  = 0;
   af.location  = APPLY_NONE;
   af.bitvector = AFF_DETECT_INVISIBLE;
   af.bitvector2 = 0;
   affect_join(victim, &af, TRUE, FALSE);
   send_to_char("Your eyes tingle.\n\r", victim);

   return SPELL_NORMAL;
}

ASPELL(spell_detect_magic)
{
   struct affected_type af;
   int level = GET_LEVEL(ch);

   if (!victim) return SPELL_FAILED;

   if ( affected_by_spell(victim, SPELL_DETECT_MAGIC) )
   {
     if (ch != victim)
       act("$E is already affected by detect magic.",FALSE,ch,0,victim,TO_CHAR);
     else
       act("You are already affected by detect magic.",FALSE,ch,0,0,TO_CHAR);
     return SPELL_NORMAL;
   }

   af.type      = SPELL_DETECT_MAGIC;
   af.duration  = level * 5;
   af.modifier  = 0;
   af.location  = APPLY_NONE;
   af.bitvector = AFF_DETECT_MAGIC;
   af.bitvector2 = 0;

   affect_to_char(victim, &af);
   send_to_char("Your eyes tingle.\n\r", victim);
   return SPELL_NORMAL;
}

ASPELL(spell_detect_poison)
{
   if (victim) 
   {
      if (victim == ch)
      {
	 if (IS_AFFECTED(victim, AFF_POISON))
	    send_to_char("You can sense poison in your blood.\n\r", ch);
	 else
	    send_to_char("You feel healthy.\n\r", ch);
      }
      else 
      if (IS_AFFECTED(victim, AFF_POISON)) 
	 act("You sense that $E is poisoned.", FALSE, ch, 0, victim, TO_CHAR);
      else 
	 act("You sense that $E is healthy.", FALSE, ch, 0, victim, TO_CHAR);
   } 
   else // it's an object
   { 
      if ((obj->type_flag == ITEM_DRINKCON) || (obj->type_flag == ITEM_FOUNTAIN) || 
          (obj->type_flag == ITEM_FOOD)) 
      {
	 if (obj->value[3])
	    act("Poisonous fumes are revealed.", FALSE, ch, 0, 0, TO_CHAR);
	 else
	    send_to_char("It looks very delicious.\n\r", ch);
      }
      else
	send_to_char("You are unsure...\n\r", ch);
   }

   return SPELL_NORMAL;
}

ASPELL(spell_enchant_weapon)
{
   int	i;
   int level = GET_LEVEL(ch);

   if (IS_WEAPON(obj) && !IS_SET(OBJ_EXTRAS(obj), ITEM_MAGIC)) 
   {
      for (i = 0; i < MAX_OBJ_AFFECT; i++)
	 if (obj->affected[i].location != APPLY_NONE)
	 {
	   act("$p cannot be enchanted any further.", FALSE, ch, obj, 0,TO_CHAR);
	   return SPELL_NORMAL;
	 }

      SET_BIT(OBJ_EXTRAS(obj), ITEM_MAGIC);

      obj->affected[0].location = APPLY_HITROLL;
      obj->affected[0].modifier = 1 + (level >= 18);

      obj->affected[1].location = APPLY_DAMROLL;
      obj->affected[1].modifier = 1 + (level >= 20);

      if (IS_GOOD(ch)) {
	 SET_BIT(OBJ_EXTRAS(obj), ITEM_ANTI_EVIL);
	 act("$p glows %B%4blue%0.", FALSE, ch, obj, 0, TO_CHAR);
      } else if (IS_EVIL(ch)) {
	 SET_BIT(OBJ_EXTRAS(obj), ITEM_ANTI_GOOD);
	 act("$p glows %1red%0.", FALSE, ch, obj, 0, TO_CHAR);
      } else {
	 act("$p glows %B%3yellow%0.", FALSE, ch, obj, 0, TO_CHAR);
      }
   }
   else 
   if (IS_SET(OBJ_EXTRAS(obj), ITEM_MAGIC))
     act("$p cannot be enchanted any further.",FALSE,ch,obj,0,TO_CHAR);
   else
   if (!IS_WEAPON(obj))
     act("$p is not an enchantable object.",FALSE,ch,obj,0,TO_CHAR);
   return SPELL_NORMAL;
}

ASPELL(spell_recharge)
{
  if ((ITEM_TYPE(obj) != ITEM_STAFF && ITEM_TYPE(obj) != ITEM_WAND) || 
      !OBJ_FLAGGED(obj, ITEM_RECHARGE)) 
  {
    act("$p cannot be recharged.", FALSE, ch, obj, 0, TO_CHAR);
    return SPELL_NORMAL;
  }

  if (MAX_CHARGES(obj) < 1)
  {
    act("$p cannot be recharged.", FALSE, ch, obj, 0, TO_CHAR);
    return SPELL_NORMAL;
  }

  if (CHARGES_LEFT(obj) >= MAX_CHARGES(obj))
  {
    act("$p is already fully charged.", FALSE, ch, obj, 0, TO_CHAR);
    return SPELL_NORMAL;
  }

  // if the minlevel is too high OR the spell level is too high, no go
  if (obj->min_level > GET_LEVEL(ch) || obj->value[0] > GET_LEVEL(ch))
  {
    act("$p is too powerful for you to recharge.", FALSE, ch, obj, 0, TO_CHAR);
    return SPELL_NORMAL;
  }   

  CHARGES_LEFT(obj) = MAX_CHARGES(obj); 

  act("You recharge $p.", FALSE, ch, obj, 0, TO_CHAR);
  act("$n recharges $p.", FALSE, ch, obj, 0, TO_ROOM);

  return SPELL_NORMAL;
}

ASPELL(spell_heal)
{
   if (!victim) return SPELL_FAILED;

   if (affected_by_spell(victim, SPELL_BLINDNESS) || 
       affected_by_spell(victim, SPELL_SPIRITLEAVES))
     spell_cure_blind(ch, arg, victim, obj);

   GET_HIT(victim) += (100 - dice(1,4));  /* changed this spell -jtrhone*/
   GET_HIT(victim) = MIN(GET_MAX_HIT(victim), GET_HIT(victim));

   update_pos(victim);

   act("A %1warm%0 feeling fills your body...",FALSE,victim,0,0,TO_CHAR);
   act("You suddenly feel much better!",FALSE,victim,0,0,TO_CHAR);
   act("$n suddenly looks much healthier.", FALSE, victim, 0, 0, TO_ROOM);
   return SPELL_NORMAL;
}

ASPELL(spell_invisibility)
{
   struct affected_type af;

   if (obj) 
   {
      if (IS_SET(OBJ_EXTRAS(obj), ITEM_NOINVIS)) 
      {
	 act("$p resists all your efforts.",FALSE,ch,obj,0,TO_CHAR);
         return SPELL_NORMAL;
      }

      if (!IS_SET(OBJ_EXTRAS(obj), ITEM_INVISIBLE) ) 
      {
	 act("$p %4fades out of existence%0.", FALSE, ch, obj, 0, TO_CHAR);
	 act("$p %4fades out of existence%0.", TRUE, ch, obj, 0, TO_ROOM);
	 SET_BIT(OBJ_EXTRAS(obj), ITEM_INVISIBLE);
      }
   } 
   else 
   if (victim)
   {
      if (!affected_by_spell(victim, SPELL_INVISIBLE)) 
      {
	 af.type      = SPELL_INVISIBLE;
	 af.duration  = 24;
	 af.modifier  = -40;
	 af.location  = APPLY_AC;
	 af.bitvector = AFF_INVISIBLE;
         af.bitvector2 = 0;
	 affect_to_char(victim, &af);
	 act("$n slowly %4fades out of existence%0.", TRUE, victim, 0, 0, TO_ROOM);
	 act("You feel yourself fade out of existence.",FALSE,victim,0,0,TO_CHAR);
      }
      else
        send_to_char("You are already invisible.\n\r",victim);
   }
   return SPELL_NORMAL;
}

ASPELL(spell_locate_object)
{
   int	j, level = GET_LEVEL(ch);
   obdata *i;

   if (strlen(arg) > MAX_INPUT_LENGTH - 10) 
   {
     send_to_char("Argument too long.\n\r",ch);
     return SPELL_FAILED;
   }

   j = level >> 1;

   act("You concentrate yourself....", FALSE, ch, 0, 0, TO_CHAR);
   act("$n sinks into deep concentration.", FALSE, ch, 0, 0, TO_ROOM);

   // added some more error protection... 7/9/98 -jtrhone
   for (i = object_list; i && j; i = i->next)
     if (i->name && *i->name && i->shdesc && *i->shdesc) 
      if (isname(arg, i->name) && !OBJ_FLAGGED(i, ITEM_NOLOCATE)) 
      {
	 if (i->carried_by && GET_LEVEL(ch) >= GET_INVIS_LEV(i->carried_by)) 
	 {
	    sprintf(buf, "%s carried by %s.\n\r", i->shdesc, PERS(i->carried_by, ch));
	    CCAP(buf);
	    S2C();
	    j--;
	 } 
	 else 
	 if (i->in_obj) 
	 {
	    sprintf(buf, "%s in %s.\n\r", i->shdesc, 
                    i->in_obj->shdesc ? i->in_obj->shdesc : "something");
	    CCAP(buf);
	    S2C();
	    j--;
	 } 
	 else
	 if (!INVALID_ROOM(i->in_room))
	 {
	   sprintf(buf, "%s in %s.\n\r", i->shdesc, 
                   world[i->in_room].name ? world[i->in_room].name : "somewhere");
	   CCAP(buf);
	   S2C();
	   j--;
	 }
      }

   if (!j)
      send_to_char("Your head begins to pound.\n\r", ch);
   else
   if (j == (level >> 1))
      send_to_char("No such object.\n\r", ch);

   return SPELL_NORMAL;
}

ASPELL(spell_poison)
{
   struct affected_type af;

   if (victim) 
   {
      if (affected_by_spell(victim, SKILL_CLEANSE))
      {
	act("$N resists the poison!",TRUE, ch, 0, victim, TO_NOTVICT);
	act("You resist the poison!",TRUE, ch, 0, victim, TO_VICT);
	act("$N resists your poisonous attempt!",TRUE, ch, 0, victim, TO_CHAR);
	return SPELL_NORMAL;
      }
      else
      if (!saves_spell(victim, SPELL_POISON)) 
      {
	 af.type = SPELL_POISON;
	 af.duration = GET_LEVEL(ch) * 2;
	 af.modifier = -2;
	 af.location = APPLY_STR;
	 af.bitvector = AFF_POISON;
         af.bitvector2 = 0;

	 affect_join(victim, &af, FALSE, FALSE);
	 act("You feel very sick.", TRUE, victim, 0, 0, TO_CHAR);
	 act("$n suddenly looks sick.", TRUE, victim, 0, 0, TO_ROOM);
      }
      else
      {
	act("$N resists the poison!",TRUE, ch, 0, victim, TO_NOTVICT);
	act("You resist the poison!",TRUE, ch, 0, victim, TO_VICT);
	act("$N resists your poisonous attempt!",TRUE, ch, 0, victim, TO_CHAR);
	return SPELL_NORMAL;
      }
   } 
   else 
   if (obj)
    if ((obj->type_flag == ITEM_DRINKCON) || (obj->type_flag == ITEM_FOUNTAIN) || 
        (obj->type_flag == ITEM_FOOD))
    {
      obj->value[3] = TRUE;
      act("You poison $p!",TRUE, ch, obj, 0, TO_CHAR);
      act("$n poisons $p!",TRUE, ch, obj, 0, TO_ROOM);
    }

   return SPELL_NORMAL;
}

ASPELL(spell_poison_dart)
{
   struct affected_type af;

   if (victim) 
   {
      if (affected_by_spell(victim, SKILL_CLEANSE))
      {
	act("$N resists the poison!",TRUE, ch, 0, victim, TO_NOTVICT);
	act("You resist the poison!",TRUE, ch, 0, victim, TO_VICT);
	act("$N resists your poisonous attempt!",TRUE, ch, 0, victim, TO_CHAR);
	return SPELL_NORMAL;
      }
      else
      if (!saves_spell(victim, SPELL_POISON_DART)) 
      {
	 af.type = SPELL_POISON_DART;
	 af.duration = GET_LEVEL(ch) * 2;
	 af.modifier = -2;
	 af.location = APPLY_STR;
	 af.bitvector = AFF_POISON;
         af.bitvector2 = 0;

	 affect_join(victim, &af, FALSE, FALSE);
	 act("You feel very sick.", TRUE, victim, 0, 0, TO_CHAR);
	 act("$n suddenly looks sick.", TRUE, victim, 0, 0, TO_ROOM);
      }
      else
      {
	act("$N resists the poison!",TRUE, ch, 0, victim, TO_NOTVICT);
	act("You resist the poison!",TRUE, ch, 0, victim, TO_VICT);
	act("$N resists your poisonous attempt!",TRUE, ch, 0, victim, TO_CHAR);
	return SPELL_NORMAL;
      }
   } 
   else 
   if (obj)
    if ((obj->type_flag == ITEM_DRINKCON) || (obj->type_flag == ITEM_FOUNTAIN) || 
        (obj->type_flag == ITEM_FOOD))
    {
      obj->value[3] = TRUE;
      act("You poison $p!",TRUE, ch, obj, 0, TO_CHAR);
      act("$n poisons $p!",TRUE, ch, obj, 0, TO_ROOM);
    }

   return SPELL_NORMAL;
}

ASPELL(spell_protection_from_evil)
{
   struct affected_type af;

   if (!victim) return SPELL_NORMAL;

   if (!affected_by_spell(victim, SPELL_PROTECT_FROM_EVIL))
   {
      af.type      = SPELL_PROTECT_FROM_EVIL;
      af.duration  = 24;
      af.modifier  = 0;
      af.location  = APPLY_NONE;
      af.bitvector = AFF_PROTECT_EVIL;
      af.bitvector2 = 0;
      affect_to_char(victim, &af);
      act("You have a righteous feeling!",FALSE,victim,0,0,TO_CHAR);
      act("A faint %Bwhite%0 aura surrounds $n.", TRUE, victim, 0, 0, TO_ROOM);
   }
   else
     send_to_char("You are already protected from evil.\n\r",victim);

   return SPELL_NORMAL;
}

ASPELL(spell_remove_curse)
{
   if (obj) 
   {
      if (GET_LEVEL(ch) < obj->min_level)
	send_to_char("That object is too powerful for you, the curse remains.\n\r",ch);
      else
      if (IS_SET(OBJ_EXTRAS(obj), ITEM_EVIL) || IS_SET(OBJ_EXTRAS(obj), ITEM_NODROP)) 
      {
	 act("$p briefly glows %B%6blue%0.", TRUE, ch, obj, 0, TO_CHAR);
	 REMOVE_BIT(OBJ_EXTRAS(obj), ITEM_EVIL);
	 REMOVE_BIT(OBJ_EXTRAS(obj), ITEM_NODROP);
      }
   } 
   else 
   {      /* Then it is a PC | NPC */
     if (!victim) return SPELL_FAILED;
     if (affected_by_spell(victim, SPELL_CURSE) ) 
     {
	act("$n briefly glows %1red%0, then %6blue%0.", FALSE, victim, 0, 0, TO_ROOM);
	act("You feel better.", FALSE, victim, 0, 0, TO_CHAR);
	affect_from_char(victim, SPELL_CURSE);
     }
     else
	act("$N is not cursed.", FALSE, ch, 0, victim, TO_CHAR);
   }
  
  return SPELL_NORMAL;
}

ASPELL(spell_remove_poison)
{
   if (victim) 
   {
     if (affected_by_spell(victim, SPELL_POISON)) 
     {
	affect_from_char(victim, SPELL_POISON);
	act("You feel %6ice%0 flow through your body.", FALSE, victim, 0, 0, TO_CHAR);
	act("You feel better!", FALSE, victim, 0, 0, TO_CHAR);
	act("$N's eyes open wide for a brief moment.", FALSE, ch, 0, victim, TO_ROOM);
        if (ch != victim)
	  act("You remove the %2poison%0 from $S blood.",FALSE,ch,0,victim,TO_CHAR);
        else
	  act("You remove the %2poison%0 from your blood.",FALSE,ch,0,0,TO_CHAR);
     }
     else
     if (affected_by_spell(victim, SPELL_POISON_DART)) 
     {
	affect_from_char(victim, SPELL_POISON_DART);
	act("You feel %6ice%0 flow through your body.", FALSE, victim, 0, 0, TO_CHAR);
	act("You feel better!", FALSE, victim, 0, 0, TO_CHAR);
	act("$N's eyes open wide for a brief moment.", FALSE, ch, 0, victim, TO_ROOM);
        if (ch != victim)
	  act("You remove the %2poison%0 from $S blood.",FALSE,ch,0,victim,TO_CHAR);
        else
	  act("You remove the %2poison%0 from your blood.",FALSE,ch,0,0,TO_CHAR);
     }
   } 
   else 
   if (obj)
   {
      if ((obj->type_flag == ITEM_DRINKCON) || (obj->type_flag == ITEM_FOUNTAIN) || 
          (obj->type_flag == ITEM_FOOD)) 
      {
	 obj->value[3] = 0;
	 act("$p steams briefly.", FALSE, ch, obj, 0, TO_CHAR);
      }
   }

   return SPELL_NORMAL;
}

ASPELL(spell_sanctuary)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;
   if (!IS_AFFECTED(victim, AFF_SANCTUARY) && !IS_AFFECTED2(victim,AFF2_CROW)) 
   {
      af.type      = SPELL_SANCTUARY;
      af.duration  = IS_IMMORTAL(ch) ? GET_LEVEL(ch) : 3;
      af.modifier  = 0;
      af.location  = APPLY_NONE;
      af.bitvector = AFF_SANCTUARY;
      af.bitvector2 = 0;
      affect_to_char(victim, &af);
      act("You start %Bglowing%0.", TRUE, victim, 0, 0, TO_CHAR);
      act("$n is surrounded by a bright %Bwhite%0 aura.", TRUE, victim, 0, 0, TO_ROOM);
   }
   else
    send_to_char("You are already protected by a powerful force.\n\r",victim);

   return SPELL_NORMAL;
}

ASPELL(spell_sleep)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;
   if (!check_mortal_combat(ch, victim))  /* then its worth a saving throw*/
     return SPELL_FAILED;

   if ( !saves_spell(victim, SPELL_SLEEP) ) 
   {
      af.type      = SPELL_SLEEP;
      af.duration  = 2 + number(1, 2);
      af.modifier  = 0;
      af.location  = APPLY_NONE;
      af.bitvector = AFF_SLEEP;
      af.bitvector2 = 0;
      affect_join(victim, &af, FALSE, FALSE);

      if (GET_POS(victim) > POS_SLEEPING) 
      {
	 act("You feel very sleepy ..... zzzzzz.....", FALSE, victim, 0, 0, TO_CHAR);
	 act("$n slowly falls asleep.", TRUE, victim, 0, 0, TO_ROOM);
	 GET_POS(victim) = POS_SLEEPING;
      }
   }
   else
   {
     if (ch != victim)
       act("$N repels your spell.",TRUE,ch,0,victim,TO_CHAR);
     else
       act("You repel your spell...?",TRUE,ch,0,victim,TO_CHAR);
   }

   return SPELL_NORMAL;
}

ASPELL(spell_strength)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;

   if (!affected_by_spell(victim, SPELL_STRENGTH))
   {
     af.type      = SPELL_STRENGTH;
     af.duration  = GET_LEVEL(ch);
     af.modifier  = 1 + (GET_LEVEL(ch) > 31);
     af.location  = APPLY_STR;
     af.bitvector = 0;
     af.bitvector2 = 0;
     act("You feel stronger!", FALSE, victim, 0, 0, TO_CHAR);
     act("$n looks stronger!", FALSE, victim, 0, 0, TO_ROOM);
     affect_to_char(victim, &af);
   }
   else
    act("You're already stronger than normal!", FALSE, victim, 0, 0,TO_CHAR);

   return SPELL_NORMAL;
}

ASPELL(spell_ventriloquate)
{
  send_to_char("This spell is currently not implemented.\n\r",ch);
  return SPELL_NORMAL;
}

ASPELL(spell_word_of_recall)
{
   int	loc_nr, location;
   BOOL found = FALSE;

   if (!victim || (IS_NPC(victim) && !victim->desc))
      return SPELL_FAILED;

   if (IS_IMMORTAL(victim) && ch != victim)
   {
     send_to_char("Your puny mortal spell has no affect on an IMMORTAL!\n\r",ch);
     return SPELL_FAILED;
   }

   if (ROOM_FLAGGED(victim->in_room, NO_RECALL) || PLR_FLAGGED(victim, PLR_ARENA))
   {
     act("$n tries to recall, but is unsuccessful!", TRUE, victim, 0, 0, TO_ROOM);
     send_to_char("Forces beyond your comprehension prevent you from recalling.\n\r",ch);
     return SPELL_FAILED;
   }

   if (!(loc_nr = GET_LOADROOM(victim)))
     loc_nr = (GET_LEVEL(victim) < LEV_IMM) ? DEF_GATEWAY : 1204;

   for (location = 0; location < top_of_world; location++)
      if (world[location].number == loc_nr) 
      {
	 found = TRUE;
	 break;
      }

   if ((location >= top_of_world) || !found)
   {
      send_to_char("You are completely lost.\n\r", victim);
      return SPELL_FAILED;
   }

   /* a location has been found. */

   act("$n disappears in a %4cone of darkness%0.", TRUE, victim, 0, 0, TO_ROOM);
   char_from_room(victim);
   char_to_room(victim, location);
   act("$n appears amidst a %1flash of light%0.", TRUE, victim, 0, 0, TO_ROOM);
   do_look_at_room(victim, 0, 0);

   if (check_room_affects(victim, victim->in_room) == CHAR_DIED)
     return SPELL_NORMAL;
   if (check_death_trap(victim, NULL))
     return SPELL_NORMAL;

   return SPELL_NORMAL;
}

ASPELL(spell_summon)
{
   sh_int target;
   sh_int zone;
   int level = GET_LEVEL(ch);

   if (IN_NOWHERE(ch)) return SPELL_FAILED;

   if (!victim) return SPELL_FAILED;

   if (IN_ARENA(ch) && !arena_info.locked)
   {
      send_to_char("You must wait until the arena begins.\n\r",ch);
      return SPELL_FAILED;
   }

   if (GET_LEVEL(victim) > MIN(LEV_IMM - 1, level + 3))
     return SPELL_FAILED;

   if (MOB_FLAGGED(victim, MOB_AGGR)) 
   {
       sprintf(buf, "As the words escape your lips and %s travels\n\r"
             "through time and space towards you, you realize that %s is\n\r"
             "aggressive and might harm you, so you wisely send it back.\n\r",
             victim->player.short_descr, HMHR(victim));
       S2C();
       return SPELL_NORMAL;  
   }

   zone = world[victim->in_room].zone;
   if (IS_NPC(victim))
   {
      if (MOB_FLAGGED(victim, MOB_NOSUMMON) || ZONE_FLAGGED(zone, Z_CLOSED) || 
	  ZONE_FLAGGED(zone, Z_LOCKED))
      {
	 act("$N is protected from summoning.",TRUE, ch, 0, victim, TO_CHAR);
	 return SPELL_NORMAL;
      }

      if (world[ch->in_room].zone != zone && MOB_FLAGGED(victim, MOB_STAY_ZONE))
      {
	 act("$N cannot be summoned from here.",TRUE, ch, 0, victim, TO_CHAR);
	 return SPELL_NORMAL;
      }

      if (ROOM_FLAGGED(ch->in_room, NO_MOB))
      {
	 act("$N cannot be summoned into this area.",TRUE, ch, 0, victim, TO_CHAR);
	 return SPELL_NORMAL;
      }

      // no mobs from outside the arena  6/25/98 -jtrhone
      if (INVALID_ROOM(victim->in_room) || ZONE_FLAGGED(world[victim->in_room].zone, Z_ARENA))
      {
	 act("$N cannot be summoned into this area.",TRUE, ch, 0, victim, TO_CHAR);
	 return SPELL_NORMAL;
      }
    }

    if (ROOM_FLAGGED2(ch->in_room, R_NO_SUMMON))
    {
	act("$N cannot be summoned into this area.",TRUE, ch, 0, victim, TO_CHAR);
	return SPELL_NORMAL;
    }

    if (IS_PC(victim) && !PRF_FLAGGED(victim, PRF_SUMMONABLE)) 
    {
         sprintf(buf, "%s just tried to summon you to: %s.\n\r"
             "%s failed because you have summon protection on.\n\r"
             "Type NOSUMMON to allow other players to summon you.\n\r",
             GET_NAME(ch), world[ch->in_room].name,
             (ch->player.sex == SEX_MALE) ? "He" : "She");
         send_to_char(buf, victim);

	act("You failed because $N has summon protection on.",TRUE,ch,0,victim,TO_CHAR);

        sprintf(buf, "%s failed summoning %s to %s.", GET_NAME(ch), 
		GET_NAME(victim), world[ch->in_room].name);
	mudlog(buf, BRF, LEV_IMM, TRUE);
        return SPELL_NORMAL;
      }
 
   if (IS_NPC(victim) && saves_spell(victim, SPELL_SUMMON) ) {
      act("$N resists your attempt!",TRUE,ch,0,victim,TO_CHAR);
      return SPELL_NORMAL;
   }

   if (IS_PC(victim))
     if (IN_ARENA(ch) != IN_ARENA(victim))
     {
       send_to_char("Forces beyond your comprehension prevent you from summoning that player.\n\r",ch);
	return SPELL_NORMAL;
     }

   act("$n disappears suddenly.", TRUE, victim, 0, 0, TO_ROOM);

   target = ch->in_room;
   char_from_room(victim);
   char_to_room(victim, target);

   act("$n arrives suddenly.", TRUE, victim, 0, 0, TO_ROOM);
   act("$n has summoned you!", FALSE, ch, 0, victim, TO_VICT);
   do_look_at_room(victim, 15, 0);
   if (check_room_affects(victim, victim->in_room) == CHAR_DIED)
     return SPELL_NORMAL;
   if (check_death_trap(victim, NULL))
     return SPELL_NORMAL;

   return SPELL_NORMAL;
}

ASPELL(spell_charm_person)
{
   struct affected_type af;
   void	add_follower(chdata *ch, chdata *leader);

   if(!ch || !victim) return SPELL_FAILED;

   if (victim == ch) {
      send_to_char("You like yourself even better!\n\r", ch);
      return SPELL_NORMAL;
   }

   if (IS_PC(ch) && IS_PC(victim)) /* a player charming another player */
      return SPELL_FAILED;	/* there's no legal reason to do this.  */

   if (GET_POS(victim) <= POS_SLEEPING)
   {
     send_to_char("Your victim is not paying attention to you.\n\r",ch);
     return SPELL_NORMAL;
   }

   if (CHARMED(victim))
   {
     send_to_char("Your victim is already charmed...\n\r",ch);
     return SPELL_NORMAL;
   }

   if (CHARMED(ch))
   {
     send_to_char("You cannot cast this spell while you are charmed...\n\r",ch);
     return SPELL_NORMAL;
   }

  if (GET_LEVEL(ch) >= GET_LEVEL(victim)) 
  {
   if (circle_follow(victim, ch)) {
	 send_to_char("Sorry, following in circles can not be allowed.\n\r", ch);
	 return SPELL_NORMAL;
   }

   if (MOB_FLAGGED(victim, MOB_NO_CHARM) || IS_IMMORTAL(victim))
   {
     act("$n resists all efforts to be charmed.", FALSE, ch, 0, victim, TO_CHAR);
     return SPELL_NORMAL;
   }

   if (GET_LEVEL(ch) < LEV_CIMP)
   if (saves_spell(victim, SPELL_CHARM_PERSON))
   {
     if (number(0,20) > 15)
     {
       act("$N is %1%Benraged%0 at your attempt!",FALSE,ch,0,victim,TO_CHAR);
       do_kill(victim, GET_NAME(ch), 0, 0);
     }
     else
       act("$N resists your attempt!",FALSE,ch,0,victim,TO_CHAR);
     return SPELL_NORMAL;
   }

   if (victim->master)
     stop_follower(victim);

   add_follower(victim, ch);

   af.type      = SPELL_CHARM_PERSON;

   if (GET_INT(victim))
     af.duration  = 12 * 18 / GET_INT(victim);
   else
     af.duration  = 36;

   af.modifier  = 0;
   af.location  = 0;
   af.bitvector = AFF_CHARM;
   af.bitvector2 = 0;
   affect_to_char(victim, &af);

   act("Isn't $n just such a nice fellow?", FALSE, ch, 0, victim, TO_VICT);
   if (IS_NPC(victim))
     REMOVE_BIT(MOB_FLAGS(victim), MOB_SPEC);
  }

  return SPELL_NORMAL;
}

ASPELL(spell_sense_life)
{
   struct affected_type af;
   int level = GET_LEVEL(ch);

   if (!victim) return SPELL_FAILED;

   if (!affected_by_spell(victim, SPELL_SENSE_LIFE)) 
   {
      af.type      = SPELL_SENSE_LIFE;
      af.duration  = 5 * level;
      af.modifier  = 0;
      af.location  = APPLY_NONE;
      af.bitvector = AFF_SENSE_LIFE;
      af.bitvector2 = 0;
      affect_to_char(victim, &af);
      act("You feel your awareness improve.",FALSE,victim,0,0,TO_CHAR);
      act("$n seems more aware of $s surroundings.", FALSE, victim, 0, 0, TO_ROOM);
   }
   else
   if (ch != victim)
      act("$N is already affected by sense life.",FALSE,victim,0,0,TO_CHAR);
   else
      act("You are already affected by sense life.",FALSE,ch,0,0,TO_CHAR);
   return SPELL_NORMAL;
}

// support wvectors 5/29/98 -jtrhone
// fixed skill_name reference bug, cleaned up a bit 6/29/98 -jtrhone
ASPELL(spell_identify)
{
   int	i;
   BOOL found;

   if (obj) 
   {
      act("$n concentrates on $p.", FALSE, ch, obj, 0, TO_ROOM);

      send_to_char("You feel informed:\n\r", ch);
      sprinttype(ITEM_TYPE(obj), item_types, buf2);
      sprintf(buf, "$p is of type: %%B%s%%0", buf2);
      act(buf, FALSE, ch, obj, 0, TO_CHAR);

      if (obj->eqaffbit || obj->eqaff2bit) 
      {
	send_to_char("Item affections:\n\r", ch);

        if (obj->eqaff2bit) 
        {
	 sprintbit(obj->eqaffbit, affected_bits, buf);
	 strcat(buf, "\n\r");
	 S2C();
        }

        if (obj->eqaff2bit) 
        {
	 sprintbit(obj->eqaff2bit, affected2_bits, buf);
	 strcat(buf, "\n\r");
	 S2C();
        }
      }

      if (OBJ_EXTRAS(obj) || OBJ_EXTRAS2(obj))
      {
        send_to_char("Item specials:\n\r", ch);
        if (OBJ_EXTRAS(obj))
        {
          sprintbit(OBJ_EXTRAS(obj), extra_bits, buf);
          strcat(buf, "\n\r");
          S2C();
        }

        if (OBJ_EXTRAS2(obj))
        {
          sprintbit(OBJ_EXTRAS2(obj), extra_bits2, buf);
          strcat(buf, "\n\r");
          S2C();
        }
      }

      if (WV_FLAGS(obj))
      {
        send_to_char("Item occupies: ", ch);
        sprintbit(WV_FLAGS(obj), wv_bits, buf);
        strcat(buf, "\n\r");
        S2C();
      }

      if (obj->min_level) 
      {
        sprintf(buf,"Minimum level on object: %d\n\r", obj->min_level);
        S2C();
      }

      sprintf(buf, "Weight: %d, Value: %d\n\r", obj->weight, obj->cost);
      S2C();

      switch (ITEM_TYPE(obj)) {

      case ITEM_SCROLL :
      case ITEM_POTION :
	 sprintf(buf, "Level %d spells of:\n\r",obj->value[0]);
	 S2C();

         for (i = 1; i < 4; i++)
	   if (obj->value[i] > 0)  
           {
             sprintf(buf, "%s\n\r", skill_names[obj->value[i]]);
             S2C();
           }
	 break;

      case ITEM_WAND :
      case ITEM_STAFF :
	 sprintf(buf, "Has %d charges, with %d charges left.\n\r", obj->value[1], obj->value[2]);
	 S2C();
	 sprintf(buf, "Level %d spell of: ", obj->value[0]);
	 S2C();
         sprintf(buf, "%s\n\r", obj->value[3] > 0 ? skill_names[obj->value[3]] : "");
         S2C();
	 break;

      case ITEM_WEAPON :
	 sprintf(buf, "Damage dice: '%dD%d'\n\r", obj->value[1], obj->value[2]);
	 S2C();
	 break;

      case ITEM_ARMOR :
	 sprintf(buf, "AC-apply: %d\n\r", obj->value[0]);
	 S2C();
	 break;
      }

      for (found = i = 0; i < MAX_OBJ_AFFECT; i++) 
	 if ((obj->affected[i].location != APPLY_NONE) && (obj->affected[i].modifier != 0)) 
         {
	    if (!found) 
            {
	       send_to_char("Can affect you as :\n\r", ch);
	       found = TRUE;
	    }

	    sprinttype(obj->affected[i].location, apply_types, buf2);
	    sprintf(buf, "    Affects : %s By %d\n\r", buf2, obj->affected[i].modifier);
	    S2C();
	 }
   } 
   else 
   {       /* victim */
      if (!victim) return SPELL_FAILED;
      if (IS_PC(victim)) 
      {
         if (victim != ch)
         {
           act("$n concentrates on $N.", FALSE, ch, 0, victim, TO_ROOM);
           act("You concentrate on $N.", FALSE, ch, 0, victim, TO_CHAR);
           act("$n stares deep into your eyes.", FALSE, ch, 0, victim, TO_VICT);
         }
         else
         {
           act("You concentrate on yourself.", FALSE, ch, 0, 0, TO_CHAR);
           act("$n concentrates on $mself.", FALSE, ch, 0, 0, TO_ROOM);
         }

	 sprintf(buf, "%d Years,  %d Months,  %d Days,  %d Hours old.\n\r",
	         age(victim).year, age(victim).month, age(victim).day, age(victim).hours);
	 S2C();

	 sprintf(buf, "Height %dcm  Weight %dpounds \n\r", GET_HEIGHT(victim), GET_WEIGHT(victim));
	 S2C();

	 sprintf(buf, "Str %d/%d,  Int %d,  Wis %d,  Dex %d,  Con %d\n\r",
	         GET_STR(victim), GET_ADD(victim), GET_INT(victim), GET_WIS(victim),
	         GET_DEX(victim), GET_CON(victim) );
	 S2C();
      } 
      else 
	 send_to_char("You learn nothing new.\n\r", ch);
   }

   return SPELL_NORMAL;
}

/**********************************************************************
 NEW SPELLS added by the crew at RoA, all spells written and added by 
   James Rhone (James Rhone) unless otherwise noted 
***********************************************************************/
/* spells that are primarily MAGE spells follow */
ASPELL(spell_implosion)  /*  */
{
   int	dam;
 
   if (!victim) return SPELL_FAILED;
   dam = number(70, 120);

   SpellDamage(ch, victim, dam, SPELL_IMPLOSION, FALSE);
   return SPELL_NORMAL;
}

ASPELL(spell_ice_shaft)
{ 
   int	dam;
   int level = GET_LEVEL(ch);

   if (!victim) return SPELL_FAILED;
   dam = dice(level, 4);

   SpellDamage(ch, victim, dam, SPELL_ICE_SHAFT, FALSE);
   return SPELL_NORMAL;
}

/* written by Sergey (freebie) */
ASPELL(spell_haste)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;

   if (!affected_by_spell(victim, SPELL_HASTE) && !affected_by_spell(victim, SKILL_HASTEN)) 
   {
      af.type      = SPELL_HASTE;
      af.duration  = 4;
      af.modifier  = 2;
      af.location  = APPLY_DEX;
      af.bitvector = AFF_HASTE;
      af.bitvector2 = 0;

      affect_to_char(victim, &af);
      act("You feel your body start to %1sizzle%0 with energy.",FALSE,victim,0,0,TO_CHAR);
      act("$n's body starts to %1sizzle%0 with energy.",FALSE,victim,0,0,TO_ROOM);
   }
   else
   if (ch != victim)
      act("$N is already affected by haste.",FALSE,victim,0,0,TO_CHAR);
   else
      act("You are already affected by haste.",FALSE,ch,0,0,TO_CHAR);
   return SPELL_NORMAL;
}

/* written by Sergey (freebie) */
ASPELL(spell_mirror_image)
{
  int mirrors;
  mirrors = ch->specials.num_of_images = MAX(GET_INT(ch) + number(1, 5) - 13, 2);    
  sprintf(buf, "%d reflected images of you form suddenly.", mirrors);
  act(buf, TRUE, ch, 0, 0, TO_CHAR);
  sprintf(buf, "%d reflected images of $n form suddenly.", mirrors);
  act(buf, TRUE, ch, 0, 0, TO_ROOM);
  return SPELL_NORMAL;
}

ASPELL(spell_gateway)
{
  /* object vnum 105 is GATE object */
   obdata *gate1, *gate2;

   if (!victim) return SPELL_FAILED;
   if (INVALID_ROOM(ch->in_room)  || INVALID_ROOM(victim->in_room))
     return SPELL_FAILED;

   if (GET_LEVEL(victim) < maxnewbielevel)
     return SPELL_FAILED;

   if (IN_ARENA(ch) && !arena_info.locked)
   {
      send_to_char("You must wait until the arena begins.\n\r",ch);
      return SPELL_NORMAL;
   }

   if (!IS_IMMORTAL(ch) && IS_PC(ch) && IS_NPC(victim))
   {
     send_to_char("You may only create a gate between players.\n\r",ch);
     return SPELL_NORMAL;
   }

   if (!IS_IMMORTAL(ch))
   if (ROOM_FLAGGED(ch->in_room, NO_TELEPORT) || ROOM_FLAGGED(victim->in_room, NO_TELEPORT))
   {
     act("Forces beyond comprehension prevent you from gating.",FALSE,ch,0,0,TO_CHAR);
     act("$n tries to gate, but is unsuccessful!",TRUE,ch,0,0,TO_ROOM);
     return SPELL_NORMAL;
   }

   if (!IS_NPC(ch) && !PRF_FLAGGED(victim, PRF_SUMMONABLE)) 
   {
     sprintf(buf, "%s just tried to gate to you!\n\r"
             "%s failed because you have gate protection on.\n\r"
             "Type NOSUMMON to allow others to gate to you.\n\r",
             GET_NAME(ch), (ch->player.sex == SEX_MALE) ? "He" : "She");
     send_to_char(buf, victim);
     act("You failed because $N has summon/gate protection on.",FALSE,ch,0,victim,TO_CHAR);
     sprintf(buf, "%s failed gating to %s.",GET_NAME(ch), GET_NAME(victim));
     mudlog(buf, BRF, LEV_IMM, TRUE);
     return SPELL_NORMAL;
   }

   if (!(gate1 = read_object(105, VIRTUAL)))
   {
     send_to_char("Something went wrong!  Notify an Immortal.\n\r",ch);
     return SPELL_NORMAL;
   }

   if (ROOM_FLAGGED(victim->in_room, NO_MAGIC) ||
       ZONE_FLAGGED(world[victim->in_room].zone, Z_IMMORT) ||
       ZONE_FLAGGED(world[victim->in_room].zone, Z_LOCKED) ||
       ZONE_FLAGGED(world[victim->in_room].zone, Z_CLOSED) ||
      (ZONE_FLAGGED(world[victim->in_room].zone, Z_ARENA) != IN_ARENA(ch)))
   {
     act("$n tries to gate, but is unsuccessful!", TRUE, victim, 0, 0, TO_ROOM);
     send_to_char("Some unknown force prevents a gateway from being formed there.\n\r",ch);
     return SPELL_NORMAL;
   }

   gate2 = read_object(105, VIRTUAL);

   gate1->value[0] = victim->in_room;
   gate2->value[0] = ch->in_room;

   gate1->timer = gate2->timer = number(1,3);

   // flag gates anchored so they dont float away  4/19/98 -jtrhone
   SET_BIT(OBJ_EXTRAS(gate1), ITEM_ANCHORED);
   SET_BIT(OBJ_EXTRAS(gate2), ITEM_ANCHORED);

   act("$p appears and shimmers slightly!", TRUE, victim, gate1, 0, TO_ROOM);
   act("$p appears and shimmers slightly!", TRUE, victim, gate1, 0, TO_CHAR);

   act("$n has created $p to $N!", TRUE, ch, gate1, victim, TO_ROOM);
   act("You have created $p to $N!", TRUE, ch, gate2, victim, TO_CHAR); 
   
   obj_to_room(gate1, ch->in_room);
   obj_to_room(gate2, victim->in_room);

   return SPELL_NORMAL;
}

// RoA spells that are primarly CLERICAL in nature follow
// Reworked slightly so only non-animal mobs are held, and added support for
// NewAffect()... 07/09/98 - callahan
ASPELL(spell_hold_person)
{
   AffType af;

   if (!victim)
      return SPELL_FAILED;

   if (Level(ch) < LEV_CIMP)
   if (saves_spell(victim, SPELL_HOLD_PERSON) || MOB_FLAGGED(victim, MOB_NO_HOLD) || 
	Level(victim) - Level(ch) > 5) {
     act("$N is enraged at your attempt to hold $M!", TRUE, ch, 0, victim,TO_CHAR);
     if (!number(0, 2))
        do_kill(victim, Name(ch), 0, 0); 
     return SPELL_NORMAL;
   }

  if (MOB_CLASS_FLAGGED(victim, MOB_MAMMAL | MOB_AVIAN | MOB_INSECT |
                                MOB_ARACHNID | MOB_ORC | MOB_OGRE |
                                MOB_REPTILE | MOB_GOBLINOID | MOB_AQUATIC |
                                MOB_CRUSTACEAN)) {
    send_to_char(tprintf("%s cannot be affected by this spell.\r\n",
                         Name(victim)), ch);
    return SPELL_FAILED;
  }

   if (!affected_by_spell(victim, SPELL_HOLD_PERSON) &&
       !affected_by_spell(victim, SPELL_ENSNARE)) {
      NewAffect(&af);

      af.type      = SPELL_HOLD_PERSON;
      af.duration  = (GET_INT(ch) / 9) + 1;
      af.bitvector = AFF_HOLD;

      affect_to_char(victim, &af);

      act("You have been held!", FALSE, victim, 0, 0, TO_CHAR);
      act("$n is %4frozen%0 in place!", FALSE, victim, 0, 0, TO_ROOM);

      // for later EXP assigning... 12/17/97 -jtrhone
      HOLDER(victim) = ch;
   } else
     act("$N is already held in place!", FALSE, ch, 0, victim, TO_CHAR);

   return SPELL_NORMAL;
}

ASPELL(spell_calm)
{
  struct affected_type af;
  chdata *person;

  if (IN_NOWHERE(ch)) return SPELL_FAILED;

  if (FIGHTING(ch))
    stop_fighting(ch);

  af.type = SPELL_CALM;
  af.duration = GET_LEVEL(ch) / 15;
  af.modifier = APPLY_NONE;
  af.location = 0;
  af.bitvector = 0;
  af.bitvector2 = AFF2_CALM;

  /* put the affect on the chars which get affected*/
  for(person = world[ch->in_room].people;person;person = person->next_in_room)
    if(IS_NPC(person) && !affected_by_spell(person, SPELL_CALM) && 
       !MOB_FLAGGED(person, MOB_NO_CALM) && !saves_spell(person, SPELL_CALM))
    { 
      if (FIGHTING(person))
	stop_fighting(person);
      affect_to_char(person, &af);
      act("$N suddenly looks much calmer!", FALSE, ch, 0, person, TO_CHAR);
      act("$N suddenly looks much calmer!", FALSE, ch, 0, person, TO_ROOM);
      act("$n has forced you to be calm!", FALSE, ch, 0, person, TO_VICT);
    }

  /* NO calm meanies */
  for(person = world[ch->in_room].people;person;person = person->next_in_room){
    if(MOB_FLAGGED(person, MOB_NO_CALM) && FIGHTING(person)) 
    {
      act("$N is extremely annoyed at your attempt to calm $M!", FALSE, ch, 0, person, TO_CHAR);
      act("$N is extremely annoyed at $n's attempt to calm $M!", FALSE, ch, 0, person, TO_ROOM);
      act("You are extremely annoyed at $n's attempt to calm you!", FALSE, ch, 0, person, TO_VICT);

      if(FIGHTING(person) != ch) 
      {
	stop_fighting(person);
	hit(person, ch, TYPE_UNDEFINED, FALSE);
      }
    }
  }

  return SPELL_NORMAL;
}

ASPELL(spell_illuminate)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;

   if (saves_spell(victim, SPELL_ILLUMINATE))
   {
      act("$N resists your attempt!",TRUE,ch,0,victim,TO_CHAR);
      return SPELL_NORMAL;
   }

   if (!affected_by_spell(victim, SPELL_ILLUMINATE)) 
   {
      af.type      = SPELL_ILLUMINATE;
      af.duration  = GET_LEVEL(ch)/2;
      af.modifier  = 0;
      af.location  = APPLY_NONE;
      af.bitvector = 0;
      af.bitvector2 = AFF2_ILLUMINATE;

      affect_to_char(victim, &af);
      act("You feel vulnerable.",FALSE,victim,0,0,TO_CHAR);
      act("$n glows with a %B%3golden%0 aura!", FALSE, victim, 0, 0, TO_ROOM);
   }
   else
   if (ch != victim)
      act("$N is already affected by illuminate.",FALSE,victim,0,0,TO_CHAR);
   else
      act("You are already affected by illuminate.",FALSE,ch,0,0,TO_CHAR);
   return SPELL_NORMAL;
}

ASPELL(spell_protection_from_good)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;
   if (!affected_by_spell(victim, SPELL_PROTECT_FROM_GOOD))
   {
      af.type      = SPELL_PROTECT_FROM_GOOD;
      af.duration  = 24;
      af.modifier  = 0;
      af.location  = APPLY_NONE;
      af.bitvector = AFF_PROTECT_GOOD;
      af.bitvector2 = 0;
      affect_to_char(victim, &af);
      send_to_char("Success!\n\r",ch);
      send_to_char("You are protected from goodness!\n\r", victim);
   }
   else
   if (ch != victim)
      act("$N is already protected from goodness.",FALSE,victim,0,0,TO_CHAR);
   else
      act("You are already protected from goodness.",FALSE,ch,0,0,TO_CHAR);
   return SPELL_NORMAL;
}

ASPELL(spell_protect_undead)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;
   if (!affected_by_spell(victim, SPELL_PROTECT_UNDEAD)) 
   {
      af.type      = SPELL_PROTECT_UNDEAD;
      af.duration  = 24;
      af.modifier  = 0;
      af.location  = APPLY_NONE;
      af.bitvector = 0;
      af.bitvector2 = 0;
      affect_to_char(victim, &af);
      send_to_char("You are protected from the undead!\n\r", victim);
      act("$n shimmers slightly and looks holy!", FALSE, victim, 0, 0, TO_ROOM);
   }
   else
   if (ch != victim)
      act("$N is already protected from the undead.",FALSE,victim,0,0,TO_CHAR);
   else
      act("You are already protected from the undead.",FALSE,ch,0,0,TO_CHAR);
   return SPELL_NORMAL;
}

ASPELL(spell_create_food)
{
   obdata *tmp_obj;
   int num;

   /* object vnum 120 - 135 is a magic food in RoA */
   num = number(120, 135);
   if (!(tmp_obj = read_object(num, VIRTUAL)))
   {
     send_to_char("Something went wrong!  Notify an Immortal.\n\r",ch);
     return SPELL_FAILED;
   }
   tmp_obj->value[0] = 5 + GET_LEVEL(ch)/2;
   act("$n has created $p!", TRUE, ch, tmp_obj, 0, TO_ROOM);
   act("$p suddenly appears in your inventory!", TRUE, ch, tmp_obj, 0, TO_CHAR);
   obj_to_char(tmp_obj, ch);
   return SPELL_NORMAL;
}

ASPELL(spell_stone_skin)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;
   if (!ch) 
     log("SYSERR: ch sanity check failed, spell_stone_skin, magic.c");

   if (!affected_by_spell(victim, SPELL_STONE_SKIN) && 
       !affected_by_spell(victim, SPELL_ARMOR) && 
       !affected_by_spell(victim, SPELL_TREESKIN) &&	// 06/07/98 -callahan
       !affected_by_spell(victim, SPELL_BARKSKIN)) 
   {
      af.type      = SPELL_STONE_SKIN;
      af.duration  = 24;
      af.modifier  = -GET_LEVEL(ch)-23;
      af.location  = APPLY_AC;
      af.bitvector = 0;
      af.bitvector2 = 0;

      affect_to_char(victim, &af);
      send_to_char("You feel protected by skin of stone!\n\r", victim);
      act("$n's skin suddenly hardens and turns %8grey%0!", FALSE, victim,0, 0, TO_ROOM);
   }
   else
   if (ch != victim)
      act("$N is already protected.",FALSE,ch,0,victim,TO_CHAR);
   else
      act("You are already protected.",FALSE,ch,0,0,TO_CHAR);
   return SPELL_NORMAL;
}

ASPELL(spell_power_heal)
{
   if (!victim) return SPELL_FAILED;

   if (affected_by_spell(victim, SPELL_BLINDNESS) || 
       affected_by_spell(victim, SPELL_SPIRITLEAVES))
     spell_cure_blind(ch, arg, victim, obj);

   GET_HIT(victim) += (250 - dice(1,4));  /* changed this spell JRHone*/
   GET_HIT(victim) = MIN(GET_MAX_HIT(victim), GET_HIT(victim));
   update_pos(victim);
   send_to_char("A %6blinding%0 light surrounds you....\n\r",victim);
   send_to_char("A %1warm%0 feeling fills your body....\n\r", victim);
   act("A %Bblinding light%0 surrounds $n.", FALSE, victim, 0, 0, TO_ROOM);
   return SPELL_NORMAL;
}

ASPELL(spell_wings)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;
   if (!affected_by_spell(victim, SPELL_WINGS)) 
   {
      af.type      = SPELL_WINGS;
      af.duration  = GET_LEVEL(ch);
      af.modifier  = 0;
      af.location  = APPLY_NONE;
      af.bitvector = AFF_WINGS;
      af.bitvector2 = 0;

      affect_to_char(victim, &af);
      act("You slowly float into the air!",FALSE,victim,0,0,TO_CHAR);
      act("$n slowly floats into the air.", FALSE, victim, 0, 0, TO_ROOM);
   }
   else
   if (ch != victim)
      act("$N is already affected by wings.",FALSE,victim,0,0,TO_CHAR);
   else
      act("You are already affected by wings.",FALSE,ch,0,0,TO_CHAR);
   return SPELL_NORMAL;
}

ASPELL(spell_gills)
{
   struct affected_type af;

   if (!victim) return SPELL_FAILED;
   if (!affected_by_spell(victim, SPELL_GILLS)) 
   {
      af.type      = SPELL_GILLS;
      af.duration  = GET_LEVEL(ch);
      af.modifier  = 0;
      af.location  = APPLY_NONE;
      af.bitvector = AFF_GILLS;
      af.bitvector2 = 0;

      affect_to_char(victim, &af);
      act("You slowly form gills.",FALSE,victim,0,0,TO_CHAR);
      act("$n slowly forms gills.", FALSE, victim, 0, 0, TO_ROOM);
   }
   else
   if (ch != victim)
      act("$N is already affected by gills.",FALSE,victim,0,0,TO_CHAR);
   else
      act("You are already affected by gills.",FALSE,ch,0,0,TO_CHAR);
   return SPELL_NORMAL;
}

ASPELL(spell_locate_being)
{
  int rm = ch->in_room;

  if (!victim)
  { 
    send_to_char("Your mind spins with confusion.\n\r",ch);
    return SPELL_FAILED;
  }
 
  if (!check_mortal_combat(ch, victim))  /* then its worth a saving throw*/
    return SPELL_FAILED;

  if (saves_spell(victim, SPELL_LOCATE_BEING))
  {
    send_to_char("Your target resists.\n\r",ch);
    return SPELL_FAILED;
  }

  act("You concentrate yourself....", FALSE, ch, 0, 0, TO_CHAR);
  act("$n sinks into deep concentration.", FALSE, ch, 0, 0, TO_ROOM);
 
  // check if victim has mindtrap set... 11/29/97 -jtrhone
  if (affected_by_spell(victim, SPELL_MINDTRAP))
  {
    act("%B%5AAAAAHHH!!!%0", FALSE, ch, 0, victim, TO_CHAR);

    act("An image of $n %Bflashes%0 in your head.",TRUE,ch,0,victim,TO_VICT);
    act("Your %B%5MINDTRAP%0 lashes out at $n!",TRUE,ch,0,victim,TO_VICT);

    act("$n drops to $s knees in pain!", FALSE, ch, 0, 0, TO_ROOM);

    // hmm.. what type of damage
    GET_HIT(ch) /= 2;
    return SPELL_FAILED;
  }

  if (!INVALID_ROOM(victim->in_room))
  {
    ch->in_room = victim->in_room;
    do_look_at_room(ch, 0, 0);
    ch->in_room = rm;
    act("An image of $n %Bflashes%0 in your head.",TRUE,ch,0,victim,TO_VICT);
  }
  else
    send_to_char("Your mind spins with confusion.\n\r",ch);

  return SPELL_NORMAL;
}

ASPELL(spell_view_hidden)
{
   struct affected_type af;
   int level = GET_LEVEL(ch);

   if (!victim) return SPELL_FAILED;
   af.type      = SPELL_VIEW_HIDDEN;
   af.duration  = level * 2;
   af.modifier  = 0;
   af.location  = APPLY_NONE;
   af.bitvector = 0;
   af.bitvector2 = 0;
   affect_join(victim, &af, TRUE, FALSE);
   act("Your awareness suddenly improves.",FALSE,victim,0,0,TO_CHAR);
   act("$n's awareness suddenly improves.",TRUE,victim,0,0,TO_ROOM);
   return SPELL_NORMAL;
}

ASPELL(spell_forest_sight)
{
   struct affected_type af;
   int level = GET_LEVEL(ch);

   if (!victim) return SPELL_FAILED;
   af.type      = SPELL_FOREST_SIGHT;
   af.duration  = level * 2;
   af.modifier  = 0;
   af.location  = APPLY_NONE;
   af.bitvector = 0;
   af.bitvector2 = 0;
   affect_join(victim, &af, TRUE, FALSE);
   act("Your awareness suddenly improves.",FALSE,victim,0,0,TO_CHAR);
   act("$n's awareness suddenly improves.",TRUE,victim,0,0,TO_ROOM);
   return SPELL_NORMAL;
}

// RoA first of the room affectual spells 10/28/96
ASPELL(spell_silence)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_SILENCE))
  {
    act("There is an aura of %Bsilence%0 already here.",FALSE, ch, 0, 0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_SILENCE;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You call forth an aura of %Bholy silence%0!", FALSE, ch, 0, 0, TO_CHAR);
  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_retrieve_corpse)
{
  char *argu = arg;
  long id;
  obdata *ob;
  long get_id_by_name(char *name);

  if (!*argu)
  {
    send_to_char("Usage: cast 'retrieve corpse' < PC name >\n\r",ch);
    return SPELL_NORMAL;
  }

  skip_spaces(&argu);
  if ((id = get_id_by_name(argu)) <= 0)
  {
    sprintf(buf, "The name %s is unknown in these realms...\n\r", argu);
    S2C();
    return SPELL_NORMAL;
  }

  for (ob=object_list; ob; ob=ob->next)
    if (!INVALID_ROOM(ob->in_room) && IS_CORPSE(ob) && ob->plr_num == id)
      break;

  // we didnt find it...
  if (!ob)
  {
    act("You fail to locate anything...", FALSE, ch, 0, 0, TO_CHAR);
    return SPELL_NORMAL;
  }

  // waste protection...
  if (ob->in_room == ch->in_room)
  {
    act("Those remains are already here...", FALSE, ch, 0, 0, TO_CHAR);
    return SPELL_NORMAL;
  }

  // we found it :)
  act("You retrieve $p!", FALSE, ch, ob, 0, TO_CHAR);
  act("$n's eyes darken momentarily...",TRUE,ch,0,0,TO_ROOM);

  obj_from_room(ob);
  obj_to_room(ob, ch->in_room);

  act("$n has retrieved $p!",TRUE,ch,ob,0,TO_ROOM);

  sprintf(buf, "PLRUPD: %s retrieved %s.", GET_NAME(ch), ob->shdesc);
  mudlog(buf, BRF, LEV_IMM, TRUE);
  return SPELL_NORMAL;
}

ASPELL(spell_mindtrap)
{
  struct affected_type af;

  if (!affected_by_spell(ch, SPELL_MINDTRAP))
  {
    af.type      = SPELL_MINDTRAP;
    af.duration  = 24 + GET_LEVEL(ch);
    af.modifier  = 0; 
    af.location  = 0;
    af.bitvector = 0;
    af.bitvector2 = 0;
    affect_to_char(ch, &af);

    act("Your mindtrap has been successfully set...", FALSE, ch, 0, 0, TO_CHAR);
    act("A shadow falls across $n's face...", FALSE, ch, 0, 0, TO_ROOM);
  }
  else
  if (ch != victim)
     act("$N is already affected by mindtrap.",FALSE,victim,0,0,TO_CHAR);
  else
     act("You are already affected by mindtrap.",FALSE,ch,0,0,TO_CHAR);
  return SPELL_NORMAL;
}

ASPELL(spell_firewall)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_FIREWALL))
  {
    act("There is a %1%Bwall of fire%0 already here.",FALSE, ch, 0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_FIREWALL;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You call forth a %B%1wall of fire%0!", FALSE, ch, 0, 0, TO_CHAR);
  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_icewall)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_ICEWALL))
  {
    act("There is an %6%Bice storm%0 already here.",FALSE, ch,0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_ICEWALL;
  af.caster = ch;
  af.duration  = number(2, 4);
  af.bitvector = 0;

  act("You call forth an %B%6ice storm%0!", FALSE, ch, 0, 0, TO_CHAR);
  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_typhoon)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_TYPHOON))
  {
    act("A %1typhoon%0 rages here already!",FALSE, ch,0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_TYPHOON;
  af.caster = ch;
  af.duration  = number(2, 4);
  af.bitvector = 0;

  act("You call forth a deadly %1typhoon%0!", FALSE, ch, 0, 0, TO_CHAR);
  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_void)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_VOID))
  {
    act("A %4temporal void%0 shimmers here already!",FALSE,ch,0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_VOID;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You call forth a %4temporal void%0!", FALSE, ch, 0, 0,TO_CHAR);
  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_gascloud)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_GASCLOUD))
  {
    act("A %2cloud of gas%0 is already here!",FALSE,ch,0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_GASCLOUD;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You call forth a %2cloud of gas%0!", FALSE, ch, 0, 0,TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_blindwall)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_BLINDWALL))
  {
    act("A %4cloak of blindness%0 is already here!",FALSE,ch,0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_BLINDWALL;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You call forth a %4cloak of blindness%0!", FALSE, ch, 0, 0,TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_confusion)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_CONFUSION))
  {
    act("This area is already confusing enough!",FALSE,ch,0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_CONFUSION;
  af.caster = ch;
  af.duration  = number(2, 5);
  af.bitvector = 0;

  act("You call forth a an area of confusion!", FALSE, ch, 0, 0,TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_swarm)
{ 
  int dam;
  int level = GET_LEVEL(ch);
  chdata *next_vict;
  BOOL found = FALSE;

  for (victim = character_list; victim; victim = next_vict)
  {
    next_vict = victim->next;
    if (FIGHTING(victim) == ch && SAME_ROOM(victim, ch) && check_mortal_combat(ch, victim))
    {
      found = TRUE;
      dam = dice(level, 4);
      if (saves_spell(victim, SPELL_SWARM))
        damage(ch, victim, (dam >> 1), SPELL_SWARM, FALSE);
      else
        damage(ch, victim, dam, SPELL_SWARM, FALSE);
    }
  }

  if (!found)
    send_to_char("You're unable to find an enemy to focus the swarm on.\n\r",ch);
  return SPELL_NORMAL;
}

ASPELL(spell_shower_of_life)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_SHOWEROFLIFE))
  {
    act("There is a %6%Bshower of life%0 already here.",FALSE, ch, 0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_SHOWEROFLIFE;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You call forth a %B%6shower of life%0!", FALSE, ch, 0, 0, TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_cursed_grounds)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_CURSED_GROUNDS))
  {
    act("This area is already cursed.",FALSE, ch, 0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_CURSED_GROUNDS;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You curse this area!", FALSE, ch, 0, 0, TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_absolute_ward)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_ABSOLUTE_WARD))
  {
    act("This area is already warded.",FALSE, ch, 0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_ABSOLUTE_WARD;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You ward this area!", FALSE, ch, 0, 0, TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_circle_of_warding)
{
  struct room_affect_type af;
  char *argu = arg;

  skip_spaces(&argu);
  if (!*argu)
  {
    send_to_char("Usage: cast 'circle of warding' < evil | neutral | good >\n\r",ch);
    return SPELL_NORMAL;
  }

  if (spell_affects_room(ch->in_room, SPELL_CIRCLE_OF_WARDING))
  {
    act("This area is already warded.",FALSE, ch, 0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  if (is_abbrev(argu, "evil"))
  {
    af.bitvector = RMAFF_VS_EVIL;
    strcpy(buf2, "evil");
  }
  else
  if (is_abbrev(argu, "neutral"))
  {
    af.bitvector = RMAFF_VS_NEUTRAL;
    strcpy(buf2, "neutrality");
  }
  else
  if (is_abbrev(argu, "good"))
  {
    af.bitvector = RMAFF_VS_GOOD;
    strcpy(buf2, "goodness");
  }
  else
  {
    send_to_char("Usage: cast 'circle of warding' < evil | neutral | good >\n\r",ch);
    return SPELL_NORMAL;
  }

  af.spell     = SPELL_CIRCLE_OF_WARDING;
  af.caster    = ch;
  af.duration  = number(1, 3);

  sprintf(buf, "You ward this area against %s!", buf2);
  act(buf, FALSE, ch, 0, 0, TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_walloffog)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_WALLOFFOG) ||
      spell_affects_room(ch->in_room, SPELL_OCCLUSION))
  {
    act("This area is already covered by a wall of fog.",FALSE, ch, 0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_WALLOFFOG;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You enshroud this area in a thick fog!", FALSE, ch, 0, 0, TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_area_of_return)
{
  struct room_affect_type af, *raf;
  int room;

  // first, remove any existing areas of return
  for (room = 0; room < top_of_world; room++)
    if ((raf = char_spell_affects_room(ch, SPELL_AREA_OF_RETURN, room)))
    {
      char_spell_affect_from_room(ch, SPELL_AREA_OF_RETURN, room);
      if (world[room].name)
      {
        sprintf(buf, "You aura has been removed from %s.\n\r", world[room].name);
        S2C();
      }
    }

  af.spell = SPELL_AREA_OF_RETURN;
  af.caster = ch;
  af.duration  = number(3, 5);
  af.bitvector = 0;

  act("You mark this area with your %Baura%0!", FALSE, ch, 0, 0, TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

ASPELL(spell_return)
{
  struct room_affect_type *raf;
  int room;

  // first, see if any areas exist...
  for (room = 0; room < top_of_world; room++)
    if ((raf = char_spell_affects_room(ch, SPELL_AREA_OF_RETURN, room)))
      break;

  if (room >= top_of_world)
  {
    act("You fail to find your %Baura%0!", FALSE, ch, 0, 0, TO_CHAR);
    return SPELL_NORMAL;
  }

  act("You slowly fade out of existence.", FALSE, ch, 0, 0, TO_CHAR);
  act("$n slowly fades out of existence.", FALSE, ch, 0, 0, TO_ROOM);
  char_from_room(ch);
  char_to_room(ch, room);
  act("You slowly fade into existence.", FALSE, ch, 0, 0, TO_CHAR);
  act("$n slowly fades into existence.", FALSE, ch, 0, 0, TO_ROOM);
  do_look_at_room(ch, 15, 0);
  if (check_room_affects(ch, ch->in_room) == CHAR_DIED)
    return SPELL_NORMAL;
  if (check_death_trap(ch, NULL))
    return SPELL_NORMAL;

  return SPELL_NORMAL;
}

ASPELL(spell_project)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_PROJECT))
  {
    act("This area already contains a projection.",FALSE, ch, 0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_PROJECT;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You project yourself onto this area!", FALSE, ch, 0, 0, TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

// rangers spell similar to implosion  3/27/98 -jtrhone
ASPELL(spell_earthdarts)  
{
   int	dam;
 
   if (!victim) return SPELL_FAILED;
   dam = number(50, 100);

   SpellDamage(ch, victim, dam, SPELL_EARTHDARTS, FALSE);
   return SPELL_NORMAL;
}

// rangers spell similar to blindness  3/27/98 -jtrhone
ASPELL(spell_spiritleaves)
{
   AffType af;

   if (!victim)
     return SPELL_FAILED;

   if (!check_mortal_combat(ch, victim))
     return SPELL_FAILED;

   if (saves_spell(victim, SPELL_SPIRITLEAVES) ||
       MOB_FLAGGED(victim, MOB_NO_BLIND)) { 
     if (ch != victim)
       act("$N repels your spell.",TRUE,ch,0,victim,TO_CHAR);
     else
       act("You repel your spell...?",TRUE,ch,0,victim,TO_CHAR);
     return SPELL_NORMAL;
   }

   if (!affected_by_spell(victim, SPELL_SPIRITLEAVES) && 
       !affected_by_spell(victim, SPELL_BLINDNESS)) {
     NewAffect(&af);

     af.type      = SPELL_SPIRITLEAVES;
     af.location  = APPLY_HITROLL;
     af.modifier  = -(GET_LEVEL(ch)/3);  /* Make hitroll WAY worse */
     af.duration  = 1;
     af.bitvector = AFF_BLIND;
     affect_to_char(victim, &af);

     af.location = APPLY_AC;
     af.modifier = 20; /* Make AC Worse! */
     affect_to_char(victim, &af);
     act("$n seems to be blinded by spirit leaves!", TRUE, victim, 0, 0, TO_ROOM);
     act("You have been blinded by spirit leaves!",FALSE,victim,0,0,TO_CHAR);
   }
   else
     send_to_char("Luckily, you are already blind!\n\r",victim);

   return SPELL_NORMAL;
}

// rangers spell similar to bard's BOG  3/27/98 -jtrhone
ASPELL(spell_entangle)
{
   AffType af;

   if (!victim)
     return SPELL_FAILED;

   if (!check_mortal_combat(ch, victim))
     return SPELL_FAILED;

   if (saves_spell(victim, SPELL_ENTANGLE) || MOB_FLAGGED(victim, MOB_NO_HOLD)) 
   { 
     if (ch != victim)
       act("$N repels your spell.",TRUE,ch,0,victim,TO_CHAR);
     else
       act("You repel your spell...?",TRUE,ch,0,victim,TO_CHAR);
     return SPELL_NORMAL;
   }

   if (!affected_by_spell(victim, SPELL_ENTANGLE) && !affected_by_spell(victim, SPELL_SONG_BOG))
   {
     NewAffect(&af);

     af.type      = SPELL_ENTANGLE;
     af.location  = APPLY_DEX;
     af.modifier  = -3;

     // level/10 ROUNDS (1 tick == 30 rounds, roughly)
     // will decrement per round in fight.c
     af.duration  = GET_LEVEL(ch) / 10;

     affect_to_char(victim, &af);

     act("You have been entangled!",FALSE,victim,0,0,TO_CHAR);
     act("$n seems to be entangled!", TRUE, victim, 0, 0, TO_ROOM);
   }
   else
       act("$N is already affected by such.",TRUE,ch,0,victim,TO_CHAR);

   return SPELL_NORMAL;
}

// ranger spell similar to stone_skin  3/27/98 -jtrhone
ASPELL(spell_barkskin)
{
   AffType af;

   if (!victim)
     return SPELL_FAILED;

   if (!ch) 
     log("SYSERR: ch sanity check failed, barkskin, magic.c");

   if (!affected_by_spell(victim, SPELL_STONE_SKIN) && 
       !affected_by_spell(victim, SPELL_ARMOR) &&
       !affected_by_spell(victim, SPELL_BARKSKIN)) 
   {
      NewAffect(&af);

      af.type      = SPELL_BARKSKIN;
      af.duration  = 24;
      af.modifier  = -GET_LEVEL(ch)-23;
      af.location  = APPLY_AC;

      affect_to_char(victim, &af);
      send_to_char("You feel protected by barkskin!\n\r", victim);
      act("$n's skin suddenly hardens in the form of bark!", FALSE, victim,0, 0, TO_ROOM);
   }
   else
   if (ch != victim)
      act("$N is already protected.",FALSE,victim,0,0,TO_CHAR);
   else
      act("You are already protected.",FALSE,ch,0,0,TO_CHAR);
   return SPELL_NORMAL;
}

// ranger spell similar to heal  3/27/98 -jtrhone
ASPELL(spell_spiritbalm)
{
   if (!victim) return SPELL_FAILED;

   if (affected_by_spell(victim, SPELL_BLINDNESS) || 
       affected_by_spell(victim, SPELL_SPIRITLEAVES))
     spell_cure_blind(ch, arg, victim, obj);

   GET_HIT(victim) += (100 - dice(1,4));
   GET_HIT(victim) = MIN(GET_MAX_HIT(victim), GET_HIT(victim));

   update_pos(victim);

   act("A %1warm%0 feeling fills your spirit...",FALSE,victim,0,0,TO_CHAR);
   act("You suddenly feel much better!",FALSE,victim,0,0,TO_CHAR);
   act("$n suddenly looks much healthier.", FALSE, victim, 0, 0, TO_ROOM);
   return SPELL_NORMAL;
}

// ranger spell similar to harm  3/27/98 -jtrhone
ASPELL(spell_spiritshock)
{
  int	dam;

  if (!victim) return SPELL_FAILED;

  dam = GET_HIT(victim) - dice(1, 4);
  if (dam < 0)
    dam = 0; 
  else
  if (saves_spell(victim, SPELL_SPIRITSHOCK))
    dam = MIN(30, dam / 3);
  damage(ch, victim, dam, SPELL_SPIRITSHOCK, FALSE);
  return SPELL_NORMAL;
}

// ranger spell similar to detect invis  3/27/98 -jtrhone
ASPELL(spell_foresteyes)
{
  AffType af;
  int level = GET_LEVEL(ch);

  if (!victim) return SPELL_FAILED;

  if (!affected_by_spell(ch, SPELL_FORESTEYES) &&
      !affected_by_spell(ch, SPELL_DETECT_INVISIBLE))
  {
    NewAffect(&af);

    af.type      = SPELL_FORESTEYES;
    af.duration  = level * 5;
    af.location  = APPLY_NONE;
    af.bitvector = AFF_DETECT_INVISIBLE;
    affect_to_char(victim, &af);

    send_to_char("You gain the eyes of the forest.\n\r", victim);
  }
  else
  if (ch != victim)
    act("$N is already affected.",FALSE,victim,0,0,TO_CHAR);
  else
    act("You are already affected.",FALSE,ch,0,0,TO_CHAR);
  
   return SPELL_NORMAL;
}

// ranger spell similar to hold  3/27/98 -jtrhone
ASPELL(spell_ensnare)
{
   AffType af;

   if (!victim) return SPELL_FAILED;

   if (GET_LEVEL(ch) < LEV_CIMP)
   if (saves_spell(victim, SPELL_ENSNARE) || MOB_FLAGGED(victim, MOB_NO_HOLD) || 
	GET_LEVEL(victim) - GET_LEVEL(ch) > 5)
   {
     act("$N is enraged at your attempt to ensnare $M!", TRUE, ch, 0, victim,TO_CHAR);
     if (!number(0, 2))  
        do_kill(victim, GET_NAME(ch), 0, 0); 
     return SPELL_NORMAL;
   }

   if (!affected_by_spell(victim, SPELL_HOLD_PERSON) &&
       !affected_by_spell(victim, SPELL_ENSNARE))
   {
      NewAffect(&af);
      af.type      = SPELL_ENSNARE;
      af.duration  = (GET_INT(ch) / 9) + 1;
      af.bitvector = AFF_HOLD;
      affect_to_char(victim, &af);

      act("You have been ensnared!",FALSE,victim,0,0,TO_CHAR);
      act("$n has been %6ensnared%0!", FALSE, victim, 0, 0, TO_ROOM);

      // for later EXP assigning... 12/17/97 -jtrhone
      HOLDER(victim) = ch;
   }
   else
     act("$N is already held in place!", FALSE, ch, 0, victim, TO_CHAR);

   return SPELL_NORMAL;
}

// ranger spell similar to wall of fog  3/27/98 -jtrhone
ASPELL(spell_occlusion)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_WALLOFFOG) ||
      spell_affects_room(ch->in_room, SPELL_OCCLUSION))
  {
    act("This area is already covered by an area of fog.",FALSE, ch, 0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_OCCLUSION;
  af.caster = ch;
  af.duration  = 1;
  af.bitvector = 0;

  act("You enshroud this area in a thick fog!", FALSE, ch, 0, 0, TO_CHAR);

  affect_to_room(ch->in_room, &af);

  // now, stop ch from fighting...
  if ((victim = FIGHTING(ch)))
  {
    if (saves_spell(victim, SPELL_OCCLUSION))
    {
      act("You fail to disengage from $N!", FALSE, ch, 0, victim, TO_CHAR);
      act("$n has disengaged from fighting you!", FALSE, ch, 0, victim, TO_VICT);
      return SPELL_NORMAL;
    }

    act("You disengage from $N!", FALSE, ch, 0, victim, TO_CHAR);

    // make mob remember...
    if (FIGHTING(victim) == ch)
      HUNTING(victim) = ch;

    stop_fighting(ch);
    stop_fighting(victim);

    
  }

  return SPELL_NORMAL;
}

// ranger spell similar to shower of life  3/27/98 -jtrhone
ASPELL(spell_campfire)
{
  struct room_affect_type af;

  if (spell_affects_room(ch->in_room, SPELL_CAMPFIRE))
  {
    act("There is a %1%Bcampfire%0 already here.",FALSE, ch, 0,0,TO_CHAR);
    return SPELL_NORMAL;
  }

  af.spell = SPELL_CAMPFIRE;
  af.caster = ch;
  af.duration  = number(1, 3);
  af.bitvector = 0;

  act("You build a soothing %B%1campfire%0!", FALSE, ch, 0, 0, TO_CHAR);

  affect_to_room(ch->in_room, &af);
  return SPELL_NORMAL;
}

// ranger spell similar to sanct  3/27/98 -jtrhone
ASPELL(spell_spiritshield)
{
   AffType af;

   if (!victim) return SPELL_FAILED;

   if (!IS_AFFECTED(victim, AFF_SANCTUARY) && !IS_AFFECTED2(victim, AFF2_CROW)) 
   {
      NewAffect(&af);

      af.type      = SPELL_SPIRITSHIELD;
      af.duration  = IS_IMMORTAL(ch) ? GET_LEVEL(ch) : 3;
      af.location  = APPLY_NONE;
      af.bitvector = AFF_SANCTUARY;
      affect_to_char(victim, &af);
      act("Your spirit is surrounded by a %Bglowing%0 aura.", TRUE, victim, 0, 0, TO_CHAR);
      act("$n's spirit is surrounded by a %Bglowing%0 aura.", TRUE, victim, 0, 0, TO_ROOM);
   }
   else
   if (ch != victim)
     act("$N is already affected.",FALSE,victim,0,0,TO_CHAR);
   else
     act("You are already affected.",FALSE,ch,0,0,TO_CHAR);

   return SPELL_NORMAL;
}

/* ***************************************************************************
 *                     NPC spells..                                          *
 * ************************************************************************* */

ASPELL(spell_fire_breath)
{
   int	dam;
   int	hpch;
   obdata *burn;

   if (!victim) return SPELL_FAILED;

   hpch = GET_HIT(ch);
   if (hpch < 10)
      hpch = 10;

   dam = number(0, hpch >> 2);

   if (SpellDamage(ch, victim, dam, SPELL_FIRE_BREATH, FALSE) == CHAR_DIED)
     return SPELL_NORMAL;

   /* And now for the damage on inventory */

   if (number(0, 70) < GET_LEVEL(ch)) 
   {
      if (!saves_spell(victim, SPELL_FIRE_BREATH) ) 
      {
	 for (burn = victim->carrying; burn && (burn->type_flag != ITEM_WAND) && 
	     (burn->type_flag != ITEM_STAFF) && (burn->type_flag != ITEM_CONTAINER) &&
	     (!number(0, 2)); burn = burn->next_content)
	    ;

	 if (burn) 
	 {
	    act("$p suddenly %B%1burns into ashes%0!", 0, victim, burn, 0, TO_CHAR);
	    extract_obj(burn);
	 }
      }
   }
   return SPELL_NORMAL;
}

ASPELL(spell_frost_breath)
{
   int	dam;
   int	hpch;
   obdata *frozen;

   if (!victim) return SPELL_FAILED;

   hpch = GET_HIT(ch);
   if (hpch < 10)
      hpch = 10;

   dam = number(0, hpch >> 2);

   if (SpellDamage(ch, victim, dam, SPELL_FROST_BREATH, FALSE) == CHAR_DIED)
     return SPELL_NORMAL;

   /* And now for the damage on inventory */

   if (number(0, 70) < GET_LEVEL(ch)) 
   {
      if (!saves_spell(victim, SPELL_FROST_BREATH) ) 
      {
	 for (frozen = victim->carrying; frozen && (frozen->type_flag != ITEM_DRINKCON) && 
	     (frozen->type_flag != ITEM_FOOD) && (frozen->type_flag != ITEM_POTION) && 
	     (frozen->type_flag != ITEM_CONTAINER) && (!number(0, 2)); frozen = frozen->next_content)
	    ;

	 if (frozen) {
	    act("$p suddenly %B%4freezes and breaks%0!", 0, victim, frozen, 0, TO_CHAR);
	    extract_obj(frozen);
	 }
      }
   }
   return SPELL_NORMAL;
}

ASPELL(spell_acid_breath)
{
   int	dam;
   int	hpch;
   int	damaged;
   int	apply_ac(chdata *ch, int eq_pos);

   if (!victim) return SPELL_FAILED;

   hpch = GET_HIT(ch);
   if (hpch < 10)
      hpch = 10;

   dam = number(0, hpch >> 2);

   if (SpellDamage(ch, victim, dam, SPELL_ACID_BREATH, FALSE) == CHAR_DIED)
     return SPELL_NORMAL;

   /* And now for the damage on equipment */
   if (number(0, 70) < GET_LEVEL(ch)) 
   {
      if (!saves_spell(victim, SPELL_ACID_BREATH) ) 
      {
	 if (number(0,1) && EQ(victim, (damaged = number(0,MAX_WEAR-1))))
         {
	    act("$p gets %B%1seered by the acid%0!", 0, victim, EQ(victim, damaged), 0, TO_CHAR);
	    damage_object(EQ(victim, damaged), victim);
	 }
      }
   }
   return SPELL_NORMAL;
}

ASPELL(spell_gas_breath)
{
   int	dam;
   int	hpch;

   if (!victim) return SPELL_FAILED;

   hpch = GET_HIT(ch);
   if (hpch < 10)
      hpch = 10;

   dam = number(0, hpch >> 2);

   SpellDamage(ch, victim, dam, SPELL_GAS_BREATH, FALSE);
   return SPELL_NORMAL;
}

ASPELL(spell_lightning_breath)
{
   int	dam;
   int	hpch;
   chdata *nxt;

   if (!victim) return SPELL_FAILED;

   hpch = GET_HIT(ch);
   if (hpch < 10)
      hpch = 10;

   dam = number(0, hpch >> 2);

   if (SpellDamage(ch, victim, dam, SPELL_LIGHTNING_BREATH, FALSE) == CHAR_DIED)
     return SPELL_NORMAL;

   if (world[victim->in_room].terrain_type == TERRAIN_WATER_SWIM ||
       world[victim->in_room].terrain_type == TERRAIN_WATER_NOSWIM ||
       world[victim->in_room].terrain_type == TERRAIN_UWATER)
   {
     act("%BElectricity flows through the area!!%0", FALSE, ch, 0, 0,TO_ROOM);
     for (victim = world[victim->in_room].people; victim; victim = nxt)
     {
       nxt = victim->next_in_room;
       if (!IS_FLYING(victim))
         damage(ch, victim, (dam*4), SPELL_LIGHTNING_BREATH, FALSE);
     }
   }
   return SPELL_NORMAL;
}