mc25b/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen  *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/
/***************************************************************************
 *                                 _/                            _/        *
 *      _/_/_/  _/_/      _/_/_/  _/    _/_/    _/    _/    _/_/_/         *
 *     _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/          *
 *    _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/           *
 *   _/    _/    _/    _/_/_/  _/    _/_/      _/_/_/    _/_/_/            *
 ***************************************************************************
 * Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius),                 *
 * Additional credits are in the help file CODECREDITS                     *
 * All Rights Reserved.                                                    *
 ***************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "interp.h"

int   calculate_dam              args (( CHAR_DATA *ch, CHAR_DATA *victim, int type ));
char *get_keywords_from_mob      args (( MOB_INDEX_DATA *pMob ));
char *get_description_from_mob   args (( MOB_INDEX_DATA *pMob ));

void do_reform( CHAR_DATA *ch, char *argument )
{
  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE) && !IS_CLASS(ch, CLASS_SAMURAI))
  {
    send_to_char("Huh?\n\r", ch );
    return;
  }
  if (ch->power[DISC_FAE_ARCANE] < 1 && IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("You need level 1 discipline in arcane.\n\r",ch);
    return;
  }
  ch->loc_hp[0] = 0;
  ch->loc_hp[1] = 0;
  ch->loc_hp[2] = 0;
  ch->loc_hp[3] = 0;
  ch->loc_hp[4] = 0;
  ch->loc_hp[5] = 0;
  ch->loc_hp[6] = 0;

  if (IS_CLASS(ch, CLASS_FAE))
  {
    ch->pcdata->powers[FAE_PLASMA_TICK] = 0;
    ch->pcdata->powers[FAE_WILL_TICK] = 0;
    ch->pcdata->powers[FAE_ENERGY_TICK] = 0;
    ch->pcdata->powers[FAE_MATTER_TICK] = 0;
    ch->pcdata->powers[FAE_PLASMA_GROWTH] = 0;
    ch->pcdata->powers[FAE_WILL_GROWTH] = 0;
    ch->pcdata->powers[FAE_ENERGY_GROWTH] = 0;
    ch->pcdata->powers[FAE_MATTER_GROWTH] = 0;
    ch->pcdata->powers[FAE_SHIELD] = 0;
  }
  send_to_char("#pYou reform your body, regrowing lost limbs.#n\n\r",ch);
  return;
}

void do_elementalform( CHAR_DATA *ch, char *argument )
{
  char buf [MAX_STRING_LENGTH];

  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("Huh?\n\r",ch);
    return;
  }
  if (ch->power[DISC_FAE_NATURE] < 10)
  {
    send_to_char("You are not a true master of nature.\n\r",ch);
    return;
  }
  if (IS_SET(ch->newbits, NEW_CUBEFORM))
  {
    REMOVE_BIT(ch->newbits, NEW_CUBEFORM);
    REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
    if (IS_SET(ch->affected_by, AFF_PASS_DOOR)) REMOVE_BIT(ch->affected_by, AFF_PASS_DOOR);
    act( "$n turns into a Fae.",ch,NULL,NULL,TO_ROOM);
    send_to_char("You turn into your normal form.\n\r",ch);
    ch->damroll -=350;
    ch->hitroll -=350;
    free_string(ch->morph);
    ch->morph=str_dup("");
    return;
  }
  if (ch->move < 2000 || ch->mana < 2000)
  {
    send_to_char("You need 2000 mana and 2000 move  to change into elemental form.\n\r",ch);
    return;
  }
  else
  {
    act( "$n transforms into an elemental storm.",ch,NULL,NULL,TO_ROOM);
    send_to_char("You become one with the elements, letting your rage guide you.\n\r",ch);
    if (!IS_SET(ch->affected_by, AFF_PASS_DOOR)) SET_BIT(ch->affected_by, AFF_PASS_DOOR);
    SET_BIT(ch->newbits, NEW_CUBEFORM);
    SET_BIT(ch->affected_by, AFF_POLYMORPH);
    xprintf(buf,"#oAn #sElemental #oStorm #0(#g%s#0)#n",ch->name);
    free_string(ch->morph);
    ch->morph = str_dup(buf);
    ch->move -= 2000;
    ch->mana -= 2000;
    ch->damroll +=350;
    ch->hitroll +=350;
    return;
  }
  return;
}

void do_channel(CHAR_DATA *ch, char *argument)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];

  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE))
  {
    do_channels(ch, argument);
    return;
  }

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );

  if (arg1[0] == '\0' || arg2[0] == '\0' )
  {
    send_to_char("Start channeling what, and at what speed?\n\r",ch);
    return;
  }
  if (!is_number(arg2) || (atoi(arg2) < 1 || atoi(arg2) > 3))
  {
    send_to_char("The speed should be a number between 1 and 3.\n\r",ch);
    return;
  }
  if (!str_prefix(arg1,"matter"))
  {
    if (atoi(arg2) > ch->pcdata->powers[FAE_MATTER])
    {
      send_to_char("You can't channel faster than your current level.\n\r",ch);
      return;
    }
    ch->pcdata->powers[FAE_MATTER_GROWTH] = atoi(arg2);
    if (ch->pcdata->powers[FAE_MATTER_TICK] == 0)
      ch->pcdata->powers[FAE_MATTER_TICK] = atoi(arg2);
    send_to_char("#pOk, you start channeling matter#n.\n\r",ch);
  }
  else if (!str_prefix(arg1,"will")) 
  {
    if (atoi(arg2) > ch->pcdata->powers[FAE_WILL])
    {
      send_to_char("You can't channel faster than your current level.\n\r",ch);
      return;
    }
    ch->pcdata->powers[FAE_WILL_GROWTH] = atoi(arg2);
    if (ch->pcdata->powers[FAE_WILL_TICK] == 0)
      ch->pcdata->powers[FAE_WILL_TICK] = atoi(arg2);
    send_to_char("#pOk, you start concentrating your willpower#n.\n\r",ch);
  }
  else if (!str_prefix(arg1,"plasma"))
  {
    if (atoi(arg2) > ch->pcdata->powers[FAE_PLASMA])
    {
      send_to_char("You can't channel faster than your current level.\n\r",ch);
      return;
    }
    ch->pcdata->powers[FAE_PLASMA_GROWTH] = atoi(arg2);
    if (ch->pcdata->powers[FAE_PLASMA_TICK] == 0)    
      ch->pcdata->powers[FAE_PLASMA_TICK] = atoi(arg2);
    send_to_char("#pOk, you start channeling plasma.#n\n\r",ch);
  }
  else if (!str_prefix(arg1,"energy"))
  {
    if (atoi(arg2) > ch->pcdata->powers[FAE_ENERGY])
    {
      send_to_char("You can't channel faster than your current level.\n\r",ch);
      return;
    }
    ch->pcdata->powers[FAE_ENERGY_GROWTH] = atoi(arg2);
    if (ch->pcdata->powers[FAE_ENERGY_TICK] == 0)
      ch->pcdata->powers[FAE_ENERGY_TICK] = atoi(arg2);
    send_to_char("#pOk, you start channeling energy.#n\n\r",ch);
  }
  else send_to_char("You cannot channel that.\n\r",ch);
  return;
}

void do_infuse(CHAR_DATA *ch, char *argument)
{
  CHAR_DATA *victim;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  int dam,i,sn;

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );

  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("Huh?\n\r",ch);
    return;
  }
  if (arg1[0] == '\0')
  {
    send_to_char("Infuse what into whom?\n\r",ch);
    return;
  }
  if (!str_prefix(arg1,"matter"))
  {
    if (ch->pcdata->powers[FAE_MATTER_TICK] == 0)
    {
      send_to_char("Your not charging matter.\n\r",ch);
      return;
    }
    if (ch->pcdata->powers[FAE_SHIELD] > 0)
    {
      send_to_char("Your shield still exists.\n\r",ch);
      return;
    }
    send_to_char("You weave a shield of charged matter from the fabric of the arcane.\n\r",ch);
    act("$n mutters a series of arcane words and weaves a shimmering shield around $m.",  ch, NULL, NULL, TO_ROOM);
    ch->pcdata->powers[FAE_SHIELD] = ch->pcdata->powers[FAE_MATTER_TICK]*7; // turns on the shield.
    ch->pcdata->powers[FAE_MATTER_TICK] = 0;
    ch->pcdata->powers[FAE_MATTER_GROWTH] = 0;
    WAIT_STATE(ch,12);
    return;
  }
  if (arg2[0] == '\0' && ch->fighting != NULL) victim = ch->fighting;
  else if ((victim = get_char_room(ch, NULL, arg2)) == NULL)
  {
    send_to_char("They are not here.\n\r", ch );
    return;
  }
  if (is_safe(ch,victim)) return;
  if (!str_prefix(arg1,"energy"))
  {
    if (ch->pcdata->powers[FAE_ENERGY_TICK] == 0)
    {
      send_to_char("Your not charging energy.\n\r",ch);
      return;
    }
    act("#pYour infuse $N's body with static energy, causing great pain.#n" ,ch,NULL,victim,TO_CHAR);
    act("#p$n#p touches you and chilling energies flow through your body.#n",ch,NULL,victim,TO_VICT);   
    act("#p$n#p touches $N, sending sparks flying.#n" ,ch,NULL,victim,TO_NOTVICT);
    dam = calculate_dam(ch,victim, FAE_ENERGY);
    damage(ch, victim, dam, gsn_lightning);
    ch->pcdata->powers[FAE_ENERGY_GROWTH] = 0;
    ch->pcdata->powers[FAE_ENERGY_TICK] = 0;
    WAIT_STATE(ch,6);
    return;
  }
  else if (!str_prefix(arg1,"plasma"))
  {
    if (ch->pcdata->powers[FAE_PLASMA_TICK] == 0)
    {
      send_to_char("Your not charging plasma.\n\r",ch);
      return;
    }
    act("#pYour body pulsates as you channel pure plasma into $N.#n" ,ch,NULL,victim,TO_CHAR);
    act("#p$n#p's body pulsates as $e channels pure plasma into you.#n",ch,NULL,victim,TO_VICT);
    act("#p$n#p's body pulsates as $e channels pure plasma into $N.#n" ,ch,NULL,victim,TO_NOTVICT);
    dam = calculate_dam(ch,victim, FAE_PLASMA);
    for (i = 0; i < ch->pcdata->powers[FAE_PLASMA_TICK]; i++)
    {
      damage(ch, victim, dam, gsn_plasma);
      dam *= 0.9;
    }
    ch->pcdata->powers[FAE_PLASMA_GROWTH] = 0;
    ch->pcdata->powers[FAE_PLASMA_TICK] = 0;
    WAIT_STATE(ch,12);
    return;
  }
  else if (!str_prefix(arg1,"will"))
  {
    if (ch->pcdata->powers[FAE_WILL_TICK] == 0)
    {
      send_to_char("Your not trying to concentrate your will.\n\r",ch);
      return;
    }
    act("#pYou bend the laws of gravity with your will and slam $N#p with stones, following up with a few spells.#n" ,ch,NULL,victim,TO_CHAR);
    act("#p$n#p stares at you while muttering a few arcane words.#n",ch,NULL,victim,TO_VICT);
    act("#pStones fly from the ground and slams into you while\n\r$n#p continues with the spellcasting.#n",ch,NULL,victim,TO_VICT);
    act("#pstones fly from the gound and slams into $N while\n\r$n#p mutters some arcane phrases.#n" ,ch,NULL,victim,TO_NOTVICT);
    for (i = 0; i < ch->pcdata->powers[FAE_WILL_TICK]; i+=2)
    {
      dam = calculate_dam(ch,victim, FAE_WILL);
      damage(ch, victim, dam, gsn_telekinetic);
    }
    if ((sn = skill_lookup( "curse" ) ) > 0) (*skill_table[sn].spell_fun) (sn,50,ch,victim);
    if ((sn = skill_lookup( "web" ) ) > 0) (*skill_table[sn].spell_fun) (sn,50,ch,victim);
    ch->pcdata->powers[FAE_WILL_GROWTH] = 0;
    ch->pcdata->powers[FAE_WILL_TICK] = 0;
    WAIT_STATE(ch,12);
    return;
  }
  else send_to_char("You have no idea how to infuse that.\n\r",ch);
  return;
}

void do_conjurebow(CHAR_DATA *ch, char *argument)
{
  OBJ_INDEX_DATA *pObjIndex;
  OBJ_DATA *obj;   
  AFFECT_DATA paf;
  char arg[MAX_INPUT_LENGTH];
  int vnum = 33260;
  int cost;

  argument = one_argument( argument, arg );
  if (IS_NPC(ch)) return;
  if( !IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("What?\n\r",ch);
    return;
  }
  if (arg[0] == '\0')
  {
    send_to_char("How much bones do you want to spend on the bow (max 20K) ?\n\r",ch);
    return;
  }
  if (!is_number(arg))
  {
    send_to_char("A number please.\n\r",ch);
    return;
  }
  cost = atoi(arg);
  if (cost < 1000 || cost > 20000)
  {
    send_to_char("between 1K and 20K please.\n\r",ch);
    return;
  }
  if (ch->bones < cost)
  {
    send_to_char("You don't have that many qps.\n\r",ch);
    return;
  }
  if ((pObjIndex = get_obj_index( vnum )) == NULL)
  {
    send_to_char("Missing object, please inform a God.\n\r",ch);
    return;
  }
  obj = create_object(pObjIndex, 50);
  obj->questowner = str_dup(ch->pcdata->switchname);
  obj->ownerid = ch->pcdata->playerid;
  if (cost > 19000)
  {
    obj->value[1] = 60;
    obj->value[2] = 90;
  }
  else if (cost > 15000)
  {
    obj->value[1] = 50;
    obj->value[2] = 80;
  }
  else if (cost > 10000)
  {
    obj->value[1] = 50;
    obj->value[2] = 70;
  }
  else if (cost > 5000)
  {
    obj->value[1] = 40;
    obj->value[2] = 60;
  }
  else
  {
    obj->value[1] = 30;
    obj->value[2] = 50;
  }

  paf.type           = 0;
  paf.duration       = -1; 
  paf.location       = APPLY_HITROLL;
  paf.modifier       = cost/40;
  paf.bitvector      = 0;
  affect_to_obj(obj, &paf);

  paf.type           = 0;
  paf.duration       = -1;
  paf.location       = APPLY_DAMROLL;
  paf.modifier       = cost/40;
  paf.bitvector      = 0;
  affect_to_obj(obj, &paf);

  paf.type           = 0;
  paf.duration       = -1;
  paf.location       = APPLY_AC;
  paf.modifier       = -cost/30;
  paf.bitvector      = 0;
  affect_to_obj(obj, &paf);

  obj_to_char(obj, ch);
  ch->bones -= cost;
  act("You stretch your mind into the plane of energy and draw $p directly from the weave of energy.",ch,obj,NULL,TO_CHAR);
  act("$p appears in $n's hands in a flash of energy.",ch,obj,NULL,TO_ROOM);
  return;
}

void do_ancients(CHAR_DATA *ch, char *argument)
{
  char buf[MAX_STRING_LENGTH];
  char arg[MAX_INPUT_LENGTH];
  int new_power;
  int cost = 2000000; // 2 million

  argument = one_argument( argument, arg );

  if (IS_NPC(ch)) return;
  if( !IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("What?\n\r",ch);
    return;
  }
  if (arg[0] == '\0')
  {
    xprintf(buf,"#pPlasma  #G[#Y%d#G]   #pMatter    #G[#Y%d#G]   #pEnergy   #G[#Y%d#G]   #pWill   #G[#Y%d#G]#n\n\r",
      ch->pcdata->powers[FAE_PLASMA], ch->pcdata->powers[FAE_MATTER],
      ch->pcdata->powers[FAE_ENERGY], ch->pcdata->powers[FAE_WILL]);
    send_to_char(buf,ch);
    send_to_char("\n\r#p        Which ancient would you like to improve?#n\n\r",ch);
    return;
  }
  if (!str_cmp(arg,"plasma")) new_power = FAE_PLASMA;
  else if (!str_cmp(arg,"will")) new_power = FAE_WILL;
  else if (!str_cmp(arg,"energy")) new_power = FAE_ENERGY;
  else if (!str_cmp(arg,"matter")) new_power = FAE_MATTER;
  else
  {
    send_to_char("No such ancients.\n\r",ch);
    return;
  }
  if (ch->pcdata->powers[new_power] > 7)
  {
    send_to_char("You know it all, your the champ.\n\r",ch);
    return;
  }
  if (ch->wpn[6] < (ch->pcdata->powers[new_power]+1)*100)
  {
    send_to_char("Your blasting powers are not good enough.\n\r",ch);
    return;
  }
  cost = cost * (ch->pcdata->powers[new_power]+1) * (ch->pcdata->powers[new_power]+1);
  if (ch->exp < cost)
  {
    xprintf(buf,"You need %d more exp to gain that ancient.\n\r", cost - ch->exp);
    send_to_char(buf,ch);
    return;
  }
  ch->exp -= cost;
  ch->pcdata->powers[new_power]++;
  send_to_char("Ok.\n\r",ch);
  return;
}

void do_will(CHAR_DATA *ch, char *argument)
{
  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("Huh?\n\r",ch);
    return;
  }
  if (ch->pcdata->powers[FAE_WILL] < 8)
  {
    send_to_char("You have not mastered your own will yet.\n\r",ch);
    return;
  }
  if (IS_SET(ch->affected_by, AFF_FLYING))
  {
    REMOVE_BIT(ch->affected_by, AFF_FLYING);
    send_to_char("You release your control and float slowly to the ground.\n\r",ch);
  }
  else
  {
    SET_BIT(ch->affected_by, AFF_FLYING);
    send_to_char("You concentrate on the forces of gravity, and slowly float into the air.\n\r",ch);
  }
  WAIT_STATE(ch, 8);
  return;
}

void do_matter(CHAR_DATA *ch, char *argument)
{
  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("Huh?\n\r",ch);
    return;
  }
  if (ch->pcdata->powers[FAE_MATTER] < 8)
  {
    send_to_char("Your control over matter is to weak.\n\r",ch);
    return;
  }
  if (IS_AFFECTED(ch, AFF_SANCTUARY))
  {
    REMOVE_BIT(ch->affected_by, AFF_SANCTUARY);
    send_to_char("No longer needing the shield, you disband it.\n\r",ch);
  }
  else
  {
    SET_BIT(ch->affected_by, AFF_SANCTUARY);
    send_to_char("You bend the fabric of space to form a shimmering shield around you.\n\r",ch);
  }
  WAIT_STATE(ch,8);
  return;
}  

void do_energy(CHAR_DATA *ch, char *argument)
{
  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("Huh?\n\r",ch);
    return;
  }
  if (ch->pcdata->powers[FAE_ENERGY] < 8)
  {
    send_to_char("You cannot harness the energy yet.\n\r",ch);
    return;
  }
  if (IS_SET(ch->itemaffect, ITEMA_CHAOSSHIELD))
  {
    if(IS_ITEMAFF(ch, ITEMA_FIRESHIELD))
      REMOVE_BIT(ch->itemaffect, ITEMA_FIRESHIELD);
    if(IS_ITEMAFF(ch, ITEMA_ACIDSHIELD))
      REMOVE_BIT(ch->itemaffect, ITEMA_ACIDSHIELD);
    if(IS_ITEMAFF(ch, ITEMA_SHOCKSHIELD))
      REMOVE_BIT(ch->itemaffect, ITEMA_SHOCKSHIELD);
    if(IS_ITEMAFF(ch, ITEMA_ICESHIELD))
      REMOVE_BIT(ch->itemaffect, ITEMA_ICESHIELD);
    if(IS_ITEMAFF(ch, ITEMA_CHAOSSHIELD))
      REMOVE_BIT(ch->itemaffect, ITEMA_CHAOSSHIELD);
    REMOVE_BIT(ch->itemaffect, ITEMA_CHAOSHANDS);
    send_to_char("Your shields flicker and die.\n\r",ch);
  }
  else   
  {
    if(!IS_ITEMAFF(ch, ITEMA_FIRESHIELD))
      SET_BIT(ch->itemaffect, ITEMA_FIRESHIELD);
    if(!IS_ITEMAFF(ch, ITEMA_ACIDSHIELD))
      SET_BIT(ch->itemaffect, ITEMA_ACIDSHIELD);
    if(!IS_ITEMAFF(ch, ITEMA_SHOCKSHIELD))
      SET_BIT(ch->itemaffect, ITEMA_SHOCKSHIELD);
    if(!IS_ITEMAFF(ch, ITEMA_ICESHIELD))
      SET_BIT(ch->itemaffect, ITEMA_ICESHIELD);
    if(!IS_ITEMAFF(ch, ITEMA_CHAOSSHIELD))
      SET_BIT(ch->itemaffect, ITEMA_CHAOSSHIELD);
    SET_BIT(ch->itemaffect, ITEMA_CHAOSHANDS);
    send_to_char("You form shields of different colors, each representing the different energies in the universe.\n\r",ch);
  }
  WAIT_STATE(ch, 8);
  return;
}  

void do_plasma2(CHAR_DATA *ch, char *argument)
{
  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("Huh?\n\r",ch);
    return;
  }
  if (ch->pcdata->powers[FAE_PLASMA] < 8)
  {
    send_to_char("The plasma refuse to do your bidding.\n\r",ch);
    return;
  }
  if (IS_AFFECTED(ch, AFF_PROTECT) || IS_AFFECTED(ch, AFF_PROTECT_GOOD))
  {
    if (IS_SET(ch->affected_by, AFF_PROTECT)) REMOVE_BIT(ch->affected_by, AFF_PROTECT);
    if (IS_SET(ch->affected_by, AFF_PROTECT_GOOD)) REMOVE_BIT(ch->affected_by, AFF_PROTECT_GOOD);
    send_to_char("You call off your shield of protection.\n\r",ch);
  }
  else
  {
    if (IS_GOOD(ch))
    {
      SET_BIT(ch->affected_by, AFF_PROTECT);
      send_to_char("You summon a mystical force to protect you from evil.\n\r",ch);
    }
    else if (IS_EVIL(ch))
    {
      SET_BIT(ch->affected_by, AFF_PROTECT_GOOD);
      send_to_char("You summon a mystical force to protect you from good.\n\r",ch);
    }
    else send_to_char("Nothing happens.\n\r",ch);
  }
  WAIT_STATE(ch, 8);
  return;
}  

int calculate_dam(CHAR_DATA *ch, CHAR_DATA *victim, int type)
{
  int dam = 0;

  dam += char_damroll(ch)/5;
  if (type == FAE_PLASMA)
  {
    dam *= 1 + ch->pcdata->powers[FAE_PLASMA]/4;
    dam *= ch->pcdata->powers[FAE_PLASMA_TICK]/1.3;
  }
  else if (type == FAE_ENERGY)
  {
    dam *= 1 + ch->pcdata->powers[FAE_ENERGY]/2;
    dam *= ch->pcdata->powers[FAE_ENERGY_TICK]*1.5;
  }
  else if (type == FAE_WILL)
  {
    dam *= 1 + ch->pcdata->powers[FAE_WILL]/4;
    dam *= ch->pcdata->powers[FAE_WILL_TICK]/1.8;
  }
  dam = number_range(dam/3, dam/2);
  if (dam > ch->damcap[DAM_CAP]) dam = ch->damcap[DAM_CAP] + number_range(-100,100);
  if (IS_AFFECTED(victim, AFF_SANCTUARY)) dam /= 2;
  return dam;
}

void do_djinn(CHAR_DATA *ch, char *argument)
{
  MOB_INDEX_DATA *pMobIndex;
  MOB_TRIGGER *mProg;
  CHAR_DATA *mob;
  ROOM_INDEX_DATA *pRoom;
  int vnum;

  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("Huh?\n\r", ch);
    return;
  }
  if (ch->power[DISC_FAE_NATURE] < 8)
  {
    send_to_char("You need at least level 8 in nature to summon The Djinn.\n\r",ch);
    return;
  }
  if (!TIME_UP(ch, TIMER_DJINN))
  {
    send_to_char("You can only summon the djinn once every 24 hours.\n\r", ch);
    return;
  }
  if ((pRoom = get_room_index(3001)) == NULL) return;
  if (pRoom->area == ch->in_room->area)
  {
    send_to_char("This power cannot function in midgaard.\n\r", ch);
    return;
  }
  if ((pMobIndex = get_mob_index(20)) == NULL)
  {
    send_to_char("Bug, please report this to an immortal.\n\r", ch);
    return;
  }
  SET_TIMER(ch, TIMER_DJINN, 24);
  mob = create_mobile(pMobIndex);
  mob->decay_pulse = number_range(4, 8);

  for (vnum = ch->in_room->area->lvnum; vnum <= ch->in_room->area->uvnum; vnum++)
  {
    if ((pMobIndex = get_mob_index(vnum)) != NULL)
    {
      if (trigger_free == NULL)
      {
        mProg             = alloc_perm(sizeof(*mProg));
      }
      else
      {
        mProg             = trigger_free;
        trigger_free      = trigger_free->next;
      }
      mProg->type         = MTRIG_SAY;
      mProg->vnum         = 0;
      mProg->keywords     = str_dup(get_keywords_from_mob(pMobIndex));
      mProg->roomOutput   = str_dup(get_description_from_mob(pMobIndex));
      mProg->chOutput     = str_dup("");
      mProg->next         = mob->triggers;
      mob->triggers       = mProg;
    }
  }
  char_to_room(mob, ch->in_room);
  do_say(ch, "Oh mighty djinn of the seven ages, I bid you to join my service");
  act("$n appears in a puff of smoke.", mob, NULL, NULL, TO_ROOM);
  do_say(mob, "I come to do your bidding master.");
  return;
}

void do_genie(CHAR_DATA *ch, char *argument)
{
  MOB_INDEX_DATA *pMobIndex;
  MOB_TRIGGER *mProg;
  CHAR_DATA *mob;

  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_FAE))
  {
    send_to_char("Huh?\n\r", ch);
    return;
  }
  if (ch->power[DISC_FAE_ARCANE] < 8)
  {
    send_to_char("You need at least level 8 in arcane to summon The Genie.\n\r",ch);
    return;
  }
  if (!TIME_UP(ch, TIMER_GENIE))
  {
    send_to_char("You can only summon The Genie once every 24 hours.\n\r", ch);
    return;
  }
  if ((pMobIndex = get_mob_index(21)) == NULL)
  {
    send_to_char("Bug, please report this to an immortal.\n\r", ch);
    return;
  }
  SET_TIMER(ch, TIMER_GENIE, 24);
  mob = create_mobile(pMobIndex);
  mob->decay_pulse = number_range(4, 8);

/*
  if (trigger_free == NULL)
  {
    mProg             = alloc_perm(sizeof(*mProg));
  }
  else
  {
    mProg             = trigger_free;
    trigger_free      = trigger_free->next;
  }
  mProg->type         = MTRIG_SCRY;
  mProg->vnum         = 0;
  mProg->keywords     = str_dup("&scry*");
  mProg->roomOutput   = str_dup("");
  mProg->chOutput     = str_dup("");
  mProg->next         = mob->triggers;
  mob->triggers       = mProg;
*/

  if (trigger_free == NULL)
  {
    mProg             = alloc_perm(sizeof(*mProg));
  }
  else
  {
    mProg             = trigger_free;
    trigger_free      = trigger_free->next;
  }
  mProg->type         = MTRIG_LOCATE;
  mProg->vnum         = 0;
  mProg->keywords     = str_dup("&locate*");
  mProg->roomOutput   = str_dup("I suggest you walk the following path, '%s'.");
  mProg->chOutput     = str_dup("I'm afraid I cannot locate that person master.");
  mProg->next         = mob->triggers;
  mob->triggers       = mProg;

  char_to_room(mob, ch->in_room);
  do_say(ch, "Oh mighty genie, bloodson to the Prince of the East, head my call");
  act("$n appears in a puff of smoke.", mob, NULL, NULL, TO_ROOM);
  do_say(mob, "Ask your questions mortal, before I bid you goodbye.");
  return;
}

