/* ************************************************************************
*  file: magic.c , Implementation of spells.              Part of DIKUMUD *
*  Usage : The actual effect of magic.                                    *
*  Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
************************************************************************* */

#include <stdio.h>
#include <assert.h>
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "spells.h"
#include "handler.h"
#include "limits.h"
#include "db.h"

/* Extern structures */
extern struct room_data *world;
extern struct zone_data *zone_table;
extern struct obj_data  *object_list;
extern struct char_data *character_list;

/* Extern procedures */

void damage(struct char_data *ch, struct char_data *victim,
            int damage, int weapontype);
bool saves_spell(struct char_data *ch, sh_int spell);
void weight_change_object(struct obj_data *obj, int weight);
char *strdup(char *source);
int dice(int number, int size);
void check_killer(struct char_data *ch, struct char_data *victim);
bool nokill(struct char_data *ch, struct char_data *victim);
void lose_exp_by_flight(struct char_data *ch,struct char_data *was_fighting);
void do_look(struct char_data *ch, char *argument, int cmd);

/* Offensive Spells */

void spell_magic_missile(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;
	int dam_each[] = 
		{0,  3,3,4,4,5, 6,6,6,6,6, 6,6,6,6,6, 6,6,6,6,6,
		     6,6,6,6,6, 6,6,6,6,6};

  assert(victim && ch);
  assert(level >= 1);

  dam = number(dam_each[level]>>1, dam_each[level]<<1);

  if ( saves_spell(victim, SAVING_SPELL) )
    dam >>= 1;

  damage(ch, victim, dam, SPELL_MAGIC_MISSILE);
}



