crodo_mud/cnf/
crodo_mud/lib/
crodo_mud/lib/house/
crodo_mud/lib/misc/
crodo_mud/lib/plralias/F-J/
crodo_mud/lib/plralias/U-Z/
crodo_mud/lib/plrobjs/
crodo_mud/lib/plrvars/A-E/
crodo_mud/lib/plrvars/F-J/
crodo_mud/lib/plrvars/K-O/
crodo_mud/lib/plrvars/P-T/
crodo_mud/lib/plrvars/U-Z/
crodo_mud/lib/text/
crodo_mud/lib/text/help/
crodo_mud/lib/world/
crodo_mud/src/
/* ************************************************************************
*   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 "constants.h"
#include "money.h"
#include "profs.h"

/*   external vars  */
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 spell_info_type spell_info[];
extern int guild_info[][3];

/* extern functions */
void add_follower(struct char_data * ch, struct char_data * leader);
void parse_multiclass(struct char_data * ch);
ACMD(do_drop);
ACMD(do_gen_door);
ACMD(do_say);
ACMD(do_profs);

/* local functions */
void sort_spells(void);
int compare_spells(const void *x, const void *y);
const char *how_good(int percent);
void list_skills(struct char_data * ch);
SPECIAL(guild);
SPECIAL(dump);
void npc_steal(struct char_data * ch, struct char_data * victim);
SPECIAL(snake);
SPECIAL(thief);
SPECIAL(magic_user);
SPECIAL(guild_guard);
SPECIAL(puff);
SPECIAL(fido);
SPECIAL(janitor);
SPECIAL(cityguard);
SPECIAL(death);
SPECIAL(pet_shops);
SPECIAL(bank);
SPECIAL(arena_guard);
SPECIAL(arena_shop);
SPECIAL(arena_exit);
SPECIAL(convictlist);


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

int spell_sort_info[MAX_SKILLS + 1];

int compare_spells(const void *x, const void *y)
{
  int	a = *(const int *)x,
	b = *(const int *)y;

  return strcmp(spell_info[a].name, spell_info[b].name);
}

void sort_spells(void)
{
  int a;

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

  qsort(&spell_sort_info[1], MAX_SKILLS, sizeof(int), compare_spells);
}

const char *how_good(int percent)
{
  if (percent < 0)
    return " error)";
  if (percent == 0)
    return " (not learned)";
  if (percent <= 10)
    return " (awful)";
  if (percent <= 20)
    return " (bad)";
  if (percent <= 40)
    return " (poor)";
  if (percent <= 55)
    return " (average)";
  if (percent <= 70)
    return " (fair)";
  if (percent <= 80)
    return " (good)";
  if (percent <= 85)
    return " (very good)";

  return " (superb)";
}

const 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)
{
  int i, sortpos;

  /* Proficiency support */
   do_profs(ch, NULL, 0, 0);

  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 + strlen(buf), "You know of the following %ss:\r\n", 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)]) ||
    ((GET_SKILL(ch, i) && str_cmp(spell_info[i].name, "!UNUSED!")))) {
      sprintf(buf, "%-20s %s\r\n", spell_info[i].name, how_good(GET_SKILL(ch, i)));
      strcat(buf2, buf);	/* The above, ^ should always be safe to do. */
    }
  }

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


