/*
 *      The spells of the guild.
 *      What more can be said?
 *
 *      (c) Auronthas  begun 10.07.91
 *          most work done 17-18.07.91
 */

#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 QNAME query_name()
#define QLEV query_level()
#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->QINT)
#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;


INT
id(STRING str) {
    if(TP->QLEV < 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",		"detma", 	0,	2,	DIVI,	1 }),
    ({ "find familiar", 	"findf", 	0,	10,	SUMM,	1 }),
    ({ "identify",		"ident", 	0,	5,	DIVI,	1 }),
    ({ "shield i",		"sh1",		10,	5,	PROT,	1 }),
    ({ "ventriliquism",		"ventr",	0,	3,	ILLU,	1 }),
    ({ "aural illusion",	"auril",	0,	6,	ILLU,	2 }),
    ({ "bladerune i",		"blru1",	5,	8,	ENCH,	2 }),
    ({ "detect evil",		"dete",		0,	2,	DIVI,	2 }),
    ({ "detect good",		"detg",		0,	2,	DIVI,	2 }),
    ({ "light",			"light",	20,	5,	ELEM,	2 }),
    ({ "armour i",		"ar1",		10,	7,	PROT,	3 }),
    ({ "chill touch",		"chto",		10,	10,	NECR,	3 }),
    ({ "darkfire bolt i",	"dafb1",	0,	8,	DARK,	3 }),
    ({ "fireblade i",		"fibl1",	10,	10,	ELEM,	3 }),
    ({ "heal i",		"heal1",	0,	5,	HEAL,	3 }),
    ({ "know alignment",	"knowa",	0,	5,	DIVI,	4 }),
    ({ "reveal invisible",	"revin",	0,	12,	DIVI,	4 }),
    ({ "analyze",		"analy",	0,	6,	DIVI,	5 }),
    ({ "scare",			"scare",	0,	15,	ENCH,	5 }),
    ({ "shield ii",		"sh2",		15,	10,	PROT,	5 }),
    ({ "summon insects",	"sumin",	5,	10,	SUMM,	5 }),
    ({ "emote",			"emote",	0,	5,	ILLU,	5 }),
    ({ "bladerune ii",		"blru2",	10,	15,	ENCH,	6 }),
    ({ "blur",			"blur",		10,	10,	ILLU,	6 }),
    ({ "clairvoyance",		"clvoy",	10,	15,	DIVI,	6 }),
    ({ "consume corpse",	"conco",	0,	10,	NECR,	6 }),
    ({ "water bolt",		"wbolt",	0,	7,	ELEM,	6 }),
    ({ "armour ii",		"ar2",		15,	14,	PROT,	7 }),
    ({ "fireblade ii",		"fibl2",	15,	15,	ELEM,	7 }),
    ({ "heal ii",		"heal2",	0,	10,	HEAL,	7 }),
    ({ "remove curse",		"recur",	0,	20,	ENCH,	7 }),
    ({ "call power i",		"capo1",	0,	10,	SUMM,	8 }),
    ({ "darkness",		"dark",		20,	15,	DARK,	8 }),
    ({ "darkfire bolt ii",	"dabf2",	0,	16,	DARK,	8 }),
    ({ "ice bolt","		ibolt",		0,	10,	ELEM,	8 }),
    ({ "locate",		"locat",	0,	10,	DIVI,	8 }),
    ({ "neutralize poison",	"nepoi",	0,	15,	HEAL,	8 }),
    ({ "levitate",		"levit",	15,	15,	ENCH,	9 }),
    ({ "rope trick",		"roptr",	20,	20,	ENCH,	9 }),
    ({ "vampiric touch",	"vamto",	0,	15,	NECR,	9 }),
    ({ "fire bolt",		"fbolt",	0,	13,	ELEM,	10 }),
    ({ "instability",		"insta",	0,	20,	SUMM,	10 }),
    ({ "invisibility",		"invis",	30,	25,	ENCH,	10 }),
    ({ "shield iii",		"sh3",		20,	15,	PROT,	10 }),
    ({ "bladerune iii",		"blru3",	15,	20,	ENCH,	11 }),
    ({ "charm",			"charm",	0,	15,	ENCH,	11 }),
    ({ "dispel magic",		"disp",		0,	20,	ENCH,	11 }),
    ({ "illusion",		"illus",	0,	10,	ILLU,	11 }),
    ({ "animate dead",		"anded",	30,	35,	NECR,	12 }),
    ({ "armour iii",		"ar3",		20,	21,	PROT,	12 }),
    ({ "fireblade iii",		"fibl3",	20,	20,	ELEM,	12 }),
    ({ "heal iii",		"heal3",	0,	15,	HEAL,	12 }),
    ({ "call power ii",		"capo2",	0,	20,	SUMM,	13 }),
    ({ "darkfire bolt iii",	"dafb3",	0,	24,	DARK,	13 }),
    ({ "lightning bolt",	"lbolt",	0,	16,	ELEM,	13 }),
    ({ "regeneration",		"regen",	15,	25,	HEAL,	13 }),
    ({ "read mind",		"readm",	0,	15,	DIVI,	14 }),
    ({ "summon spirit",		"suspi",	20,	30,	SUMM,	14 }),
    ({ "shadow warrior",	"shwar",	20,	20,	ILLU,	14 }),
    ({ "spell wall",		"spwal",	10,	10,	PROT,	14 }),
    ({ "harm",			"harm",		0,	20,	DARK,	15 }),
    ({ "summon demon",		"sudem",	20,	60,	DARK,	15 }),
    ({ "bladerune iv",		"blru4",	20,	25,	ENCH,	16 }),
    ({ "fireblade iv",		"fibl4",	20,	20,	ELEM,	16 }),
    ({ "shield iv","		sh4",		25,	20,	PROT,	16 }),
    ({ "armour iv",		"ar4",		25,	28,	PROT,	17 }),
    ({ "heal iv",		"heal4",	0,	20,	HEAL,	17 }),
    ({ "shadow monster",	"shmon",	20,	30,	ILLU,	17 }),
    ({ "darkfire bolt iv",	"dafb4",	0,	32,	DARK,	18 }),
    ({ "dimension door",	"dimdo",	0,	50,	ENCH,	18 }),
    ({ "unlife",		"unlif",	0,	50,	NECR,	18 }),
    ({ "call total power",	"catop",	0,	40,	SUMM,	19 }),
    ({ "disintegrate",		"disin",	0,	30,	DARK,	19 }),
    ({ "meteor swarm",		"metsw",	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->QNAME+" 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->QNAME+" 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->QNAME + d2;
  while(sscanf(mess3, "%s#%s", d1, d2))
    mess3 = d1 + TP->QNAME + 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->QNAME+" starts mumbling and arches of fire leap between "+
	    TP->query_possessive()+" fingers.\n"+
	    CAP(TP->query_pronoun())+" stretches a hand towards "+
	    who->QNAME+".";
	}
      else if(type=="cold" || type=="ice")
	{
	  s1="You utter the harsh tones of a spell.";
	  s2=TP->QNAME+" utters a spell in harsh tones, stretching a hand\n"+
	    "towards "+who->QNAME+".";
	}
      else if(type=="lightning" || type=="electricity")
	{
	  s1="Lightning crackles between your fingers as you start casting a spell.";
	  s2=TP->QNAME+" mumbles something and stretches a hand towards\n"+
	    who->QNAME+", lightning crackling between "+TP->query_possessive()+" fingers.";
	}
      else if(type=="crush" || type=="impact")
	{
	  s1="You perform somatic preparations to a spell.";
	  s2=TP->QNAME+" waves "+TP->query_possessive()+" hands in front of "+
	    TP->query_objective()+".";
	}
      else if(type=="drain")
	{
	  s1="You start preparing black art.";
	  s2=TP->QNAME+" starts preparing black art, glaring towards "+who->QNAME;
	}
      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->QNAME);
    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->QNAME+" tried to ventriliquate something from "+CAP(who)+
	    "'s mouth.\n",guy);
	tell_object(guy,TP->QNAME+" 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->QNAME+"..\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->QNAME + " 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->QNAME+" heals you.\n");
  say(TP->QNAME+" mumbles a spell of healing.\n");
  say(TP->QNAME+" heals "+CAP(ob->QNAME)+".\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]->QNAME);
          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]->QNAME);
          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]->QLEV > 19 || invisible[t]->resist_magic())
	{
	  write("You feel the presence of someone invisible.\n");
	} 
      else
	{
	  invisible[t]->vis();
	  write(CAP(invisible[t]->QNAME)+" 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]->QNAME)+" 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->QNAME+" tries to scare "+who->short()+".\n");
      return 1;
    }
  if ((TP->SK_ENCH - who->QLEV) < 0)
    {
      if(!random(4) && !MR(who))
	{
	  write("You scare "+CAP(who->QNAME)+".\n");
	  tell_object(who,TP->QNAME+" suddenly appears very frightening!\n");
	  say(TP->QNAME+" scares "+CAP(who->QNAME)+".\n",who);
	  who->run_away();
	}
      else
	{
	  write(who->QNAME+" resists your spell!\n");
	  say(who->QNAME+" mumbles a useless spell.\n",who);
	  tell_object(who,TP->QNAME+" tries to scare you.\n");
        }
      return 1;
    }
  if (!MR(who))
    {
      write("You scare " + who->QNAME+".\n");
      tell_object(who,TP->QNAME+" suddenly appears very frightening!\n");
      say(TP->QNAME+" scares "+CAP(who->QNAME)+".\n",who);
      who->run_away();
    } 
  else
    {
      write(CAP(who->QNAME)+" resists your spell!\n");
      tell_object(who,TP->QNAME+" tries to scare you.\n");
    }
  return 1;
}