void spell_chill_touch(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;
  int dam;
	int dam_each[] = 
		{0,  0,0,8,7,9, 9,12,13,13,13, 13,13,13,13,13, 13,13,13,13,13,
		     13,13,13,13,13, 13,13,13,13,13};

  assert(victim && ch);
  assert(level >= 3);

  dam = number(dam_each[level]>>1, dam_each[level]<<1);

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



void spell_burning_hands(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;
	int dam_each[] = 
		{0,  0,0,0,0,19, 17,20,19,19,19, 19,19,19,19,19, 19,19,19,19,19,
		     19,19,19,19,19, 19,19,19,19,19};


  assert(victim && ch);
  assert(level >= 5);

  dam = number(dam_each[level]>>1, dam_each[level]<<1);

  if ( saves_spell(victim, SAVING_SPELL) )
    dam >>= 1;

  damage(ch, victim, dam, SPELL_BURNING_HANDS);
}



void spell_shocking_grasp(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;
	int dam_each[] = 
		{0,  0,0,0,0,0, 0,41,33,29,27, 25,25,25,25,25, 25,25,25,25,25,
		     25,25,25,25,25, 25,25,25,25,25};

  assert(victim && ch);
  assert(level >= 7);

  dam = number(dam_each[level]>>1, dam_each[level]<<1);

  if ( saves_spell(victim, SAVING_SPELL) )
    dam >>= 1;

  damage(ch, victim, dam, SPELL_SHOCKING_GRASP);
}



void spell_lightning_bolt(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;
	int dam_each[] = 
		{0,  0,0,0,0,0, 0,0,0,59,46, 39,35,38,36,36, 36,36,36,36,36,
		     36,36,36,36,36, 36,36,36,36,36};

  assert(victim && ch);
  assert(level >= 9);

  dam = number(dam_each[level]>>1, dam_each[level]<<1);

  if ( saves_spell(victim, SAVING_SPELL) )
    dam >>= 1;

  damage(ch, victim, dam, SPELL_LIGHTNING_BOLT);
}



void spell_colour_spray(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;
	int dam_each[] = 
		{0,  0,0,0,0,0, 0,0,0,0,0, 79,60,57,51,47, 44,44,44,44,44,
		     44,44,44,44,44, 44,44,44,44,44};


	assert(victim && ch);
	assert(level >= 11);

  dam = number(dam_each[level]-20, dam_each[level]+20);

  if ( saves_spell(victim, SAVING_SPELL) )
    dam >>= 1;

  damage(ch, victim, dam, SPELL_COLOUR_SPRAY);
}


/* Drain XP, MANA, HP - caster gains HP and MANA */
void spell_energy_drain(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam, xp, mana;

  void set_title(struct char_data *ch);
	void gain_exp(struct char_data *ch, int gain);

  assert(victim && ch);
  assert(level >= 13);

  if ( !saves_spell(victim, SAVING_SPELL) ) {
		GET_ALIGNMENT(ch) = MIN(-1000, GET_ALIGNMENT(ch)-200);
    if (GET_LEVEL(victim) <= 2) {
      damage(ch, victim, 100, SPELL_ENERGY_DRAIN); /* Kill the sucker */
    } else {
		if(!IS_SET(world[ch->in_room].room_flags,ARENA)) {
			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;

      		send_to_char("Your life energy is drained!\n\r", victim);

		damage(ch, victim, dam, SPELL_ENERGY_DRAIN);
	  }
  } else {
    damage(ch, victim, 0, SPELL_ENERGY_DRAIN); /* Miss */
  }
}



void spell_fireball(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;

  assert(victim && ch);
  assert(level >= 15);

  dam = MIN(150,number(40+level,70+level*5));

  if (saves_spell(victim, SAVING_SPELL) )
    dam >>= 1;

  damage(ch, victim, dam, SPELL_FIREBALL);
}




void spell_earthquake(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;
  struct char_data *tmp_victim, *temp;

  assert(ch);
  assert(level >= 7);

	dam =  dice(1,8)+level;

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


  for(tmp_victim = character_list; tmp_victim; tmp_victim = temp)
  {
    temp = tmp_victim->next;
    if((ch->in_room == tmp_victim->in_room) && (ch != tmp_victim) && 
		!IS_TRUSTED(tmp_victim)) {
	damage(ch, tmp_victim, dam, SPELL_EARTHQUAKE);
    } else
      if (world[ch->in_room].zone == world[tmp_victim->in_room].zone)
        send_to_char("The earth trembles and shivers.", tmp_victim);
  }

}



void spell_dispel_evil(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;

	assert(ch && victim);
	assert(level >= 10);

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

	dam = dice(level,4);

	if(saves_spell(victim, SAVING_SPELL))
		dam >>= 1;

	damage(ch, victim, dam, SPELL_DISPEL_EVIL);
}



void spell_call_lightning(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;

  assert(victim && ch);
  assert(level >= 12);

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

  if (OUTSIDE(ch) && (zone_table[world[ch->in_room].zone].conditions.precip_rate > 5)) {

	  if ( saves_spell(victim, SAVING_SPELL) )
  	  dam >>= 1;
  
  	damage(ch, victim, dam, SPELL_CALL_LIGHTNING);
	}
}



void spell_harm(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;

	assert(victim && ch);
	assert(level >= 15);

/*	dam = GET_HIT(victim) - dice(1,4);   ***old version */

	/* put in a check for to_hit.. */
	if(to_hit_char(ch,victim)) {
		dam = 5*level;
		if(dam >= (GET_HIT(victim)-4))
			dam = GET_HIT(victim)-number(1,4);
	} else {
		/* This should really be done through the messages...
			but there's no entry for harm there... */
		act("$n tries to touch $N, but misses!",TRUE,ch,0,victim,TO_NOTVICT);
		act("$n tries to touch you, but misses!",TRUE,ch,0,victim,TO_VICT);
		act("You try to touch $N, but miss!",TRUE,ch,0,victim,TO_CHAR);
		return;
	}

	if (dam < 0)
		dam = 0; /* Kill the suffering bastard */
	else if ( saves_spell(victim, SAVING_SPELL) ) {
		dam = MIN(50, dam/2);
	}

	damage(ch, victim, dam, SPELL_HARM);
}



/* spells2.c - Not directly offensive spells */

void spell_armor(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim);
  assert(level >= 0);

	if (!affected_by_spell(victim, SPELL_ARMOR)) {
	  af.type      = SPELL_ARMOR;
  	af.duration  = 24;
	  af.modifier  = -20;
	  af.location  = APPLY_AC;
	  af.bitvector = 0;

	  affect_to_char(victim, &af);
		send_to_char("You feel someone protecting you.\n\r", victim);
	}
}



void spell_teleport(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	int to_room,low,high,i;
	extern int top_of_world;      /* ref to the top element of world */

	void teleport_to(struct char_data *ch,int to_room);

	if(!ch || !victim) {
		log("Bad call to spell_teleport");
		return;
	}

	if(world[ch->in_room].zone!=world[victim->in_room].zone) {
		send_to_char("Teleports must be with nearby people.",ch);
		return;
	}
	low=MAX(2,zone_table[world[ch->in_room].zone].real_bottom);
	high=zone_table[world[ch->in_room].zone].real_top;

	/* So people can't enter or leave arena by this spell */
	if(IS_SET(world[victim->in_room].room_flags,ARENA)) {
		do {
			to_room = number(low, high);
		} while(!can_enter_room(victim,to_room,FALSE) && --level &&
			IS_SET(world[to_room].room_flags,ARENA) &&
			IS_SET(world[to_room].room_flags,NO_TELEPORT));
	} else {
		do {
			to_room = number(low, high);
		} while(!can_enter_room(victim,to_room,FALSE) && --level &&
			!IS_SET(world[to_room].room_flags,ARENA) &&
			IS_SET(world[to_room].room_flags,NO_TELEPORT));
	}

	if(level)
		teleport_to(victim,to_room);
	else {
		act("$n blurs for a moment, but remains here.",FALSE,victim,0,0,TO_ROOM);
		send_to_char("You feel weird for a second, but it fades away.\n\r",victim);
	}
}

void teleport_to(struct char_data *ch,int to_room)
{
	act("$n slowly fades out of existence.", FALSE,ch,0,0,TO_ROOM);
	char_from_room(ch);
	char_to_room(ch, to_room,0);
	act("$n slowly fades into existence.", FALSE,ch,0,0,TO_ROOM);

	do_look(ch, "", 0);

	if (IS_SET(world[to_room].room_flags, DEATH) && !IS_TRUSTED(ch)) {
		death_cry(ch);
		extract_char(ch);
	}
}


void spell_bless(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(ch && (victim || obj));
  assert(level >= 0);

  if (obj) {
    if ( (5*GET_LEVEL(ch) > GET_OBJ_WEIGHT(obj)) &&
         (GET_POS(ch) != POSITION_FIGHTING) &&
         !IS_OBJ_STAT(obj, ITEM_EVIL)) {
	    SET_BIT(obj->obj_flags.extra_flags, ITEM_BLESS);
			act("$p briefly glows.",FALSE,ch,obj,0,TO_CHAR);
		}
	} else {

		if ((GET_POS(victim) != POSITION_FIGHTING) &&
		    (!affected_by_spell(victim, SPELL_BLESS))) {

			send_to_char("You feel righteous.\n\r", victim);
			af.type      = SPELL_BLESS;
  	  af.duration  = 6;
    	af.modifier  = 1;
	    af.location  = APPLY_HITROLL;
  	  af.bitvector = 0;
    	affect_to_char(victim, &af);

	    af.location = APPLY_SAVING_SPELL;
  	  af.modifier = -1;                 /* Make better */
    	affect_to_char(victim, &af);
		}
	}
}



void spell_blindness(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(ch && victim);
  assert(level >= 0);

  if(nokill(ch,victim)==TRUE){ return; }
  check_killer(ch,victim);

  if (saves_spell(victim, SAVING_SPELL) ||
	   affected_by_spell(victim, SPELL_BLINDNESS))
		return;

  act("$n seems to be blinded!", TRUE, victim, 0, 0, TO_ROOM);
  send_to_char("You have been blinded!\n\r", victim);

  af.type      = SPELL_BLINDNESS;
  af.location  = APPLY_HITROLL;
  af.modifier  = -4;  /* Make hitroll worse */
  af.duration  = 1;
  af.bitvector = AFF_BLIND;
  affect_to_char(victim, &af);


  af.location = APPLY_AC;
  af.modifier = +40; /* Make AC Worse! */
  affect_to_char(victim, &af);
}



void spell_clone(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{

  assert(ch && (victim || obj));
  assert(level >= 0);

	send_to_char("Clone is not ready yet.", ch);

  if (obj) {

	} else {
		/* clone_char(victim); */
	}
}



void spell_control_weather(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
   /* Control Weather is not possible here!!! */
   /* Better/Worse can not be transferred     */
}



void spell_create_food(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct obj_data *tmp_obj;

	assert(ch);
	assert(level >= 0);

	if(!(tmp_obj=read_object(900,VIRTUAL))) {
		send_to_char("Bug! Please report!",ch);
		return;
	}

	tmp_obj->obj_flags.value[0] = 5+level;

	obj_to_room(tmp_obj,ch->in_room);

	act("$p suddenly appears.",TRUE,ch,tmp_obj,0,TO_ROOM);
	act("$p suddenly appears.",TRUE,ch,tmp_obj,0,TO_CHAR);
}



void spell_create_water(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	int water;

	void name_to_drinkcon(struct obj_data *obj,int type);
	void name_from_drinkcon(struct obj_data *obj);

	assert(ch && obj);

	if (GET_ITEM_TYPE(obj) == ITEM_DRINKCON) {
		if ((obj->obj_flags.value[2] != LIQ_WATER)
		     && (obj->obj_flags.value[1] != 0)) {

			name_from_drinkcon(obj);
			obj->obj_flags.value[2] = LIQ_SLIME;
			name_to_drinkcon(obj, LIQ_SLIME);

		} else {

			water = 2*level * ((zone_table[world[ch->in_room].zone].conditions.precip_rate > 5) ? 2 : 1);

			/* Calculate water it can contain, or water created */
			water = MIN(obj->obj_flags.value[0]-obj->obj_flags.value[1], water);

			if (water > 0) {
			  obj->obj_flags.value[2] = LIQ_WATER;
				obj->obj_flags.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);
			}
		}
	}
}



void spell_cure_blind(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  assert(victim);
  assert(level >= 0);

	if (affected_by_spell(victim, SPELL_BLINDNESS)) {
	  affect_from_char(victim, SPELL_BLINDNESS);

	  send_to_char("Your vision returns!\n\r", victim);
	}
}



void spell_cure_critic(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int healpoints;

  assert(victim);
  assert(level >= 0);

  healpoints = dice(3,8)+3;

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

  send_to_char("You feel better!\n\r", victim);

  update_pos(victim);
}



void spell_cure_light(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int healpoints;

  assert(ch && victim);
  assert(level >= 0);

  healpoints = dice(1,8);

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

  update_pos( victim );

  send_to_char("You feel better!\n\r", victim);
}



void spell_curse(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim || obj);
  assert(level >= 0);

  if(nokill(ch,victim)==TRUE){ return; }
  if(victim)
	check_killer(ch,victim);
  if (obj) {
     SET_BIT(obj->obj_flags.extra_flags, ITEM_EVIL);
     SET_BIT(obj->obj_flags.extra_flags, ITEM_NODROP);

     /* LOWER ATTACK DICE BY -1 */
     if(obj->obj_flags.type_flag == ITEM_WEAPON)  {
         if (obj->obj_flags.value[2] > 1) {
            obj->obj_flags.value[2]--; 
            act("$p glows red.", FALSE, ch, obj, 0, TO_CHAR);
         } 
	 else {
	    send_to_char("Nothing happens.\n\r", ch);
	 }
      }
   } else {
      if ( saves_spell(victim, SAVING_SPELL) ||
		   affected_by_spell(victim, SPELL_CURSE))   return;

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

      af.location = APPLY_SAVING_PARA;
      af.modifier = 1; /* Make worse */
      affect_to_char(victim, &af);

      act("$n briefly reveal a red aura!", FALSE, victim, 0, 0, TO_ROOM);
  		act("You feel very uncomfortable.",FALSE,victim,0,0,TO_CHAR);
   }
}