SPECIAL(guild)
{
  int skill_num, percent;

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

  skip_spaces(&argument);

  if (!*argument) {
    list_skills(ch);
    return (1);
  }

 /* Proficiency Support */

    if (!strcmp(argument, "weapon") || is_abbrev(argument, "weapon")) {

  if (GET_PROF_SLOTS(ch) <= 0) {
    send_to_char("You do not have enough proficiency slots to practice with.\r\n", ch);
    return (1);
  }

     if (GET_EQ(ch, WEAR_WIELD) == NULL) {
      send_to_char("You must wield a weapon to practice with.\r\n", ch);
      return (1); }

  /* First time with this weapon? */
     if (GET_CUR_PROF(ch) == NULL) {
      prof_set(ch, 2, GET_OBJ_VNUM(GET_EQ(ch, WEAR_WIELD)), 0.00);
      GET_CUR_PROF(ch) = prof_get_node(ch, 2, GET_OBJ_VNUM(GET_EQ(ch, WEAR_WIELD)));      
          }

     if (GET_CUR_PROF(ch)->value >= 90) {
      send_to_char("You are allready an expert with your weapon!\r\n", ch);
      return (1); }

     if (GET_CUR_PROF(ch)->value >= 70) {
      send_to_char("You need a more corpral type of practice to increase further.\r\n", ch);
      return (1); }

     if (GET_CUR_PROF(ch)->value >= 41) {
     GET_CUR_PROF(ch)->value = 81;
     send_to_char("You are now specialized in your weapon.\r\n", ch); 
     } else {
     GET_CUR_PROF(ch)->value = 41; 
     send_to_char("You practice makes you more proficient with your weapon.\r\n", ch); }

     GET_PROF_SLOTS(ch)--;
     return (1);
}

/* Spell & Skill processing */
  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;

  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(40, GET_OBJ_COST(k) / 10));
    extract_obj(k);
  }

  if (value) {
    send_to_char("You are awarded for outstanding performance.\r\n", ch);
    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
      add_cash_to_char(ch, value, COIN_COPPER);
  }
  return (1);
}

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


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

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

  type = number(0, 3);

  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 money 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) {
      sub_cash_from_copper(victim, gold);
      add_cash_from_copper(ch, 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), CAST_SPELL);
    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 && IN_ROOM(FIGHTING(ch)) == IN_ROOM(ch))
    vict = FIGHTING(ch);

  /* Hm...didn't pick anyone...I'll wait a round. */
  if (vict == NULL)
    return (TRUE);

  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_DUST_OF_DEAD);

  if ((GET_LEVEL(ch) > 12) && (number(0, 12) == 0)) {
    if (IS_EVIL(ch))
      cast_spell(ch, vict, NULL, SPELL_LIFE_TAP);
    else if (IS_GOOD(ch))
      cast_spell(ch, vict, NULL, SPELL_DISPEL_EVIL);
  }
  if (number(0, 4))
    return (TRUE);

  switch (GET_LEVEL(ch)) {
  case 4:
  case 5:
    cast_spell(ch, vict, NULL, SPELL_MAGIC_MISSILE);
    break;
  case 6:
  case 7:
    cast_spell(ch, vict, NULL, SPELL_CONE_OF_COLD);
    break;
  case 8:
  case 9:
    cast_spell(ch, vict, NULL, SPELL_FLAME_STRIKE);
    break;
  case 10:
  case 11:
    cast_spell(ch, vict, NULL, SPELL_ACID_ARROW);
    break;
  case 12:
  case 13:
    cast_spell(ch, vict, NULL, SPELL_LIGHTNING_BOLT);
    break;
  case 14:
  case 15:
  case 16:
  case 17:
    cast_spell(ch, vict, NULL, SPELL_PRISMATIC_SPRAY);
    break;
  default:
    cast_spell(ch, vict, NULL, SPELL_FIREBALL);
    break;
  }
  return (TRUE);

}


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

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

  if (!IS_MOVE(cmd) || AFF_FLAGGED(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_FIRST_CLASS(ch) != guild_info[i][0] &&
         GET_SECOND_CLASS(ch) != guild_info[i][0])) &&
        GET_ROOM_VNUM(IN_ROOM(ch)) == 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(puff)
{
  if (cmd)
    return (0);

  switch (number(0, 60)) {
  case 0:
    do_say(ch, "My god!  It's full of stars!", 0, 0);
    return (1);
  case 1:
    do_say(ch, "How'd all those fish get up here?", 0, 0);
    return (1);
  case 2:
    do_say(ch, "I'm a very female dragon.", 0, 0);
    return (1);
  case 3:
    do_say(ch, "I've got a peaceful, easy feeling.", 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 (IS_CORPSE(i)) {
      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) && PLR_FLAGGED(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) && PLR_FLAGGED(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);
}
SPECIAL(death) {
struct char_data *death = me;
struct obj_data *obj;
char class_arg[MAX_STRING_LENGTH];
char outmsg[MAX_STRING_LENGTH];
int cost;
int new_class = -1;
int i;
int level_exp(int chclass, int level);

      if CMD_IS("multi") {

        if (IS_NPC(ch)) {
          do_say(death, "Monsters have no class, begone!",0,0);
          return 1; }

        if (IS_MULTI(ch)) {
          do_say(death, "You have allready been reborn, begone!",0,0);
          return 1; }

        if (GET_LEVEL(ch) < 30) {
          do_say(death, "You are not worldly enough to be reborn.",0,0);
          return 1; }

        cost = GET_LEVEL(ch) * 5013;

        if (GET_GOLD(ch) < cost) {
          do_say(death, "You do not have enough cash to be reborn.",0,0);
          sprintf(outmsg, "One needs%sat your level.", expand_copper(cost, 1));
          do_say(death, outmsg,0,0);
          return 1; }

        if (GET_EXP(ch) < level_exp(GET_CLASS(ch), GET_LEVEL(ch))) {
          do_say(death, "You have not the experience to be reborn.", 0,0);
          return 1; }

        one_argument(argument, class_arg);

        if (GET_CLASS(ch) == CLASS_SORCERER) {
          if (strcmp(class_arg, "warrior") == 0)
             new_class = CLASS_SORCERER_WARRIOR;
          if (strcmp(class_arg, "rogue")  == 0)
             new_class = CLASS_SORCERER_THIEF;
          if (strcmp(class_arg, "necromancer") == 0)
             new_class = CLASS_SORCERER_NECROMANCER; }

        if (GET_CLASS(ch) == CLASS_NECROMANCER) {
          if (strcmp(class_arg, "warrior") == 0)
             new_class = CLASS_NECROMANCER_WARRIOR;
          if (strcmp(class_arg, "rogue")  == 0)
             new_class = CLASS_NECROMANCER_THIEF;
          if (strcmp(class_arg, "mage") == 0)
             new_class = CLASS_NECROMANCER_SORCERER; }

        if (GET_CLASS(ch) == CLASS_THIEF) {
          if (strcmp(class_arg, "warrior") == 0)
             new_class = CLASS_THIEF_WARRIOR;
          if (strcmp(class_arg, "mage") == 0)
             new_class = CLASS_THIEF_SORCERER;
          if (strcmp(class_arg, "necromancer") == 0)
             new_class = CLASS_THIEF_NECROMANCER; }

	if (GET_CLASS(ch) == CLASS_WARRIOR) {
          if (strcmp(class_arg, "mage") == 0)
             new_class = CLASS_WARRIOR_SORCERER;
          if (strcmp(class_arg, "rogue") == 0)
             new_class = CLASS_WARRIOR_THIEF;
          if (strcmp(class_arg, "necromancer") == 0)
             new_class = CLASS_WARRIOR_NECROMANCER; }


         if (new_class == -1) {
           do_say(death, "Idiot, do you mock me with such a request?",0,0);
           return 1; }

         /* If they got to here, time to multiclass them */

           GET_CLASS(ch) = new_class;
	   parse_multiclass(ch);
           sub_cash_from_copper(ch, cost);
           GET_LEVEL(ch) = 1;
           GET_EXP(ch) = 1;
           set_title(ch, NULL);

          while (ch->carrying) {
          obj = ch->carrying;
          obj_from_char(obj);
          extract_obj(obj);
                                }

         for (i = 0; i < NUM_WEARS; i++)
         if (GET_EQ(ch, i))
         extract_obj(unequip_char(ch, i));

    act("$n makes some strange gestures.\r\n"
        "A strange feeling comes upon you,\r\n"
        "Like a giant hand, light comes down\r\n"
        "from above, grabbing your body, that\r\n"
        "begins to pulse with colored lights\r\n"
        "from inside.\r\n\r\n"
        "Your head seems to be filled with demons\r\n"
        "from another plane as your body dissolves\r\n"
        "to the elements of time and space itself.\r\n"
        "Suddenly a violent explosion of light.\r\n\r\n"
        "You are reborn...", FALSE, death, 0, ch, TO_VICT);

    send_to_room("Death grins with an evil smile.\r\n", ch->in_room);
          return 1; }

          return 0; }

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

SPECIAL(pet_shops)
{
  char buf[MAX_STRING_LENGTH], pet_name[256];
  room_rnum 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, "%s - %s\r\n", expand_copper(PET_PRICE(pet), 1), GET_NAME(pet));
      send_to_char(buf, ch);
    }
    return (TRUE);
  } else if (CMD_IS("buy")) {

    two_arguments(argument, buf, 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 money!\r\n", ch);
      return (TRUE);
    }
    sub_cash_from_copper(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);

    /* 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(bank)
{
  int amount, type, dotmode;
  char currency[40];

  if (CMD_IS("balance")) {

    if (GET_BANK_GOLD(ch) > 0)
      sprintf(buf, "Balance: %s\r\n",
	      expand_copper(GET_BANK_GOLD(ch), 0));
    else
      sprintf(buf, "You currently have no money deposited.\r\n");
    send_to_char(buf, ch);
    return (1);
  } 

   if (CMD_IS("deposit")) {
    argument = one_argument(argument, arg);

    dotmode = find_all_dots(arg);

    if ((dotmode == FIND_ALL) || (dotmode == FIND_ALLDOT)) 
      amount = -100;
     else
    if ((amount = atoi(arg)) <= 0) {
      send_to_char("How much do you want to deposit?\r\n", ch);
      return (1);
    }

    if (dotmode == FIND_ALLDOT)
     strcpy(currency, arg);
    else
     one_argument(argument, currency);
 
   type = parse_cash_type(currency);

    if (strcmp(currency, "coins") == 0)
     type = 5;

    if (type < 0) {
       send_to_char("Deposit what kind of coins?\r\n", ch);
       return (1);
    }

   /* Deposit all my coins */
     if (type == 5) {

      amount = char_cash_in_copper(ch);

      if (amount < 1) {
       send_to_char("Yeah sure...all of none!\r\n", ch);
       return (1); }

      sub_cash_from_copper(ch, amount);
      GET_BANK_GOLD(ch) += amount;
      send_to_char("You deposit all of your coins.\r\n", ch);
      act("$n makes a bank transaction.", TRUE, ch, 0, FALSE, TO_ROOM);
      return (1);
      } 
     
    if ( (amount == -100) && (get_money(ch, type) < 1) ) {
      send_to_char("You cannot deposit what you do not have!\r\n",ch);
      return (1); }
     else
    if (get_money(ch, type) < amount) {
      send_to_char("You cannot deposit what you do not have!\r\n", ch);
      return (1); }

    /* If depositing all */
   if (amount == -100)
     amount = get_money(ch, type);

    sub_cash_from_char(ch, amount, type);
    GET_BANK_GOLD(ch) += value_in_copper(amount, type);
    sprintf(buf, "You deposit %d %s coins.\r\n", amount, coin_types[type]);
    send_to_char(buf, ch);
    act("$n makes a bank transaction.", TRUE, ch, 0, FALSE, TO_ROOM);
    return (1);
  }  

   if (CMD_IS("withdraw")) {
    argument = one_argument(argument, arg);
    
    if ((amount = atoi(arg)) <= 0) {
      send_to_char("How much do you want to withdraw?\r\n", ch);
      return (1);
    }

    one_argument(argument, currency);
    type = parse_cash_type(currency);

    if (type < 0) {
     send_to_char("Withdraw what kind of coins?\r\n", ch);
     return (1);
    }
    if (GET_BANK_GOLD(ch) < value_in_copper(amount, type)) {
      send_to_char("You cannot withdraw more than you have deposited!\r\n", ch);
      return (1);
    }
    add_cash_to_char(ch, amount, type);
    GET_BANK_GOLD(ch) -= value_in_copper(amount, type);
    sprintf(buf, "You withdraw %d %s coins.\r\n", amount, coin_types[type]);
    send_to_char(buf, ch);
    act("$n makes a bank transaction.", TRUE, ch, 0, FALSE, TO_ROOM);
    return (1);
  } else
    return (0);
}

