/
Crimson2/alias/
Crimson2/area.tmp/
Crimson2/area.tmp/AnomalySpaceDock/
Crimson2/area.tmp/AnomalyStation/
Crimson2/area.tmp/AntHill/
Crimson2/area.tmp/ArcticTerrarium/
Crimson2/area.tmp/BuilderCity/
Crimson2/area.tmp/Dungeon/
Crimson2/area.tmp/MiningDock/
Crimson2/area.tmp/PipeSystem/
Crimson2/area.tmp/RattArea/
Crimson2/area.tmp/RobotFactory/
Crimson2/area.tmp/SilverDale/
Crimson2/area.tmp/StarshipFearless/
Crimson2/area.tmp/StationConduits/
Crimson2/area.tmp/TerrariumAlpha/
Crimson2/area.tmp/TerrariumBeta/
Crimson2/area.tmp/TestArea/
Crimson2/area.tmp/Void/
Crimson2/area/
Crimson2/area/AnomalySpaceDock/
Crimson2/area/AnomalyStation/
Crimson2/area/MiningDock/
Crimson2/area/PipeSystem/
Crimson2/area/SilverDale/
Crimson2/area/StationConduits/
Crimson2/area/Void/
Crimson2/board/
Crimson2/clone/
Crimson2/lib/
Crimson2/mole/
Crimson2/mole/mole_src/HELP/
Crimson2/player/
Crimson2/util/
Crimson2/wldedit/
Crimson2/wldedit/res/
/* Crimson2 Mud Server
 * All source written/copyright Ryan Haksi 1995 *
 * This source code is proprietary. Use in whole or in part without
 * explicity permission by the author is strictly prohibited
 *
 * Current email address(es): cryogen@infoserve.net
 * Phone number: (604) 591-5295
 *
 * C4 Script Language written/copyright Cam Lesiuk 1995
 * Email: clesiuk@engr.uvic.ca
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>

#include "crimson2.h"
#include "macro.h"
#include "log.h"
#include "str.h"
#include "property.h"
#include "queue.h"
#include "send.h"
#include "parse.h"
#include "thing.h"
#include "exit.h"
#include "world.h"
#include "base.h"
#include "char.h"
#include "group.h"
#include "mobile.h"
#include "player.h"
#include "affect.h"
#include "object.h"
#include "fight.h"
#include "skill.h"
#include "effect.h"
#include "cmd_move.h"
#include "cmd_cbt.h"


/* look for something to kill along the lines of <key> <direction> */
/* synonymous with shoot, kill */
CMDPROC(CmdHit) { /*(THING *thing, BYTE *cmd)*/ 
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *target;
  EXIT  *exit;
  BYTE   dir[256];
  LWORD  range = 1; /* 1 is inside the same room,
                       thus a weapon with a range
                       of 0 isnt very usefull */

  cmd = StrOneWord(cmd, NULL);
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);
  target = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_PLR|TF_MOB, &srcOffset);

  if (!target) {
    SendThing("^wWho was that again?\n", thing);
    return;
  }

  if (target->tType==TTYPE_PLR) {
    if (thing->tType==TTYPE_PLR && Character(thing)->cLevel<6) {
      SendThing("^wYou must be at least 6th level before you may attack other players\n", thing);
      return;
    }
  }

  if (target) {
    FightStart(thing, target, 1, NULL);
    return;
  }

  /* the following is for ranged attacks */
return;

  /* Look to see if they are aiming somewhere */
  cmd = StrOneWord(cmd, dir);
  if (!*dir) return;
  if (!Character(thing)->cWeapon) return;
  if (Character(thing)->cWeapon->tType != TTYPE_OBJ) return;
  if (Obj(Character(thing)->cWeapon)->oTemplate->oType != OTYPE_WEAPON) return;

  exit = ExitFind(Wld(Base(thing)->bInside)->wExit, dir);
  while (exit) {
    range++;
    if (range > OBJECTGETFIELD(Character(thing)->cWeapon, OF_WEAPON_RANGE))
      break;
    target = CharThingFind(thing, srcKey, -1, exit->eWorld, TF_PLR|TF_MOB, &srcOffset);
    if (target) {
      FightStart(thing, target, 1, NULL);
      return;
    }
    exit = ExitDir(Wld(exit->eWorld)->wExit, exit->eDir);
  }
}

/* Add/Remove/View Current Group */
/* It would be cool if this tacked: Re, As, Lo etc combat related
 * flags after group members names
 */