void spell_detect_evil(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

	assert(victim);
	assert(level >= 0);

	if ( affected_by_spell(victim, SPELL_DETECT_EVIL) )
		return;

  af.type      = SPELL_DETECT_EVIL;
  af.duration  = level*5;
  af.modifier  = 0;
  af.location  = APPLY_NONE;
  af.bitvector = AFF_DETECT_EVIL;

  affect_to_char(victim, &af);

  send_to_char("Your eyes tingle.\n\r", victim);
}



void spell_detect_invisibility(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim);
  assert(level >= 0);

  if ( affected_by_spell(victim, SPELL_DETECT_INVISIBLE) )
		return;

  af.type      = SPELL_DETECT_INVISIBLE;
  af.duration  = level*5;
  af.modifier  = 0;
  af.location  = APPLY_NONE;
  af.bitvector = AFF_DETECT_INVISIBLE;

  affect_to_char(victim, &af);

  send_to_char("Your eyes tingle.\n\r", victim);
}



void spell_detect_magic(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim);
  assert(level >= 0);

  if ( affected_by_spell(victim, SPELL_DETECT_MAGIC) )
		return;

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

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



void spell_detect_poison(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	assert(ch && (victim || obj));

  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->obj_flags.type_flag == ITEM_DRINKCON) ||
        (obj->obj_flags.type_flag == ITEM_FOOD)) {
      if (obj->obj_flags.value[3])
        act("Poisonous fumes are revealed.",FALSE, ch, 0, 0, TO_CHAR);
      else
        send_to_char("It looks very delicious.\n\r", ch);
    }
  }
}



