deltamud/deltamud/
deltamud/deltamud/bin/
deltamud/deltamud/cnf/
deltamud/deltamud/lib/
deltamud/deltamud/lib/etc/
deltamud/deltamud/lib/misc/
deltamud/deltamud/lib/plrobjs/
deltamud/deltamud/lib/text/
deltamud/deltamud/lib/text/help/
deltamud/deltamud/lib/world/
deltamud/deltamud/lib/world/trg/
/* ************************************************************************
   *   File: spells.c                                      Part of CircleMUD *
   *  Usage: Implementation of "manual spells".  Circle 2.2 spell compat.    *
   *                                                                         *
   *  All rights reserved.  See license.doc for complete information.        *
   *                                                                         *
   *  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
   *  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
   ************************************************************************ */


#include "conf.h"
#include "sysdep.h"

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "spells.h"
#include "handler.h"
#include "db.h"
#include "interpreter.h"
#include "house.h"

extern int arena_zone;
extern int arena_preproom;
extern int arena_observeroom;
extern int arena_combatant;
extern int arena_observer;
extern int arena_flee_timeout;
extern struct char_data *arenamaster;
extern struct room_data *world;
extern struct obj_data *object_list;
extern struct char_data *character_list;
extern struct cha_app_type cha_app[];
extern struct int_app_type int_app[];
extern struct index_data *obj_index;

extern struct descriptor_data *descriptor_list;
extern struct zone_data *zone_table;

struct house_control_rec house_control[MAX_HOUSES];
int num_of_houses;

extern int mini_mud;
extern int pk_allowed;

extern struct default_mobile_stats *mob_defaults;
extern char weapon_verbs[];
extern int *max_ac_applys;
extern struct apply_mod_defaults *apmd;

extern char *dirs[];
void clearMemory (struct char_data *ch);
void act (char *str, int i, struct char_data *c, struct obj_data *o,
	  void *vict_obj, int j);

void damage (struct char_data *ch, struct char_data *victim,
	     int damage, int weapontype);

void match_over(struct char_data *, struct char_data *, char *, int);
void weight_change_object (struct obj_data *obj, int weight);
void add_follower (struct char_data *ch, struct char_data *leader);
int mag_savingthrow (struct char_data *ch, struct char_data *victim);
char* numdisplay(int);
int find_house (room_vnum vnum);

/*
 * Special spells appear below.
 */

ASPELL (spell_create_water)
{
  int water;

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

  if (ch == NULL || obj == NULL)
    return;
  level = MAX (MIN (level, LVL_IMPL), 1);

  if (GET_OBJ_TYPE (obj) == ITEM_DRINKCON)
    {
      if ((GET_OBJ_VAL (obj, 2) != LIQ_WATER) && (GET_OBJ_VAL (obj, 1) != 0))
	{
	  name_from_drinkcon (obj);
	  GET_OBJ_VAL (obj, 2) = LIQ_SLIME;
	  name_to_drinkcon (obj, LIQ_SLIME);
	}
      else
	{
	  water = MAX (GET_OBJ_VAL (obj, 0) - GET_OBJ_VAL (obj, 1), 0);
	  if (water > 0)
	    {
	      if (GET_OBJ_VAL (obj, 1) >= 0)
		name_from_drinkcon (obj);
	      GET_OBJ_VAL (obj, 2) = LIQ_WATER;
	      GET_OBJ_VAL (obj, 1) += water;
	      name_to_drinkcon (obj, LIQ_WATER);
	      weight_change_object (obj, water);
	      act ("$p is filled.", FALSE, ch, obj, 0, TO_CHAR);
	    }
	}
    }
}