CMDPROC(CmdGroup) { /*(THING *thing, BYTE *cmd)*/ 
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *target;
  BYTE   buf[256];
  BYTE   share[256];
  LWORD  followLevel = 0;
  LWORD  followNumber = 0;
  THING *i;
  THING *tree[CHAR_MAX_FOLLOW];
  LWORD  treePos;
  LWORD  j;
  LWORD  skip;

  cmd = StrOneWord(cmd, NULL);
  if (!*cmd) {
    if (!Character(thing)->cLead) {
      SendThing("You're not IN a group\n", thing);
      return;
    }
    
    /* We're going to print them a pretty picture of their group. */
     
    /* Collect Statistics on the group */
    GroupGetStat(thing,&followNumber,&followLevel);
    
    /* Show them the group */
    SendThing("^cGroup Member         ^gLevel  XP Share    Hits   Move   Power\n", thing);
    SendThing("^C-+-+-+-+-+-+         ^G-+-+-  +-+-+-+-    -+-+   -+-+   -+-+-\n", thing);
    /* ok, the stuff to follow involves recursion. That's why it's 
     * so complicated. */
    tree[0]=GroupGetHighestLeader(thing);
    tree[1]=tree[0];
    treePos=1;
    skip=0;
    do {
      /* let's print everyone at this level by this leader. */
      for (;  
        tree[treePos];  
        tree[treePos]=Character(tree[treePos])->cFollow) {
        if (Character(tree[treePos])->cLead==tree[treePos-1]) {
          /* print this character */
          for (j=0;j<(treePos-1);j++)    
            SendThing(" ", thing);
          i=tree[treePos];
          if (GroupIsGroupedMember(tree[treePos],thing)) {
            sprintf(share, "%ld%%", Character(i)->cLevel*100/followLevel);
            sprintf(buf,"^c%-15s",i->tSDesc->sText);
            SendThing(buf,thing);
            for (j=0;j<(7-treePos);j++)
              SendThing(" ", thing);
            sprintf(buf, 
                    "^g%-5hd  %-8s    %-5ld  %-5ld  %-5ld ", 
                    Character(i)->cLevel, 
                    share,
                    Character(i)->cHitP,
                    Character(i)->cMoveP,
                    Character(i)->cPowerP);
            if (i->tType == TTYPE_PLR) {
              if (BIT(Plr(i)->pAuto, PA_AUTOLOOT))
                strcat(buf, "Lo");
              if (BIT(Plr(i)->pAuto, PA_AUTOAGGR))
                strcat(buf, "Ag");
              if (BIT(Plr(i)->pAuto, PA_AUTORESCUE))
                strcat(buf, "Re");
              if (BIT(Plr(i)->pAuto, PA_AUTOASSIST))
                strcat(buf, "As");
            } else if (i->tType == TTYPE_MOB) {
              if (BIT(Mob(i)->mTemplate->mAct, MACT_RESCUE))
                strcat(buf, "Re");
              if (BIT(Mob(i)->mTemplate->mAct, MACT_AGGRESSIVE))
                strcat(buf, "Ag");
              if (BIT(Mob(i)->mTemplate->mAct, MACT_SCAVENGER))
                strcat(buf, "Sc");
            }
            strcat(buf, "\n");
          } else {
            sprintf(buf,"^C%-15s",i->tSDesc->sText);
            SendThing(buf,thing);
            for (j=0;j<(7-treePos);j++)
              SendThing(" ", thing);
            sprintf(buf,"^W<NOT GROUPED>\n");
          }
          SendThing(buf,thing);
          /* check if we need to recurse deeper */
          if (GroupIsLeader(tree[treePos])&&(tree[treePos]!=tree[treePos-1])){
            treePos++; 
            tree[treePos]=GroupGetHighestLeader(thing);
            skip=1;
            break;
          }
        }
      }
      if (!skip) {
        treePos--;
        tree[treePos]=Character(tree[treePos])->cFollow;
      }
      skip=0;
    } while(treePos>0);
    
    
 /*     if (i == GroupGetHighestLeader(i)) {
        if (BIT(Character(i)->cAffectFlag, AF_GROUP)) {
          if (BIT(Character(thing)->cAffectFlag, AF_GROUP)) {
            sprintf(share, "%ld%%", Character(i)->cLevel*100/followLevel);
            sprintf(buf, 
                    "^c%-20s ^g%-5hd  %-8s    %-5ld  %-5ld  %-5ld ", 
                    i->tSDesc->sText, 
                    Character(i)->cLevel, 
                    share,
                    Character(i)->cHitP,
                    Character(i)->cMoveP,
                    Character(i)->cPowerP);
            if (i->tType == TTYPE_PLR) {
              if (BIT(Plr(i)->pAuto, PA_AUTOLOOT))
                strcat(buf, "Lo");
              if (BIT(Plr(i)->pAuto, PA_AUTOAGGR))
                strcat(buf, "Ag");
              if (BIT(Plr(i)->pAuto, PA_AUTORESCUE))
                strcat(buf, "Re");
              if (BIT(Plr(i)->pAuto, PA_AUTOASSIST))
                strcat(buf, "As");
            } else if (i->tType == TTYPE_MOB) {
              if (BIT(Mob(i)->mTemplate->mAct, MACT_RESCUE))
                strcat(buf, "Re");
              if (BIT(Mob(i)->mTemplate->mAct, MACT_AGGRESSIVE))
                strcat(buf, "Ag");
              if (BIT(Mob(i)->mTemplate->mAct, MACT_SCAVENGER))
                strcat(buf, "Sc");
            }
            strcat(buf, "\n");
          } else {
            sprintf(buf, 
                    "^c%-20s ^w<GROUPED>\n", 
                    i->tSDesc->sText);
          }
        } else {
          sprintf(buf, 
                  "^c%-20s ^w<NOT GROUPED>\n", 
                  i->tSDesc->sText);
        }
      } else if (Character(i)->cLead==thing) {
        sprintf(buf, 
                "^c%-20s ^y<FOLLOWING YOU>\n", 
                i->tSDesc->sText);
      } else if (Character(i)->cLead==i) {
        sprintf(buf, 
                "^c%-20s ^y<LEADING>\n", 
                i->tSDesc->sText);
      } else if (i==Character(thing)->cLead && Character(i)->cLead) {
        sprintf(buf, 
                "^c%-20s ^p<FOLLOWING> %s, <LEADING YOU>\n", 
                i->tSDesc->sText,
                Character(i)->cLead->tSDesc->sText);
      } else if (Character(i)->cLead) {
        sprintf(buf, 
                "^c%-20s ^p<FOLLOWING> %s\n", 
                i->tSDesc->sText,
                Character(i)->cLead->tSDesc->sText);
      } else
        buf[0]=0;
        
      if (buf[0]) SendThing(buf, thing);
    }*/
    
    sprintf(buf, "\n^wPeople in Group: ^c%ld, ^wTotal Level: ^c%ld\n", followNumber, followLevel);
    SendThing(buf, thing);
    return;
  }

  
  /* add or remove target as appropriate */

  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);
  target = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_PLR|TF_MOB, &srcOffset);
  if (target) {
    if (Character(target)->cLead != thing) {
      SendThing("They're not following you\n", thing);
    } else if (target==thing) {
      SendThing("You are always grouped within the group you lead\n", thing);
    } else {
      BITFLIP(Character(target)->cAffectFlag, AF_GROUP);
      if (!GroupVerifySize(thing)) {
        BITFLIP(Character(target)->cAffectFlag, AF_GROUP);
	SendAction("You cannout group $N: your group would be too big!\n",
	  thing, target, SEND_SRC|SEND_CAPFIRST);
	SendAction("$n tried to group you but failed: $n's group would be too big!\n",
	  thing, target, SEND_DST|SEND_VISIBLE|SEND_CAPFIRST);
	SendAction("$n tried to group $N but failed: $n's group would be too big!\n",
	  thing, target, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
	return;
      }
      if (BIT(Character(target)->cAffectFlag, AF_GROUP)) {
        SendAction("You add $N to your group\n", 
       thing, target, SEND_SRC |SEND_AUDIBLE|SEND_CAPFIRST);
        SendAction("$n adds you to $s group\n", 
       thing, target, SEND_DST |SEND_AUDIBLE|SEND_CAPFIRST);
        SendAction("$n adds $N to $s group\n",   
       thing, target, SEND_ROOM|SEND_AUDIBLE|SEND_CAPFIRST);
      } else {
        SendAction("You kick $N out of your group\n", 
       thing, target, SEND_SRC |SEND_AUDIBLE|SEND_CAPFIRST);
        SendAction("$n kicks you out of $s group\n", 
       thing, target, SEND_DST |SEND_AUDIBLE|SEND_CAPFIRST);
        SendAction("$n kicks $N out of $s group\n",   
       thing, target, SEND_ROOM|SEND_AUDIBLE|SEND_CAPFIRST);
      }
    }
  }
} 