void spell_enchant_weapon(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	int i;

	assert(ch && obj);
	assert(MAX_OBJ_AFFECT >= 2);

	if ((GET_ITEM_TYPE(obj) == ITEM_WEAPON) &&
	   !IS_SET(obj->obj_flags.extra_flags, ITEM_MAGIC)) {

		for (i=0; i < MAX_OBJ_AFFECT; i++)
			if (obj->affected[i].location != APPLY_NONE)
				return;

		SET_BIT(obj->obj_flags.extra_flags, 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->obj_flags.extra_flags, ITEM_ANTI_EVIL);
			act("$p glows blue.",FALSE,ch,obj,0,TO_CHAR);
		} else if (IS_EVIL(ch)) {
      SET_BIT(obj->obj_flags.extra_flags, ITEM_ANTI_GOOD);
      act("$p glows red.",FALSE,ch,obj,0,TO_CHAR);
    } else {
      act("$p glows yellow.",FALSE,ch,obj,0,TO_CHAR);
		}
	}
}



void spell_heal(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	assert(victim);

	spell_cure_blind(level, ch, victim, obj);

	GET_HIT(victim) += 100;

	if (GET_HIT(victim) >= hit_limit(victim))
		GET_HIT(victim) = hit_limit(victim)-dice(1,4);

  update_pos( victim );

  send_to_char("A warm feeling fills your body.\n\r", victim);
}


void spell_invisibility(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

	assert((ch && obj) || victim);

  if (obj) {
    if ( !IS_SET(obj->obj_flags.extra_flags, ITEM_INVISIBLE) ) {
			act("$p turns invisible.",FALSE,ch,obj,0,TO_CHAR);
			act("$p turns invisible.",TRUE,ch,obj,0,TO_ROOM);
      SET_BIT(obj->obj_flags.extra_flags, ITEM_INVISIBLE);
		}
  } else {              /* Then it is a PC | NPC */
		if (!affected_by_spell(victim, SPELL_INVISIBLE)) {

		  act("$n slowly fade out of existence.", TRUE, victim,0,0,TO_ROOM);
  	  send_to_char("You vanish.\n\r", victim);

	    af.type      = SPELL_INVISIBLE;
    	af.duration  = 24;
    	af.modifier  = -40;
  	  af.location  = APPLY_AC;
	    af.bitvector = AFF_INVISIBLE;
  	  affect_to_char(victim, &af);
  	}
	}
}


void spell_locate_object(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	struct obj_data *i;
	char name[256];
	char buf[MAX_STRING_LENGTH];
	int j;

	assert(ch);

	strcpy(name, fname(obj->name));

	j=level>>1;

	for (i = object_list; i && (j>0); i = i->next)
		if (isname(name, i->name)) {
			if((!IS_TRUSTED(ch) && number(0,100)<level*4) ||
					!CAN_SEE_OBJ(ch,i))
				;
			else {
			  if(i->carried_by) {
				sprintf(buf,"%s carried by %s.\n\r",
				i->short_description,PERS(i->carried_by,ch));
				send_to_char(buf,ch);
			  } else if (i->in_obj) {
				sprintf(buf,"%s in %s.\n\r",
					i->short_description,
					i->in_obj->short_description);
				send_to_char(buf,ch);
			  } else if(i->equipped_by) {
				sprintf(buf,"%s equipped by %s.\n\r",
				i->short_description,PERS(i->equipped_by,ch));
				send_to_char(buf,ch);
			  } else {
				sprintf(buf,"%s in %s.\n\r",
					i->short_description,
					(i->in_room == NOWHERE ?
					"Uncertain." :
					world[i->in_room].name));
				send_to_char(buf,ch);
			  }
			  if(!IS_TRUSTED(ch))
				j--;
			}
		}

		if(j==0)
			send_to_char("You are very confused.\n\r",ch);
		if(j==level>>1)
			send_to_char("No such object.\n\r",ch);
}