char *get_keywords_from_mob(MOB_INDEX_DATA *pMob)
{
  static char buf[MAX_STRING_LENGTH];
  char *ptr, *ptr2, *ptr3;

  buf[0] = '\0';

  ptr = pMob->player_name;
  ptr2 = buf;
  ptr3 = "&what*|";

  while ((*ptr2 = *ptr3) != '\0')
    ++ptr2, ++ptr3;

  while (*ptr != '\0')
  {
    if (*ptr != ' ') *ptr2 = *ptr;
    else
    {
      *ptr2 = '*';
    }
    ptr++; ptr2++;
  }
  *ptr2 = '*'; ptr2++; *ptr2 = '\0';

  return buf;
}

char *mob_might(MOB_INDEX_DATA *pMob)
{
  static char buf[MAX_STRING_LENGTH];

  if (pMob->level < 100)
    xprintf(buf, "a pitiful creature");
  else if (pMob->level < 250)
    xprintf(buf, "a dangerous creature");
  else if (pMob->level < 500)
    xprintf(buf, "a fierce beast");
  else if (pMob->level < 1000)
    xprintf(buf, "a mighty beast");
  else
    xprintf(buf, "a powerful being");

  return buf;
}
    
char *mob_toughness(MOB_INDEX_DATA *pMob)
{
  static char buf[MAX_STRING_LENGTH];

  if (pMob->toughness < - 50)
    xprintf(buf, "a frail body");
  else if (pMob->toughness < 0)
    xprintf(buf, "a weak body");
  else if (pMob->toughness < 25)
    xprintf(buf, "a normal toughness");
  else if (pMob->toughness < 50)
    xprintf(buf, "increased toughness");
  else
    xprintf(buf, "superior toughness");
  return buf;
}
   
