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: spec_procs.c                                  Part of CircleMUD *
   *  Usage: implementation of special procedures for mobiles/objects/rooms  *
   *                                                                         *
   *  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 "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"
#include "dg_scripts.h"
#include "maputils.h"

/*   external vars  */
extern int arena_zone;
extern int arena_preproom;
extern int arena_observeroom;
extern int arena_combatant;
extern int arena_observer;
extern struct char_data *arenamaster;
extern struct char_data *defaultobserve;
extern struct room_data *world;
extern struct char_data *character_list;
extern struct descriptor_data *descriptor_list;
extern struct index_data *mob_index;
extern struct index_data *obj_index;
extern struct time_info_data time_info;
extern struct command_info cmd_info[];

/* extern functions */
extern int has_boat(struct char_data *ch);
void write_aliases(struct char_data *ch);
void add_follower (struct char_data *ch, struct
char_data *leader);
void deobserve(struct char_data *);
void clearobservers(struct char_data*);
void linkobserve(struct char_data *who, struct char_data *to);
void bup_affects(struct char_data *ch);
void restore_bup_affects(struct char_data *ch);
char* numdisplay(int);
ACMD(do_tell);
ACMD(do_action);
ACMD (do_gen_comm);
void Crash_rentsave (struct char_data *ch, int cost);

struct social_type
  {
    char *cmd;
    int next_line;
  };


/* ********************************************************************
   *  Special procedures for mobiles                                     *
   ******************************************************************** */

int spell_sort_info[MAX_SKILLS + 1];

extern char *spells[];

void 
sort_spells (void)
{
  int a, b, tmp;

  /* initialize array */
  for (a = 1; a < MAX_SKILLS; a++)
    spell_sort_info[a] = a;

  /* Sort.  'a' starts at 1, not 0, to remove 'RESERVED' */
  for (a = 1; a < MAX_SKILLS - 1; a++)
    for (b = a + 1; b < MAX_SKILLS; b++)
      if (strcmp (spells[spell_sort_info[a]], spells[spell_sort_info[b]]) > 0)
	{
	  tmp = spell_sort_info[a];
	  spell_sort_info[a] = spell_sort_info[b];
	  spell_sort_info[b] = tmp;
	}
}


char *
how_good (int percent)
{
  static char buf[256];

  if (percent == 0)
    strcpy (buf, " (not learned)");
  else if (percent <= 10)
    strcpy (buf, " (awful)");
  else if (percent <= 20)
    strcpy (buf, " (bad)");
  else if (percent <= 40)
    strcpy (buf, " (poor)");
  else if (percent <= 55)
    strcpy (buf, " (average)");
  else if (percent <= 70)
    strcpy (buf, " (fair)");
  else if (percent <= 80)
    strcpy (buf, " (good)");
  else if (percent <= 85)
    strcpy (buf, " (very good)");
  else
    strcpy (buf, " (superb)");
  sprintf(buf+strlen(buf), " %d", percent);
  return (buf);
}

char *prac_types[] =
{
  "spell",
  "skill"
};

#define LEARNED_LEVEL	0	/* % known which is considered "learned" */
#define MAX_PER_PRAC	1	/* max percent gain in skill per practice */
#define MIN_PER_PRAC	2	/* min percent gain in skill per practice */
#define PRAC_TYPE	3	/* should it say 'spell' or 'skill'?       */

/* actual prac_params are in class.c */
extern int prac_params[4][NUM_CLASSES];

#define LEARNED(ch) (prac_params[LEARNED_LEVEL][(int)GET_CLASS(ch)])
#define MINGAIN(ch) (prac_params[MIN_PER_PRAC][(int)GET_CLASS(ch)])
#define MAXGAIN(ch) (prac_params[MAX_PER_PRAC][(int)GET_CLASS(ch)])
#define SPLSKL(ch) (prac_types[prac_params[PRAC_TYPE][(int)GET_CLASS(ch)]])

void 
list_skills (struct char_data *ch)
{
  extern char *spells[];
  extern struct spell_info_type spell_info[];
  int i, sortpos;

  if (!GET_PRACTICES (ch))
    strcpy (buf, "You have no practice sessions remaining.\r\n");
  else
    sprintf (buf, "You have %d practice session%s remaining.\r\n",
	     GET_PRACTICES (ch), (GET_PRACTICES (ch) == 1 ? "" : "s"));

  sprintf (buf, "%sYou know of the following %ss:\r\n", buf, SPLSKL (ch));

  strcpy (buf2, buf);

  for (sortpos = 1; sortpos < MAX_SKILLS; sortpos++)
    {
      i = spell_sort_info[sortpos];
      if (strlen (buf2) >= MAX_STRING_LENGTH - 32)
	{
	  strcat (buf2, "**OVERFLOW**\r\n");
	  break;
	}
      if (GET_LEVEL (ch) >= spell_info[i].min_level[(int) GET_CLASS (ch)])
	{
	  sprintf (buf, "%-20s %s\r\n", spells[i], how_good (GET_SKILL (ch, i)));
	  strcat (buf2, buf);
	}
    }

  page_string (ch->desc, buf2, 1);
}