void spell_poison(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim || obj);

  if (victim) {
    if(nokill(ch,victim)==TRUE){ return; }
    check_killer(ch,victim);
    if(!saves_spell(victim, SAVING_PARA))
    {
      af.type = SPELL_POISON;
      af.duration = level*2;
      af.modifier = -2;
      af.location = APPLY_STR;
      af.bitvector = AFF_POISON;

      affect_join(victim, &af, FALSE, FALSE);

      send_to_char("You feel very sick.\n\r", victim);
    }

  } else { /* Object poison */
    if ((obj->obj_flags.type_flag == ITEM_DRINKCON) ||
        (obj->obj_flags.type_flag == ITEM_FOOD)) {
      obj->obj_flags.value[3] = 1;
    }
  }
}


void spell_protection_from_evil(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim);

  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;
    affect_to_char(victim, &af);
		send_to_char("You have a righteous feeling!\n\r", victim);
	}
}


void spell_remove_curse(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	struct affected_type af;

	assert(ch && (victim || obj));

	if (obj) {

		if ( IS_SET(obj->obj_flags.extra_flags, ITEM_EVIL) ||
		     IS_SET(obj->obj_flags.extra_flags, ITEM_NODROP)) {
			act("$p briefly glows blue.", TRUE, ch, obj, 0, TO_CHAR);

			REMOVE_BIT(obj->obj_flags.extra_flags, ITEM_EVIL);
			REMOVE_BIT(obj->obj_flags.extra_flags, ITEM_NODROP);
		}
	} else {      /* Then it is a PC | NPC */
		if (affected_by_spell(victim, SPELL_CURSE) ) {
			act("$n briefly glows red, then blue.",FALSE,victim,0,0,TO_ROOM);
			act("You feel better.",FALSE,victim,0,0,TO_CHAR);
      affect_from_char(victim, SPELL_CURSE);
    }
	}
}


void spell_remove_poison(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{

  assert(ch && (victim || obj));

  if (victim) {
    if(affected_by_spell(victim,SPELL_POISON)) {
      affect_from_char(victim,SPELL_POISON);
      act("A warm feeling runs through your body.",FALSE,victim,0,0,TO_CHAR);
			act("$N looks better.",FALSE,ch,0,victim,TO_ROOM);
    }
	} else {
    if ((obj->obj_flags.type_flag == ITEM_DRINKCON) ||
        (obj->obj_flags.type_flag == ITEM_FOOD)) {
      obj->obj_flags.value[3] = 0;
			act("The $p steams briefly.",FALSE,ch,obj,0,TO_CHAR);
		}
	}
}



void spell_sanctuary(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  if (!affected_by_spell(victim, SPELL_SANCTUARY) &&
                      !(victim->specials.affected_by & AFF_SANCTUARY) ) {

    act("$n is surrounded by a white aura.",TRUE,victim,0,0,TO_ROOM);
		act("You start glowing.",TRUE,victim,0,0,TO_CHAR);

    af.type      = SPELL_SANCTUARY;
    af.duration  = (!IS_TRUSTED(ch)) ? 3 : level;
    af.modifier  = 0;
		af.location  = APPLY_NONE;
		af.bitvector = AFF_SANCTUARY;
    affect_to_char(victim, &af);
  }
}



void spell_sleep(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;
  char buf[80];

  assert(victim);

  /* You can't sleep someone higher level than you except in the arena*/

  if ((GET_LEVEL(ch)<GET_LEVEL(victim))&&
     !IS_SET(world[ch->in_room].room_flags,ARENA)){
	sprintf(buf,"%s laughs in your face at your feeble attempt.\n\r",
		GET_NAME(victim));
	send_to_char(buf,ch);
	sprintf(buf,"%s tries to sleep you, but fails horribly.\n\r",
		GET_NAME(ch));
	send_to_char(buf,ch);
	return;
  }

  if ( !saves_spell(victim, SAVING_SPELL) )
  {
    af.type      = SPELL_SLEEP;
    af.duration  = 4+level;
    af.modifier  = 0;
    af.location  = APPLY_NONE;
    af.bitvector = AFF_SLEEP;
    affect_join(victim, &af, FALSE, FALSE);

    if (GET_POS(victim)>POSITION_SLEEPING)
    {
      act("You feel very sleepy... Zzzzzz",FALSE,victim,0,0,TO_CHAR);
      act("$n go to sleep.",TRUE,victim,0,0,TO_ROOM);
	    GET_POS(victim)=POSITION_SLEEPING;
    }

    return;
  }
}



void spell_strength(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim);

  act("You feel stronger.", FALSE, victim,0,0,TO_CHAR);

  af.type      = SPELL_STRENGTH;
  af.duration  = level;
  af.modifier  = 1+(level>18);

  af.location  = APPLY_STR;
  af.bitvector = 0;

  affect_join(victim, &af, TRUE, FALSE);
}