/*** Emote ***/

emote(str) {
    write ("Ok.\n");
    say(TP->QNAME+" "+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->QNAME+" 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->QNAME+" 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->QNAME),curseflags);
        return 1;
    }
    for (t=0 ; t<sizeof(curseflags) ; t++) {
        call_other(HOME+"flagger","clear_flag",lower_case(who->QNAME),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->QNAME+" 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->QNAME+" 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->QNAME+" 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->QNAME+" 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(1);
  move_object(light, this_player());
  i = light->SET_DUR("light");
  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() {
  int i;
  object darkness;

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

/*** Ice Bolt ***/

ibolt(str) {
    if(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") return 1;
}

/*** 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->QNAME+" 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) {
    if(attack_spell(str,
        "You cast a firebolt at #.",
        "# casts a firebolt at you.",
        "# casts a firebolt at &.",
        random(35),"fire")) return 1;
}

/*** 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->QNAME+" makes you invisible.\n");
        write("You make "+CAP(who->QNAME)+" 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->QNAME+" 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]->QLEV-4+random(10)) > TP->QINT)
	tell_object(all[t],TP->QNAME+" 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->QNAME)+" is not working magic.\n");
      return 1;
    }
  tell_object(who,TP->QNAME+" probes your mind.\n");
  say(TP->QNAME+" looks intensely at "+CAP(who->QNAME)+".\n",who);
  know=skill->query_known();
  write(CAP(who->QNAME)+" 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->QNAME+" mutters an ancient spell.");
  write("You disintegrate "+str+".\n");
  say(TP->QNAME+" 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])
      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;
}