SPECIAL (guild)
{
  int skill_num, percent;

  extern struct spell_info_type spell_info[];
  extern struct int_app_type int_app[];

  if (IS_NPC (ch) || !CMD_IS ("practice"))
    return 0;

  skip_spaces (&argument);

  if (!*argument)
    {
      list_skills (ch);
      return 1;
    }
  if (GET_PRACTICES (ch) <= 0)
    {
      send_to_char ("You do not seem to be able to practice now.\r\n", ch);
      return 1;
    }

  skill_num = find_skill_num (argument);

  if (skill_num < 1 ||
      GET_LEVEL (ch) < spell_info[skill_num].min_level[(int) GET_CLASS (ch)])
    {
      sprintf (buf, "You do not know of that %s.\r\n", SPLSKL (ch));
      send_to_char (buf, ch);
      return 1;
    }
  if (GET_SKILL (ch, skill_num) >= LEARNED (ch))
    {
      send_to_char ("You are already learned in that area.\r\n", ch);
      return 1;
    }
  send_to_char ("You practice for a while...\r\n", ch);
  GET_PRACTICES (ch)--;

  percent = GET_SKILL (ch, skill_num);
  percent += MIN (MAXGAIN (ch), MAX (MINGAIN (ch), int_app[GET_INT (ch)].learn));

  SET_SKILL (ch, skill_num, MIN (LEARNED (ch), percent));

  if (GET_SKILL (ch, skill_num) >= LEARNED (ch))
    send_to_char ("You are now learned in that area.\r\n", ch);

  return 1;
}



SPECIAL (dump)
{
  struct obj_data *k;
  int value = 0;

  ACMD (do_drop);
  char *fname (char *namelist);

  for (k = world[ch->in_room].contents; k; k = world[ch->in_room].contents)
    {
      act ("$p vanishes in a puff of smoke!", FALSE, 0, k, 0, TO_ROOM);
      extract_obj (k);
    }

  if (!CMD_IS ("drop"))
    return 0;

  do_drop (ch, argument, cmd, 0);

  for (k = world[ch->in_room].contents; k; k = world[ch->in_room].contents)
    {
      act ("$p vanishes in a puff of smoke!", FALSE, 0, k, 0, TO_ROOM);
      value += MAX (1, MIN (50, GET_OBJ_COST (k) / 10));
      extract_obj (k);
    }

  if (value)
    {
       if (GET_LEVEL(ch) < LVL_IMMORT) {
      act ("You are awarded for being a good citizen.", FALSE, ch, 0, 0, TO_CHAR);
      act ("$n has been awarded for being a good citizen.", TRUE, ch, 0, 0, TO_ROOM);

      if (GET_LEVEL (ch) < 3)
	gain_exp (ch, value);
      else
	GET_GOLD (ch) += value;
      }
    }
  return 1;
}


SPECIAL (mayor)
{
  ACMD (do_gen_door);

  static char open_path[] =
  "W3a3003b33000c111d0d111Oe333333Oe22c222112212111a1S.";

  static char close_path[] =
  "W3a3003b33000c111d0d111CE333333CE22c222112212111a1S.";

  static char *path;
  static int index;
  static bool move = FALSE;

  if (!move)
    {
      if (time_info.hours == 6)
	{
	  move = TRUE;
	  path = open_path;
	  index = 0;
	}
      else if (time_info.hours == 20)
	{
	  move = TRUE;
	  path = close_path;
	  index = 0;
	}
    }
  if (cmd || !move || (GET_POS (ch) < POS_SLEEPING) ||
      (GET_POS (ch) == POS_FIGHTING))
    return FALSE;

  switch (path[index])
    {
    case '0':
    case '1':
    case '2':
    case '3':
      perform_move (ch, path[index] - '0', 1);
      break;

    case 'W':
      GET_POS (ch) = POS_STANDING;
      act ("$n awakens and groans loudly.", FALSE, ch, 0, 0, TO_ROOM);
      break;

    case 'S':
      GET_POS (ch) = POS_SLEEPING;
      act ("$n lies down and instantly falls asleep.", FALSE, ch, 0, 0, TO_ROOM);
      break;

    case 'a':
      act ("$n says 'Hello, Honey!'", FALSE, ch, 0, 0, TO_ROOM);
      act ("$n smirks.", FALSE, ch, 0, 0, TO_ROOM);
      break;

    case 'b':
      act ("$n says 'What a view!  I must get something done about that dump!'",
	   FALSE, ch, 0, 0, TO_ROOM);
      break;

    case 'c':
      act ("$n says 'Vandals!  Youngsters nowadays have no respect for anything!'",
	   FALSE, ch, 0, 0, TO_ROOM);
      break;

    case 'd':
      act ("$n says 'Good day, citizens!'", FALSE, ch, 0, 0, TO_ROOM);
      break;

    case 'e':
      act ("$n says 'I hereby declare the markets open!'", FALSE, ch, 0, 0, TO_ROOM);
      break;

    case 'E':
      act ("$n says 'I hereby declare Anacreon closed!'", FALSE, ch, 0, 0, TO_ROOM);
      break;

    case 'O':
      do_gen_door (ch, "gate", 0, SCMD_UNLOCK);
      do_gen_door (ch, "gate", 0, SCMD_OPEN);
      break;

    case 'C':
      do_gen_door (ch, "gate", 0, SCMD_CLOSE);
      do_gen_door (ch, "gate", 0, SCMD_LOCK);
      break;

    case '.':
      move = FALSE;
      break;

    }

  index++;
  return FALSE;
}


