/*
 *      The spells of the mage guild.
 *      What more can be said?
 *
 *      (C) 1991, 1992 Auronthas
 */

#include "/std/include/std.h"
#include "defines.h"
#include "spells.h"

#define DESTINATION "players/auronthas/workroom"

#define QAL query_alignment()
#define QINT query_int()
#define SPELLHOME "players/auronthas/spells/"
#define HOME "players/auronthas/"
#define SET_CASTER set_caster_name(environment()->query_name())
#define MR(o) (random(100)<o->query_skill("magic_resistance"))
#define CAP(c) capitalize(c)
#define REDUCE "drain"
#define MORE_EVIL(n) this_player()->set_al(this_player()->query_al()-n)
#define SET_DUR(s) set_duration(query_spell_duration(recognize_spell(s))*TP->QL)
#define CHECK_FOR_RESISTANCE(o) if(o->query_skill("magic_resistance")>random(100)){write("Your magic fails.\n");return;}
#define ILLEGAL_INDEX(n) (n < 0 || n >= sizeof(spell_info))
#define in_room(o) present(o,environment(this_player()))
#define on_player(o) present(o,this_player())


int     t, n, ran;
int     spinc, max_spells;
string  temp1, temp2;
object  all, ting, target, next;
object  dispel_ob;
string  damage_type;
string  whoname,temp1,temp2,d1;
string  drain_mess1, drain_mess2, drain_mess3;
mixed *spell_info;


id(STRING str) {
    if(TP->QL < 20) return 0;
    return str == "spells" || str == "master spell object" ||
           str == "master";
}

STRING
short() {
    return "master spell object";
}


VOID
reset(INT arg)
{
  if(arg) return;
  spell_info = ({
/*     SPELL NAME               ABBREV.        DUR.    COST    SCHOOL  LEVEL */
/*     -----------------------  -------------  ------  ------  ------  ----- */
    ({ "Detect Magic",		"detectmagic", 	0,	2,	DIVI,	1 }),
    ({ "Find Familiar", 	"familiar", 	0,	10,	SUMM,	1 }),
    ({ "Identify",		"identify", 	0,	5,	DIVI,	1 }),
    ({ "Shield I",		"shield1",	10,	5,	PROT,	1 }),
    ({ "Ventriliquism",		"ventr",	0,	3,	ILLU,	1 }),
    ({ "Aural Illusion",	"auril",	0,	6,	ILLU,	2 }),
    ({ "Bladerune I",		"bladerune",	5,	8,	ENCH,	2 }),
    ({ "Detect Evil",		"detectevil",	0,	2,	DIVI,	2 }),
    ({ "Detect Good",		"detectgood",	0,	2,	DIVI,	2 }),
    ({ "Light",			"light",	20,	5,	ELEM,	2 }),
    ({ "Armour I",		"armor",	10,	7,	PROT,	3 }),
    ({ "Chill Touch",		"chill",	10,	10,	NECR,	3 }),
    ({ "Darkfire Bolt I",	"darkfire",	0,	8,	DARK,	3 }),
    ({ "Fireblade I",		"fireblade",	10,	10,	ELEM,	3 }),
    ({ "Cure Wounds I ",	"cure",		0,	5,	HEAL,	3 }),
    ({ "Know Alignment",	"knowalign",	0,	5,	DIVI,	4 }),
    ({ "See Invisible",		"seeinvis",	0,	12,	DIVI,	4 }),
    ({ "Analyze",		"analyze",	0,	6,	DIVI,	5 }),
    ({ "Scare",			"scare",	0,	15,	ENCH,	5 }),
    ({ "Shield II",		"shield2",	15,	10,	PROT,	5 }),
    ({ "Summon Insects",	"insects",	5,	10,	SUMM,	5 }),
    ({ "Bladerune II",		"bladerune2",	10,	15,	ENCH,	6 }),
    ({ "Blur",			"blur",		10,	10,	ILLU,	6 }),
    ({ "Clairvoyance",		"clairvoyance",	10,	15,	DIVI,	6 }),
    ({ "Consume Corpse",	"consume",	0,	10,	NECR,	6 }),
    ({ "Water Bolt",		"waterbolt",	0,	7,	ELEM,	6 }),
    ({ "Armour II",		"armour2",	15,	14,	PROT,	7 }),
    ({ "Fireblade II",		"fireblade2",	15,	15,	ELEM,	7 }),
    ({ "Heal II",		"heal2",	0,	10,	HEAL,	7 }),
    ({ "Remove Curse",		"removecurse",	0,	20,	ENCH,	7 }),
    ({ "Call Power I",		"callpower",	0,	10,	SUMM,	8 }),
    ({ "Darkness",		"darkness",	20,	15,	DARK,	8 }),
    ({ "Darkfire Bolt II",	"darkfire2",	0,	16,	DARK,	8 }),
    ({ "Ice Bolt",		"icebolt",	0,	10,	ELEM,	8 }),
    ({ "Locate",		"locate",	0,	10,	DIVI,	8 }),
    ({ "Neutralize Poison",	"neutralize",	0,	15,	HEAL,	8 }),
    ({ "Levitate",		"levitate",	15,	15,	ENCH,	9 }),
    ({ "Rope Trick",		"rope",		20,	20,	ENCH,	9 }),
    ({ "Vampiric Touch",	"touch",	0,	15,	NECR,	9 }),
    ({ "Fire Bolt",		"firebolt",	0,	13,	ELEM,	10 }),
    ({ "Instability",		"instability",	0,	20,	SUMM,	10 }),
    ({ "Invisibility",		"invis",	30,	25,	ENCH,	10 }),
    ({ "Shield III",		"shield3",	20,	15,	PROT,	10 }),
    ({ "Bladerune III",		"bladerune3",	15,	20,	ENCH,	11 }),
    ({ "Charm",			"charm",	0,	15,	ENCH,	11 }),
    ({ "Dispel Magic",		"dispel",	0,	20,	ENCH,	11 }),
    ({ "Illusion",		"illusion",	0,	10,	ILLU,	11 }),
    ({ "Animate Dead",		"animate",	30,	35,	NECR,	12 }),
    ({ "Armour III",		"armour3",	20,	21,	PROT,	12 }),
    ({ "Fireblade III",		"fireblade3",	20,	20,	ELEM,	12 }),
    ({ "Cure Wounds III",	"cure3",	0,	15,	HEAL,	12 }),
    ({ "Call Power II",		"callpower2",	0,	20,	SUMM,	13 }),
    ({ "Darkfire Bolt III",	"darkfire3",	0,	24,	DARK,	13 }),
    ({ "Lightning Bolt",	"lightning",	0,	16,	ELEM,	13 }),
    ({ "Regeneration",		"regen",	15,	25,	HEAL,	13 }),
    ({ "Read Mind",		"readmind",	0,	15,	DIVI,	14 }),
    ({ "Summon Spirit",		"spirit",	20,	30,	SUMM,	14 }),
    ({ "Shadow Warrior",	"warrior",	20,	20,	ILLU,	14 }),
    ({ "Spell Wall",		"spellwall",	10,	10,	PROT,	14 }),
    ({ "Harm",			"Harm",		0,	20,	DARK,	15 }),
    ({ "Summonc Demon",		"summondemon",	20,	60,	DARK,	15 }),
    ({ "Bladerune IV",		"rune4",	20,	25,	ENCH,	16 }),
    ({ "Fireblade IV",		"fireblade4",	20,	20,	ELEM,	16 }),
    ({ "Shield IV",		"shield4",	25,	20,	PROT,	16 }),
    ({ "Armour IV",		"armour4",	25,	28,	PROT,	17 }),
    ({ "Heal IV",		"cure4",	0,	20,	HEAL,	17 }),
    ({ "Shadow Monster",	"monster",	20,	30,	ILLU,	17 }),
    ({ "Darkfire Bolt IV",	"darkfire4",	0,	32,	DARK,	18 }),
    ({ "Dimension Door",	"dimdoor",	0,	50,	ENCH,	18 }),
    ({ "Unlife",		"unlife",	0,	50,	NECR,	18 }),
    ({ "Call Total Power",	"totalpower",	0,	40,	SUMM,	19 }),
/*    ({ "Disintegrate",		"disintegrate",	0,	30,	DARK,	19 }),*/
    ({ "Meteor Swarm",		"meteor",	0,	50,	ELEM,	19 }),
  });
  DESTINATION->load_me();
  move_object(THO, DESTINATION);
}

 
/* in_room(str) checks if an object with the id str is in the room */