ASPELL (spell_recall)
{
  extern long mortal_start_room[NUM_STARTROOMS + 1]; 
  /*  extern long r_mortal_start_room[NUM_STARTROOMS + 1]; */
  char mybuf[1024];
  struct char_data *victor;
  int home;

  home = GET_HOME(ch);
  if (!(home >= 1 && home <= NUM_STARTROOMS)){
    sprintf(mybuf, "DEBUG: Recall Trigger - %s GET_HOME is %d (invalid)",
	    GET_NAME(ch), home);
    mudlog(mybuf, NRM, LVL_GRGOD, TRUE);
    home = 0;
  }

  if (victim == NULL || IS_NPC (victim))
    return;

  if (RIDING(victim) || RIDDEN_BY(victim)) {
  send_to_char("The spell fails because your victim is atop a mount.\r\n", ch);
  return;  
  }

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

  if (IS_ARENACOMBATANT(victim)){
    victor = FIGHTING(victim);
    sprintf(mybuf, "(Recalled)");
    if (GET_ARENAFLEETIMER(victim) >= 1 
	&& GET_ARENAFLEETIMER(victim) <= 1+arena_flee_timeout){
      victor = LASTFIGHTING(victim);
      send_to_char("You recalled before the flee-recall timer expired.\r\n"
		   "You have conceded the match!\r\n", victim);
      sprintf(mybuf, "(Fled & Recalled)");
      GET_ARENAFLEETIMER(victim) = 0;
    }
    match_over(victor, victim, mybuf, FALSE);
    char_from_room (victim);
    char_to_room (victim, real_room (arena_preproom));
    act ("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
    look_at_room (victim, 0);
    return;
  }

  char_from_room (victim);
  if (GET_ARENASTAT(victim) == ARENA_OBSERVER){
    char_to_room (victim, real_room (arena_observeroom));
    act ("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
    look_at_room (victim, 0);
    return;
  }

  if (home == 0) {
    char_to_room (victim, real_room (mortal_start_room[1]));
    act ("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
    look_at_room (victim, 0);
  } else {
    char_to_room (victim, real_room (mortal_start_room[home]));
    act ("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
    look_at_room (victim, 0);
  }
}


ASPELL (spell_teleport)
{
  int to_room;
  extern int top_of_world;

  if (victim != NULL)
    return;

  do
    {
      to_room = number (0, top_of_world);
    }
  while (ROOM_FLAGGED (to_room, ROOM_PRIVATE | ROOM_DEATH));

  act ("$n slowly fades out of existence and is gone.",
       FALSE, victim, 0, 0, TO_ROOM);
  char_from_room (victim);
  char_to_room (victim, to_room);
  act ("$n slowly fades into existence.", FALSE, victim, 0, 0, TO_ROOM);
  look_at_room (victim, 0);
}

#define SUMMON_FAIL "You failed.\r\n"

ASPELL (spell_summon)
{
  extern int real_zone(int number);
  extern struct index_data *mob_index;
  if (ch == NULL || victim == NULL)
    return;

  if (GET_LEVEL (victim) > MIN (LVL_IMMORT - 1, level + 3))
    {
      send_to_char (SUMMON_FAIL, ch);
      return;
    }
  if (IS_NPC(victim))
    if (real_zone(GET_MOB_VNUM(victim))!=-1)
      if (zone_table[real_zone(GET_MOB_VNUM(victim))].status_mode==0) {
        send_to_char(SUMMON_FAIL, ch);
        return;
      }
 if (GET_ARENASTAT(victim) != ARENA_NOT && GET_ARENASTAT(ch) == ARENA_NOT){
   send_to_char ("Your target is in the arena right now.\r\n"
		 "Eldrich magic obstructs thee!\r\n", ch);
   return;
 }
 if (GET_ARENASTAT(victim) == ARENA_NOT && GET_ARENASTAT(ch) != ARENA_NOT){
   send_to_char ("You're in the arena right now whereas your target is not.\r\n"
		 "Eldrich magic obstructs thee!\r\n", ch);
   return;
 }

/*  if (!pk_allowed)
 *   { */
      if (MOB_FLAGGED (victim, MOB_AGGRESSIVE))
	{
	  act ("As the words escape your lips and $N travels\r\n"
	    "through time and space towards you, you realize that $E is\r\n"
	       "aggressive and might harm you, so you wisely send $M back.",
	       FALSE, ch, 0, victim, TO_CHAR);
	  return;
	}
      if (!IS_NPC (victim) && !PRF_FLAGGED (victim, PRF_SUMMONABLE))
	/* && !PLR_FLAGGED (victim, PLR_KILLER)) */
	{
	  sprintf (buf, "%s just tried to summon you to: %s.\r\n"
		   "%s failed because you have summon protection on.\r\n"
		   "Type NOSUMMON to allow other players to summon you.\r\n",
		   GET_NAME (ch), world[ch->in_room].name,
		   (ch->player.sex == SEX_MALE) ? "He" : "She");
	  send_to_char (buf, victim);

	  sprintf (buf, "You failed because %s has summon protection on.\r\n",
		   GET_NAME (victim));
	  send_to_char (buf, ch);

	  sprintf (buf, "%s failed summoning %s to %s.",
		 GET_NAME (ch), GET_NAME (victim), world[ch->in_room].name);
	  mudlog (buf, BRF, LVL_IMMORT, TRUE);
	  return;
/*	} */
    }

  if (MOB_FLAGGED (victim, MOB_NOSUMMON) ||
      (IS_NPC (victim) && mag_savingthrow (ch, victim)))
    {
      send_to_char (SUMMON_FAIL, ch);
      return;
    }

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

  char_from_room (victim);
  char_to_room (victim, ch->in_room);

  act ("$n arrives suddenly.", TRUE, victim, 0, 0, TO_ROOM);
  act ("$n has summoned you!", FALSE, ch, 0, victim, TO_VICT);
  look_at_room (victim, 0);
}



ASPELL (spell_locate_object)
{
  struct obj_data *i;
  char name[MAX_INPUT_LENGTH];
  int j;

  strcpy (name, fname (obj->name));
  j = level >> 1;

  for (i = object_list; i && (j > 0); i = i->next)
    {
      if (!is_name (name, i->name))
	continue;

      if (i->carried_by)
	sprintf (buf, "%s is being carried by %s.\n\r",
		 i->short_description, PERS (i->carried_by, ch));
      else if (i->in_room != NOWHERE)
	sprintf (buf, "%s is in %s.\n\r", i->short_description,
		 world[i->in_room].name);
      else if (i->in_obj)
	sprintf (buf, "%s is in %s.\n\r", i->short_description,
		 i->in_obj->short_description);
      else if (i->worn_by)
	sprintf (buf, "%s is being worn by %s.\n\r",
		 i->short_description, PERS (i->worn_by, ch));
      else
	sprintf (buf, "%s's location is uncertain.\n\r",
		 i->short_description);

      CAP (buf);
      send_to_char (buf, ch);
      j--;
    }

  if (j == level >> 1)
    send_to_char ("You sense nothing.\n\r", ch);
}



ASPELL (spell_charm)
{
  struct affected_type af;

  if (victim == NULL || ch == NULL)
    return;

  if (victim == ch)
    send_to_char ("You like yourself even better!\r\n", ch);
  else if (!IS_NPC (victim) && !PRF_FLAGGED (victim, PRF_SUMMONABLE))
    send_to_char ("You fail because SUMMON protection is on!\r\n", ch);
  else if (IS_AFFECTED (victim, AFF_SANCTUARY))
    send_to_char ("Your victim is protected by sanctuary!\r\n", ch);
  else if (MOB_FLAGGED (victim, MOB_NOCHARM))
    send_to_char ("Your victim resists!\r\n", ch);
  else if (IS_AFFECTED (ch, AFF_CHARM))
    send_to_char ("You can't have any followers of your own!\r\n", ch);
  else if (IS_AFFECTED (victim, AFF_CHARM) || level < GET_LEVEL (victim))
    send_to_char ("You fail.\r\n", ch);
  /* player charming another player - no legal reason for this */
  else if (!pk_allowed && !IS_NPC (victim))
    send_to_char ("You fail - shouldn't be doing it anyway.\r\n", ch);
  else if (circle_follow (victim, ch))
    send_to_char ("Sorry, following in circles can not be allowed.\r\n", ch);
  else if (mag_savingthrow (ch, victim))
    send_to_char ("Your victim resists!\r\n", ch);
  else
    {
      if (victim->master)
	stop_follower (victim);

      add_follower (victim, ch);

      af.type = SPELL_CHARM;

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

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

      act ("Isn't $n just such a nice fellow?", FALSE, ch, 0, victim, TO_VICT);
      if (IS_NPC (victim))
	{
	  REMOVE_BIT (MOB_FLAGS (victim), MOB_AGGRESSIVE);
	  REMOVE_BIT (MOB_FLAGS (victim), MOB_SPEC);
	}
    }
}



ASPELL (spell_identify)
{
  int i;
  int found;
  int condition;

  struct time_info_data age (struct char_data *ch);

  extern char *spells[];

  extern char *item_types[];
  extern char *extra_bits[];
  extern char *apply_types[];
  extern char *affected_bits[];

  if (obj)
    {
      send_to_char ("You feel informed:\r\n", ch);
      sprintf (buf, "Object '%s', Item type: ", obj->short_description);
      sprinttype (GET_OBJ_TYPE (obj), (const char **) item_types, buf2);
      strcat (buf, buf2);
      strcat (buf, "\r\n");
      send_to_char (buf, ch);

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

      sprintf (buf, "Weight: %s, ",
	       numdisplay(GET_OBJ_WEIGHT (obj)));
      sprintf (buf, "%sValue: %s, ", buf,
	       numdisplay(GET_OBJ_COST (obj)));
      sprintf (buf, "%sRent: %s\r\n", buf,
	       numdisplay(GET_OBJ_RENT (obj)));

    send_to_char(buf, ch);

   if (GET_OBJ_TSLOTS(obj))
  condition = (GET_OBJ_CSLOTS(obj) * 100)/GET_OBJ_TSLOTS(obj);
    else
  condition = 0;

  if ((GET_OBJ_CSLOTS(obj) == 0) && (GET_OBJ_TSLOTS(obj) == 0)) {
        sprintf(buf, "Quality: INDESTRUCTABLE\r\n");
    send_to_char(buf, ch);
        }
       else
    if ((GET_LEVEL(ch) >= LVL_HERO)) {
        sprintf(buf, "Quality: %d/%d\r\nCondition: %d percent\r\n",
     GET_OBJ_CSLOTS(obj), GET_OBJ_TSLOTS(obj), condition);
    send_to_char(buf, ch);
        }
      else
    if ((condition <= 10)) {
        sprintf(buf, "Quality: Extremley Poor\r\n");
    send_to_char(buf, ch);
        }
      else
    if ((condition <= 20)) {
        sprintf(buf, "Quality: Poor\r\n");
    send_to_char(buf, ch);
        }
       else
    if ((condition <= 30)) {
        sprintf(buf, "Quality: Fair\r\n");
    send_to_char(buf, ch);
        }
     else
    if ((condition <= 40)) {
        sprintf(buf, "Quality: Moderate\r\n");
    send_to_char(buf, ch);
        }
     else
    if ((condition <= 50)) {
        sprintf(buf, "Quality: Good\r\n");
    send_to_char(buf, ch);
        }
     else
    if ((condition <= 60)) {
        sprintf(buf, "Quality: Very Good\r\n");
    send_to_char(buf, ch);
        }
     else
    if ((condition <= 70)) {
        sprintf(buf, "Quality: Excellent\r\n");
    send_to_char(buf, ch);
    }
    else
    if ((condition <= 80)) {
        sprintf(buf, "Quality: Superior\r\n");
    send_to_char(buf, ch);
    }
    else
  if ((condition <= 90)) {
        sprintf(buf, "Quality: Extremely Superior\r\n");
    send_to_char(buf, ch);
    }
   else
  if ((condition <= 100)) {
        sprintf(buf, "Quality: Brand New\r\n");
    send_to_char(buf, ch);
    }

      switch (GET_OBJ_TYPE (obj))
	{
	case ITEM_SCROLL:
	case ITEM_POTION:
	  sprintf (buf, "This %s casts: ", item_types[(int) GET_OBJ_TYPE (obj)]);

	  if (GET_OBJ_VAL (obj, 1) >= 1)
	    sprintf (buf, "%s %s", buf, spells[GET_OBJ_VAL (obj, 1)]);
	  if (GET_OBJ_VAL (obj, 2) >= 1)
	    sprintf (buf, "%s %s", buf, spells[GET_OBJ_VAL (obj, 2)]);
	  if (GET_OBJ_VAL (obj, 3) >= 1)
	    sprintf (buf, "%s %s", buf, spells[GET_OBJ_VAL (obj, 3)]);
	  sprintf (buf, "%s\r\n", buf);
	  send_to_char (buf, ch);
	  break;
	case ITEM_WAND:
	case ITEM_STAFF:
	  sprintf (buf, "This %s casts: ", item_types[(int) GET_OBJ_TYPE (obj)]);
	  sprintf (buf, "%s %s\r\n", buf, spells[GET_OBJ_VAL (obj, 3)]);
	  sprintf (buf, "%sIt has %d maximum charge%s and %d remaining.\r\n", buf,
		 GET_OBJ_VAL (obj, 1), GET_OBJ_VAL (obj, 1) == 1 ? "" : "s",
		   GET_OBJ_VAL (obj, 2));
	  send_to_char (buf, ch);
	  break;
	case ITEM_WEAPON:
	  sprintf (buf, "Damage Dice is '%dD%d'", GET_OBJ_VAL (obj, 1),
		   GET_OBJ_VAL (obj, 2));
	  sprintf (buf, "%s for an average per-round damage of %.1f.\r\n", buf,
	       (((GET_OBJ_VAL (obj, 2) + 1) / 2.0) * GET_OBJ_VAL (obj, 1)));
	  send_to_char (buf, ch);
	  break;
	case ITEM_ARMOR:
	  sprintf (buf, "Defense apply is %d\r\n", GET_OBJ_VAL (obj, 0));
	  send_to_char (buf, ch);
	  break;
	}
      found = FALSE;
      for (i = 0; i < MAX_OBJ_AFFECT; i++)
	{
	  if ((obj->affected[i].location != APPLY_NONE) &&
	      (obj->affected[i].modifier != 0))
	    {
	      if (!found)
		{
		  send_to_char ("Can affect you as :\r\n", ch);
		  found = TRUE;
		}
	      sprinttype (obj->affected[i].location, (const char **) apply_types, buf2);
	      sprintf (buf, "   Affects: %s By %d\r\n", buf2, obj->affected[i].modifier);
	      send_to_char (buf, ch);
	    }
	}
    }
  else if (victim)
    {				/* victim */
      sprintf (buf, "Name: %s\r\n", GET_NAME (victim));
      send_to_char (buf, ch);
      if (!IS_NPC (victim))
	{
	  sprintf (buf, "%s is %d years, %d months, %d days and %d hours old.\r\n",
                   GET_NAME (victim), (int) age (victim).year, (int) age (victim).month,
                   (int) age (victim).day, age (victim).hours);
	  send_to_char (buf, ch);
	}
      sprintf (buf, "Height %d cm, Weight %d pounds\r\n",
	       GET_HEIGHT (victim), GET_WEIGHT (victim));
      sprintf (buf, "%sLevel: %d, Hits: %d, Mana: %d\r\n", buf,
	       GET_LEVEL (victim), (int) GET_HIT (victim), (int) GET_MANA (victim));
      sprintf (buf, "%sPower: %d, Magic Power: %d, Defense: %d, Magic Defense: %d, Technique: %d\r\n", buf,
	       GET_POWER (victim), GET_MPOWER (victim), GET_DEFENSE (victim), GET_MDEFENSE(victim), GET_TECHNIQUE(victim));
      sprintf (buf, "%sStr: %d/%d, Int: %d, Wis: %d, Dex: %d, Con: %d, Cha: %d\r\n",
	       buf, GET_STR (victim), GET_ADD (victim), GET_INT (victim),
	       GET_WIS (victim), GET_DEX (victim), GET_CON (victim), GET_CHA (victim));
      send_to_char (buf, ch);

    }
}



ASPELL (spell_enchant_weapon)
{
  int i;

  if (ch == NULL || obj == NULL)
    return;

  if ((GET_OBJ_TYPE (obj) == ITEM_WEAPON) &&
      !IS_SET (GET_OBJ_EXTRA (obj), ITEM_MAGIC))
    {

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

      SET_BIT (GET_OBJ_EXTRA (obj), ITEM_MAGIC);

      obj->affected[0].location = APPLY_POWER;
      obj->affected[0].modifier = 1 + (level >= MAX_PLAYER_STAT);

      obj->affected[1].location = APPLY_TECHNIQUE;
      obj->affected[1].modifier = 1 + (level >= MAX_PLAYER_STAT);

      if (IS_GOOD (ch))
	{
	  SET_BIT (GET_OBJ_EXTRA (obj), ITEM_ANTI_EVIL);
	  act ("$p glows blue.", FALSE, ch, obj, 0, TO_CHAR);
	}
      else if (IS_EVIL (ch))
	{
	  SET_BIT (GET_OBJ_EXTRA (obj), ITEM_ANTI_GOOD);
	  act ("$p glows red.", FALSE, ch, obj, 0, TO_CHAR);
	}
      else
	{
	  act ("$p glows yellow.", FALSE, ch, obj, 0, TO_CHAR);
	}
    }
}


ASPELL (spell_detect_poison)
{
  if (victim)
    {
      if (victim == ch)
	{
	  if (IS_AFFECTED (victim, AFF_POISON))
	    send_to_char ("You can sense poison in your blood.\r\n", ch);
	  else
	    send_to_char ("You feel healthy.\r\n", ch);
	}
      else
	{
	  if (IS_AFFECTED (victim, AFF_POISON))
	    act ("You sense that $E is poisoned.", FALSE, ch, 0, victim, TO_CHAR);
	  else
	    act ("You sense that $E is healthy.", FALSE, ch, 0, victim, TO_CHAR);
	}
    }

  if (obj)
    {
      switch (GET_OBJ_TYPE (obj))
	{
	case ITEM_DRINKCON:
	case ITEM_FOUNTAIN:
	case ITEM_FOOD:
	  if (GET_OBJ_VAL (obj, 3))
	    act ("You sense that $p has been contaminated.", FALSE, ch, obj, 0, TO_CHAR);
	  else
	    act ("You sense that $p is safe for consumption.", FALSE, ch, obj, 0,
		 TO_CHAR);
	  break;
	default:
	  send_to_char ("You sense that it should not be consumed.\r\n", ch);
	}
    }
}
ASPELL (spell_fear)
{
  struct char_data *target = (struct char_data *) victim;
  struct char_data *next_target;
  int rooms_to_flee = 0;

  ACMD (do_flee);

  if (ch == NULL)
    return;

  send_to_char ("You radiate an aura of fear into the room!\r\n", ch);
  act ("$n is surrounded by an aura of fear!", TRUE, ch, 0, 0, TO_ROOM);

  for (target = world[ch->in_room].people; target; target = next_target)
    {
      next_target = target->next_in_room;

      if (target == NULL)
	return;

      if (target == ch)
	continue;

      if (GET_LEVEL (target) >= LVL_IMMORT)
	continue;

      if (mag_savingthrow (ch, target))
	{
	  sprintf (buf, "%s is unaffected by the fear!\r\n", GET_NAME (target));
	  act (buf, TRUE, ch, 0, 0, TO_ROOM);
	  send_to_char ("Your victim is not afraid of the likes of you!\r\n", ch);
	  if (IS_NPC (target))
	    hit (target, ch, TYPE_UNDEFINED);
	}
      else
	{
	  for (rooms_to_flee = level / 10; rooms_to_flee > 0; rooms_to_flee--)
	    {
	      send_to_char ("You flee in terror!\r\n", target);
	      do_flee (target, "", 0, 0);
	    }
	}
    }
}
ASPELL (spell_recharge)
{
  int restored_charges = 0, explode = 0;
  if (ch == NULL || obj == NULL)
    return;
  /* This is on my mud, comment off on yours
   * if (GET_OBJ_EXTRA(obj) == ITEM_NO_RECHARGE) {
   * send_to_char("This item cannot be recharged.\r\n", ch);   return; } */
  if (GET_OBJ_TYPE (obj) == ITEM_WAND)
    {
      if (GET_OBJ_VAL (obj, 2) < GET_OBJ_VAL (obj, 1))
	{
	  send_to_char ("You attempt to recharge the wand.\r\n", ch);
	  restored_charges = number (1, 5);
	  GET_OBJ_VAL (obj, 2) += restored_charges;
	  if (GET_OBJ_VAL (obj, 2) > GET_OBJ_VAL (obj, 1))
	    {
	      send_to_char ("The wand is overcharged and explodes!\r\n", ch);
	      sprintf (buf, "%s overcharges %s and it explodes!\r\n",
		       GET_NAME (ch), obj->name);
	      act (buf, TRUE, 0, 0, 0,
		   TO_NOTVICT);
	      explode = dice (GET_OBJ_VAL (obj, 2), 2);
	      GET_HIT (ch) -= explode;
	      update_pos (ch);
	      extract_obj (obj);
	      return;
	    }
	  else
	    {
	      sprintf (buf, "You restore %d charges to the wand.\r\n",
		       restored_charges);
	      send_to_char (buf, ch);
	      return;
	    }
	}
      else
	{
	  send_to_char ("That item is already at full charges!\r\n", ch);
	  return;
	}
    }
  else if (GET_OBJ_TYPE (obj) == ITEM_STAFF)
    {
      if (GET_OBJ_VAL (obj, 2) < GET_OBJ_VAL (obj, 1))
	{
	  send_to_char ("You attempt to recharge the staff.\r\n", ch);
	  restored_charges = number (1, 3);
	  GET_OBJ_VAL (obj, 2) += restored_charges;
	  if (GET_OBJ_VAL (obj, 2) > GET_OBJ_VAL (obj, 1))
	    {
	      send_to_char ("The staff is overcharged and explodes!\r\n", ch);
	      sprintf (buf, "%s overcharges %s and it explodes!\r\n",
		       GET_NAME (ch), obj->name);
	      act (buf, TRUE, 0, 0, 0, TO_NOTVICT);
	      explode = dice (GET_OBJ_VAL (obj, 2), 3);
	      GET_HIT (ch) -=
		explode;
	      update_pos (ch);
	      extract_obj (obj);
	      return;
	    }
	  else
	    {
	      sprintf (buf, "You restore %d charges to the staff.\r\n",
		       restored_charges);
	      send_to_char (buf, ch);
	      return;
	    }
	}
      else
	{
	  send_to_char ("That item is already at full charges!\r\n", ch);
	  return;
	}
    }
}
#define PORTAL 20

ASPELL(spell_portal)
{
  /* create a magic portal */
  struct obj_data *tmp_obj, *tmp_obj2;
  struct extra_descr_data *ed;
  struct room_data *rp, *nrp;
  struct char_data *tmp_ch = (struct char_data *) victim;
  char buf[512];

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


  /*
    check target room for legality.
   */
  rp = &world[ch->in_room];
  tmp_obj = read_object(PORTAL, VIRTUAL);
  if (!rp || !tmp_obj) {
    send_to_char("The magic fails.\n\r", ch);
    extract_obj(tmp_obj);
    return;
  }
  if (IS_SET(rp->room_flags, ROOM_NOMAGIC) || (PRF2_FLAGGED(victim, PRF2_INTANGIBLE) &&
(GET_LEVEL(ch)<LVL_IMMORT || IS_NPC(ch)))) {
    send_to_char("Eldritch wizardry obstructs thee.\n\r", ch);
    extract_obj(tmp_obj);
    return;
  }

  if (IS_SET(rp->room_flags, ROOM_TUNNEL)) {
    send_to_char("There is no room in here to summon!\n\r", ch);
    extract_obj(tmp_obj);
    return;
  }

  if (!(nrp = &world[tmp_ch->in_room])) {
    char str[180];
    sprintf(str, "%s tried to portal to %s but target not in any room!", GET_NAME(ch), GET_NAME(tmp_ch));
    log(str);
    send_to_char("The magic cannot locate the target.\n", ch);
    extract_obj(tmp_obj);
    return;
  }

 if (IS_NPC(tmp_ch) && GET_LEVEL(ch) < LVL_IMMORT) {
    send_to_char("The magic cannot locate the target.\n", ch);
    extract_obj(tmp_obj);
    return;
  }

 if (tmp_ch->in_room == ch->in_room) {
        send_to_char("You are already at the target area.\n", ch);
     extract_obj(tmp_obj);
     return;
}
 if ((GET_LEVEL(tmp_ch) >= LVL_IMMORT) && (GET_LEVEL(ch) < LVL_IMMORT)) {
     send_to_char("You cannot travel to the gods!\n", ch);
     extract_obj(tmp_obj);
     return;
}

 if (GET_ARENASTAT(tmp_ch) != ARENA_NOT && GET_ARENASTAT(ch) == ARENA_NOT){
   send_to_char ("Your target is in the arena right now.\r\n"
		 "Eldrich magic obstructs thee!\r\n", ch);
   extract_obj(tmp_obj);
   return;
 }
 if (GET_ARENASTAT(tmp_ch) == ARENA_NOT && GET_ARENASTAT(ch) != ARENA_NOT){
   send_to_char ("You're in the arena right now whereas your target is not.\r\n"
		 "Eldrich magic obstructs thee!\r\n", ch);
   extract_obj(tmp_obj);
   return;
 }
   
  if (ROOM_FLAGGED(tmp_ch->in_room, ROOM_NOMAGIC)) {
    send_to_char("Your target is protected against your magic.\n\r", ch);
    extract_obj(tmp_obj);
    return;
  }
  if (ROOM_FLAGGED(tmp_ch->in_room, ROOM_HOUSE) || ROOM_FLAGGED(tmp_ch->in_room, ROOM_HOUSE_CRASH)) {
    if (find_house(world[tmp_ch->in_room].number) != GET_IDNUM(ch)) {
      send_to_char("Your target is protected against your magic.\n\r", ch);
      extract_obj(tmp_obj);
      return;
    }
  }

  if (ROOM_FLAGGED(tmp_ch->in_room, ROOM_PRIVATE)) {
    send_to_char("Your target is protected against your magic.\n\r", ch);
    extract_obj(tmp_obj);
    return;
  }

  if (ROOM_FLAGGED(tmp_ch->in_room, ROOM_TUNNEL)) {
    send_to_char("There is not enough room there to portal!\n\r", ch);
    extract_obj(tmp_obj);
    return;
  }

 if (IS_AFFECTED (tmp_ch, AFF_NOPORTAL)) {
   send_to_char("Your target's magic resists your portal attempt.\r\n", ch);
   extract_obj(tmp_obj);
   return;
 }

sprintf(buf, "Through the mists of the portal, you can faintly see %s", nrp->name);
  CREATE(ed , struct extra_descr_data, 1);
  ed->next = tmp_obj->ex_description;
  tmp_obj->ex_description = ed;
  CREATE(ed->keyword, char, strlen(tmp_obj->name) + 1);
  strcpy(ed->keyword, tmp_obj->name);
  ed->description = str_dup(buf);

  tmp_obj->obj_flags.value[0] = 1;
  tmp_obj->obj_flags.value[1] = tmp_ch->in_room;

  if (GET_LEVEL(ch) < LVL_IMMORT)
    GET_OBJ_TIMER(tmp_obj)=1;
  else
    GET_OBJ_TIMER(tmp_obj)=-1; // Never dissapear.
  obj_to_room(tmp_obj,ch->in_room);

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

/* Portal at other side */
   rp = &world[ch->in_room];
   tmp_obj2 = read_object(PORTAL, VIRTUAL);
   if (!rp || !tmp_obj2) {
     send_to_char("The magic fails.\n\r", ch);
     extract_obj(tmp_obj2);

     return;
   }
  sprintf(buf, "Through the mists of the portal, you can faintly see %s", rp->name);

  CREATE(ed , struct extra_descr_data, 1);
  ed->next = tmp_obj2->ex_description;
  tmp_obj2->ex_description = ed;
  CREATE(ed->keyword, char, strlen(tmp_obj2->name) + 1);
  strcpy(ed->keyword, tmp_obj2->name);
  ed->description = str_dup(buf);

  tmp_obj2->obj_flags.value[0] = 1;
  tmp_obj2->obj_flags.value[1] = ch->in_room;

  if (GET_LEVEL(ch) < LVL_IMMORT)
    GET_OBJ_TIMER(tmp_obj2)=1;
  else
    GET_OBJ_TIMER(tmp_obj2)=-1; // Never dissapear.

  obj_to_room(tmp_obj2,tmp_ch->in_room);

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

ASPELL(spell_locate_target)
{
  struct char_data *i;
  char name[MAX_INPUT_LENGTH];
  int j;

  strcpy(name, fname(victim->player.name));
  j = level >> 1;

  for (i = character_list; i && (j > 0); i = i->next) {
    if (!is_name(name, i->player.name))
      continue;

    if (i->in_room != NOWHERE)
        sprintf(buf, "%s is in %s.\n\r", IS_NPC(i) ? i->player.short_descr : i->player.name,
                world[i->in_room].name);
    else
      sprintf(buf, "%s's location is uncertain.\r\n",
              IS_NPC(i) ? i->player.short_descr : i->player.name);

    CAP(buf);
    send_to_char(buf, ch);
    j--;
  }

  if (j == level >> 1)
    send_to_char("You sense nothing.\n\r", ch);
}
ACMD(do_speed)
{
if (GET_SKILL(ch, SKILL_SPEED) == 0)
{
send_to_char("You have no idea how to speed.\r\n", ch);
 return;
}
if (GET_MANA(ch) == GET_MAX_MANA(ch))
{
send_to_char("You retract and flex your muscles with strength.\r\n", ch);
GET_MANA(ch) = 0;
GET_MOVE(ch) = GET_MAX_MOVE(ch);
send_to_char("You feel revived and ready to move again.\r\n", ch);
}
 else {
send_to_char("You must have full mana in order to speed!\r\n", ch);
return;
}
}
#define CAN_LISTEN_BEHIND_DOOR(ch,dir)  \
                (GET_CLASS(ch) == CLASS_THIEF) && \
                (EXIT(ch, dir) && EXIT(ch, dir)->to_room != NOWHERE && \
                 IS_SET(EXIT(ch, dir)->exit_info, EX_CLOSED)))

ACMD(do_listen)
{
   struct char_data *tch, *tch_next;
   int dir, percent, found = 0;
   char *heard_nothing = "You don't hear anything unusual.\r\n";
   char *room_spiel    = "$n seems to listen intently for something.";

   percent = number(1,101);

   if(GET_SKILL(ch, SKILL_LISTEN) < percent) {
      send_to_char(heard_nothing, ch);
      return;
   }

   one_argument(argument, buf);

   if(!*buf) {  
      /* no argument means that the character is listening for
       * hidden or invisible beings in the room he/she is in
       */
      for(tch = world[ch->in_room].people; tch; tch = tch_next) {
         tch_next = tch->next_in_room;
         if((tch != ch) && !CAN_SEE(ch, tch) && (GET_LEVEL(tch) < LVL_IMMORT)) 
            found++;
      }
      if(found) {
         if(GET_LEVEL(ch) >= 15) {  
            /* being a higher level is better */
            sprintf(buf, "You hear what might be %d creatures invisible, or hiding.\r\n", \
                        MAX(1,(found+number(0,1)-number(0,1))));
         }
         else sprintf(buf, "You hear an odd rustling in the immediate area.\r\n");
         send_to_char(buf, ch);
      }
      else send_to_char(heard_nothing, ch);
      act(room_spiel, TRUE, ch, 0, 0, TO_ROOM);
      return;
   }
   else {
      /* the argument must be one of the cardinal directions: north, 
       * south, etc.
       */
      for(dir = 0; dir < NUM_OF_DIRS; dir++) {
         if(!strncmp(buf, dirs[dir], strlen(buf)))
            break;
      }
      if (dir == NUM_OF_DIRS) {
         send_to_char("Listen where?\r\n", ch);
         return;
      }
      if((CAN_GO(ch, dir)) || (CAN_LISTEN_BEHIND_DOOR(ch, dir)) {
         for(tch = world[EXIT(ch, dir)->to_room].people; tch; tch=tch_next) {
            tch_next = tch->next_in_room;
            found++;
         }
         if(found) {
            if(GET_LEVEL(ch) >= 15) {
               sprintf(buf, "You hear what might be %d creatures %s%s.\r\n", \
                        MAX(1,(found+number(0,1)-number(0,1))),
                        ((dir==5)?"below":(dir==4)?"above": "to the "), 
                        ((dir==5)?"":(dir==4)?"":dirs[dir]));
            }
            else sprintf(buf, "You hear sounds from %s%s.\r\n", \
                        ((dir==5)?"below":(dir==4)?"above": "the "), 
                        ((dir==5)?"":(dir==4)?"":dirs[dir]));
            send_to_char(buf, ch);
         }
         else send_to_char(heard_nothing, ch);
         act(room_spiel, TRUE, ch, 0, 0, TO_ROOM);
         return;
      }
      else send_to_char("You can't listen in that direction.\r\n", ch);
      return;
   }
   return;
}
ASPELL(spell_home)
{
  extern long mortal_start_room[NUM_STARTROOMS + 1];
  int i, homenum = 0, loadrm = -1;
  char mybuf[1024];
  struct char_data *victor;

  for (i = 0; i < num_of_houses; i++)
    if (house_control[i].owner == GET_IDNUM(ch))
      homenum = house_control[i].vnum;

  if (homenum == 0){
    send_to_char("The spell fails because you don't own a house!\r\n", ch);
    return;
  }

  if (RIDING(victim) || RIDDEN_BY(victim)) {
  send_to_char("The spell fails because your victim is atop a mount.\r\n", ch);
  return;  
  }

  loadrm = GET_HOME(ch);
  if (!(loadrm >= 1 && loadrm <= NUM_STARTROOMS)){
    sprintf(buf, "DEBUG: Home Recall Trigger - %s GET_HOME is %d (invalid)",
            GET_NAME(ch), loadrm);
    mudlog(buf, NRM, LVL_GRGOD, TRUE);
    loadrm = 1;
  }
  loadrm = real_room(mortal_start_room[loadrm]);

  if (ch->in_room == real_room(homenum)){
    send_to_char("The spell fails because you're already at home!\r\n", ch);
    return;
  }

  if (IS_ARENACOMBATANT(victim)){
    victor = FIGHTING(victim);
    sprintf(mybuf, "(Recalled)");
    if (GET_ARENAFLEETIMER(victim) >= 1
        && GET_ARENAFLEETIMER(victim) <= 1+arena_flee_timeout){
      victor = LASTFIGHTING(victim);
      send_to_char("You recalled before the flee-recall timer expired.\r\n"
                   "You have conceded the match!\r\n", victim);
      sprintf(mybuf, "(Fled & Recalled)");
      GET_ARENAFLEETIMER(victim) = 0;
    }
    match_over(victor, victim, mybuf, FALSE);
    char_from_room (victim);
    char_to_room (victim, real_room (arena_preproom));
    act ("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
    look_at_room (victim, 0);
    return;
  }

  act ("$n magically teleports out.", FALSE, ch, 0, 0, TO_ROOM);
  char_from_room(ch);

  if (GET_ARENASTAT(victim) == ARENA_OBSERVER){
    char_to_room (victim, real_room (arena_observeroom));
    act ("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
    look_at_room (victim, 0);
    return;
  }

  char_to_room(ch, real_room(homenum));
  act("$n suddenly appears in the room.", FALSE, ch, 0, 0, TO_ROOM);

  look_at_room(ch, 0);
  send_to_char("\r\nAhhhh... Home Sweet Home!\r\n", ch);

}
ASPELL (spell_retreat)
{
  int load_room = 0;
  char mybuf[1024];
  struct char_data *victor;

  if (victim == NULL || IS_NPC (victim))
    return;

    if ((load_room == NOWHERE || load_room == 0 || !load_room)) {
    send_to_char("You must rent somewhere before you can retreat!\r\n", ch);
    return;
  }

  if (RIDING(victim) || RIDDEN_BY(victim)) {
  send_to_char("The spell fails because your victim is atop a mount.\r\n", ch);
  return;  
  }

  act ("$n disappears.", TRUE, victim, 0, 0, TO_ROOM);
  if (IS_ARENACOMBATANT(victim)){
    victor = FIGHTING(victim);
    sprintf(mybuf, "(Recalled)");
    if (GET_ARENAFLEETIMER(victim) >= 1
        && GET_ARENAFLEETIMER(victim) <= 1+arena_flee_timeout){
      victor = LASTFIGHTING(victim);
      send_to_char("You recalled before the flee-recall timer expired.\r\n"
                   "You have conceded the match!\r\n", victim);
      sprintf(mybuf, "(Fled & Recalled)");
      GET_ARENAFLEETIMER(victim) = 0;
    }
    match_over(victor, victim, mybuf, FALSE);
    char_from_room (victim);
    char_to_room (victim, real_room (arena_preproom));
    act ("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
    look_at_room (victim, 0);
    return;
  }
    
  char_from_room (victim);
  if (GET_ARENASTAT(victim) == ARENA_OBSERVER){
    char_to_room (victim, real_room (arena_observeroom));
    act ("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
    look_at_room (victim, 0);
    return;
  }
     
    char_to_room (victim, real_room(GET_LOADROOM(victim)));
    act ("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM);
    look_at_room (victim, 0);
}