/* ********************************************************************
   *  General special procedures for mobiles                             *
   ******************************************************************** */


void 
npc_steal (struct char_data *ch, struct char_data *victim)
{
  int gold;

  if (IS_NPC (victim))
    return;
  if (GET_LEVEL (victim) >= LVL_IMMORT)
    return;

  if (AWAKE (victim) && (number (0, GET_LEVEL (ch)) == 0))
    {
      act ("You discover that $n has $s hands in your wallet.", FALSE, ch, 0, victim, TO_VICT);
      act ("$n tries to steal gold from $N.", TRUE, ch, 0, victim, TO_NOTVICT);
    }
  else
    {
      /* Steal some gold coins */
      gold = (int) ((GET_GOLD (victim) * number (1, 10)) / 100);
      if (gold > 0)
	{
	  GET_GOLD (ch) += gold;
	  GET_GOLD (victim) -= gold;
	}
    }
}


SPECIAL (snake)
{
  if (cmd)
    return FALSE;

  if (GET_POS (ch) != POS_FIGHTING)
    return FALSE;

  if (FIGHTING (ch) && (FIGHTING (ch)->in_room == ch->in_room) &&
      (number (0, 42 - GET_LEVEL (ch)) == 0))
    {
      act ("$n bites $N!", 1, ch, 0, FIGHTING (ch), TO_NOTVICT);
      act ("$n bites you!", 1, ch, 0, FIGHTING (ch), TO_VICT);
      call_magic (ch, FIGHTING (ch), 0, SPELL_POISON, GET_LEVEL (ch));
      return TRUE;
    }
  return FALSE;
}


SPECIAL (thief)
{
  struct char_data *cons;

  if (cmd)
    return FALSE;

  if (GET_POS (ch) != POS_STANDING)
    return FALSE;

  for (cons = world[ch->in_room].people; cons; cons = cons->next_in_room)
    if (!IS_NPC (cons) && (GET_LEVEL (cons) < LVL_IMMORT) && (!number (0, 4)))
      {
	npc_steal (ch, cons);
	return TRUE;
      }
  return FALSE;
}


SPECIAL (magic_user)
{
  struct char_data *vict;

  if (cmd || GET_POS (ch) != POS_FIGHTING)
    return FALSE;

  /* pseudo-randomly choose someone in the room who is fighting me */
  for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
    if (FIGHTING (vict) == ch && !number (0, 4))
      break;

  /* if I didn't pick any of those, then just slam the guy I'm fighting */
  if (vict == NULL)
    vict = FIGHTING (ch);

  if ((GET_LEVEL (ch) > 13) && (number (0, 10) == 0))
    cast_spell (ch, vict, NULL, SPELL_SLEEP);

  if ((GET_LEVEL (ch) > 7) && (number (0, 8) == 0))
    cast_spell (ch, vict, NULL, SPELL_BLINDNESS);

  if (number (0, 4))
    return TRUE;

  if ( (GET_HIT(ch)/GET_MAX_HIT(ch) > 0.05)
       && (GET_HIT(ch)/GET_MAX_HIT(ch) < 0.5)){
    if (number(1,50) > (number(1,150)-GET_LEVEL(ch))){
      cast_spell(ch, ch, NULL, SPELL_HEAL);
      return TRUE;
    }
  }

  switch (GET_LEVEL (ch))
    {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
    case 11:
    case 12:
    case 13:
    case 14:
    case 15:
    case 16:
    case 17:
    case 18:
    case 19:
    case 20:
    case 21:
    case 22:
    case 23:
    case 24:
    case 25:
    case 26:
    case 27:
    case 28:
    case 29:
    case 30:
    case 31:
    case 32:
    case 33:
    case 34:
    case 35:
    case 36:
    case 37:
    case 38:
    case 39:
    case 40:
    case 41:
    case 42:
    case 43:
    case 44:
    case 45:
    case 46:
    case 47:
    case 48:
    case 49:
    case 50:
    case 51:
    case 52:
    case 53:
    case 54:
    case 55:
    case 56:
    case 57:
    case 58:
    case 59:
    case 60:
    case 61:
    case 62:
    case 63:
    case 64:
    case 65:
    case 66:
    case 67:
    case 68:
    case 69:
    case 70:
    case 71:
    case 72:
    case 73:
    case 74:
    case 75:
    case 76:
    case 77:
    case 78:
    case 79:
    case 80:
    case 81:
    case 82:
    case 83:
    case 84:
    case 85:
    case 86:
    case 87:
    case 88:
    case 89:
    case 90:
    case 91:
    case 92:
    case 93:
    case 94:
    case 95:
    case 96:
    case 97:
    case 98:
    case 99:
    case 100:
    default:
    }
  return TRUE;

}


/* ********************************************************************
   *  Special procedures for mobiles                                      *
   ******************************************************************** */