#if 0  /* Using macros for these */
OBJECT
in_room(STRING str)
{
  return present(str,EN(TP));
}

OBJECT
on_player(STRING str)
{
  return present(str,TP);
}
#endif

OBJECT
is_here(str)
{
  if(IN_ROOM(str)) return IN_ROOM(str);
  return ON_PLAYER(str);
}

/* General attack spell, 17/07-91
 *
 * Argument descriptions:
 *
 * string mess1: Replaces # with name of the target (sent to caster)
 * string mess2: Replaces # with name of the caster (sent to target)
 * string mess3: Replaces # with name of the caster and & with name of the
 *   target (sent to everyone else in the room)
 * string name: Name of target. 0 is returned if that being is not present in
 *   the room.
 * int damage: The actual amount of damage done. (Armour helps)
 * string type: The type of damage done. Types: heat,cold,impact,electricity,
 *              
 *   not hit_player.
 * Returns 1 if the spell works, 0 otherwise.
 */

INT
attack_spell(name,mess1,mess2,mess3,damage,type) {
  
  object who, splw, skill;
  string s1,s2,s3,d2;
  int dam, i, j;

  if (EN(TP)->query_property("no_fight")) 
    {
      write("You can not fight here.\n");
      return 0;
    }
  if (EN(TP)->query_property("no_mattack"))
    {
      write("You are unable to use aggressive magic here.\n");
      return;
    }
  if (!name) who=TP->query_attack();
  else who=IN_ROOM(name);
  if (!who) 
    {
      write("At whom?\n");
      return 0;
    }
  if(!living(who)) 
    {
      write("Not a living thing!\n");
      return 0;
    }
  if(who == TP) 
    {
      write("What? Yourself?\n");
      say(TP->QN+" was about to attack "+TP->QOBJ+
	  "self, but changed "+TP->QPOS+" mind.\n");
      return 0;
    }
  skill = present("spell_skill",TP);
  if(!skill)
    {
      write("Your magic seriously fails you!\n");
      say(TP->QN+" fails terribly!\n");
      return 0;
    }
  damage_type = type;
  whoname = who->query_name();
/*  while(sscanf(mess1, "%s#%s", d1, d2))
    mess1 = d1 + whoname + d2;
  while(sscanf(mess2, "%s#%s", d1, d2))
    mess2 = d1 + TP->QN + d2;
  while(sscanf(mess3, "%s#%s", d1, d2))
    mess3 = d1 + TP->QN + d2;
  while(sscanf(mess3, "%s&%s", d1, d2))
    mess3 = d1 + whoname + d2;
  skill->set_messages(mess1,mess2,mess3);*/

  skill->set_damage_type(type);
  skill->set_spell_damage(damage);
  if(!TP->query_attack())
    {
      if(type=="fire" || type=="heat")
	{
	  s1="You start calling the forces of fire.";
	  s2=TP->QN+" starts mumbling and arches of fire leap between "+
	    TP->query_possessive()+" fingers.\n"+
	    CAP(TP->query_pronoun())+" stretches a hand towards "+
	    who->QN+".";
	}
      else if(type=="cold" || type=="ice")
	{
	  s1="You utter the harsh tones of a spell.";
	  s2=TP->QN+" utters a spell in harsh tones, stretching a hand\n"+
	    "towards "+who->QN+".";
	}
      else if(type=="lightning" || type=="electricity")
	{
	  s1="Lightning crackles between your fingers as you start casting a spell.";
	  s2=TP->QN+" mumbles something and stretches a hand towards\n"+
	    who->QN+", lightning crackling between "+TP->query_possessive()+" fingers.";
	}
      else if(type=="crush" || type=="impact")
	{
	  s1="You perform somatic preparations to a spell.";
	  s2=TP->QN+" waves "+TP->query_possessive()+" hands in front of "+
	    TP->query_objective()+".";
	}
      else if(type=="drain")
	{
	  s1="You start preparing black art.";
	  s2=TP->QN+" starts preparing black art, glaring towards "+who->QN;
	}
      write(s1+"\n");
      say(s2+"\n");
    }
/*  write(mess1 + "\n");
  say(mess3 + "\n",TP);*/
  splw = ON_PLAYER("spellwall");
  if (splw)
    {
      damage -= splw->query_effect(damage);
      write(whoname + " has protective magic on " + who->query_objective() + ".\n");
      tell_object(who, "A protective spell reduces the effects.\n");
    }
  if(who->query_skill("magic_resistance") > random(100)) 
    {
      say("It had no obvious effect.\n");
      write("It had no obvious effect.\n");
      damage=0;
      if(!who->query_attack())
	{
	  who->attacked_by(TP);
	}
      return 1;
    }
  temp1=who->query_possessive();   /** Have to use these variables, there */
  temp2=who->query_pronoun();     /** would be too many locals if else.  */
  d1=who->query_objective();
/*  if (type == "drain")
    {
      s3 = convert(drain_mess3,whoname,temp1,temp2,d1);
      if (who->query_hp() <= damage-1)
	{
	  who->hit_player(who->query_ac()+5+damage);
	  if(!who)
	    {
	      write(s3+"\n");
	      say(s3+"\n");
	    }
	  return 1;
	}
      i = who->query_hp();
      dam = i - who->reduce_hit_point(damage);
      j = get_mess(dam);
      s1 = convert(drain_mess1[j],whoname,temp1,temp2,d1);
      s2 = convert(drain_mess2[j],whoname,temp1,temp2,d1);
      tell_object(who,s2+"\n");
      say(CAP(s1)+"\n",who);
      who->attacked_by(TP);            /** To start a combat **/
/*      return 1;
    }*/
  TP->do_attack(who,skill);
  return 1;
}