/* Follow / Unfollow somebody */
CMDPROC(CmdFollow) { /*(THING *thing, BYTE *cmd)*/ 
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *target;

  /*
   * Should check for domination here, the dominated cant change who
   * they are following 
   */

  cmd = StrOneWord(cmd, NULL);
  /* Stop following */
  if (!*cmd) {
    if ((!Character(thing)->cLead) || (Character(thing)->cLead==thing)) {
      SendThing("^wYes, but who do you want to follow...\n", thing);
      return;
    }
    SendAction("You stop following $N\n", 
         thing, Character(thing)->cLead, SEND_SRC |SEND_AUDIBLE|SEND_CAPFIRST);
    SendAction("$n stops following you\n", 
         thing, Character(thing)->cLead, SEND_DST |SEND_AUDIBLE|SEND_CAPFIRST);
    SendAction("$n stops following $N\n",   
         thing, Character(thing)->cLead, SEND_ROOM|SEND_AUDIBLE|SEND_CAPFIRST);
    CharRemoveFollow(thing);
    return;
  }


  /* Follow the target */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);
  target = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_PLR|TF_MOB, &srcOffset);
  if (target) {
    if (target == thing) {
      SendThing("^wYou start to follow yourself\n", thing);
      CharRemoveFollow(thing);
      return;
    }

    if (CharAddFollow(thing, target)) {
      SendAction("You start following $N\n", 
                 thing, Character(thing)->cLead, SEND_SRC |SEND_AUDIBLE|SEND_CAPFIRST);
      SendAction("$n starts following you\n", 
                 thing, Character(thing)->cLead, SEND_DST |SEND_AUDIBLE|SEND_CAPFIRST);
      SendAction("$n starts following $N\n",   
                 thing, Character(thing)->cLead, SEND_ROOM|SEND_AUDIBLE|SEND_CAPFIRST);
    } else {
      SendThing("I'm afraid they've got too many followers allready\n", thing);
    }
  }
}

/*
 * I could make this so that it pulls the text out of the skill table,
 * but I'd rather have the minor annoyance of double-entering the text
 * than a non-standard text lookup method 
 */
