/* ************************************************************************
*  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 "os.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "db.h"
#include "spells.h"
#include "handler.h"
#include "limits.h"
#include "interpreter.h"
#include "prototypes.h"

/* Extern structures */
extern struct room_data *world;
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 *str_dup (char *source);
int dice (int number, int size);


/* Offensive Spells */

void spell_magic_missile (int 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) && (level <= 30));

  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 (int 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) && (level <= 30));

  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 (int 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) && (level <= 30));

  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 (int 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) && (level <= 30));

  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 (int 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) && (level <= 30));

  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 (int 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) && (level <= 30));

  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 (int 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) && (level <= 30));

  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 {
      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 (int 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, 0, 0, 0, 0, 143, 105, 88, 77, 71, 71,
    71, 71, 71, 71, 71, 71, 71, 71, 71, 71
  };

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

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

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

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




void spell_earthquake (int 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) && (level <= 30));

  dam = dice (1, 8) + level;

  send_to_char ("The earth trembles beneath your feet!\n\r", ch);
  act
    ("$n makes the earth trembles and shivers\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)) {
      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\n\r", tmp_victim);
  }

}



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

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

  if (IS_EVIL (ch))
    victim = ch;
  else if (IS_GOOD (victim)) {
    act ("God protects $N.", FALSE, ch, 0, victim, TO_CHAR);
    return;
  }

  if ((GET_LEVEL (victim) < level) || (victim == ch))
    dam = 100;
  else {
    dam = dice (level, 4);

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

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



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

  extern struct weather_data weather_info;

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

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

  if (OUTSIDE (ch) && (weather_info.sky >= SKY_RAINING)) {

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

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



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

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

  dam = GET_HIT (victim) - dice (1, 4);

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert (victim);
  assert ((level >= 0) && (level <= 30));

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int to_room;
  extern int top_of_world;      /* ref to the top element of world */

  assert (ch);

  do {
    to_room = number (0, top_of_world);
  } while (IS_SET (world[to_room].room_flags, PRIVATE));

  act ("$n slowly fade out of existence.", FALSE, ch, 0, 0, TO_ROOM);
  char_from_room (ch);
  char_to_room (ch, to_room);
  act ("$n slowly fade in to existence.", FALSE, ch, 0, 0, TO_ROOM);

  do_look (ch, "", 0);

  if (IS_SET (world[to_room].room_flags, DEATH) && GET_LEVEL (ch) < 21) {
    death_cry (ch);
    extract_char (ch);
  }
}



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

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

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

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


  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{

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

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

  if (obj) {

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



void spell_control_weather (int 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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct obj_data *tmp_obj;

  assert (ch);
  assert ((level >= 0) && (level <= 30));

  CREATE (tmp_obj, struct obj_data, 1);
  clear_object (tmp_obj);

  tmp_obj->name = str_dup ("mushroom");
  tmp_obj->short_description = str_dup ("A Magic Mushroom");
  tmp_obj->description =
    str_dup ("A really delicious looking magic mushroom lies here.");

  tmp_obj->obj_flags.type_flag = ITEM_FOOD;
  tmp_obj->obj_flags.wear_flags = ITEM_TAKE | ITEM_HOLD;
  tmp_obj->obj_flags.value[0] = 5 + level;
  tmp_obj->obj_flags.weight = 1;
  tmp_obj->obj_flags.cost = 10;
  tmp_obj->obj_flags.cost_per_day = 1;

  tmp_obj->next = object_list;
  object_list = tmp_obj;

  obj_to_room (tmp_obj, ch->in_room);

  tmp_obj->item_number = -1;

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int water;

  extern struct weather_data weather_info;
  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 * ((weather_info.sky >= SKY_RAINING) ? 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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  assert (victim);
  assert ((level >= 0) && (level <= 30));

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int healpoints;

  assert (victim);
  assert ((level >= 0) && (level <= 30));

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int healpoints;

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

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

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

  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)
      obj->obj_flags.value[2]--;
    act ("$p glows red.", FALSE, ch, obj, 0, TO_CHAR);
  } 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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert (victim);
  assert ((level >= 0) && (level <= 30));

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert (victim);
  assert ((level >= 0) && (level <= 30));

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert (victim);
  assert ((level >= 0) && (level <= 30));

  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 (int 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 (int 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 (int 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 (int 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 (int 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 (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 {
        sprintf (buf, "%s in %s.\n\r", i->short_description,
          (i->in_room ==
            NOWHERE ? "use, but uncertain." : world[i->in_room].name));
        send_to_char (buf, 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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  assert (victim || obj);

  if (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 (int 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 (int 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 (int 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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  struct affected_type af;

  if (!affected_by_spell (victim, SPELL_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 = (level < 21) ? 3 : level;
    af.modifier = 0;
    af.location = APPLY_NONE;
    af.bitvector = AFF_SANCTUARY;
    affect_to_char (victim, &af);
  }
}



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

  assert (victim);

  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 (int 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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  /* Not possible!! No argument! */
}



void spell_word_of_recall (int 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 = GET_HOME(ch); */

  loc_nr = 3001;
  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;
  }

  /* a location has been found. */

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

}


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

  assert (ch && victim);

  if (GET_LEVEL (victim) > MIN (20, level + 3)) {
    send_to_char ("You failed.\n\r", ch);
    return;
  }

  if ((IS_NPC (victim) && saves_spell (victim, SAVING_SPELL)) ||
    IS_SET (world[victim->in_room].room_flags, PRIVATE)) {
    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);

  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);
}


void spell_charm_person (int 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);

  /* 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 (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 (int 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 (int 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 chages, 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 (int 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) && (level <= 30));

  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 (int 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) && (level <= 30));

  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 (int 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) && (level <= 30));

  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 (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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;
  int hpch;

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

  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 (int level, struct char_data *ch,
  struct char_data *victim, struct obj_data *obj)
{
  int dam;
  int hpch;

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

  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);


}