/******* HERE THEY ARE: SPELLS! ********/


/*** Detect Magic ***/

INT
detma()
{
  object obj;
  t=0;
  obj = first_inventory(environment(TP));
  while(obj)
    {      
      if(obj->query_property("magic"))
	{
	  write(obj->short()+" (in the room) is magical.\n");
	  t=1;
	}
      obj = next_inventory(obj);
    }
  obj = first_inventory(TP);
  while(obj)
    {      
      if(obj->query_property("magic"))
	{
	  write(obj->short()+" (on you) is magical.\n");
	  t=1;
	}
      obj = next_inventory(obj);
    }
  if(!t)
    write("Nothing magical here.\n");
  else
    write("Ok.\n");
  return 1;
}

/*** Find Familiar ***/
/*
INT
findf()
{
    object familiar;
    if(call_other(SPELLHOME+"flagger","check_flag",TP->query_real_name(),3))
        write("You already have a familiar!\n");
        return 1;
    }
    if(do_cost("findf")) return 1;
    call_other(SPELLHOME+"flagger","set_flag",TP->query_real_name(),2);
    ran = random(11)+2;
    ran += (TP->QAL/100);
    if (ran < 2)
        familiar = clone_object(SPELLHOME+"imp");
    else if (ran >= 2 && ran <= 4)
        familiar = clone_object(SPELLHOME+"toad");
    else if (ran >= 5 || ran == 6 || ran == 8 || ran == 9)
        familiar = clone_object(SPELLHOME+"cat");
    else if (ran == 7)
        familiar = clone_object(SPELLHOME+"drake");
    else if (ran >= 10 && ran <= 12)
        familiar = clone_object(SPELLHOME+"weasel");
    else if (ran >= 13)
        familiar = clone_object(SPELLHOME+"brownie");
    familiar->set_master(TP->QN);
    move_object(familiar,environment(TP));
    say(familiar->short()+" arrives.\n");
    write(familiar->short()+" comes to you. You are now bound together.\n");
    return 1;
}
*/

/*** Identify ***/

INT
ident(STRING item)
{
    object ting;
    string kort;
    if(!item) {
        write("Please specify an item.\n");
        return 0;
    }
    ting = ON_PLAYER(item);
    if (!ting) {
        write("No "+item+" on you.\n");
        return 0;
    }
    if(ting->query_info())
      write(ting->query_info());
    kort = ting->short();
    ting->identify();
    if (kort != ting->short())
      write(CAP(ting ->short())+"\n");
    write("Ok.\n");
    return 1;
}

/*** Shield I ***/

sh1()
{
  return shield(2);
}

/*** Shield II ***/

sh2()
{
  return shield(2);
}

/*** Shield III ***/

sh3()
{
  return shield(3);
}

/*** Shield IV ***/

sh4()
{
  return shield(4);
}