SPECIAL(arena_shop) {
char outmsg[MAX_STRING_LENGTH];
char team_choice[MAX_STRING_LENGTH]; 
int gold_needed;

	gold_needed = GET_LEVEL(ch) * 10;

	if CMD_IS("list") {
	 send_to_char("Your choice of team colors are:\n\r", ch);
         send_to_char("\n\r&rRED&n\n\r&bBLUE&n\n\r\n\r",ch);
         send_to_char("You may JOIN &rRED&n, or JOIN &bBLUE&n\n\r\n\r",ch);
         send_to_char("No outlaws are allowed in the Holy Arena\n\r",ch);
	 sprintf(outmsg,"It will cost you %s to join a team.\n\r", 
		 expand_copper(gold_needed, 0));
         send_to_char(outmsg,ch);
	return 1;         }

	if CMD_IS("join") {

        if (PLR_FLAGGED(ch, PLR_RED) || PLR_FLAGGED(ch, PLR_BLUE)) {
         send_to_char("You have allready made your choice. Onward!\r\n",ch);
         return 1; }

	if (PLR_FLAGGED(ch, PLR_THIEF) || PLR_FLAGGED(ch, PLR_KILLER)) {
	 send_to_char("No outlaws permitted.  Arena combat is honorable!\r\n",ch);
	 return 1; 			 }

        if (GET_GOLD(ch) < gold_needed) {
         sprintf(outmsg,"You need %s to join!\n\r",expand_copper(gold_needed, 0));
         send_to_char(outmsg,ch);
         return 1; }

	one_argument(argument, team_choice);

	if (strcmp(team_choice, "red") == 0) {
	send_to_char("You have joined the &rRED&n team!\r\n",ch);
	SET_BIT(PLR_FLAGS(ch), PLR_RED);
	sub_cash_from_copper(ch, gold_needed);
	return 1; 			     }
	else
        if (strcmp(team_choice, "blue") == 0) {
        send_to_char("You have joined the &bBLUE&n team!\r\n",ch);
        SET_BIT(PLR_FLAGS(ch), PLR_BLUE);
        sub_cash_from_copper(ch, gold_needed);
        return 1;                            }
        else
	send_to_char("That is not a valid team.  Foolish mortal.\r\n",ch);
	return 1; }
	return 0; }