char *mob_attacks(MOB_INDEX_DATA *pMob)
{
  static char buf[MAX_STRING_LENGTH];

  if (pMob->extra_attack < 1)
    xprintf(buf, "a few");
  else if (pMob->extra_attack < 5)
    xprintf(buf, "some");
  else if (pMob->extra_attack < 10)  
    xprintf(buf, "many");
  else if (pMob->extra_attack < 15)
    xprintf(buf, "increadible many");
  else
    xprintf(buf, "a huge amount of");

  return buf;
}
 
char *mob_damage(MOB_INDEX_DATA *pMob)
{
  static char buf[MAX_STRING_LENGTH];
  
  if (pMob->dam_modifier < 2)
    xprintf(buf, "a normal amount of");
  else if (pMob->dam_modifier == 2)
    xprintf(buf, "an increased amount of");
  else if (pMob->dam_modifier > 2)
    xprintf(buf, "a huge amount of");

  return buf;
} 

char *get_description_from_mob(MOB_INDEX_DATA *pMob)
{
  static char buf[MAX_STRING_LENGTH];

  xprintf(buf, "%s is %s with %s. It has %s attacks, each dealing %s damage.",
    pMob->short_descr, mob_might(pMob), mob_toughness(pMob), mob_attacks(pMob), mob_damage(pMob));
  return buf;
}