static shield(ac)
{
  object shieldspell;
  if(EN(TP)->query_property("no_mdefense"))
    {
      write("You cannot use defensive magic here!\n");
      return;
    }
  shieldspell = clone_object(SPELLHOME+"prot_spell");
  shieldspell->set_spell_name("shield");
  shieldspell->set_ac(ac);
  shieldspell->SET_CASTER;
  shieldspell->SET_DUR("ar"+ac);
  move_object(shieldspell,TP);
  return 1;
}

/*** Armour I ***/

ar1()
{
  return armour(1);
}

/*** Armour II ***/

ar2()
{
  return armour(2);
}

/*** Armour III ***/

ar3()
{
  return armour(3);
}

/*** Armour IV ***/

ar4()
{
  return armour(4);
}

static armour(ac)
{
  object armourspell;
  if(EN(TP)->query_property("no_mdefense"))
    {
      write("You cannot use defensive magic here!\n");
      return;
    }
  armourspell = clone_object(SPELLHOME+"prot_spell");
  armourspell->set_spell_name("armour");
  armourspell->set_ac(ac+1);
  armourspell->SET_CASTER;
  armourspell->SET_DUR("ar"+ac);
  move_object(armourspell,TP);
  return 1;
}

/*** Ventriliquism ***/

ventr(str)
{
    string  who,what;
    object  guy;

    sscanf(str,"%s %s",who,what);
    guy = present(lower_case(who),environment(TP));
    if (!guy) {
        write("Who?\n");
        return 0;
    }
    if(((guy->QINT) - 4 + random(10) <= TP->SK_ILLU) && !MR(guy)) {
        write("You made it!\n");
        say(who+" says: "+what+"\n",guy);
	tell_object(guy,"You say: "+what+"\n");
        return 1;
    } else {
        write(who+" resisted the magic!\n");
        say(TP->QN+" tried to ventriliquate something from "+CAP(who)+
	    "'s mouth.\n",guy);
	tell_object(guy,TP->QN+" tried to ventriliquate something from your mouth.\n");
    }
    return 1;
}

/*** Aural Illusion ***/

auril(what)
{
  object all;
  
  say("There is a sound of "+what+"\n");
  all=all_inventory(EN(TP));
  for (t=0 ; t<sizeof(all) ; t++) 
    {
      if((living(all[t]) && !all[t]->query_npc() &&
	  all[t]->query_int()-4+random(10) > TP->SK_ILLU) || MR(all[t]))
	{
	  tell_object(all[t],"..but it was just an illusion cast by "+
		      TP->QN+"..\n");
	}
    }
  return 1;
}



/*** Bladerune I-IV ***/

blru1(str)
{
  bladerune(str, "1");
  return 1;
}

blru2(str)
{
  bladerune(str, "2");
  return 1;
}

blru3(str)
{
  bladerune(str, "3");
  return 1;
}

blru4(str)
{
  bladerune(str, "4");
  return 1;
}

bladerune(str, f)
{
  object weapon;
  object enchantment;
  weapon = is_here(str);
  if(!weapon) 
    {
      write("Cast spell on what weapon?\n");
      return;
    }
  if(!weapon->weapon_class())
    {
      write("Not a weapon!\n");
      return;
    }
  enchantment = clone_object(SPELLHOME + "bla_run" + f);
  weapon->set_hit_func(enchantment);
  weapon->set_short(weapon->short() + " (enchanted)");
  write("You enchant "+ str +".\n");
  say(TP->QN + " enchants " + str + ".\n");
  move_object(enchantment, weapon);
  enchantment->SET_CASTER;
  enchantment->SET_DUR("blru"+f);
}

/* Chill touch */

chto(str)
{
  object chill;
  if(!attack_spell
     (str,"You touch #.",
      "# touches you with an icing chill.",
      "# touches &.",
      random(10) + 1, REDUCE)) return 0;
  chill = clone_object(SPELLHOME + "chill");
  move_object(chill, IN_ROOM(str));
  chill->SET_DUR("chto");
}

/*** Darkfire bolt I ***/

dafb1(str)
{
  if(!attack_spell(str,
		   "You throw a black flame at #.",
		   "# throws a black flame at you.",
		   "# throws a black flame at &.",
		   random(15),"fire")) return;
  MORE_EVIL(1);
  return 1;
}

/*** Darkfire bolt II ***/

dafb2(str)
{
  if(!attack_spell(str,
		   "You hurl darkfire at #.",
		   "# hurls black fire at you.",
		   "# hurls black fire at &.",
		   random(25),"fire")) return;
  MORE_EVIL(2);
  return 1;
}

/*** Darkfire bolt III ***/

dafb3(str)
{
  if(!attack_spell(str,
		   "You shoot a bolt of darkfire at #.",
		   "# shoots a bolt of black fire at you.",
		   "# shhots a bolt of black fire at &.",
		   random(40),"fire")) return;
  MORE_EVIL(3);
  return 1;
}

/** Darkfire bolt IV ***/

dafb4(str)
{
  if(!attack_spell(str,
		   "You unleash the flames of hell at #.",
		   "Black fire pours from #'s arms at you.",
		   "Black fire pours from #'s arms at &.",
		   random(55),"fire")) return;
  MORE_EVIL(4);
  return 1;
}

/*** Heal I to IV ***/

heal1(str)
{
  return heal(str,random(10)+1);
}

heal2(str)
{
  return heal(str,random(20)+1);
}

heal3(str)
{
  return heal(str,random(30)+1);
}

heal4(str)
{
  return heal(str,random(40)+1);
}