struct PsiListType psiList[] = {
  /* Body */
  { "Cell-Repair",     &SKILL_CELL_REPAIR,   EFFECT_CELL_REPAIR,  50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Refresh",         &SKILL_REFRESH,       EFFECT_REFRESH,      50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Endurance",       &SKILL_ENDURANCE,     EFFECT_ENDURANCE,    50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Breathwater",     &SKILL_BREATHWATER,   EFFECT_BREATHWATER,  50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Strength",        &SKILL_STRENGTH,      EFFECT_STRENGTH,     50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Darkvision",      &SKILL_DARKVISION,    EFFECT_DARKVISION,   50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Slow-Poison",     &SKILL_SLOW_POISON,   EFFECT_SLOW_POISON,  50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Cure-Poison",     &SKILL_CURE_POISON,   EFFECT_CURE_POISON,  50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Heal-Minor",      &SKILL_HEAL_MINOR,    EFFECT_HEAL_MINOR,   50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Regeneration",    &SKILL_REGENERATION,  EFFECT_REGENERATION, 50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Heal-Major",      &SKILL_HEAL_MAJOR,    EFFECT_HEAL_MAJOR,   100,25, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Dexterity",       &SKILL_DEXTERITY,     EFFECT_DEXTERITY,    50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Constitution",    &SKILL_CONSTITUTION,  EFFECT_CONSTITUTION, 50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Haste",           &SKILL_HASTE,         EFFECT_HASTE,        50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Quench",          &SKILL_QUENCH,        EFFECT_QUENCH,       50,  5, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Sustenance",      &SKILL_SUSTENANCE,    EFFECT_SUSTENANCE,   50,  5, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Acidtouch",       &SKILL_ACIDTOUCH,     EFFECT_ACIDTOUCH,    70, 10, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Poisontouch",     &SKILL_POISONTOUCH,   EFFECT_POISONTOUCH,  70, 10, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
   
  /* Telekinetic */                     
  { "Crush",           &SKILL_CRUSH,         EFFECT_CRUSH,        60, 20, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Forcestorm",      &SKILL_FORCESTORM,    EFFECT_FORCESTORM,   60, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Ghostfist",       &SKILL_GHOSTFIST,     EFFECT_GHOSTFIST,    60, 10, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Kinetic-Shield",  &SKILL_KINETIC_SHIELD,EFFECT_KINETIC_SHIELD,50,15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Immobilize",      &SKILL_IMMOBILIZE,    EFFECT_IMMOBILIZE,   50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Heartstop",       &SKILL_HEARTSTOP,     EFFECT_HEARTSTOP,    50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Asphyxiate",      &SKILL_ASPHYXIATE,    EFFECT_ASPHYXIATE,   50, 15, },
  { "Invisibility",    &SKILL_INVISIBILITY,  EFFECT_INVISIBILITY, 50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Slow",            &SKILL_SLOW,          EFFECT_SLOW,         50,  5, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "ImprovedInvis",   &SKILL_IMPROVEDINVIS, EFFECT_IMPROVEDINVIS,75, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Vacuumwalk",      &SKILL_VACUUMWALK,    EFFECT_VACUUMWALK,   50, 15, TAR_SELF_DEF},

  /* Telepathy */                     
  { "PhantomEar",      &SKILL_PHANTOMEAR,    EFFECT_PHANTOMEAR,   50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_NODEFAULT},
  { "PhantomEye",      &SKILL_PHANTOMEYE,    EFFECT_PHANTOMEYE,   50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_NODEFAULT},
  { "Mindlink",        &SKILL_MINDLINK,      EFFECT_MINDLINK,     50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_NODEFAULT},
  { "Domination",      &SKILL_DOMINATION,    EFFECT_DOMINATION,   75, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_NODEFAULT},
  { "Thoughtblade",    &SKILL_THOUGHTBLADE,  EFFECT_THOUGHTBLADE, 50,  5, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Mindcrush",       &SKILL_MINDCRUSH,     EFFECT_MINDCRUSH,    55, 10, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Deathdream",      &SKILL_DEATHDREAM,    EFFECT_DEATHDREAM,   60, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Mindshield",      &SKILL_MINDSHIELD,    EFFECT_MINDSHIELD,   50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Sleep",           &SKILL_SLEEP,         EFFECT_SLEEP,        50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_NODEFAULT},
  { "Berserk",         &SKILL_BERSERK,       EFFECT_BERSERK,      99, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Mindclear",       &SKILL_MINDCLEAR,     EFFECT_MINDCLEAR,    50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},

  /* Apportation */                     
  { "Teleport",        &SKILL_TELEPORT,      EFFECT_TELEPORT,     99, 25, TAR_SELF_DEF },
  { "Summon",          &SKILL_SUMMON,        EFFECT_SUMMON,       99, 25, TAR_PLR_WLD|TAR_MOB_WLD },
  { "Succor",          &SKILL_SUCCOR,        EFFECT_SUCCOR,       99, 25, TAR_SELF_DEF},
  { "Banish",          &SKILL_BANISH,        EFFECT_BANISH,       99, 25, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "MassTeleport",    &SKILL_MASSTELEPORT,  EFFECT_TELEPORT,     99, 25, TAR_GROUP_DEF },
  { "MassSuccor",      &SKILL_MASSSUCCOR,    EFFECT_SUCCOR,       99, 25, TAR_SELF_DEF|TAR_GROUPWLD_DEF },
  { "MassSummon",      &SKILL_MASSSUMMON,    EFFECT_SUMMON,       99, 25, TAR_SELF_DEF|TAR_GROUPWLD_DEF },
  { "DisruptDoor",     &SKILL_DISRUPTDOOR,   EFFECT_DISRUPTDOOR,  50, 15, },
  { "PhaseDoor",       &SKILL_PHASEDOOR,     EFFECT_PHASEDOOR,    50, 15, },
  { "Phasewalk",       &SKILL_PHASEWALK,     EFFECT_PHASEWALK,    50, 15, TAR_SELF_DEF},
  { "Phantompocket",   &SKILL_PHANTOMPOCKET, EFFECT_PHANTOMPOCKET,75, 25, TAR_SELF_DEF},
  { "Waterwalk",       &SKILL_WATERWALK,     EFFECT_WATERWALK,    50, 15, TAR_SELF_DEF},
  { "Teletrack",       &SKILL_TELETRACK,     EFFECT_TELETRACK,    75, 25, TAR_PLR_WLD|TAR_MOB_WLD},
  { "Recall",          &SKILL_RECALL,        EFFECT_RECALL,       75, 25, TAR_SELF_DEF },
  { "Mark",            &SKILL_MARK,          EFFECT_MARK,         75, 25, TAR_SELF_DEF },
  { "Translocate",     &SKILL_TRANSLOCATE,   EFFECT_TRANSLOCATE,  99, 30, TAR_SELF_DEF },

  /* Spirit */                     
  { "Spiritwalk",      &SKILL_SPIRITWALK,    EFFECT_SPIRITWALK,   50, 15, TAR_SELF_DEF },
  { "SenseLife",       &SKILL_SENSELIFE,     EFFECT_SENSELIFE,    50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF },
  { "SeeInvisible",    &SKILL_SEEINVISIBLE,  EFFECT_SEEINVISIBLE, 50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF },
  { "LuckShield",      &SKILL_LUCKSHIELD,    EFFECT_LUCKSHIELD,   99, 25, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF },
  { "Identify",        &SKILL_IDENTIFY,      EFFECT_IDENTIFY,    150, 50, TAR_OBJ_ROOM|TAR_OBJ_INV },
  { "Stat",            &SKILL_STAT,          EFFECT_STAT,        150, 50, TAR_PLR_ROOM|TAR_MOB_ROOM },
  { "Luckyhits",       &SKILL_LUCKYHITS,     EFFECT_LUCKYHITS,    99, 10, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF },
  { "Luckydamage",     &SKILL_LUCKYDAMAGE,   EFFECT_LUCKYDAMAGE,  99, 10, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF },

  /* Pyrokinetic */                     
  { "BurningFist",     &SKILL_BURNINGFIST,   EFFECT_BURNINGFIST,  50, 5,  TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "FlameStrike",     &SKILL_FLAMESTRIKE,   EFFECT_FLAMESTRIKE,  55, 10, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Incinerate",      &SKILL_INCINERATE,    EFFECT_INCINERATE,   60, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Ignite",          &SKILL_IGNITE,        EFFECT_IGNITE,       50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_FIGHT_DEF},
  { "Heatshield",      &SKILL_HEATSHIELD,    EFFECT_HEATSHIELD,   50, 15, TAR_PLR_ROOM|TAR_MOB_ROOM|TAR_SELF_DEF},
  { "Fireblade",       &SKILL_FIREBLADE,     EFFECT_FIREBLADE,    75, 20, TAR_SELF_DEF},
  { "Fireshield",      &SKILL_FIRESHIELD,    EFFECT_FIRESHIELD,   75, 20, TAR_SELF_DEF},
  { "Firearmor",       &SKILL_FIREARMOR,     EFFECT_FIREARMOR,    75, 20, TAR_SELF_DEF},

  { "",                0,                   0,                   0,   0,  0 }
};

/* Cast spells/Concentrate psionics etc */
CMDPROC(CmdConcentrate) { /*(THING *thing, BYTE *cmd)*/ 
  LWORD i;
  LWORD numShown;
  BYTE  buf[256];
  BYTE  line[256];
  LWORD cost;
  LWORD skill;
  
  #define SCALEFACTOR 50

  /* throwaway concentrate */
  cmd = StrOneWord(cmd, NULL);
  if (!*cmd) {
    SendThing("^wYes but the question remains, what should I cast... Your options are:\n", thing);
    numShown = 0;
    for(i=0; *psiList[i].pName; i++) {
      skill = CharGetSkill(thing, *(psiList[i].pSkill) );
      if (skill) {
        if (thing->tType==TTYPE_PLR && Character(thing)->cLevel >= LEVEL_GOD) {
          cost = 0;
        } else {
          cost = psiList[i].pMaxCost*SCALEFACTOR/( skill + SCALEFACTOR );
          MINSET(cost, psiList[i].pMinCost);
          MAXSET(cost, psiList[i].pMaxCost);
        }
        sprintf(line, "%s[%ld]", psiList[i].pName, cost);
        sprintf(buf,"%-19s", line);
        SendThing(buf, thing);
        numShown++;
        if (numShown%4 == 0) 
          SendThing("\n", thing);
      }
    }
    if (numShown%4 != 0)
      SendThing("\n", thing);
    return;
  }
  /* get the next word - ie what they cast */
  cmd = StrOneWord(cmd, buf);

  i = TYPEFIND(buf, psiList);
  if (i == -1) {
    SendThing("^wOh, good one... making this up as we go are we?", thing);
    return;
  }
  
  /* Can they cast it */
  skill = CharGetSkill(thing, *(psiList[i].pSkill) );
  if (skill <= 0) {
    SendThing("^rI'm afraid you're not very good at that sort of thing.\n", thing);
    return;
  }

  /* Calc Cost */  
  if (thing->tType==TTYPE_PLR && Character(thing)->cLevel >= LEVEL_GOD) {
    cost = 0;
  } else {
    cost = psiList[i].pMaxCost*SCALEFACTOR/( skill + SCALEFACTOR );
    MINSET(cost, psiList[i].pMinCost);
    MAXSET(cost, psiList[i].pMaxCost);
  }

  if (Character(thing)->cPowerP < cost) {
    SendThing("^rI'm afraid you dont have enough energy left for that sort of thing.\n", thing);
    return;
  }

  /* produce an effect */
  sprintf(buf, "^cYou concentrate briefly on ^g'%s' ^c(expending ^w%ld ^cpoints)\n", psiList[i].pName, cost);
  SendAction(buf, thing, NULL, SEND_SRC);
  SendAction("^c$n concentrates briefly.\n", thing, NULL, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
  thing->tWait++; /* make it so they cant initiate a command for a "round" */
  if (!Effect(psiList[i].pEffect, psiList[i].pTarget, thing, cmd, skill)) {
    SendThing("^wUmm, yeah okay, maybe you should specify a target for that\n", thing);
    return;
  }
  Character(thing)->cPowerP -= cost;
}

CMDPROC(CmdPractice) { /*(THING *thing, BYTE *cmd)*/ 
  SkillShow(thing, cmd, 0xFFFFFFFF, 0, 0); /* Thing, Cmd, CanPractice, CantPractice, maxLevel */
                                           /* Since MaxLevel is 0, it is display only and will
                                            * not allow any actual practicing to take place
                                            */
}

void CbtConsider(THING *thing, THING *target) {
  LWORD  relLevel = 1;

  if (!thing || !target) return;
  if (thing->tType<TTYPE_CHARACTER || target->tType<TTYPE_CHARACTER) return;
  relLevel = Character(target)->cLevel - Character(thing)->cLevel;
/* Tough fight */
  if (relLevel > 10) {
    SendThing("^wIt gives you the willies just thinking about it. Brrrr...\n", thing);
  } else if (relLevel > 5) {
    SendThing("^wWith a great group and a little luck you might be able to pull it off\n", thing);
  } else if (relLevel > 2) {
    SendThing("^wTheres safety in numbers, I wouldnt try this alone\n", thing);
  } else if (relLevel > 0) {
    SendThing("^wA little luck and you're there\n", thing);

/* Equal Fight */
  } else if (relLevel == 0) {
    SendThing("^wHeads you win.....\n", thing);

/* Easy Fight */
  } else if (relLevel < 10) {
    SendThing("^wSure you could do it, but why bother\n", thing);
  } else if (relLevel < 5) {
    SendThing("^wYou could take 'em in your sleep\n", thing);
  } else if (relLevel < 2) {
    SendThing("^wI dont think its going to put up too stiff a fight\n", thing);
  } else if (relLevel < 0) {
    SendThing("^wAs long as it doesnt have something up its sleeves\n", thing);
  }

  /* Warn if their weapon sucks */
}

CMDPROC(CmdConsider) { /*(THING *thing, BYTE *cmd)*/ 
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *target;

  cmd = StrOneWord(cmd, NULL);
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);
  target = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_PLR|TF_MOB, &srcOffset);
  if (!target) {
    SendThing("^wWho was that again?\n", thing);
    return;
  }
  CbtConsider(thing, target);
}

BYTE Flee(THING *thing) {
  EXIT  *exit;
  LWORD  exitNum;
  LWORD  success = FALSE;
  LWORD  check;

  /* additional movement point cost check here */
  if (Character(thing)->cMoveP < 10)
    return FALSE;
  Character(thing)->cMoveP -= 10;

  check = DiceOpenEnded(1, 100, 100);
  if (thing->tType == TTYPE_PLR) {
    check += Plr(thing)->pSkill[SKILL_FLEE];
  } else if (thing->tType == TTYPE_MOB) {
    check += PropertyGetLWord(thing, "%Flee", Mob(thing)->mTemplate->mLevel*2);
  }
  if (Character(thing)->cFight) {
    if (Character(thing)->cFight->tType == TTYPE_PLR) {
      check -= Plr(Character(thing)->cFight)->pSkill[SKILL_PURSUE];
    } else if (Character(thing)->cFight->tType == TTYPE_MOB) {
      check -= PropertyGetLWord(Character(thing)->cFight, "%Pursue", Mob(Character(thing)->cFight)->mTemplate->mLevel*2);
    }
  }

  /* See if they made it */
  if (check >= 50) { /* 50% chance of fleeing */
    /* count exits */
    for (exitNum=0,exit=Wld(Base(thing)->bInside)->wExit; exit; exit=exit->eNext) exitNum++;
    /* pick a random direction */
    exitNum = Number(1,exitNum);
    for (exit=Wld(Base(thing)->bInside)->wExit; exit&&exitNum!=1; exit=exit->eNext,exitNum--);
    /* see if we can go this way */
    if(exit && exit->eWorld)
      success = MoveExit(thing, exit);
  } 

  if (!Character(thing)->cFight) {
    SendThing("^bAck, Eeek, panic, panic... ^P(^pWhat are we running from again?^P)\n", thing);
  } else if (!success) {
    SendThing("^wAck, Eeek, panic, panic... ^P(^bYOU COULDNT GET AWAY^P)\n", thing);
  } else {
    SendThing("^wRun Away! Run Away!\n", thing);
  }
  
  return success;
}

CMDPROC(CmdFlee) { /*(THING *thing, BYTE *cmd)*/ 
  /*
   Check for code script interception
   */

  if (!Flee(thing))
    thing->tWait++; /* make it so they cant initiate a command for a "round" */
}

BYTE CbtRescue(THING *thing, THING *target) {
  LWORD  check;
  LWORD  cost;

  if (!thing || !target || Base(target)->bInside!=Base(thing)->bInside)
    return FALSE;

  if (!Character(target)->cFight) {
    /* found somebody to rescue */
    SendThing("^wThey're not in need of rescuing right now...\n", thing);
    return FALSE;
  }

  thing->tWait+=3; /* make it so theycant initiate a command for a "round" */
  cost = RESCUE_MOVE_COST;
  cost = CharMoveCostAdjust(thing, cost);
  if (Character(thing)->cMoveP < cost) {
    /* failed the rescue */
    SendAction("^YYou try to rescue $N, ^ybut are too exhausted!\n", 
      thing, target, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^Y$n tries to rescue you, ^ybut $h is too exhausted!!\n", 
      thing, target, SEND_DST |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^Y$n tries to rescue $N, ^ybut is too exhausted!\n",   
      thing, target, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
    return FALSE;
  }
  Character(thing)->cMoveP -= cost;

  check = DiceOpenEnded(1, 100, 100);
  if (thing->tType == TTYPE_PLR) {
    check += Plr(thing)->pSkill[SKILL_RESCUE];
  } else if (thing->tType == TTYPE_MOB) {
    check += PropertyGetLWord(thing, "%Rescue", Mob(thing)->mTemplate->mLevel*2);
  }
  if (Character(target)->cFight->tType == TTYPE_PLR) {
    check -= Plr(Character(target)->cFight)->pSkill[SKILL_PURSUE];
  } else if (Character(target)->cFight->tType == TTYPE_MOB) {
    check -= PropertyGetLWord(Character(target)->cFight, "%Pursue", Mob(Character(target)->cFight)->mTemplate->mLevel*2);
  } else
    return FALSE;

  if (check >= 75) {
    /* Made the rescue */
    SendAction("^yYou rescue $N\n", 
      thing, target, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^y$n rescues you\n", 
      thing, target, SEND_DST |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^y$n rescues $N\n",   
      thing, target, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);

    FightStart(thing, Character(target)->cFight, Character(target)->cFightRange, Character(target)->cFightExit);
    Character(Character(target)->cFight)->cFight = thing;
    Character(thing)->cFight = Character(target)->cFight;
    return TRUE;
  } else {
    /* failed the rescue */
    SendAction("^YYou try to rescue $N, ^ybut FAIL!\n", 
      thing, target, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^Y$n tries to rescue you, ^ybut FAILS!\n", 
      thing, target, SEND_DST |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^Y$n tries to rescue $N, ^ybut FAILS!\n",   
      thing, target, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
    return FALSE;
  }
}

CMDPROC(CmdRescue) { /*(THING *thing, BYTE *cmd)*/ 
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *target;

  cmd = StrOneWord(cmd, NULL);
  /* Stop following */
  if (!*cmd) {
    SendThing("^wYes, but who do you want to rescue...\n", thing);
    return;
  }

  /* rescue the target */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);
  target = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_PLR|TF_MOB, &srcOffset);
  if (!target) {
    /* found somebody to rescue */
    SendThing("^wWho did you want to rescue again?...\n", thing);
    return;
  }
  CbtRescue(thing, target);
}

CMDPROC(CmdHide) { /*(THING *thing, BYTE *cmd)*/ 
  LWORD  cost; 
  LWORD  check; 

  if (BIT(Character(thing)->cAffectFlag, AF_HIDDEN)) {
    SendThing("^wBut you're allready hiding!\n", thing);
    return;
  }

  if (thing->tType == TTYPE_PLR && !Plr(thing)->pSkill[SKILL_HIDE]) {
    SendThing("^wI'm afraid you're not much good at this sort of thing\n", thing);
    return;
  }

  thing->tWait++; /* make it so theycant initiate a command for a "round" */
  cost = HIDE_MOVE_COST;
  cost = CharMoveCostAdjust(thing, cost);
  if (Character(thing)->cMoveP < cost) {
    /* failed to hide */
    SendAction("^YYou try to hide, ^ybut are too exhausted!\n", 
      thing, NULL, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^Y$n tries to hide, ^ybut is too exhausted!\n",   
      thing, NULL, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
    return;
  }
  Character(thing)->cMoveP -= cost;

  check = DiceOpenEnded(1, 100, 100);
  if (thing->tType == TTYPE_PLR) {
    check += Plr(thing)->pSkill[SKILL_HIDE];
  } else if (thing->tType == TTYPE_MOB) {
    check += PropertyGetLWord(thing, "%Hide", Mob(thing)->mTemplate->mLevel*2);
  }

  if (check >= 75) {
    SendThing("^YYou disappear into the shadows\n", thing);
    /* Should probably tell everyone who makes a PERCEPTION check
      what just happened */
    BITSET(Character(thing)->cAffectFlag, AF_HIDDEN);
  } else {
    SendAction("^YYou try to hide, ^ybut FAIL!\n", 
      thing, NULL, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^Y$n tries to hide, ^ybut FAILS!\n",   
      thing, NULL, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
  }
}


/* Peek into someone elses inventory... naughty, naughty... */
CMDPROC(CmdPeek) {
  BYTE      srcKey[256];
  LWORD     srcNum;
  LWORD     srcOffset;
  THING    *found;
  LWORD     cost;
  LWORD     guard;
  LWORD     perception;
  LWORD     peek;
  LWORD     check;
  THING    *i;

  cmd = StrOneWord(cmd, NULL);
  if (!*cmd) {
    SendThing("^rTry Peek <Person>\n", thing);
    return;
  }
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);
  
  found = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_MOB|TF_PLR, &srcOffset);
  if (!found) {
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
    return;
  }
  
  thing->tWait+=3; /* make it so they cant initiate a command for a "round" */
  cost = PEEK_MOVE_COST;
  cost = CharMoveCostAdjust(thing, cost);
  if (Character(thing)->cMoveP < cost) {
    /* failed to peek */
    SendAction("^YYou try to peek into $N's inventory, ^ybut are too exhausted!\n", 
      thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
    return;
  }
  Character(thing)->cMoveP -= cost;

  /* get skills involved */
  peek       = CharGetPeek(thing);
  if (peek <= 0) {
    SendThing("^bYou've never bothered to learn how to do that\n", thing);
    return;
  }
  
  perception = CharGetPerception(found);
  guard      = CharGetGuard(found);
  
  /* Guard against it */
  check = DiceOpenEnded(1, 100, 100);
  if (perception + 50 > peek + check) {
    if (guard > peek) {
      SendAction("^YYou try to peek into $N's inventory, but they guard against it\n", 
        thing, found, SEND_SRC |SEND_VISIBLE);
      SendAction("^YYou notice $n trying to peek into your inventory and guard against it\n", 
        thing, found, SEND_DST |SEND_VISIBLE);
      return;
    } else {
      SendAction("^YYou notice $n trying to peek into your inventory\n", 
        thing, found, SEND_DST |SEND_VISIBLE);
      peek -= guard;
    }
    /* If the mob we peeked is unfriendly to thieves attack them here */
    if (found->tType == TTYPE_MOB && perception+50 > peek + check) {
      if (Number(1,100) < 10)
        FightStart(found, thing, 1, NULL);
    }
  }
  SendAction("^YYou try to peek into $N's inventory, and see:\n", 
    thing, found, SEND_SRC |SEND_VISIBLE);
  
  for (i=found->tContain; i;) {
    check = DiceOpenEnded(1, 100, 100);
    check += peek; /* Peek has been adjusted for guard allready */
    if (check >= 75 && i->tType==TTYPE_OBJ && !Obj(i)->oEquip) {
      /* Show them the item */
      i = ThingShow(i, thing);
    } else
      i = i->tNext;
  }
  
}


/* Steal an item from someone's inventory */
CMDPROC(CmdSteal) {     /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  BYTE   dstKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  LWORD  dstOffset;
  THING *found;
  THING *search;
  THING *dest;
  LWORD  guard;
  LWORD  perception;
  LWORD  steal;
  LWORD  check;
  LWORD  cost;
  THING *i;
  LWORD  noticed = 0;

  cmd = StrOneWord(cmd, NULL); /* lose the command at the start */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, dstKey, &dstOffset);

  /* search the room for a target */
  if (*dstKey) { 
    dest = CharThingFind(thing, dstKey, -1, Base(thing)->bInside, TF_PLR|TF_MOB, &dstOffset);
  } else
    dest = NULL;
  if (!dest) {
    SendThing("^bThere doesnt appear to be anyone like that to steal from\n", thing);
    return;
  }

  /* search them for an object */
  search = dest;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV, &srcOffset);
  if (!found) {
    SendThing("^bThere doesnt appear to be anything like that on them to steal\n", thing);
    return;
  }