SPECIAL(arena_guard) {

	if (CMD_IS("north") && ch->in_room == real_room(3702)) {
	 if (!PLR_FLAGGED(ch, PLR_BLUE) ||
 	      PLR_FLAGGED(ch,PLR_KILLER) || PLR_FLAGGED(ch, PLR_THIEF)) {
          send_to_char("The arena Gods bar your entry",ch);
	  return 1; } }

        if (CMD_IS("south") && ch->in_room == real_room(3703)) {
         if (!PLR_FLAGGED(ch, PLR_RED) ||
              PLR_FLAGGED(ch,PLR_KILLER) || PLR_FLAGGED(ch, PLR_THIEF)) {
          send_to_char("The arena Gods bar your entry",ch);
          return 1; } }

	  return 0; }

SPECIAL(arena_exit) {

        if (CMD_IS("west") && ch->in_room == real_room(3751)) {

         REMOVE_BIT(PLR_FLAGS(ch), PLR_RED);
         REMOVE_BIT(PLR_FLAGS(ch), PLR_BLUE);

         send_to_char("&rThe Arena Gods bid you farewell.&n\r\n",ch);
                                                              }
         return 0;  }

SPECIAL(convictlist) {

struct obj_data *list = me;
struct obj_data *obj;
struct char_data *convict;
char outmsg[MAX_STRING_LENGTH];
char arg1[MAX_STRING_LENGTH];
int cell;

        if (CMD_IS("look") || CMD_IS("read")) {

        one_argument(argument, arg1);
        obj=get_obj_in_list_vis(ch, arg1, world[ch->in_room].contents);
        if (obj != list)
         return 0;

        if (ROOM_FLAGGED(ch->in_room, ROOM_JAIL))
         cell=ch->in_room;
        else
        if (ROOM_FLAGGED(ch->in_room+1, ROOM_JAIL))
         cell=ch->in_room+1;
        else
         return 0;

        send_to_char("The tally sheet lists the following inmates:\n\r",ch);

 	for(convict=world[cell].people;convict;convict=convict->next_in_room) {
         if (IS_NPC(convict))
          continue;
         if (IS_OUTLAW(convict) && GET_JAIL_TIME(convict)) {
         sprintf(outmsg, "%s - %d more ticks.\r\n",GET_NAME(convict),GET_JAIL_TIME(convict));
         send_to_char(outmsg, ch); }
        }
        return 1;
        }
        return 0;
        }