static heal(st,am)
{
  object ob;
  if(!st) ob=TP; else ob=IN_ROOM(st);
  if(!ob)
    {
      write("No-one with that name here..\n");
      return;
    }
  if(!living(ob))
    {
      write("That is not a living thing!\n");
      return 0;
    }
  ob->reduce_hit_point(-am);
  tell_object(ob,TP->QN+" heals you.\n");
  say(TP->QN+" mumbles a spell of healing.\n");
  say(TP->QN+" heals "+CAP(ob->QN)+".\n",ob);
  write("Ok.\n");
  return 1;
}

/* Detect evil and good */

dete()
{
  int    al;
  string na;
  all = all_inventory(environment(TP));
  for(t = 0 ; t < sizeof(all) ; t++)
    {
      if(living(all[t]) && !all[t]->resist_magic())
        {
          al = all[t]->QAL;
          na = capitalize(all[t]->QN);
          if (al <= -1000)
            write(na + " radiates an extremely evil aura.\n");
          if (al <= -200 && al > -1000)
            write(na + " is evil.\n");
          if (al <= -40 && al > -200)
            write(na + " is a little evil.");
          if (al > -40)
            write(na + " is not particularly evil.\n");
        }
    }
  write("Ok.\n");
  return 1;
}

detg()
{
  int    al;
  string na;
  all = all_inventory(environment(TP));
  for(t = 0 ; t < sizeof(all) ; t++)
    {
      if(living(all[t]) && !all[t]->resist_magic())
        {
          al = all[t]->QAL;
          na = capitalize(all[t]->QN);
          if (al >= 1000)
            write(na + " radiates an extremely good aura.\n");
          if (al >= 200 && al < 1000)
            write(na + " is good.\n");
          if (al >= 40 && al < 200)
            write(na + " is a little good.");
          if (al < 40)
            write(na + " is not particularly good.\n");
        }
    }
  write("Ok.\n");
  return 1;
}

/*** Reveal Invisible ***/

revin() 
{
  object invisible;
  invisible = filter_objects(all_inventory(EN(TP)),"is_invisible",this_object());
  for (t=0 ; t<sizeof(invisible) ; t++) 
    {
      if(invisible[t]->QL > 19 || invisible[t]->resist_magic())
	{
	  write("You feel the presence of someone invisible.\n");
	} 
      else
	{
	  invisible[t]->vis();
	  write(CAP(invisible[t]->QN)+" was invisible.\n");
        }
    }
  write("Ok.\n");
  return 1;
}

is_invisible(ob)
{
  if (living(ob) && (ob->short() == "" || ob->short() == 0 || !ob->short()))
    return 1;
}


/*** Know Alignment ***/

knowa()
{
  object beings;
  int al;
  all=all_inventory(EN(TP));
  beings = filter_objects(all,"knowal_filter",this_object());
  for (t=0 ; t<sizeof(beings) ; t++)
    {
      if (beings[t] != TP) 
	{
	  al = beings[t]->QAL;
	  write(CAP(beings[t]->QN)+" is ");
	  if (al > 1000)
	    {
	      write("saintly");
	    } 
	  else if (al > 200)
	    {
	      write("good");
	    } 
	  else if (al > 40)
	    {
	      write("nice");
	    } 
	  else if (al > -40)
	    {
	      write ("neutral");
	    }
	  else if (al > -200)
	    {
	      write ("nasty");
	    } 
	  else if (al > -1000) 
	    {
	      write ("evil");
	    } 
	  else write("demonic");
	  write(".\n");
	}
    }
  write("Ok.\n");
  return 1;
}

knowal_filter(ob)
{
  if (living(ob) && !ob->resist_magic())
    return 1;
}

/*** Scare ***/

scare(str)
{
  object who;
  if(!str) 
    {
      write("Scare who?\n");
      return 0;
    }
  who = IN_ROOM(str);
  if (!who) return 0;
  if (!living(who))
    {
      write("Seemed like it had no effect...\n");
      say(TP->QN+" tries to scare "+who->short()+".\n");
      return 1;
    }
  if ((TP->SK_ENCH - who->QL) < 0)
    {
      if(!random(4) && !MR(who))
	{
	  write("You scare "+CAP(who->QN)+".\n");
	  tell_object(who,TP->QN+" suddenly appears very frightening!\n");
	  say(TP->QN+" scares "+CAP(who->QN)+".\n",who);
	  who->run_away();
	}
      else
	{
	  write(who->QN+" resists your spell!\n");
	  say(who->QN+" mumbles a useless spell.\n",who);
	  tell_object(who,TP->QN+" tries to scare you.\n");
        }
      return 1;
    }
  if (!MR(who))
    {
      write("You scare " + who->QN+".\n");
      tell_object(who,TP->QN+" suddenly appears very frightening!\n");
      say(TP->QN+" scares "+CAP(who->QN)+".\n",who);
      who->run_away();
    } 
  else
    {
      write(CAP(who->QN)+" resists your spell!\n");
      tell_object(who,TP->QN+" tries to scare you.\n");
    }
  return 1;
}

/*** Emote ***/

emote(str) {
    write ("Ok.\n");
    say(TP->QN+" "+str+"\n");
    return 1;
}

/*** Blur ***/

blur()
{
  object blur;
  if(EN(TP)->query_property("no_mdefense"))
    {
      write("You cannot use defensive magic here!\n");
      return;
    }
  blur = clone_object(SPELLHOME+"prot_spell");
  blur->set_spell_name("blur");
  blur->set_ac(1+random(3));
  blur->SET_CASTER;
  blur->SET_DUR("blur");
  move_object(blur,TP);
  return 1;
}