  /* get skills involved */
  steal      = CharGetSteal(thing);
  if (steal <= 0) {
    SendThing("^bYou've never bothered to learn how to do that\n", thing);
    return;
  }
  
  perception = CharGetPerception(dest);
  guard      = CharGetGuard(dest);
  
  while (found && srcNum!=0) {
    thing->tWait+=3; /* make it so they cant initiate a command for a "round" */
    cost = STEAL_MOVE_COST;
    cost = CharMoveCostAdjust(thing, cost);
    if (Character(thing)->cMoveP < cost) {
      SendAction("^YYou try to steal from $N's inventory, ^ybut are too exhausted!\n", 
        thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      return;
    }
    Character(thing)->cMoveP -= cost;

    if (Base(found)->bWeight + Base(thing)->bConWeight > CharGetCarryMax(thing)) {
      SendAction("^CYou try to steal ^g$N", thing, found, SEND_SRC);
      SendAction("^Cfrom ^g$N^C, but its too heavy!\n", thing, dest, SEND_SRC);
    } else {
      check = DiceOpenEnded(1, 100, 100);
      if (perception + 50 >= steal + check) {
        /* They noticed */
        steal -= guard;
        noticed += 1;
      }
      if (steal + check >= 75) {
        /* Steal succeeds */
        for (i= Base(thing)->bInside->tContain; i; i=i->tNext) {
          perception = CharGetPerception(dest);
          if (i != thing && perception+50 > steal + check) {
            /* Someone noticed acts */ 
            SendAction("^b$N ",         i, thing, SEND_SRC|SEND_VISIBLE|SEND_CAPFIRST);
            SendAction("^bsteals ^g$N ", i, found, SEND_SRC|SEND_VISIBLE);
            SendAction("^bfrom ^g$N\n", i, dest,  SEND_SRC|SEND_VISIBLE);
            noticed += 1;
          }
        }
  
        SendAction("^bYou steal ^g$N ", thing, found, SEND_SRC|SEND_CAPFIRST);
        SendAction("^bfrom ^g$N\n", thing, dest, SEND_SRC);
        ThingTo(found, thing);

        /* Infamy */
        if (DiceOpenEnded(1, 100, 100) < noticed) {
          if (thing->tType==TTYPE_PLR) {
            BYTE buf[256];

            sprintf(buf, "^yYou've been ^wcaught ^ystealing, you gain 1 point of ^wINFAMY^w!!\n");
            SendThing(buf, thing);
            PlayerGainInfamy(thing, 1, buf);
          }
        }

      } else {
        /* Steal fails */
        for (i= Base(thing)->bInside->tContain; i; i=i->tNext) {
          perception = CharGetPerception(i);
          if (i != thing && perception+50 > steal + check) {
            /* Someone noticed acts */ 
            SendAction("^b$N ", i, thing, SEND_SRC|SEND_VISIBLE|SEND_CAPFIRST);
            SendAction("^btries to steal ^g$N ", i, found, SEND_SRC|SEND_VISIBLE);
            SendAction("^bfrom ^g$N^w and FAILS!\n", i, dest,  SEND_SRC|SEND_VISIBLE);
            noticed += 1;
          }
        }
  
        SendAction("^bYou try to steal ^g$N ", thing, found, SEND_SRC|SEND_CAPFIRST);
        SendAction("^bfrom ^g$N ^wand FAIL!\n", thing, dest, SEND_SRC);

        /* Infamy */
        if (DiceOpenEnded(1, 100, 100) < noticed/2) {
          if (thing->tType==TTYPE_PLR) {
            BYTE buf[256];

            sprintf(buf, "^yYou've been ^wcaught ^ystealing, you gain 1 point of ^wINFAMY^w!!\n");
            SendThing(buf, thing);
            PlayerGainInfamy(thing, 1, buf);
          }
        }

        /* If the mob we steal from is unfriendly to thieves attack them here */
        if (dest->tType == TTYPE_MOB && perception+50 > steal + check) {
          FightStart(dest, thing, 1, NULL);
        }
      }
    }

    /* see if there is more (will not find successive matches unless offset is TF_ALLMATCH) */
    found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV|TF_CONTINUE, &srcOffset);
    if (srcNum>0) srcNum--;
  }
}