char *cut_after_tracking(char *str)
{
  static char buf[MAX_STRING_LENGTH];
  char *ptr;
  bool found = FALSE;

  buf[0] = '\0';
  ptr = buf;

  if (!is_contained2(" tracking ", str)) return NULL;

  for (;;)
  {
    while (*str != ' ') str++;
    str++;

    while (*str != '\0' && *str != ' ')
    {
      *ptr = *str;
      ptr++; str++;
    }
    *ptr = '\0';

    if (found) return buf;
    if (!str_cmp(buf, "tracking"))
      found = TRUE;

    buf[0] = '\0';
    ptr = buf;
  }
  return buf;
}

char *cut_after_locate(char *str)
{
  static char buf[MAX_STRING_LENGTH];
  char *ptr;
  bool found = FALSE;

  buf[0] = '\0';
  ptr = buf;

  if (!is_contained2(" locate ", str)) return NULL;

  for (;;)
  {
    while (*str != ' ') str++;
    str++;

    while (*str != '\0' && *str != ' ')
    {
      *ptr = *str;
      ptr++; str++;
    }
    *ptr = '\0';

    if (found) return buf;
    if (!str_cmp(buf, "locate"))
      found = TRUE;

    buf[0] = '\0';
    ptr = buf;
  }
  return buf;
}

char *cut_after_scry(char *str)
{
  static char buf[MAX_STRING_LENGTH];
  char *ptr;
  bool found = FALSE;
  
  buf[0] = '\0';
  ptr = buf;
  
  if (!is_contained2(" scry ", str)) return NULL;
  
  for (;;)
  {
    while (*str != ' ') str++;
    str++;
    
    while (*str != '\0' && *str != ' ')
    {
      *ptr = *str;
      ptr++; str++;
    }
    *ptr = '\0';
 
    if (found) return buf;
    if (!str_cmp(buf, "scry"))
      found = TRUE;
      
    buf[0] = '\0';
    ptr = buf;
  }
  return buf;
}