/*** Clairvoyance ***/
/*
clvoy() {
    write("You sit down and start concentrating deeply.\n");
    say(TP->QN+" sits down and starts to concentrate.\n");
    write("\nType 'abort' to abort the spell.\n"+
          "You can now walk around visually for a while.\n");
    eyes = clone_object(SPELLHOME+"clv_eyes");
    keeper = clone_object(SPELLHOME+"keeper");
    keeper->set_caller(this_object());
    eyes->set_keeper(keeper);
    eyes->set_viewer(TP);
    eyes->set_oldroom(EN(TP));
    move_object(keeper, TP);
    move_object(eyes, EN(TP));
    call_out("no_clairvoyance", query_duration(recognize_abbr("clvoy")));
    return 1;
}

clv_interruption() {
    write("You are interrupted!\n");
    remove_call_out("no_clairvoyance");
    no_clairvoyance();
}

no_clairvoyance() {
    write("You are yanked back to your body!\n");
    destruct(eyes);
    destruct(keeper);
}
*/

/*** Consume Corpse ***/

conco()
{
  object cor;
  t=0;
  cor=IN_ROOM("corpse");
  if(!cor)
    {
      write("No corpse here!\n");
      return;
    }
  while (cor)
    {
      write("You consume "+cor->short()+".\n");
      say(TP->QN+" greedily eats "+cor->short()+".\n");
      destruct(cor);
      t++;
      cor=present("corpse",this_object());
    }
  write("You feel better.\n");
  TP->heal_self((t*random(8))+t);
  if(TP->QAL > -200)
    {
      write("You feel your soul perverting.\n");
      MORE_EVIL(30);
    }
  return 1;
}


/*** Water Bolt ***/

wbolt(str) {
    if(attack_spell(str,
        "You aim a bolt of water at #.",
        "# shoots a bolt of water at you.",
        "# fires a bolt of water at &.",
        random(10)+5,"impact")) return 1;
}

/*** Remove Curse ***/

recur(str) {
    object who;
    object curse;
    int    curseflags;
    if (!str) who = TP;
    else who = IN_ROOM(str);
    if(!who) {
        write("At whom?");
        return 0;
    }
    if(!living(who)) {
        write("Not a living thing!\n");
        return 0;
    }
    while(present("curse",who)) {
        curse = present("curse",who);
        curse->remove_curse();
    }
    curseflags = call_other(HOME+"workroom", "query_curse_flags");
    if(intp(curseflags)) {
        call_other(HOME+"flagger","clear_flag",lower_case(who->QN),curseflags);
        return 1;
    }
    for (t=0 ; t<sizeof(curseflags) ; t++) {
        call_other(HOME+"flagger","clear_flag",lower_case(who->QN),curseflags[t]);
    }
    write("Ok.\n");
    return 1;
}

/*** Call Power I ***/

capo1() {
    if (TP->query_hp() < 35) {
        write("You are too weak!\n");
        return 0;
    }
    TP->reduce_hit_point(25);
    spinc = 10+random(30);
    call_out("giveback_sp",1);
    write("You feel your body wither, but your mind fills up with energy!\n");
    say(TP->QN+" trades blood with power!\n");
    return 1;
}

/*** Call Power II ***/

capo2() {
    if (TP->query_hp() < 60) {
        write("You are not strong enough right now.\n");
        return 0;
    }
    TP->reduce_hit_point(50);
    spinc = 30 + random(50);
    call_out("giveback_sp",1);
    write("You fall to your knees as you sacrifice your body for power.\n");
    say(TP->QN+" falls to "+TP->query_possessive()+" knees, there is "+
        "an aura of power around "+TP->query_objective()+".\n");
    if (! random(6)) {
        write("This was worse than you had imagined. You start trembling.\n");
        say(TP->QN+" starts trembling from the strain.\n");
        TP->set_con(TP->query_con()-1);
    }
    return 1;
}

/*** Call Total Power ***/

catop() {
    int oldhp, sp1, sp2, dms, con;
    if (TP->query_hp() < 100) {
        write("You do not possess the strength to accomplish such a spell.\n");
        return 0;
    }
    oldhp = TP->query_hp();
    sp1 = TP->query_spell_points();
    TP->reduce_hit_point(oldhp-10);
    spinc = random(((oldhp-10)*8)/5);
    call_out("giveback_sp",1);
    sp2 = TP->query_spell_points();
    if (spinc-sp2+sp1 > 70) {
        write("This was more energy than your body could handle. You lose control!\n");
        say(TP->QN+" starts burning. Fire spews out of "+
            TP->query_possessive()+" mouth,\n"+
            "and "+TP->query_possessive()+" eyes glow bright red!\n");
        say("You cannot avoid being hit by the flames.\n");
        all=all_inventory(EN(TP));
        for(t=0 ; t<sizeof(all) ; t++) {
            if(living(all[t])) {
                dms++;
                all[t]->reduce_hit_point(random(20));
            }
        }
        write("Your head clears just enough for you to understand what just happened.\n");
        if(dms) {
            write("You feel weaker, and you have accidentally damaged\n"+
                  "the others in the room person");
            if(dms > 1) write("s");
            write(".\n");
        con = TP->query_con()-(random(3)+1);
        if (con < 1) con = 1;
        TP->set_con(con);
        }
    }
    return 1;
}

giveback_sp()
{
  ENV -> restore_spell_points(spinc);
}

/*** Light ***/

light()
{
  object light;
  int i;

  light = clone_object(SPELLHOME + "light");
  i = TP->query_skill(query_spell_school(recognize_spell("light"))) / 25;
  if (!i) i = 1;
  light->set_level(i);
  i = light->SET_DUR("light");
  move_object(light, TP);
  say(TP->QN + " mumbles softly, and a globe of light appears between " +
      TP->QPOS + " hands.\n");
  write("You summon a small globe of light.\n");
}

/*** Darkness ***/