void spell_ventriloquate(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	/* Not possible!! No argument! */
}

void spell_word_of_recall(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  extern int top_of_world;
  int loc_nr,location;
  bool found = FALSE;

  assert(victim);

  if (IS_NPC(victim))
    return;

  loc_nr = default_loc(GET_HOME(victim));

  if (loc_nr==-1 || (location=real_room(loc_nr))==NOWHERE) {
	send_to_char("You are lost!\n\r",ch);
	log("RECALL: character's dest location not found.");
	return;
  }
  if(IS_SET(world[ch->in_room].room_flags,ARENA)) {
        act("$n is wrenched by a spell, but it fizzles out before completion.",
		FALSE,ch,0,0,TO_ROOM);
	act("You are tossed around by some force, which quickly dissipates.",
		FALSE,ch,0,0,TO_CHAR);
        return;
  }
	/* a location has been found. */
  if(victim->specials.fighting) {
	lose_exp_by_flight(victim,victim->specials.fighting);
	stop_fighting(victim);
  }

  act("$n disappears.", TRUE, victim, 0, 0, TO_ROOM);
  char_from_room(victim);
  char_to_room(victim, location,0);
  act("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
  do_look(victim, "",15);
}


void spell_summon(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	sh_int target;

	assert(ch && victim);
	if (IS_SET(victim->specials.act, PLR_NOSUMMON) && level < LV_DEMIGOD) {
	     send_to_char("You failed.\n\r",ch);
	     return;
	}
   

	if ((IS_SET(world[victim->in_room].room_flags, SAFE) ||
	     IS_SET(world[victim->in_room].room_flags, ARENA))&&
	     !IS_TRUSTED(ch)){
		send_to_char("That person is in a safe area!\n\r",ch);
		return;
	}
	if(IS_NPC(victim)&& !IS_TRUSTED(ch) &&
	   IS_SET(world[ch->in_room].room_flags, SAFE)) {
		send_to_char("You can't summon creatures to a safe area!\n\r",ch);
		return;
	}
	if(!IS_TRUSTED(ch) && IS_NPC(victim) && IS_SET(victim->specials.act,ACT_AGGRESSIVE)) {
		send_to_char("You feel a sudden surge of hatred and halt the spell.\n\r",ch);
		return;
	}
	if(!IS_NPC(victim) && IS_SET(world[ch->in_room].room_flags,ARENA)) {
		send_to_char("You can't bring in help in the arena.\n\r",ch);
		return;
	}
	if(!can_enter_room(victim,ch->in_room,FALSE)) {
		send_to_char("That person can't come here.\n\r",ch);
		return;
	}
	if(IS_SET(world[ch->in_room].room_flags, ARENA)) {
		send_to_char("The Arena Gods forbid outside help!\n\r",ch);
		return;
	}
	if (GET_LEVEL(victim) > level+3 ||
			(IS_TRUSTED(victim) && !IS_TRUSTED(ch))) {
		send_to_char("You failed.\n\r",ch);
		return;
	}

	if (IS_NPC(victim) && saves_spell(victim, SAVING_SPELL) ) {
		send_to_char("You failed.\n\r", ch);
		return;
	}

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

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

	act("$n arrives suddenly.",TRUE,victim,0,0,TO_ROOM);
	act("$n has summoned you!",FALSE,ch,0,victim,TO_VICT);
	do_look(victim,"",15);
	if(!IS_NPC(victim))
		SET_BIT(victim->specials.act,PLR_NOSUMMON);
}


void spell_charm_person(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  void add_follower(struct char_data *ch, struct char_data *leader);
  bool circle_follow(struct char_data *ch, struct char_data *victim);
  void stop_follower(struct char_data *ch);

  assert(ch && victim);

  if (!IS_NPC(victim) && (GET_LEVEL(ch) < LV_DEMIGOD)) {
       send_to_char("Do to abuse, players can no longer be charmed.\n\r", ch);
       return;
  }

  /* By testing for IS_AFFECTED we avoid ei. Mordenkainens sword to be */
  /* abel to be "recharmed" with duration                              */

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

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

		if (saves_spell(victim, SAVING_PARA))
			return;

    if(IS_NPC(victim) && IS_SET(victim->specials.act,ACT_BREAK_CHARM)) {
	return;
    }
    if (victim->master)
      stop_follower(victim);

    add_follower(victim, ch);

    af.type      = SPELL_CHARM_PERSON;

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

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

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



void spell_sense_life(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim);

  if (!affected_by_spell(victim, SPELL_SENSE_LIFE)) {
    send_to_char("Your feel your awareness improve.\n\r", ch);

    af.type      = SPELL_SENSE_LIFE;
    af.duration  = 5*level;
    af.modifier  = 0;
    af.location  = APPLY_NONE;
    af.bitvector = AFF_SENSE_LIFE;
    affect_to_char(victim, &af);
  }
}


/* ***************************************************************************
 *                     Not cast-able spells                                  *
 * ************************************************************************* */

void spell_identify(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  char buf[256], buf2[256];
	int i;
  bool found;

	struct time_info_data age(struct char_data *ch);

  /* Spell Names */
	extern char *spells[];

	/* For Objects */
	extern char *item_types[];
	extern char *extra_bits[];
	extern char *apply_types[];
	extern char *affected_bits[];


  assert(ch && (obj || victim));

  if (obj) {
		send_to_char("You feel informed:\n\r", ch);

		sprintf(buf, "Object '%s', Item type: ", obj->name);
		sprinttype(GET_ITEM_TYPE(obj),item_types,buf2);
		strcat(buf,buf2); strcat(buf,"\n\r");
		send_to_char(buf, ch);

		if (obj->obj_flags.bitvector) {
			send_to_char("Item will give you following abilities:  ", ch);
			sprintbit(obj->obj_flags.bitvector,affected_bits,buf);
			strcat(buf,"\n\r");
			send_to_char(buf, ch);
		}

		send_to_char("Item is: ", ch);
		sprintbit(obj->obj_flags.extra_flags,extra_bits,buf);
		strcat(buf,"\n\r");
		send_to_char(buf,ch);

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

    switch (GET_ITEM_TYPE(obj)) {

			case ITEM_SCROLL : 
			case ITEM_POTION :
				sprintf(buf, "Level %d spells of:\n\r",	obj->obj_flags.value[0]);
				send_to_char(buf, ch);
				if (obj->obj_flags.value[1] >= 1) {
					sprinttype(obj->obj_flags.value[1]-1,spells,buf);
					strcat(buf,"\n\r");
					send_to_char(buf, ch);
				}
				if (obj->obj_flags.value[2] >= 1) {
					sprinttype(obj->obj_flags.value[2]-1,spells,buf);
					strcat(buf,"\n\r");
					send_to_char(buf, ch);
				}
				if (obj->obj_flags.value[3] >= 1) {
					sprinttype(obj->obj_flags.value[3]-1,spells,buf);
					strcat(buf,"\n\r");
					send_to_char(buf, ch);
				}
				break;

			case ITEM_WAND : 
			case ITEM_STAFF : 
				sprintf(buf, "Has %d charges, with %d charges left.\n\r",
				  obj->obj_flags.value[1],
				  obj->obj_flags.value[2]);
				send_to_char(buf, ch);

				sprintf(buf, "Level %d spell of:\n\r",	obj->obj_flags.value[0]);
				send_to_char(buf, ch);

				if (obj->obj_flags.value[3] >= 1) {
					sprinttype(obj->obj_flags.value[3]-1,spells,buf);
					strcat(buf,"\n\r");
					send_to_char(buf, ch);
				}
				break;

			case ITEM_WEAPON :
				sprintf(buf, "Damage Dice is '%dD%d'\n\r",
					obj->obj_flags.value[1],
	   			obj->obj_flags.value[2]);
				send_to_char(buf, ch);
				break;

			case ITEM_ARMOR :
				sprintf(buf, "AC-apply is %d\n\r",
					obj->obj_flags.value[0]);
				send_to_char(buf, ch);
				break;

    }

		found = FALSE;

		for (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);
				send_to_char(buf, ch);
			}
		}

  } else {       /* victim */

		if (!IS_NPC(victim)) {
			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);
			send_to_char(buf,ch);

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

/*
			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) );
			send_to_char(buf,ch);
*/

    } else {
      send_to_char("You learn nothing new.\n\r", ch);
    }
  }

}


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