/* Steal an item from someone's inventory */
CMDPROC(CmdPickpocket) {     /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   buf[256];
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *found;
  THING *search;
  LWORD  guard;
  LWORD  perception;
  LWORD  pickpocket;
  LWORD  check;
  LWORD  cost;
  LWORD  amount;
  THING *i;

  cmd = StrOneWord(cmd, NULL); /* lose the command at the start */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);

  /* search the room for a target */
  search = Base(thing)->bInside;
  if (*srcKey) { 
    found = CharThingFind(thing, srcKey, -1, search, TF_PLR|TF_MOB, &srcOffset);
  } else
    found = NULL;
  if (!found) {
    SendThing("^bThere doesnt appear to be anyone like that to pickpocket\n", thing);
    return;
  }

  /* get skills involved */
  pickpocket = CharGetPickpocket(thing);
  if (pickpocket <= 0) {
    SendThing("^bYou've never bothered to learn how to do that\n", thing);
    return;
  }
  
  perception = CharGetPerception(found);
  guard      = CharGetGuard(found);
  
  while (found && srcNum!=0) {
    thing->tWait+=3; /* make it so they cant initiate a command for a "round" */
    cost = PICKPOCKET_MOVE_COST;
    cost = CharMoveCostAdjust(thing, cost);
    if (Character(thing)->cMoveP < cost) {
      SendAction("^YYou try to pickpocket $N, ^ybut are too exhausted!\n", 
        thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      return;
    }
    Character(thing)->cMoveP -= cost;

    check = DiceOpenEnded(1, 100, 100);
    if (perception + 50 >= pickpocket + check) {
      /* They noticed */
      pickpocket -= guard;
    }
    if (pickpocket + check >= 75) {
      /* Steal succeeds */
      for (i= Base(thing)->bInside->tContain; i; i=i->tNext) {
        perception = CharGetPerception(found);
        if (i != thing && perception+50 > pickpocket + check) {
          /* Someone noticed acts */ 
          SendAction("^b$N ", i, thing, SEND_SRC|SEND_VISIBLE|SEND_CAPFIRST);
          SendAction("^bpicks ^g$N's pocket\n", i, found, SEND_SRC|SEND_VISIBLE);
        }
      }
  
      SendAction("^bYou pick ^g$N's ^bpocket ", thing, found, SEND_SRC|SEND_CAPFIRST);
      /* Take some money */
      if (Character(found)->cMoney == 0) {
        SendAction("but they're broke!\n", thing, found, SEND_SRC);
      } else {
        amount = Number(1, MAXV(1,pickpocket*3));
        MAXSET(amount, Character(found)->cMoney);
        Character(found)->cMoney -= amount;
        Character(thing)->cMoney += amount;
        sprintf(buf, "and get ^w%ld ^bcredits\n", amount);
        SendAction(buf, thing, found, SEND_SRC);
      }
      
    } else {
      /* Pickpocket fails */
      for (i= Base(thing)->bInside->tContain; i; i=i->tNext) {
        perception = CharGetPerception(i);
        if (i != thing && perception+50 > pickpocket + check) {
          /* Someone noticed acts */ 
          SendAction("^b$N ", i, thing, SEND_SRC|SEND_VISIBLE|SEND_CAPFIRST);
          SendAction("^btries to pickpocket ^g$N^w and FAILS!\n", i, found,  SEND_SRC|SEND_VISIBLE);
        }
      }
  
      SendAction("^bYou try to pickpocket ^g$N ^wand FAIL!\n", thing, found, SEND_SRC);

      /* If the mob we pickpocket is unfriendly to thieves attack them here */
      if (found->tType == TTYPE_MOB && perception+50 > pickpocket + check) {
        FightStart(found, thing, 1, NULL);
      }
    }

    /* see if there is more (will not find successive matches unless offset is TF_ALLMATCH) */
    found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV|TF_CONTINUE, &srcOffset);
    if (srcNum>0) srcNum--;
  }
}