dark()
{
  object dark;
  int i;

  dark = clone_object(SPELLHOME + "light");
  i = TP->query_skill(query_spell_school(recognize_spell("darkness"))) / 25;
  if (!i)
    i = 1;
  dark->set_level(-i);
  i = dark->SET_DUR("darkmess");
  move_object(dark, EN(TP));
  write("You summon darkness.\n");
  say(TP->QN + " casts a spell.\n");
}

/*** Ice Bolt ***/

ibolt(str) {
  return attack_spell(str,
		      "You hurl a bolt of ice towards #.",
		      "# casts an ice bolt in your direction.",
		      "# smites a bolt of ice towards &.",
		      random(15)+10,
		      "ice");
}

/*** Locate ***/

locat(str) {
    object who;
    who = find_player(lower_case(str));
    if (!who) {
        write("No such player.\n");
        return 1;
    }
    write("You see:\n");
    EN(who)->long();
    return 1;
}

/*** Neutralize Poison ***/

nepoi(str) {
    object who, poison;
    if(!who) who=TP;
    else who=IN_ROOM(str);
    if(!who) {
        write("At whom?\n");
        return 0;
    }
    if(!living(who) && who->id("corpse")) {
        write("Sorry, "+CAP(str)+" is already dead.\n");
        return 0;
    }
    if(!living(who)) {
        write("Not a living thing!\n");
        return 0;
    }
    while(present("poison",who)) {
        poison = present("poison",who);
        poison->neutralize();
    }
    write("Ok.\n");
    return 1;
}

/*** Rope Trick ***/

roptr() {
    object ob;
    write("You create a magical rope which you climb into safety.\n");
    say(TP->QN+" summons a magical rope and climbs it. Then both are gone.\n");
    while (TP->query_attack()) {
        TP->query_attack()->stop_fight();
    }
    TP->stop_fight();
    ob=clone_object(SPELLHOME+"rope_obj");
    ob->SET_DUR("roptr");
    ob->set_oldroom(EN(TP));
    move_object(ob,TP);
    move_object(TP,SPELLHOME+"ethplane");
    TP->glance();
    return 1;
}

/*** Vampiric Touch ***/

vamto(str) {
    int dam;
    dam=random(20)+5;
    if(!attack_spell(str,
        "You draw life force from #.",
        "# touches you with a life draining touch.",
        "# touches &.",
        dam,"drain")) return 0;
    TP->heal_self(dam);
    tell_object(IN_ROOM(str),"You feel weaker!\n");
    write("You feel a surge in your blood.\n");
    if(TP->QAL > -200)
      MORE_EVIL(20);
    return 1;
}

/*** Fire Bolt ***/

fbolt(str) {
  return attack_spell(str,
		      "You cast a firebolt at #.",
		      "# casts a firebolt at you.",
		      "# casts a firebolt at &.",
		      random(35),"fire");
}

/*** Invisibility ***/

invis(str) {
    object who, invisibility;
    if(!str) who=TP;
    else who=IN_ROOM(str);
    if(!who) {
        write("At whom?\n");
        return 0;
    }
    if(!living(who)) {
        write("Cannot make non-living objects invisible!\n");
        return 0;
    }
    if(who->query_npc()) {
        write("Can only make players invisible.\n");
        return 0;
    }
    if(who != TP) {
        tell_object(who,TP->QN+" makes you invisible.\n");
        write("You make "+CAP(who->QN)+" invisible.\n");
    }
    invisibility = clone_object(SPELLHOME+"invis_sp");
    move_object(invisibility,who);
    return 1;
}

/*** Charm ***/
/*
charm(str) {
    object who;
    who=IN_ROOM(str);
    if(!who) {
        write("Charm who?\n");
        return 0;
    }
    if(who==TP) {
        write("Oh yeah, you're such a nice guy!\n");
        return 0;
    }
    if(!living(who)) {
        write("Well, you could try, but you can't exactly expect any results..\n");
        return 0;
    }

}
*/

/*** Dispel Magic ***/

disp()
{
  object all2;
  
  say(TP->QN+" casts a spell.\n");
  all=all_inventory(EN(TP));
  for(t=0 ; t<sizeof(all) ; t++) 
    {
      if(all[t]->dispel())
	{
	  all[t]->dispel();
	}
      all2 = present("spell",all[t]);
      if((all2) && (all[t] != TP))
	{
	  while(present("spell", all[t]))
	    {
	      all2 = present("spell",all[t]);
	      if(all2->id("spell"))
		{
		  all2->dispel();
		}
	      all2 = next_inventory(all[t]);
	    }
	}
    }
  write("Ok.\n");
  return 1;
}


/*** Illusion ***/

illus(str) 
{
  all=filter_objects(all_inventory(EN(TP)),"illusion_filter",this_object());
  for(t=0 ; t<sizeof(all) ; t++)
    {
      if((all[t]->QL-4+random(10)) > TP->QINT)
	tell_object(all[t],TP->QN+" casts an illusion of:\n");
    }
  say(str+"\n");
  write("Ok.\n");
  return 1;
}

illusion_filter(ob)
{
  if(living(ob)) return 1;
}


/*** Lightning Bolt ***/

lbolt(str) {
    if(attack_spell(str,
        "You shoot a lightning bolt at #.",
        "# shoots a bolt of lightning at you.",
        "# zaps & with a lightning bolt.",
        random(20)+10),"lightning") return 1;
}

/*** Regeneration ***/

regen(str) {
    object who,regen;
    if(!str) who=TP;
    else who=IN_ROOM(str);
    if(!who) {
        write("At whom?\n");
        return 0;
    }
    if(!living(who)) {
        write("Non-living matter cannot regenerate!\n");
        return 0;
    }
    regen = clone_object(SPELLHOME+"regener");
    regen->SET_DUR("regen");
    move_object(regen,who);
    return 1;
}