void spell_fire_breath(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	int dam;
	int hpch;
	struct obj_data *burn;

	assert(victim && ch);
	assert(level >= 1);

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

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

	if ( saves_spell(victim, SAVING_BREATH) )
		dam >>= 1;

	damage(ch, victim, dam, SPELL_FIRE_BREATH);

	/* And now for the damage on inventory */

	if(number(0,30)<GET_LEVEL(ch))
	{
		if (!saves_spell(victim, SAVING_BREATH) )
		{
			for(burn=victim->carrying ; 
				burn && (burn->obj_flags.type_flag!=ITEM_SCROLL) && 
				(burn->obj_flags.type_flag!=ITEM_WAND) &&
				(burn->obj_flags.type_flag!=ITEM_STAFF) &&
				(burn->obj_flags.type_flag!=ITEM_NOTE) &&
            (number(0,2)==0) ;
				 burn=burn->next_content);
			if(burn)
			{
				act("$o burns",0,victim,burn,0,TO_CHAR);
				extract_obj(burn);
			}
		}
	}
}


void spell_frost_breath(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	int dam;
	int hpch;
	struct obj_data *frozen;

	assert(victim && ch);
	assert(level >= 1);

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

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

	if ( saves_spell(victim, SAVING_BREATH) )
		dam >>= 1;

	damage(ch, victim, dam, SPELL_FROST_BREATH);

	/* And now for the damage on inventory */

	if(number(0,30)<GET_LEVEL(ch))
	{
		if (!saves_spell(victim, SAVING_BREATH) )
		{
			for(frozen=victim->carrying ; 
				frozen &&
				(frozen->obj_flags.type_flag!=ITEM_DRINKCON) && 
				(frozen->obj_flags.type_flag!=ITEM_FOOD) &&
				(frozen->obj_flags.type_flag!=ITEM_POTION) &&
				(number(0,2)==0) ;
				 frozen=frozen->next_content); 
			if(frozen)
			{
				act("$o breaks.",0,victim,frozen,0,TO_CHAR);
				extract_obj(frozen);
			}
		}
	}
}