SPECIAL (guild_guard)
{
  int i;
  extern int guild_info[][3];
  struct char_data *guard = (struct char_data *) me;
  char *buf = "The guard humiliates you, and blocks your way.\r\n";
  char *buf2 = "The guard humiliates $n, and blocks $s way.";

  if (!IS_MOVE (cmd) || IS_AFFECTED (guard, AFF_BLIND))
    return FALSE;

  if (GET_LEVEL (ch) >= LVL_IMMORT)
    return FALSE;

  for (i = 0; guild_info[i][0] != -1; i++)
    {
      if ((IS_NPC (ch) || GET_CLASS (ch) != guild_info[i][0]) &&
	  world[ch->in_room].number == guild_info[i][1] &&
	  cmd == guild_info[i][2])
	{
	  send_to_char (buf, ch);
	  act (buf2, FALSE, ch, 0, 0, TO_ROOM);
	  return TRUE;
	}
    }

  return FALSE;
}

SPECIAL (librarian)
{
  struct char_data *vict;

  if (cmd)
    return (0);
for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
{
  switch (number (0, 72))
    {
    case 0:
     act("$n says, 'I sell books from all over the land, why not buy one?'", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 1:
      act("$n turns a page in the book she's reading.", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 2:
      act("$n drinks a glass of wine.", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 3:
     act("$n says, 'I'm reading a book about ancient Midgaard.'", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 4:
      act("$n says, 'Thanks for being quiet in the library.'", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 5:
      act("$n winks at $N suggestively.", TRUE, ch, 0, vict, TO_ROOM);
      return (1);
    case 6:
      act("$n starts sorting new books.", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 7:
      act ("$n points at the sign on the wall.", FALSE, ch, 0, 0, TO_ROOM);
      act ("$n says, 'If you're looking for books just type: list'", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 8:
      act ("$n says, 'I need a vacation. I'd love to see Jhaden'", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 9:
      act("$n puts several books on a shelf.", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 10:
act("$n snickers softly.", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 11:
      act ("$n says, 'I wish people like you would write books.'", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 12:
      act ("$n says, 'I once met AJ Trfiante here long ago.'", FALSE, ch, 0, 0, TO_ROOM);
      act ("$n says, 'It was at the debute of his restraunt'", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 13:
act("$n seems to be getting tired.", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 14:
act("$n leaves to a back room.", FALSE, ch, 0, 0, TO_ROOM);
act("$n returns with a new pile of books.", FALSE, ch, 0, 0, TO_ROOM);
      return (1);
    case 15:
      act ("$n says, 'I love to read. It makes you smart, you know.'", FALSE, ch, 0, 0, TO_ROOM);
      return (1);

    default:
      return (0);
    }
}
return (0);
}
SPECIAL (puff)
{
  ACMD (do_say);

  if (cmd)
    return (0);

  switch (number (0, 66))
    {
    case 0:
      do_say (ch, "The force is strong with this one!", 0, 0);
      return (1);
    case 1:
      do_say (ch, "If you only knew the POWER of the dark side", 0, 0);
      return (1);
    case 2:
  
      do_say (ch, "Read my lips.. no new taxes", 0, 0);
      return (1);
    case 3:
      do_say (ch, "Whenever I climb I am followed by a dog called Ego", 0, 0);
      return (1);
    case 4:
      do_say (ch, "I'll sleep when I'm dead", 0, 0);
      return (1);
    case 5:
      do_say (ch, "My advice to you is get married: if you find a good wife you'll be happy; if not,
you'll become a philosopher", 0, 0);
      return (1);
    case 6:
      do_say (ch, "We all agree that your theory is crazy, but is it crazy enough?", 0, 0);
      return (1);
    case 7:
      do_say (ch, "I loved Welmar more than any woman I had ever known", 0, 0);
      return (1);
    case 8:
      do_say (ch, "The graveyards are full of indispensable men", 0, 0);
      return (1);
    case 9:
      do_say (ch, "I have an existential map; it has 'you are here' written all over it", 0, 0);
      return (1);
    default:
      return (0);
    }
}



SPECIAL (fido)
{

  struct obj_data *i, *temp, *next_obj;


  if (cmd || !AWAKE (ch))
    return (FALSE);

  for (i = world[ch->in_room].contents; i; i = i->next_content)
    {
      if (GET_OBJ_TYPE (i) == ITEM_CONTAINER && GET_OBJ_VAL (i, 3))
	{
	  act ("$n savagely devours a corpse.", FALSE, ch, 0, 0, TO_ROOM);
	  for (temp = i->contains; temp; temp = next_obj)
	    {
	      next_obj = temp->next_content;
	      obj_from_obj (temp);
	      obj_to_room (temp, ch->in_room);
	    }
	  extract_obj (i);
	  return (TRUE);
	}
    }
  return (FALSE);
}



SPECIAL (janitor)
{
  struct obj_data *i;

  if (cmd || !AWAKE (ch))
    return (FALSE);

  for (i = world[ch->in_room].contents; i; i = i->next_content)
    {
      if (!CAN_WEAR (i, ITEM_WEAR_TAKE))
	continue;
      if (GET_OBJ_TYPE (i) != ITEM_DRINKCON && GET_OBJ_COST (i) >= 15)
	continue;
      act ("$n picks up some trash.", FALSE, ch, 0, 0, TO_ROOM);
      obj_from_room (i);
      obj_to_char (i, ch);
      return TRUE;
    }

  return FALSE;
}


SPECIAL (cityguard)
{
  struct char_data *tch, *evil;
  int max_evil;

  if (cmd || !AWAKE (ch) || FIGHTING (ch))
    return FALSE;


  max_evil = 1000;
  evil = 0;

  for (tch = world[ch->in_room].people; tch; tch = tch->next_in_room)
    {
      if (!IS_NPC (tch) && CAN_SEE (ch, tch) && IS_SET (PLR_FLAGS (tch), PLR_KILLER))
	{
	  act ("$n screams 'HEY!!!  You're one of those PLAYER KILLERS!!!!!!'", FALSE, ch, 0, 0, TO_ROOM);
	  hit (ch, tch, TYPE_UNDEFINED);
	  return (TRUE);
	}
    }

  for (tch = world[ch->in_room].people; tch; tch = tch->next_in_room)
    {
      if (!IS_NPC (tch) && CAN_SEE (ch, tch) && IS_SET (PLR_FLAGS (tch), PLR_THIEF))
	{
	  act ("$n screams 'HEY!!!  You're one of those PLAYER THIEVES!!!!!!'", FALSE, ch, 0, 0, TO_ROOM);
	  hit (ch, tch, TYPE_UNDEFINED);
	  return (TRUE);
	}
    }

  for (tch = world[ch->in_room].people; tch; tch = tch->next_in_room)
    {
      if (CAN_SEE (ch, tch) && FIGHTING (tch))
	{
	  if ((GET_ALIGNMENT (tch) < max_evil) &&
	      (IS_NPC (tch) || IS_NPC (FIGHTING (tch))))
	    {
	      max_evil = GET_ALIGNMENT (tch);
	      evil = tch;
	    }
	}
    }

  if (evil && (GET_ALIGNMENT (FIGHTING (evil)) >= 0))
    {
      act ("$n screams 'PROTECT THE INNOCENT!  BANZAI!  CHARGE!  ARARARAGGGHH!'", FALSE, ch, 0, 0, TO_ROOM);
      hit (ch, evil, TYPE_UNDEFINED);
      return (TRUE);
    }
  return (FALSE);
}


#define PET_PRICE(pet) (GET_LEVEL(pet) * 300)

SPECIAL (pet_shops)
{
  char buf[MAX_STRING_LENGTH], pet_name[256];
  int pet_room;
  struct char_data *pet;

  pet_room = ch->in_room + 1;

  if (CMD_IS ("list"))
    {
      send_to_char ("Available pets are:\r\n", ch);
      for (pet = world[pet_room].people; pet; pet = pet->next_in_room)
	{
	  sprintf (buf, "%8d - %s\r\n", PET_PRICE (pet), GET_NAME (pet));
	  send_to_char (buf, ch);
	}
      return (TRUE);
    }
  else if (CMD_IS ("buy"))
    {

      argument = one_argument (argument, buf);
      argument = one_argument (argument, pet_name);

      if (!(pet = get_char_room (buf, pet_room)))
	{
	  send_to_char ("There is no such pet!\r\n", ch);
	  return (TRUE);
	}
      if (GET_GOLD (ch) < PET_PRICE (pet))
	{
	  send_to_char ("You don't have enough gold!\r\n", ch);
	  return (TRUE);
	}
      GET_GOLD (ch) -= PET_PRICE (pet);

      pet = read_mobile (GET_MOB_RNUM (pet), REAL);
      GET_EXP (pet) = 0;
      SET_BIT (AFF_FLAGS (pet), AFF_CHARM);

      if (*pet_name)
	{
	  sprintf (buf, "%s %s", pet->player.name, pet_name);
	  /* free(pet->player.name); don't free the prototype! */
	  pet->player.name = str_dup (buf);

	  sprintf (buf, "%sA small sign on a chain around the neck says 'My name is %s'\r\n",
		   pet->player.description, pet_name);
	  /* free(pet->player.description); don't free the prototype! */
	  pet->player.description = str_dup (buf);
	}
      char_to_room (pet, ch->in_room);
      add_follower (pet, ch);
      load_mtrigger(pet);

      /* Be certain that pets can't get/carry/use/wield/wear items */
      IS_CARRYING_W (pet) = 1000;
      IS_CARRYING_N (pet) = 100;

      send_to_char ("May you enjoy your pet.\r\n", ch);
      act ("$n buys $N as a pet.", FALSE, ch, 0, pet, TO_ROOM);

      return 1;
    }
  /* All commands except list and buy */
  return 0;
}



/* ********************************************************************
   *  Special procedures for objects                                     *
   ******************************************************************** */


SPECIAL (temple_cleric)
{
  struct char_data *vict;
  struct char_data *hitme = NULL;
  static int this_hour;
  float temp1 = 1;
  float temp2 = 1;

  if (cmd)
    return FALSE;

  if (time_info.hours != 0)
    {

      this_hour = time_info.hours;

      for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
	{
	  if (IS_AFFECTED (vict, AFF_POISON))
	    hitme = vict;
	}
      if (hitme != NULL)
	{
	  cast_spell (ch, hitme, NULL, SPELL_REMOVE_POISON);
	  return TRUE;
	}

      for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
	{
	  if (IS_AFFECTED (vict, AFF_BLIND))
	    hitme = vict;
	}
      if (hitme != NULL)
	{
	  cast_spell (ch, hitme, NULL, SPELL_CURE_BLIND);
	  return TRUE;
	}

      for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
	{
	  temp1 = GET_HIT (vict) / GET_MAX_HIT (vict);
	  if (temp1 < temp2)
	    {
	      temp2 = temp1;
	      hitme = vict;
	    }
	}
    if (hitme != NULL) {
          cast_spell(ch, hitme, NULL, SPELL_CURE_LIGHT);
          return TRUE;
          }
    }
  return 0;
}

SPECIAL (temple_healer)
{
  struct char_data *vict;
  struct char_data *hitme = NULL;
  static int this_hour;
  float temp1 = 1;
  float temp2 = 1;

  if (cmd)
    return FALSE;

  if (time_info.hours != 0)
    {

      this_hour = time_info.hours;

      for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
	{
	  if (IS_AFFECTED (vict, AFF_POISON))
	    hitme = vict;
	}
      if (hitme != NULL)
	{
	  cast_spell (ch, hitme, NULL, SPELL_REMOVE_POISON);
	  return TRUE;
	}

      for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
	{
	  if (IS_AFFECTED (vict, AFF_CURSE))
	    hitme = vict;
	}
      if (hitme != NULL)
	{
	  cast_spell (ch, hitme, NULL, SPELL_REMOVE_CURSE);
	  return TRUE;
	}

      for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
	{
	  if (IS_AFFECTED (vict, AFF_BLIND))
	    hitme = vict;
	}
      if (hitme != NULL)
	{
	  cast_spell (ch, hitme, NULL, SPELL_CURE_BLIND);
	  return TRUE;
	}

      for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
	{
	  temp1 = GET_HIT (vict) / GET_MAX_HIT (vict);
	  if (temp1 < temp2)
	    {
	      temp2 = temp1;
	      hitme = vict;
	    }
	}
    if (hitme != NULL) {
          cast_spell(ch, hitme, NULL, SPELL_HEAL);
          return TRUE;
          }
    }
  return 0;
}

SPECIAL (temple_mana_regenerator)
{
  struct char_data *vict;
  struct char_data *hitme = NULL;
  static int this_hour;
  float temp1 = 1;
  float temp2 = 1;

  if (cmd)
    return FALSE;

  if (time_info.hours != 0)
    {

      this_hour = time_info.hours;

      for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room)
	{
	  temp1 = GET_MANA (vict) / GET_MAX_MANA (vict);
	  if (temp1 < temp2)
	    {
	      temp2 = temp1;
	      hitme = vict;
	    }
	}
    if (hitme != NULL) {
          cast_spell(ch, hitme, NULL, SPELL_REGEN_MANA);
          return TRUE;
          }
    }
  return 0;
}

SPECIAL (portal)
{
  struct obj_data *obj = (struct obj_data *) me;
  struct obj_data *port;
  char obj_name[MAX_STRING_LENGTH];

    if (!CMD_IS("enter")) return FALSE;

    argument = one_argument(argument,obj_name);
    if (!(port = get_obj_in_list_vis(ch, obj_name, world[ch->in_room].contents)))     {
      return(FALSE);
    }

    if (port != obj)
      return(FALSE);

    if (port->obj_flags.value[1] <= 0 ||
        port->obj_flags.value[1] > 32000) {
      send_to_char("The portal leads nowhere.\n\r", ch);
      return TRUE;
    }

    if (SECT(ch->in_room) == SECT_WATER_NOSWIM || SECT(port->obj_flags.value[1]) ==
SECT_WATER_NOSWIM) {
      if (RIDING(ch)) {
        if (!has_boat(RIDING(ch))) {
          send_to_char("Your mount needs a boat to go there.\r\n", ch);
          return TRUE;
        }
      }
      else
        if (!has_boat(ch)) {
          send_to_char("You need a boat to go there.\r\n", ch);
          return TRUE;
        }
    }
    act("$n enters $p, and vanishes!", FALSE, ch, port, 0, TO_ROOM);
    act("You enter $p, and you are transported elsewhere.", FALSE, ch, port, 0, TO_CHAR);
    char_from_room(ch);
    char_to_room(ch, port->obj_flags.value[1]);
    look_at_room(ch,0);
    act("$n appears from the glowing portal!", FALSE, ch, 0, 0, TO_ROOM);
  return TRUE;
}
extern int train_params[6][NUM_CLASSES];

SPECIAL(trainer)
{
  char trainitem[1024];

  if (IS_NPC(ch) || !CMD_IS("train"))
    return 0;

  skip_spaces(&argument); 

  if (!*argument) 
  {
    sprintf(buf,"Hit:%d Mana:%d Str:%d Con:%d Wis:%d Int:%d Dex:%d Cha:%d\r\n",
      (int) GET_MAX_HIT(ch), (int) GET_MAX_MANA(ch), GET_STR(ch), GET_CON(ch),
GET_WIS(ch),
      GET_INT(ch), GET_DEX(ch), GET_CHA(ch));
    sprintf(buf,"%sYou have %d training session",buf, GET_TRAINING(ch));
    if (GET_TRAINING(ch) == 1)
       sprintf(buf,"%s.\r\n",buf);
    else
       sprintf(buf,"%ss.\r\n",buf);
    send_to_char(buf,ch);
    return 1;
  }

  if (GET_TRAINING(ch) <= 0) {
    send_to_char("You do not seem to be able to train now.\r\n", ch);
    return 1;
  }

  /*  if (strcmp(argument,"hit")==0) */
  if (is_abbrev(argument,"hitpoints"))
    {
      GET_TRAINING(ch) -=1;
      ch->points.max_hit += 10;
      sprintf(trainitem, "maxhits goes up by 5!");
    } else
  if (is_abbrev(argument,"move"))
    {
      GET_TRAINING(ch) -=1;
      ch->points.max_move += 10;
      sprintf(trainitem, "maxmoves goes up by 5!");
    } else
  if (is_abbrev(argument,"mana"))
    {
      GET_TRAINING(ch) -=1;
      ch->points.max_mana += 10;
      sprintf(trainitem, "maxmana goes up by 5!");
    } else
  if (is_abbrev(argument,"strength"))
    {
      if (ch->real_abils.str >= train_params[0][(int)GET_CLASS(ch)])
       { 
	 send_to_char("Your are already fully trained there!\r\n",ch);
	 return 1; 
       }
      GET_TRAINING(ch) -=1;
      ch->real_abils.str+=1; 
      sprintf(trainitem, "strength goes up by 1!");
    } else
  if (is_abbrev(argument,"constitution"))
    {
      if (ch->real_abils.con >= train_params[1][(int)GET_CLASS(ch)])
       { send_to_char("Your are already fully trained there!\r\n",ch);
return 1; }
      GET_TRAINING(ch) -=1;
      /* ch->real_abils.con+=1; */
      ch->real_abils.con +=1; 
      sprintf(trainitem, "constitution goes up by 1!");
    } else
  if (is_abbrev(argument,"wisdom"))
    {
      if (ch->real_abils.wis >= train_params[2][(int)GET_CLASS(ch)])
       { send_to_char("Your are already fully trained there!\r\n",ch);
return 1; }
      GET_TRAINING(ch) -=1;
      ch->real_abils.wis +=1; 
      sprintf(trainitem, "wisdom goes up by 1!");
    } else
  if (is_abbrev(argument,"intelligence"))
    {
      if (ch->real_abils.intel >= train_params[3][(int)GET_CLASS(ch)])
       { send_to_char("Your are already fully trained there!\r\n",ch);
return 1; }
      GET_TRAINING(ch) -=1;
      ch->real_abils.intel+=1; 
      sprintf(trainitem, "intelligence goes up by 1!");
    } else
  if (is_abbrev(argument,"dexterity"))
    {
      if (ch->real_abils.dex >= train_params[4][(int)GET_CLASS(ch)])
       { send_to_char("Your are already fully trained there!\r\n",ch);
return 1; }
      GET_TRAINING(ch) -=1;
      ch->real_abils.dex+=1; 
      sprintf(trainitem, "dexterity goes up by 1!");
    } else
  if (is_abbrev(argument,"charisma"))
    {
      if (ch->real_abils.cha >= train_params[5][(int)GET_CLASS(ch)])
       { send_to_char("Your are already fully trained there!\r\n",ch);
return 1; }
      GET_TRAINING(ch) -=1;
      ch->real_abils.cha+=1; 
      sprintf(trainitem, "charisma goes up by 1!");
    } else
    {
      send_to_char("Train what?\r\n",ch);
      return 1;
    }
  affect_total (ch);
  save_char (ch, NOWHERE);

  sprintf(buf, "You train for a while...\r\nYour %s\r\n",trainitem);
  send_to_char(buf, ch);
  return 1;
}


SPECIAL(arenaentrancemaster)
{
//  struct char_data *who, *tmp;
  int cmd_puke = find_command("puke");
  int cmd_tell = find_command("tell");
  int fee = 0;
  char mybuf[1024];

  arenamaster = (struct char_data *) me;

  if (IS_NPC(ch) || !CMD_IS("arena"))
    return 0;
  
  skip_spaces(&argument); 

  if (!*argument) {
    fee = GET_LEVEL(ch) * arena_combatant;
    sprintf (mybuf, "%s Welcome to my Arena! Your fee as a "
	     "combatant will be %s coins,", GET_NAME(ch), numdisplay(fee));
    fee = GET_LEVEL(ch) * arena_observer;
    if (fee == 0)
      sprintf (mybuf, "%s and as an observer it's FREE!", mybuf);
    else
      sprintf (mybuf, "%s and as an observer it's %s coins.", mybuf, 
	       numdisplay(fee));

    do_tell(arenamaster, mybuf, cmd_tell, 0);
    deobserve(ch);
    clearobservers(ch);
    GET_ARENASTAT(ch) = ARENA_NOT;
    return 1;
  }
  if (is_abbrev(argument,"combatant")){
    fee = GET_LEVEL(ch) * arena_combatant;
    if (GET_GOLD(ch) < fee){
      sprintf(mybuf, "%s The fee for you is %s coins. "
	      "You don't have enough gold!", GET_NAME(ch),
	      numdisplay(fee));
      do_tell(arenamaster, mybuf, cmd_tell, 0);
      do_action(arenamaster, GET_NAME(ch), cmd_puke, 0);
      return 1;
    }
    sprintf(mybuf, "%s That'll be %s coins, thanks!", 
	    GET_NAME(ch), numdisplay(fee));
    do_tell(arenamaster, mybuf, cmd_tell, 0); 
    GET_GOLD(ch) -= fee;
    GET_ARENASTAT(ch) = ARENA_COMBATANT1;
    act ("$n admits $N as a combatant into the arena.", FALSE,
	 arenamaster, 0, ch, TO_NOTVICT);
    act ("$n admits you as a combatant into the arena.", FALSE, 
	 arenamaster, 0, ch, TO_VICT);
    char_from_room (ch);
    char_to_room (ch, real_room(arena_preproom));
    act ("$n has arrived.", FALSE, ch, 0, 0, TO_NOTVICT);
    look_at_room (ch, 0);
    if (defaultobserve != NULL){
      if (!IS_ARENACOMBATANT(defaultobserve))
	defaultobserve = ch;      
    }else{
      defaultobserve = ch;
    }
    if (GET_LEVEL(ch) < LVL_IMMORT){
      sprintf(mybuf, "%s has entered the arena as a combatant.", 
	      GET_NAME(ch));
      log (mybuf);
      do_gen_comm (arenamaster, mybuf, 1, SCMD_ARENA);
    }

    bup_affects(ch);
  } else if (is_abbrev(argument,"observer")){
    fee = GET_LEVEL(ch) * arena_observer;
    if (GET_GOLD(ch) < fee){
      sprintf(mybuf, "%s The fee for you is %s coins. "
	      "You don't have enough gold!", GET_NAME(ch),
	      numdisplay(fee));
      do_tell(arenamaster, mybuf, cmd_tell, 0); 
      do_action(arenamaster, GET_NAME(ch), cmd_puke, 0);
      return 1;
    }
    bzero(mybuf, 1024);
    if (defaultobserve == NULL)
      sprintf(mybuf, "%s Looks like there's currently no combatants there.",
	      GET_NAME(ch));
    else  if (!IS_ARENACOMBATANT(defaultobserve))
      sprintf(mybuf, "%s Looks like there's currently no combatants there.",
	      GET_NAME(ch));
    if (strlen(mybuf) > 0){
      do_tell(arenamaster, mybuf, cmd_tell, 0); 
      return 1;
    }

    if (fee == 0){
      sprintf(mybuf,"%s It's free to observe now!", GET_NAME(ch));
    }else{
      sprintf(mybuf, "%s That'll be %d coins, thanks!", 
	      GET_NAME(ch), fee);
    }
    do_tell(arenamaster, mybuf, cmd_tell, 0); 
    sprintf(mybuf, "%s You're currently observing the actions of %s.",
	    GET_NAME(ch), GET_NAME(defaultobserve));
    do_tell(arenamaster, mybuf, cmd_tell, 0); 
    /* Now let's link */
    linkobserve(ch, defaultobserve);

    GET_GOLD(ch) -= fee;
    GET_ARENASTAT(ch) = ARENA_OBSERVER;
    act ("$n admits $N into the arena observatory.", FALSE, 
	 arenamaster, 0, ch, TO_NOTVICT);
    act ("$n admits you into the arena observatory.", FALSE, 
	 arenamaster, 0, ch, TO_VICT);
    char_from_room (ch);
    char_to_room (ch, real_room(arena_observeroom));
    act ("$n has arrived.", FALSE, ch, 0, 0, TO_NOTVICT);
    look_at_room (ch, 0);

    if (GET_LEVEL(ch) < LVL_IMMORT){
      sprintf(mybuf, "%s has entered the arena as an observer.", 
	      GET_NAME(ch));
      do_gen_comm (arenamaster, mybuf, 1, SCMD_ARENA);
    }
    
  } else{
    sprintf (mybuf, "%s Welcome to my Arena! Combatant or Observer?\r\n",
	     GET_NAME(ch));
    do_tell(arenamaster, mybuf, cmd_tell, 0);
    deobserve(ch);
    clearobservers(ch);
    GET_ARENASTAT(ch) = ARENA_NOT;
    return 1;
  }

  return 1;
}

SPECIAL(tent) {
  struct obj_data *obj;
  struct descriptor_data *d, *next_d;

  if (CMD_IS("camp")) {
    if (!ismap(ch->in_room)) {
      send_to_char("You may only setup camp on the surface map.\r\n", ch);
      return 1;
    }
    for (obj=ch->carrying; obj; obj=obj->next_content) {
      if (obj==me) {
        ch->player_specials->saved.mapx=rm2x(ch->in_room);
        ch->player_specials->saved.mapy=rm2y(ch->in_room);
          send_to_char("\r\nYou setup camp and safely fall asleep...\r\n", ch);
          act("$n sets up camp and leaves the game.", FALSE, ch, 0, 0, TO_ROOM);
          write_aliases(ch);
          Crash_rentsave(ch, 0);
          sprintf (buf, "%s has camped out of the game. (%s)", GET_NAME (ch),
rcds(ch->in_room));
          mudlog (buf, NRM, MAX (LVL_IMMORT, GET_INVIS_LEV (ch)), TRUE);
          for (d = descriptor_list; d; d = next_d)
            {
              next_d = d->next;
              if (d == ch->desc)
                continue;
              if (d->character && (GET_IDNUM (d->character) == GET_IDNUM (ch)))
                close_socket (d);
            }
          extract_char(ch);
          return 1;
      }
    }
    send_to_char("You carry nothing to setup camp with.\r\n", ch);
    return 1;
  }
  return 0;
}