/*** Read Mind ***/

readm(str)
{
  object who,skill;
  string know,dummy;
  who=IN_ROOM(str);
  if(who==TP)
    {
      write("That shouldn't really be necessary, should it?\n");
      return 0;
    }
  if(!who)
    {
      write("Read who's mind?\n");
      return 0;
    }
    if(!living(who))
      {
        write("No mind to read there, dummy!\n");
        return 0;
      }
  skill=present("spell_skill",who);
  if(!skill)
    {
      write(CAP(who->QN)+" is not working magic.\n");
      return 1;
    }
  tell_object(who,TP->QN+" probes your mind.\n");
  say(TP->QN+" looks intensely at "+CAP(who->QN)+".\n",who);
  know=skill->query_known();
  write(CAP(who->QN)+" knows the following spells:\n");
  for (t=0,n=0 ; t<query_max_spells() ; t++,n++)
    {
      if(test_bit(know,t))
	{
	  dummy = query_all_spell_names()[t]+"                         ";
	  write(CAP(extract(dummy,0,19)));
	  if(n==3) {
	    write("\n");
	    n=-1;
	  }
        }
    }
  if(n != -1) write("\n");
  return 1;
}

/*** Harm ***/

harm(str)
{
  if(!attack_spell(str,
		   "You point a finger at #, inflicting pain.",
		   "You feel a sharp pain in your chest as # points a finger at you.",
		   "# points a finger at &, who staggers.",
		   random(40),"drain")) return 0;
  if(TP->QAL > -200)
    MORE_EVIL(10);
  return 1;
}

/*** Meteor Swarm ***/

metsw(str)
{
  if(attack_spell(str,
		  "You send a swarm of burning meteors towards #.",
		  "# hurls a swarm of fiery meteors at you!",
		  "# sends a small swarm of fiery meteors right towards &.",
        random(60)+30,"impact")) return 1;
}

/*** Disintegrate ***/

INT
disintegrate(STRING str)
{
  object what;
  what = is_here(str);
  if(!what)
 {
   write("Disintegrate what?\n");
   return 0;
 }
  if(living(what) && !what->query_npc())
    {
      write("Cannot disintegrate living players.\n");
      return 0;
    }
  if(!what->get()) 
    {
      write("You cannot disintegrate "+what->short()+"!\n");
      return 0;
    }
  if(living(what)) 
    move_object(what,"/room/void");
  say(TP->QN+" mutters an ancient spell.");
  write("You disintegrate "+str+".\n");
  say(TP->QN+" turned "+what->short()+" to dust!\n");
  destruct(what);
  return 1;
}



/*****************************************************************************/

INT
spell_help(INT spell)
{
  if(ILLEGAL_INDEX(spell)) return 0;
  write(CAP(spell_info[spell][SP_NAME]) + " (" +
	CAP(query_school(spell)) +
	") :\n" + "Level: "+query_spell_level(spell) + "  MP: " + 
	query_cost(spell));
  if(query_duration(spell) > 0)
    write("  Duration: " + query_duration(spell));
  write("\nAbbrevation: " + query_spell_abbr(spell) + "\n");
  cat("/"+SPELLHOME + "helpdir/" + query_spell_abbr(spell) + ".doc");
  return 1;
}

INT recognize_spell(STRING str)
{
  for (t=0 ; t<sizeof(spell_info) ; t++)
    if (spell_info[t][SP_ABBR] == str || spell_info[t][SP_NAME] == str)
      return t;
  return -1;
}

INT
recognize_spell_abbr(STRING str)
{
  for (t=0 ; t<sizeof(spell_info) ; t++)
    if (spell_info[t][SP_ABBR] == str) 
      return t;
  return -1;
}

INT
recognize_spell_name(STRING str)
{
  for (t=0 ; t<sizeof(spell_info) ; t++)
    if (spell_info[t][SP_NAME] == str)
      return t;
  return -1;
}

STRING
query_school(INT n)
{
  switch (n) {
  case DARK: return "dark arts"; break;
  case DIVI: return "divination"; break;
  case ELEM: return "elemental magic"; break;
  case ENCH: return "enchantment magic"; break;
  case HEAL: return "healing magic"; break;
  case ILLU: return "illusion"; break;
  case NECR: return "necromancy"; break;
  case PROT: return "protection magic"; break;
  case SUMM: return "summoning"; break;
  default: return "unknown"; break;
  }
}

INT
query_spell_school(INT n)
{
  if (ILLEGAL_INDEX(n)) return -1;
  return spell_info[n][SP_SCHOOL];
}

INT
query_spell_level(INT n)
{
  if (ILLEGAL_INDEX(n)) return -1;
  return spell_info[n][SP_LEVEL];
}

STRING
query_spell_name(INT n)
{
  if (ILLEGAL_INDEX(n)) return -1;
  return spell_info[n][SP_NAME];
}

INT
query_spell_cost(INT n)
{
  if (ILLEGAL_INDEX(n)) return -1;
  return spell_info[n][SP_COST];
}

STRING
query_spell_abbr(INT n)
{
  if (ILLEGAL_INDEX(n)) return -1;
  return spell_info[n][SP_ABBR];
}

INT
query_spell_duration(INT n)
{
  if (ILLEGAL_INDEX(n)) return -1;
  return spell_info[n][SP_DURATION];
}

INT
query_max_spells()
{
  return sizeof(spell_info); 
}

MIXED
query_spell_info(INT spell, INT info)
{
  if (ILLEGAL_INDEX(spell)) return -1;
  return spell_info[spell][info];
}

MIXED_ARR
return_spell_info()
{
  return spell_info;
}