void spell_acid_breath(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	int dam;
	int hpch;
	int damaged;

	int apply_ac(struct char_data *ch, int eq_pos);
	
	assert(victim && ch);
	assert(level >= 1);

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

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

	if ( saves_spell(victim, SAVING_BREATH) )
		dam >>= 1;

	damage(ch, victim, dam, SPELL_ACID_BREATH);

	/* And now for the damage on equipment */

	if(number(0,30)<GET_LEVEL(ch))
	{
		if (!saves_spell(victim, SAVING_BREATH) )
		{
			for(damaged = 0; damaged<MAX_WEAR &&
				(victim->equipment[damaged]) &&
				(victim->equipment[damaged]->obj_flags.type_flag!=ITEM_ARMOR) &&
				(victim->equipment[damaged]->obj_flags.value[0]>0) && 
				(number(0,2)==0) ; damaged++);
			if(victim->equipment[damaged] && damaged<MAX_WEAR)
			{
				act("$o is damaged.",0,victim,victim->equipment[damaged],0,TO_CHAR);
				GET_AC(victim)-=apply_ac(victim,damaged);
				victim->equipment[damaged]->obj_flags.value[0]-=number(1,7);
				GET_AC(victim)+=apply_ac(victim,damaged);
				victim->equipment[damaged]->obj_flags.cost = 0;
			}
		}
	}
}


void spell_gas_breath(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	int dam;
	int hpch;

	assert(victim && ch);
	assert(level >= 1);

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

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

	if ( saves_spell(victim, SAVING_BREATH) )
		dam >>= 1;

	damage(ch, victim, dam, SPELL_GAS_BREATH);


}


void spell_lightning_breath(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
	int dam;
	int hpch;

	assert(victim && ch);
	assert(level >= 1);

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

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

	if ( saves_spell(victim, SAVING_BREATH) )
		dam >>= 1;

	damage(ch, victim, dam, SPELL_LIGHTNING_BREATH);


}

void spell_levitate(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim);
  assert(level >= 0);

  af.type      = SPELL_LEVITATE;
  af.duration  = 2*GET_LEVEL(ch);
  af.modifier  = 0;
  af.location  = APPLY_NONE;
  af.bitvector = AFF_LEVITATE;

  if(GET_POS(victim)<POSITION_LEVITATED) {
	act("You float up in the air!",FALSE,victim,0,0,TO_CHAR);
	act("$n floats up in the air!",TRUE,victim,0,0,TO_ROOM);
	GET_POS(victim)=POSITION_LEVITATED;
  }

  affect_join(victim, &af, FALSE, FALSE);
}

void spell_fly(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert(victim);
  assert(level >= 0);

  af.type      = SPELL_FLY;
  af.duration  = 2*GET_LEVEL(ch);
  af.modifier  = 0;
  af.location  = APPLY_NONE;
  af.bitvector = AFF_FLY;

  if(GET_POS(victim)<POSITION_FLYING) {
	act("You fly through the air, free as a bird!",
		FALSE,victim,0,0,TO_CHAR);
	act("$n flies through the air, free as a bird!",TRUE,
		victim,0,0,TO_ROOM);
	GET_POS(victim)=POSITION_FLYING;
  }

  affect_join(victim, &af, FALSE, FALSE);
}
/* A routine for ITEM_TELEPORT objects */

bool check_item_teleport(struct char_data *ch,char *arg,int cmd)
{
	struct obj_data *obj=NULL;
	struct char_data *dummy;
	int bits;

	bits=generic_find(arg,FIND_OBJ_INV|FIND_OBJ_EQUIP|FIND_OBJ_ROOM,ch,&dummy,&obj);
	if(!obj)
		return FALSE;

	if(obj->obj_flags.type_flag!= ITEM_TELEPORT || 
				obj->obj_flags.value[1]!=cmd)
		return FALSE;

	if(IS_SET(world[ch->in_room].room_flags,NO_MAGIC)) {
		send_to_char("That doesn't seem to do anything!\n\r",ch);
		return FALSE;
	}

	/* Ignore argument for now...eventually we could "throw dust Dbra"..*/
	if(!obj->obj_flags.value[2] || (IS_SET(world[ch->in_room].room_flags,ARENA)!=IS_SET(world[real_room(obj->obj_flags.value[0])].room_flags,ARENA))) {
		send_to_char("Nothing happens.\n\r\n\r",ch);
		return;
	}
	act("$p in $n's hands suddenly glows brightly!",FALSE,ch,obj,0,TO_ROOM);
	act("$p in your hands suddenly glows brightly!",FALSE,ch,obj,0,TO_CHAR);
	teleport_to(ch,real_room(obj->obj_flags.value[0]));
	if(obj->obj_flags.value[2]>0) {
		if(!--obj->obj_flags.value[2]) {
			act("$p in $n's hands shatters and the pieces disappear in smoke.",TRUE,ch,obj,0,TO_ROOM);
			act("$p in your hands shatters and the pieces disappear in smoke.",TRUE,ch,obj,0,TO_CHAR);
			extract_obj(obj);
		}
	}
}


void spell_quickness(byte level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

        assert(victim);

  act("You feel nimbler.", FALSE, victim,0,0,TO_CHAR);

  af.type      = SPELL_QUICKNESS;
  af.duration  = level;
  af.modifier  = 1;

  af.location  = APPLY_DEX;
  af.bitvector = 0;

  affect_join(victim, &af, TRUE, FALSE);
}