/
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
 */

/* Inventory related commands */

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

#include "crimson2.h"
#include "macro.h"
#include "queue.h"
#include "log.h"
#include "str.h"
#include "ini.h"
#include "extra.h"
#include "property.h"
#include "file.h"
#include "thing.h"
#include "index.h"
#include "area.h"
#include "reset.h"
#include "code.h"
#include "exit.h"
#include "world.h"
#include "edit.h"
#include "history.h"
#include "socket.h"
#include "send.h"
#include "base.h"
#include "affect.h"
#include "effect.h"
#include "object.h"
#include "board.h"
#include "char.h"
#include "fight.h"
#include "player.h"
#include "skill.h"
#include "parse.h"
#include "cmd_move.h"
#include "cmd_inv.h"


/* Each type of object can be worn in up to 3 different locations
   alter the table to taste */

struct WearListType wearList[] = {
  { "NOWEAR",       0, {   0,0,0 } },

  { "HEAD",         0, {   EQU_HEAD,
                           0,
                           0 } },

  { "NECK",         0, {   EQU_NECK_1,
                           EQU_NECK_2,
                           0 } },

  { "LARGE-NECK",   0, {   EQU_NECK_1|EQU_NECK_2,
                           0,
                           0 } },

  { "SHIRT",        0, {   EQU_TORSO,
                           0,
                           0 } },

  { "UPPER-BODY",   0, {   EQU_TORSO|EQU_ARM_R|EQU_ARM_L,
                           0,
                           0 } },

  { "ARM",          0, {   EQU_ARM_R,
                           EQU_ARM_L,
                           0 } },

  { "BOTH-ARMS",    0, {   EQU_ARM_R|EQU_ARM_L,
                           0,
                           0 } },

  { "WRIST",        0, {   EQU_WRIST_R,
                           EQU_WRIST_L,
                           0 } },

  { "BOTH-WRISTS",  0, {   EQU_WRIST_R|EQU_WRIST_L,
                           0,
                           0 } },

  { "HELD",         0, {   EQU_HELD_R,
                           EQU_HELD_L,
                           EQU_TAILGRIP } },

  { "TWO-HANDED",   0, {   EQU_HELD_R|EQU_HELD_L,
                           0,
                           0 } },

  { "FINGER",       0, {   EQU_FINGER_R,
                           EQU_FINGER_L,
                           0 } },

  { "WAIST",        0, {   EQU_WAIST,
                           0,
                           0 } },

  { "LEGS",         0, {   EQU_LEGS,
                           0,
                           0 } },

  { "FEET",         0, {   EQU_FEET,
                           0,
                           0 } },

  { "OVERBODY",     0, {   EQU_BODY,
                           0,
                           0 } },

  { "EITHER-HAND",  0, {   EQU_HAND_R,
                           EQU_HAND_L,
                           0 } },

  { "BOTH-HANDS",   0, {   EQU_HAND_R|EQU_HAND_L,
                           0,
                           0 } },

  { "R-HAND",       0, {   EQU_HAND_R,
                           0,
                           0 } },

  { "L-HAND",       0, {   EQU_HAND_L,
                           0,
                           0 } },

  { "MECH-ARM",     0, {   EQU_ARM_R|EQU_HELD_R,
                           EQU_ARM_L|EQU_HELD_L,
                           0 } },
  
  { "TAIL",         0, {   EQU_TAIL,
                           0,
                           0 } },

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


/* internal equipment position flags */
BYTE *equipList[] = {
  "HEAD",
  "NECK",
  "NECK",
  "TORSO",
  "OVER-BODY",
  "RIGHT-ARM",
  "LEFT-ARM",
  "RIGHT-WRIST",
  "LEFT-WRIST",
  "RIGHT-HAND",
  "LEFT-HAND",
  "HELD-IN-RIGHT-HAND",
  "HELD-IN-LEFT-HAND",
  "FINGER-ON-RIGHT-HAND",
  "FINGER-ON-LEFT-HAND",
  "WAIST",
  "LEGS",
  "FEET",
  "TAIL",
  "GRIPPED-IN-TAIL",
  ""
};


CMDPROC(CmdGet) {     /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  BYTE   dstKey[256];
  BYTE   buf[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  LWORD  dstOffset;
  THING *found;
  THING *search;
  FLAG   flag;
  THING *world;

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

  if (*dstKey) { /* search a target */
    search = CharThingFind(thing, dstKey, -1, thing, TF_OBJ, &dstOffset);
    if (!search)
      search = CharThingFind(thing, dstKey, -1, Base(thing)->bInside, TF_OBJ, &dstOffset);
    if (!search) {
      SendThing("^bThere doesnt appear to be anything like that around to look in\n", thing);
      return;
    }
  } else  /* search the room */
    search = Base(thing)->bInside;

  found = CharThingFind(thing, srcKey, -1, search, TF_OBJ, &srcOffset);
  if (!found)
    SendThing("^bThere doesnt appear to be anything to get\n", thing);

  while (found && srcNum!=0) {
    if (found->tType==TTYPE_OBJ && (Base(found)->bWeight<0)) {
      /* cant grab an item with negative weight or NOTAKE item */
      SendAction("^bYou ^ccant^b take ^g$N\n", 
        thing, found, SEND_SRC|SEND_VISIBLE|SEND_CAPFIRST);
    } else if (!CharCanCarry(thing, found)) {
      /* check if too heavy */
      SendAction("^b$N is too heavy for you to lift\n", 
        thing, found, SEND_SRC|SEND_VISIBLE|SEND_CAPFIRST);
    } else {
      /* Check whether we are looting a corpse */
      if (*dstKey 
       && search->tType==TTYPE_OBJ 
       && Obj(search)->oTemplate->oType==OTYPE_CONTAINER)
      {
        flag=OBJECTGETFIELD(search, OF_CONTAINER_CFLAG);
        if ( BIT(flag, OCF_CLOSED) ) {
          SendAction("^bYou try to take something from ^g$N ^b, then realize its closed\n", 
            thing, search, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
          SendAction("^b$n tries to take something from ^g$N ^b, then realizes that its closed\n",   
            thing, search, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
          return;
        } else if ( BIT(flag, OCF_PLAYERCORPSE) ) {
          /* check whether we are looting our OWN corpse */
          sprintf(buf, FIGHT_CORPSE_KEY, Base(thing)->bKey->sText);
          if (STRICMP(Base(search)->bKey->sText, buf)) {
            if (BIT(flag, OCF_PLAYERLOOTED)) {
              SendAction("^wYou try to loot ^g$N ^wbut someone beat you to it\n", 
                thing, search, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
              SendAction("^b$n tries to loot ^g$N ^wbut someone beat $m to it\n",   
                thing, search, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
              return;
            } else {
              BITSET(flag, OCF_PLAYERLOOTED);
              OBJECTSETFIELD(search, OF_CONTAINER_CFLAG, flag);
              srcNum = 0; /* only one object */
            }
          }
        }
      }

      /* guess we can take it */
      SendAction("^bYou get ^g$N", 
        thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^b$n gets ^g$N",   
        thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);

      /* complete the action */
      if (*dstKey) {
        SendAction(" ^bfrom $S ^g$N", thing, search, SEND_SRC|SEND_ROOM|SEND_VISIBLE);
      } 
      SendAction("\n", thing, search, SEND_SRC|SEND_ROOM|SEND_VISIBLE);

      if (found->tType==TTYPE_OBJ 
      && Obj(found)->oTemplate->oValue<5
      && Obj(found)->oTemplate->oValue>=0
      && thing->tType==TTYPE_PLR
      && BIT(Plr(thing)->pAuto, PA_AUTOJUNK)) {
        /* autojunk it its worthless */
        SendAction("^CYou autojunk ^g$N\n", 
          thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^C$n autojunks ^g$N\n",   
          thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
        ThingFree(found);
      } else {
        /* move the object into the chars inventory */
        if (found->tType==TTYPE_OBJ&&Obj(found)->oTemplate->oType==OTYPE_MONEY) {
          /* guard against no gain zones etc here */
          world = Base(thing)->bInside;
          if (world->tType==TTYPE_WLD 
           && BIT(areaList[Wld(world)->wArea].aResetFlag, RF_NOMONEY)) {
            sprintf(buf, "^yYou ^rWOULD ^yhave gained %ld credits! (This zone isnt open yet)\n", OBJECTGETFIELD(found, OF_MONEY_AMOUNT));
            SendThing(buf, thing);
          } else {
            sprintf(buf, "^yYou get %ld credits!\n", OBJECTGETFIELD(found, OF_MONEY_AMOUNT));
            SendThing(buf, thing);
            Character(thing)->cMoney += OBJECTGETFIELD(found, OF_MONEY_AMOUNT);
          }
          THINGFREE(found);
        } else {
          ThingTo(found, thing);
        }
      }
    }
    
    /* see if there is more (will not find successive matches unless offset is TF_ALLMATCH) */
    found = CharThingFind(thing, srcKey, -1, search, TF_OBJ|TF_CONTINUE, &srcOffset);
    if (srcNum>0) srcNum--;
  }
}

CMDPROC(CmdDrop) {    /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  BYTE   dstKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  LWORD  dstOffset;
  THING *found;
  THING *search;

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

  search = thing;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV, &srcOffset);
  if (!found)
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);

  while (found && srcNum!=0) {
    if (InvUnEquip(thing, found, IUE_BLOCKABLE)) {
      SendAction("^bYou drop ^g$N\n", 
     thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^b$n drops ^g$N\n",   
     thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
      ThingTo(found, Base(thing)->bInside);
    }

    /* 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--;
  }
}


CMDPROC(CmdJunk) {    /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *found;
  THING *search;

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

  search = thing;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV, &srcOffset);
  if (!found)
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);

  while (found && srcNum!=0) {
    if (InvUnEquip(thing, found, IUE_BLOCKABLE)) {
      SendAction("^bYou junk ^g$N\n", 
     thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^b$n junks ^g$N\n",   
     thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
      ThingFree(found);
    }

    /* 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--;
  }
}


CMDPROC(CmdPut) {     /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  BYTE   dstKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  LWORD  dstOffset;
  THING *found = NULL;
  THING *search = NULL;
  THING *dest = NULL;
  THING *ammo = NULL;
  LWORD  ammoType;
  LWORD  ammoUse;
  LWORD  ammoLeft;
  
  cmd = StrOneWord(cmd, NULL); /* lose the command at the start */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, dstKey, &dstOffset);
  
  if (*dstKey) { /* search a target */
    dest = CharThingFind(thing, dstKey, -1, thing, TF_OBJ, &dstOffset);
    if (!dest) /* search the room */
      dest = CharThingFind(thing, dstKey, -1, Base(thing)->bInside, TF_OBJ, &dstOffset);
  } else
    dest = NULL;
  if (!dest)
    SendThing("^bThere doesnt appear to be anything like that to put things into\n", thing);
  
  search = thing;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV, &srcOffset);
  if (!found) { /* also search ourself if no 2nd object specified */
    search = Base(thing)->bInside;
    found = CharThingFind(thing, srcKey, -1, search, TF_OBJ, &srcOffset);
  }
  if (!found)
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
  
  while (found && srcNum!=0) {
    if (dest) {
      ammo = ObjectGetAmmo(dest, &ammoType, &ammoUse, &ammoLeft);
      if (  (Obj(dest)->oTemplate->oType == OTYPE_CONTAINER)
          ||(Obj(found)->oTemplate->oType == OTYPE_AMMO
             && ammoType
             && OBJECTGETFIELD(found, OF_AMMO_AMMOTYPE) == ammoType)
      ) {
        if (  (Obj(dest)->oTemplate->oType == OTYPE_CONTAINER
               && Base(dest)->bConWeight + Base(found)->bWeight > OBJECTGETFIELD(dest, OF_CONTAINER_MAX))
            ||(ammoType 
               && ammo)
        ) {
          SendThing("^bYou cant fit that in there!\n", thing);
          return;
        } else if (Obj(dest)->oTemplate->oType == OTYPE_CONTAINER
                   && BIT(OBJECTGETFIELD(dest, OF_CONTAINER_CFLAG), OCF_CLOSED)
        ) {
          SendThing("^bBut its closed!\n", thing);
          return;
        } else if (dest == found) {
          SendThing("^bYou cant put something inside itself!\n", thing);
          return;
        } else {
          SendAction("^bYou put ^g$N", 
               thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
          SendAction("^b$n puts ^g$N",   
               thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
          SendAction(" ^binto ^g$N\n", 
               thing, dest, SEND_SRC|SEND_ROOM|SEND_VISIBLE);
          ThingTo(found, dest);
        }
      } else {
        SendThing("^bYou cant put that in there!\n", thing);
        return;
      }
    }
    
    /* 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 (!found) { /* also search room if no 2nd object specified */
      search = Base(thing)->bInside;
      found = CharThingFind(thing, srcKey, -1, search, TF_OBJ|TF_CONTINUE, &srcOffset);
    }
    if (srcNum>0) srcNum--;
  }
}

CMDPROC(CmdGive) {     /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   buf[256];
  BYTE   srcKey[256];
  BYTE   dstKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  LWORD  dstOffset;
  THING *found;
  THING *search;
  THING *dest;

  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 give things to\n", thing);
    return;
  }

  /* search ourself for an object */
  search = thing;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV, &srcOffset);
  /* intercept here to give credits */
  if ( (!found && StrAbbrev("credits", srcKey)) 
    || (StrExact("credits", srcKey)) )
  {
    if (srcNum < 0) {
      SendThing("^wAnd how does that work again!?!\n", thing);
      return;
    } else if (srcNum > Character(thing)->cMoney) {
      SendThing("^wYou dont have that much money!\n", thing);
      return;
    } else {
      /* transfer the money */
      Character(thing)->cMoney -= srcNum;
      Character(dest)->cMoney += srcNum;
      /* send the messages */
      sprintf(buf, "^CYou give $N %ld credits\n", srcNum);
      SendAction(buf, thing, dest, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      sprintf(buf, "^b$n gives you %ld credits\n", srcNum);
      SendAction(buf, thing, dest, SEND_DST |SEND_VISIBLE|SEND_CAPFIRST);
      sprintf(buf, "^C$n gives $N some money\n");
      SendAction(buf, thing, dest, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
      return;
    }
  }

  if (!found) {
    SendThing("^bThere doesnt appear to be anything like that around to give\n", thing);
    return;
  }

  while (found && srcNum!=0) {
    if (Base(found)->bWeight + Base(dest)->bConWeight > CharGetCarryMax(dest)) {
      SendAction("^CYou try to give ^g$N", 
        thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^C$n tries to give ^g$N",   
        thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
      SendAction(" ^Cto ^g$N^C, but its too heavy!\n", 
        thing, dest, SEND_SRC|SEND_ROOM|SEND_VISIBLE);
      SendAction(" ^bto ^gyou^C, but its too heavy!\n", 
        thing, dest, SEND_DST|SEND_VISIBLE);
    } else {
      SendAction("^bYou give ^g$N", 
        thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^b$n gives ^g$N",   
        thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
      SendAction(" ^bto ^g$N\n", 
        thing, dest, SEND_SRC|SEND_ROOM|SEND_VISIBLE);
      SendAction(" ^bto ^gyou\n", 
        thing, dest, SEND_DST|SEND_VISIBLE);
      ThingTo(found, dest);
    }

    /* 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--;
  }
}

/* Add direct applies of an equipped item */
void InvApply(THING *thing, THING *equip) {
  LWORD apply;
  LWORD aType;
  LWORD aValue;

  switch (Obj(equip)->oTemplate->oType) {
  case OTYPE_ARMOR:
    Effect(AFFECT_ARMOR,          TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_ARMOR));
    Effect(AFFECT_RES_PUNCTURE,   TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_RPUNCTURE));
    Effect(AFFECT_RES_SLASH,      TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_RSLASH));
    Effect(AFFECT_RES_CONCUSSIVE, TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_RCONCUSSIVE));
    Effect(AFFECT_RES_HEAT,       TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_RHEAT));
    Effect(AFFECT_RES_EMR,        TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_REMR));
    Effect(AFFECT_RES_LASER,      TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_RLASER));
    Effect(AFFECT_RES_PSYCHIC,    TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_RPSYCHIC));
    Effect(AFFECT_RES_ACID,       TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_RACID));
    Effect(AFFECT_RES_POISON,     TAR_AFFECT, thing, NULL, OBJECTGETFIELD(equip, OF_ARMOR_RPOISON));
    break;
  }
  /* apply direct effects */
  for (apply=0; apply < OBJECT_MAX_APPLY; apply++) {
    aType  = Obj(equip)->oApply[apply].aType;
    if (applyList[aType].aTarget==TAR_AFFECT) {
      aValue = Obj(equip)->oApply[apply].aValue;
      Effect(applyList[aType].aEffect, applyList[aType].aTarget, thing, NULL, aValue);
    }
  }
}

/* return FALSE if we cant equip this */
BYTE InvEquip(THING *thing, THING *equip, BYTE *message) {
  LWORD i;
  LWORD wearType;
  LWORD apply;
  LWORD aType;
  LWORD aValue;
  THING *ammo;
  LWORD ammoType;
  LWORD ammoUse;
  LWORD ammoLeft;

  if (message) message[0]='\0';
  /* MinStr etc */
  if (thing->tType == TTYPE_PLR) {
    if (Plr(thing)->pStr < PropertyGetLWord(thing, "%MINSTR", 0)) {
      if (message) sprintf(message, "You are not strong enough\n");
      return FALSE;
    } 
    if (Plr(thing)->pDex < PropertyGetLWord(thing, "%MINDEX", 0)) {
      if (message) sprintf(message, "You are not dexterous enough\n");
      return FALSE;
    } 
    if (Plr(thing)->pCon < PropertyGetLWord(thing, "%MINCON", 0)) {
      if (message) sprintf(message, "You are not tough enough\n");
      return FALSE;
    } 
    if (Plr(thing)->pWis < PropertyGetLWord(thing, "%MINWIS", 0)) {
      if (message) sprintf(message, "You are not wise enough\n");
      return FALSE;
    } 
    if (Plr(thing)->pInt < PropertyGetLWord(thing, "%MININT", 0)) {
      if (message) sprintf(message, "You are not smart enough\n");
      return FALSE;
    }
  }

  if (Character(thing)->cLevel < PropertyGetLWord(thing, "%MINLEVEL", 0)) {
    if (message) sprintf(message, "You are not high enough in level\n");
    return FALSE;
  }

  /* Aura check */
  if (Character(thing)->cAura>400) {
    if (BIT(Obj(equip)->oAct, OA_ANTI_GOOD)) {
      if (message) sprintf(message, "You are too good\n");
      return FALSE;
    }
  } else if (Character(thing)->cAura<-400) {
    if (BIT(Obj(equip)->oAct, OA_ANTI_EVIL)) {
      if (message) sprintf(message, "You are too evil\n");
      return FALSE;
    }
  } else if (BIT(Obj(equip)->oAct, OA_ANTI_NEUTRAL)) {
    if (message) sprintf(message, "You are too neutral\n");
    return FALSE;
  }

  /* ensure they have ammo for it */
  if (thing->tType==TTYPE_PLR && Obj(equip)->oTemplate->oType!=OTYPE_WEAPON) {
    ammo = ObjectGetAmmo(equip, &ammoType, &ammoUse, &ammoLeft);
    if (!ammo && ammoType) {
      if (message) sprintf(message, "It is out of ammo\n");
      return FALSE;
    }
  }

  wearType = Obj(equip)->oTemplate->oWear;

  /* for loop searches for an available location to equip the item in */
  for (i=0; i<MAX_EQUIP; i++) {
    if (!wearList[wearType].wEquipList[i]) continue;
    if ( ( (thing->tType == TTYPE_PLR)
         &&(!BITANY(Character(thing)->cEquip,           wearList[wearType].wEquipList[i]))
         &&( BIT(raceList[Plr(thing)->pRace].rLocation, wearList[wearType].wEquipList[i]))
         &&(!wearList[wearType].wEquipNot || !BITANY(raceList[Plr(thing)->pRace].rLocation, wearList[wearType].wEquipNot))
         )
       ||( (thing->tType == TTYPE_MOB)
         &&(!BITANY(Character(thing)->cEquip,           wearList[wearType].wEquipList[i]))
         )
       )
    {
      BITSET(Obj(equip)->oEquip,       wearList[wearType].wEquipList[i]);
      BITSET(Character(thing)->cEquip, wearList[wearType].wEquipList[i]);

      switch (Obj(equip)->oTemplate->oType) {
      case OTYPE_WEAPON:
        Character(thing)->cWeapon = equip;
        break;
      case OTYPE_LIGHT:
        if (Base(thing)->bInside->tType==TTYPE_WLD)
          Wld(Base(thing)->bInside)->wLight += OBJECTGETFIELD(equip, OF_LIGHT_INTENSITY);
        break;
      }
      
      InvApply(thing, equip);

      /* add non-direct applies */
      for (apply=0; apply < OBJECT_MAX_APPLY; apply++) {
        aType  = Obj(equip)->oApply[apply].aType;
        if (applyList[aType].aTarget!=TAR_AFFECT) {
          aValue = Obj(equip)->oApply[apply].aValue;
          Effect(applyList[aType].aEffect, applyList[aType].aTarget, thing, NULL, aValue);
        }
      }
      return TRUE;
    }
  }
  if (message) sprintf(message, "You have no place available to use that\n");
  return FALSE;
}

/* Temporarily remove applies of an equipped item, must reapply in same routine */
void InvUnapply(THING *thing, THING *equip) {
  LWORD apply;
  LWORD aType;
  LWORD aValue;

  switch (Obj(equip)->oTemplate->oType) {
  case OTYPE_ARMOR:
    EffectFree(AFFECT_ARMOR,          TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_ARMOR));
    EffectFree(AFFECT_RES_PUNCTURE,   TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_RPUNCTURE));
    EffectFree(AFFECT_RES_SLASH,      TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_RSLASH));
    EffectFree(AFFECT_RES_CONCUSSIVE, TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_RCONCUSSIVE));
    EffectFree(AFFECT_RES_HEAT,       TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_RHEAT));
    EffectFree(AFFECT_RES_EMR,        TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_REMR));
    EffectFree(AFFECT_RES_LASER,      TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_RLASER));
    EffectFree(AFFECT_RES_PSYCHIC,    TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_RPSYCHIC));
    EffectFree(AFFECT_RES_ACID,       TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_RACID));
    EffectFree(AFFECT_RES_POISON,     TAR_AFFECT, thing, OBJECTGETFIELD(equip, OF_ARMOR_RPOISON));
    break;
  }
  /* remove direct effects */
  for (apply=0; apply < OBJECT_MAX_APPLY; apply++) {
    aType  = Obj(equip)->oApply[apply].aType;
    if (applyList[aType].aTarget==TAR_AFFECT) {
      aValue = Obj(equip)->oApply[apply].aValue;
      EffectFree(applyList[aType].aEffect, applyList[aType].aTarget, thing, aValue);
    }
  }
}

/* return FALSE if we cant unequip this */
BYTE InvUnEquip(THING *thing, THING *equip, BYTE blockable) {
  LWORD apply;
  LWORD aType;
  LWORD aValue;

  /* check params for validity */
  if (!thing || !equip) return TRUE;
  if (thing->tType < TTYPE_CHARACTER) return TRUE;

  /* Check to see if its allready unequipped */
  if (equip->tType!=TTYPE_OBJ || Obj(equip)->oEquip==0)
    return TRUE;

  /* If we can, unequip it */
  if (blockable) {
    if (BIT(Obj(equip)->oAct, OA_NODROP))
      return FALSE;
  }
  BITCLR(Character(thing)->cEquip, Obj(equip)->oEquip);

  Obj(equip)->oEquip = 0;
  switch (Obj(equip)->oTemplate->oType) {
  case OTYPE_WEAPON:
    if (Character(thing)->cWeapon == equip)
      Character(thing)->cWeapon = NULL;
    break;
  case OTYPE_LIGHT:
    if (Base(thing)->bInside && Base(thing)->bInside->tType==TTYPE_WLD)
      Wld(Base(thing)->bInside)->wLight -= OBJECTGETFIELD(equip, OF_LIGHT_INTENSITY);
    break;
  }

  InvUnapply(thing, equip);

  /* remove non-direct apply's */
  for (apply=0; apply < OBJECT_MAX_APPLY; apply++) {
    aType  = Obj(equip)->oApply[apply].aType;
    if (applyList[aType].aTarget!=TAR_AFFECT) {
      aValue = Obj(equip)->oApply[apply].aValue;
      EffectFree(applyList[aType].aEffect, applyList[aType].aTarget, thing, aValue);
    }
  }
  return TRUE;
}

void InvEquipShow(THING *thing) { 
  BYTE  buf[256];
  LWORD shotLeft;
  THING *ammo;
  LWORD ammoType;
  LWORD ammoUse;
  LWORD ammoLeft;
  LWORD fireRate;

  SendThing("^pYou are currently Equipped with:\n", thing);
  SendThing("^P-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n", thing);

  CharShowEquip(thing, thing); /* show them their own equip list */
  
  /* Show Weapon */
  if (Character(thing)->cWeapon) {
    SendThing("\n^GYour Currently Selected Weapon is:\n^g", thing);
    SendThing(Character(thing)->cWeapon->tSDesc->sText, thing);
    ammo = ObjectGetAmmo(Character(thing)->cWeapon, &ammoType, &ammoUse, &ammoLeft);
    if (ammoUse>0) {
      if (!ammo)  {
        SendThing(" ^r<UNLOADED>", thing);
      } else if (ammoLeft<0) {
        SendThing(" ^r<UNLIMITED AMMO>", thing);
      } else {
        fireRate = OBJECTGETFIELD(Character(thing)->cWeapon, OF_WEAPON_FIRERATE);
        shotLeft = ammoLeft/ammoUse;
        if (!shotLeft) {
          SendThing(" ^w<OUT OF AMMO>", thing);
        } else if ( fireRate*3 > shotLeft) {
          sprintf(buf, " ^r<Only %ld shots left!>", shotLeft);
          SendThing(buf, thing);
        } else {
          sprintf(buf, " ^y<%ld shots left>", shotLeft);
          SendThing(buf, thing);
        }
      }
    } else
      SendThing(" ^r<NO AMMO NEEDED>", thing);
    SendThing("\n", thing);
  }
}

/* Eat primitive, called by CmdEat as well as PlayerTick */
void InvEat(THING *thing, THING *found) {
  LWORD poison;

  SendAction("^bYou eat ^g$N\n", 
       thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
  SendAction("^b$n eats ^g$N\n",   
       thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
  if (thing->tType == TTYPE_PLR) {
    Plr(thing)->pHunger -= OBJECTGETFIELD(found, OF_FOOD_HOWFILLING);
    /* ADD: Check OF_FOOD_POISON here too */
    poison = OBJECTGETFIELD(found, OF_FOOD_POISON);
    if (poison > 0)
      Effect(EFFECT_POISON, TAR_SELF_DEF, thing, "", poison);  
    
    /* check min hunger against race */
    BOUNDSET((-1*raceList[Plr(thing)->pRace].rMaxThirst), Plr(thing)->pThirst, raceList[Plr(thing)->pRace].rMaxThirst);
    BOUNDSET((-1*raceList[Plr(thing)->pRace].rMaxHunger), Plr(thing)->pHunger, raceList[Plr(thing)->pRace].rMaxHunger);
    BOUNDSET((-1*raceList[Plr(thing)->pRace].rMaxIntox) , Plr(thing)->pIntox,  raceList[Plr(thing)->pRace].rMaxIntox );
  }
  THINGFREE(found);
}

/* Eat primitive, called by CmdEat as well as PlayerTick */
void InvDrink(THING *thing, THING *found) {
  LWORD liquid;
  LWORD liquidLeft;
  LWORD poison;

  if (Base(found)->bInside != thing) {
    SendAction("^bYou take a drink from $A ^g$N\n", 
         thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^b$n takes a drink from $A ^g$N\n",   
         thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
  } else {
    SendAction("^bYou take a drink from your ^g$N\n", 
         thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
    SendAction("^b$n takes a drink from $s ^g$N\n",   
         thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
  }
  if (thing->tType == TTYPE_PLR) {
    liquid = OBJECTGETFIELD(found, OF_DRINKCON_LIQUID);
    TYPECHECK(liquid, oLiquidList);
    /* thirst */
    if (Plr(thing)->pThirst>=-1*raceList[Plr(thing)->pRace].rMaxThirst) {
      Plr(thing)->pThirst -= oLiquidList[liquid].oLThirst;
      BOUNDSET((-1*raceList[Plr(thing)->pRace].rMaxThirst), Plr(thing)->pThirst, raceList[Plr(thing)->pRace].rMaxThirst);
    }
    /* Hunger */
    if (Plr(thing)->pHunger>=-1*raceList[Plr(thing)->pRace].rMaxHunger) {
      Plr(thing)->pHunger += oLiquidList[liquid].oLHunger;
      BOUNDSET((-1*raceList[Plr(thing)->pRace].rMaxHunger), Plr(thing)->pHunger, raceList[Plr(thing)->pRace].rMaxHunger);
    }
    /* Intox */
    if (Plr(thing)->pIntox>=-1*raceList[Plr(thing)->pRace].rMaxIntox) {
      Plr(thing)->pIntox  += oLiquidList[liquid].oLIntox;
      BOUNDSET((-1*raceList[Plr(thing)->pRace].rMaxIntox) , Plr(thing)->pIntox,  raceList[Plr(thing)->pRace].rMaxIntox );
    }
    if (oLiquidList[liquid].oLPoison > 0)
      Effect(EFFECT_POISON, TAR_SELF_DEF, thing, "", oLiquidList[liquid].oLPoison);  
  }

  /* ADD: Check OF_DRINKCON_POISON here too */
  poison = OBJECTGETFIELD(found, OF_DRINKCON_POISON);
  if (poison > 0)
    Effect(EFFECT_POISON, TAR_SELF_DEF, thing, "", poison);  

  liquidLeft = OBJECTGETFIELD(found, OF_DRINKCON_CONTAIN);
  if (liquidLeft>0) {
    liquidLeft--;
    MINSET(liquidLeft, 0);
  }
  OBJECTSETFIELD(found, OF_DRINKCON_CONTAIN, liquidLeft);
}

CMDPROC(CmdEquip) {   /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  BYTE   dstKey[256];
  BYTE   message[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  LWORD  dstOffset;
  THING *found;

  cmd = StrOneWord(cmd, NULL); /* lose the command at the start */
  if (!*cmd) { /* give the player the list of things they have equipped */
    InvEquipShow(thing);
    return;
  }
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, dstKey, &dstOffset);
  
  found = CharThingFind(thing, srcKey, -1, thing, TF_OBJINV, &srcOffset);
  if (!found) {
    SendThing("^bEquip what?!?\n", thing);
    return;
  }
  
  while(found && srcNum!=0) {
    if (Obj(found)->oEquip==0) {
      if (InvEquip(thing, found, message)) {
        SendAction("^bYou equip yourself with ^g$N\n", 
          thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n equips $mself with ^g$N\n",   
          thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
      } else {
        /* was unable to equip the item */
        if (STRICMP(srcKey, "all")) {
          SendThing("^bYou dont seem to be able to equip ^g", thing);
          SendThing(found->tSDesc->sText, thing);
          SendThing("\n", thing);
          SendThing(message, thing);
        }
      }
    }
    
    found = CharThingFind(thing, srcKey, -1, thing, TF_OBJINV|TF_CONTINUE, &srcOffset);
    if (srcNum>0) srcNum--;
  }
}


CMDPROC(CmdUnEquip) { /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING  *found;
  AFFECT *affect;

  cmd = StrOneWord(cmd, NULL); /* lose the command at the start */
  if (!*cmd) { /* give the player the list of things they have equipped */
    InvEquipShow(thing);
    return;
  }
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);

  found = CharThingFind(thing, srcKey, -1, thing, TF_OBJEQUIP, &srcOffset);
  if (!found) {
    SendThing("^bUnEquip what?!?\n", thing);
    return;
  }

  while(found && srcNum!=0) {
    if (Obj(found)->oEquip!=0) {
      /* Expire the psi-power object */
      if (Obj(found)->oTemplate == phantomPocketTemplate) {
        affect = AffectFind(thing, EFFECT_PHANTOMPOCKET);
        if (affect) AffectRemove(thing, affect);

      /* Expire the psi-power object */
      } else if (Obj(found)->oTemplate == fireBladeTemplate) {
        affect = AffectFind(thing, EFFECT_FIREBLADE);
        if (affect) AffectRemove(thing, affect);

      /* Expire the psi-power object */
      } else if (Obj(found)->oTemplate == fireShieldTemplate) {
        affect = AffectFind(thing, EFFECT_FIRESHIELD);
        if (affect) AffectRemove(thing, affect);

      /* Expire the psi-power object */
      } else if (Obj(found)->oTemplate == fireArmorTemplate) {
        affect = AffectFind(thing, EFFECT_FIREARMOR);
        if (affect) AffectRemove(thing, affect);

      /* Try to unequip it */
      } else if (InvUnEquip(thing, found, IUE_BLOCKABLE)) {
        SendAction("^bYou unequip ^g$N\n", 
          thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n unequips ^g$N\n",   
          thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);

      /* was unable to unequip the item */
      } else {
        SendThing("^bYou dont seem to be able to unequip ^g", thing);
        SendThing(found->tSDesc->sText, thing);
        SendThing("\n", thing);
      }
    }

    found = CharThingFind(thing, srcKey, -1, thing, TF_OBJEQUIP|TF_CONTINUE, &srcOffset);
    if (srcNum>0) srcNum--;
  }
}

CMDPROC(CmdInventory) { /* void CmdProc(THING *thing, BYTE* cmd) */
  THING *show;
  BYTE  buf[256];
  SOCK *sock;
  BYTE  expert = FALSE;
  
  sock = BaseControlFind(thing);
  if (sock && BIT(Plr(sock->sHomeThing)->pAuto, PA_EXPERT)) expert = TRUE;

  if (Base(thing)->bConWeight <= CharGetCarryMax(thing)/4)
    sprintf(buf, 
            "^pYou are currently carrying: ^w%hd/%ld pounds ^y(Move cost = Normal)\n", 
            Base(thing)->bConWeight, 
            CharGetCarryMax(thing));
  else if (Base(thing)->bConWeight <= CharGetCarryMax(thing)/2)
    sprintf(buf, 
            "^pYou are currently carrying: ^w%hd/%ld pounds ^y(Move cost = 1.5X)\n", 
            Base(thing)->bConWeight, 
            CharGetCarryMax(thing));
  else if (Base(thing)->bConWeight <= 75*CharGetCarryMax(thing)/100)
    sprintf(buf, 
            "^pYou are currently carrying: ^w%hd/%ld pounds ^y(Move cost = 2X)\n", 
            Base(thing)->bConWeight, 
            CharGetCarryMax(thing));
  else 
    sprintf(buf, 
            "^pYou are currently carrying: ^w%hd/%ld pounds ^y(Move cost = 2.5X)\n", 
            Base(thing)->bConWeight, 
            CharGetCarryMax(thing));
  SendThing(buf, thing);
  SendThing("^P-=-=-=-=-=-=-=-=-=-=-=-=-=-\n", thing);
  show=thing->tContain; 
  while (show) {
    if (show->tType!=TTYPE_OBJ || Obj(show)->oEquip==0) {
      show = ThingShow(show, thing);
    } else
      show = show->tNext;
  }
  /* Hint for total newbies */
  if (Character(thing)->cEquip && Character(thing)->cLevel<=5 && !expert)
    SendHint("^;HINT: To see what you are equipped with, type ^<EQUIP\n", thing);

}

CMDPROC(CmdEat) {    /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *found;
  THING *search;
  
  cmd = StrOneWord(cmd, NULL); /* lose the command at the start */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);
  
  search = thing;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV, &srcOffset);
  if (!found)
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
  
  while (found && srcNum!=0) {
    if (InvUnEquip(thing, found, IUE_BLOCKABLE)) {
      if (Obj(found)->oTemplate->oType == OTYPE_FOOD) {
        InvEat(thing, found);
      } else {
        SendAction("^bYou try to eat the ^g$N ^bthen realize it isnt food\n", 
          thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n tries to eat $A ^g$N ^bthen realizes it isnt food\n",
          thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
      }
    } else {
      SendAction("^bYou dont seem to be able to unequip ^g$N ^blong enough to eat it!\n", 
        thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^b$n  doesnt seem to be able to unequip ^g$N ^blong enough to eat it!\n",   
        thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
    }
    
    /* 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--;
  }
}


CMDPROC(CmdDrink) {    /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *found;
  THING *search;
  LWORD  liquidLeft;
  
  cmd = StrOneWord(cmd, NULL); /* lose the command at the start */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);
  
  search = thing;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV, &srcOffset);
  if (!found)
    found = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_OBJ, &srcOffset);
  if (!found)
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
  
  while (found && srcNum!=0) {
    if (Obj(found)->oTemplate->oType == OTYPE_DRINKCON) {
      liquidLeft = OBJECTGETFIELD(found, OF_DRINKCON_CONTAIN);
      if (liquidLeft!=0) {
        InvDrink(thing, found);
      } else {
        SendAction("^bYou try to drink from ^g$N ^bthen realize its empty\n", 
          thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n tries to drink from ^g$N ^bthen realizes its empty\n",   
          thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
      }
    } else {
      SendAction("^bYou try to drink from ^g$N ^bthen realizes it isnt possible\n", 
        thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^b$n tries to eat $A ^g$N ^bthen realizes it isnt possible\n",   
        thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
    }
    
    /* 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--;
  }
}


CMDPROC(CmdFill) {     /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  BYTE   dstKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  LWORD  dstOffset;
  THING *found = NULL;
  THING *search = NULL;
  THING *dest = NULL;
  LWORD  maxFound;
  LWORD  containFound;
  LWORD  liquidFound;
  LWORD  poisonFound;
  LWORD  containDest;
  LWORD  liquidDest;
  LWORD  poisonDest;
  LWORD  transfer;
  
  cmd = StrOneWord(cmd, NULL); /* lose the command at the start */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, dstKey, &dstOffset);
  
  if (*dstKey) { /* search a target */
    dest = CharThingFind(thing, dstKey, -1, thing, TF_OBJINV, &dstOffset);
    if (!dest) /* search the room */
      dest = CharThingFind(thing, dstKey, -1, Base(thing)->bInside, TF_OBJ, &dstOffset);
  } else
    dest = NULL;
  if (!dest) {
    SendThing("^bTry something along the lines of ^wfill canteen fountain\n", thing);
    return;
  } 

  search = thing;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV, &srcOffset);
  if (!found)
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
  
  while (found && srcNum!=0) {
    if (  (Obj(found)->oTemplate->oType == OTYPE_DRINKCON)
  &&(Obj(dest )->oTemplate->oType == OTYPE_DRINKCON)
  ) {
      /* Read data from found */
      maxFound     = OBJECTGETFIELD(found, OF_DRINKCON_MAX);
      containFound = OBJECTGETFIELD(found, OF_DRINKCON_CONTAIN);
      liquidFound  = OBJECTGETFIELD(found, OF_DRINKCON_LIQUID);
      poisonFound  = OBJECTGETFIELD(found, OF_DRINKCON_POISON);
      /* read data from dest */
      containDest  = OBJECTGETFIELD(dest,  OF_DRINKCON_CONTAIN);
      liquidDest   = OBJECTGETFIELD(dest,  OF_DRINKCON_LIQUID);
      poisonDest   = OBJECTGETFIELD(dest,  OF_DRINKCON_POISON);
      
      if (containFound!=0 && liquidFound != liquidDest) {
        /* source allready has a different liquid in it */
        SendAction("^bYou start to fill your ^g$N^b, then realize that you allready have something in it\n", 
          thing, found, SEND_SRC |SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n starts to fill $s ^g$N^b, then realizes that $h allready has something in it\n",   
          thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
      } else if (containFound<0 || containFound>=maxFound) {
        /* trying to fill to an infinite source or full drinkcon */
        SendAction("^bYou start to fill your ^g$N^b, then realize its allready full\n", 
          thing, found, SEND_SRC |SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n starts to fill $s ^g$N^b, then realizes that its allready full\n",   
          thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
      } else if (containDest == 0) {
        /* trying to fill from a empty drinkcon */
        SendAction("^bYou start to fill your ^g$N", 
          thing, found, SEND_SRC |SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n starts to fill $s ^g$N",   
          thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b, but the ^g$N^b is empty\n", 
          thing, dest, SEND_SRC|SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE);
      } else if (dest==found) {
        /* trying to fill a drinkcon from itself */
        SendAction("^bYou fill your ^g$N ^bfrom itself (real productive).", 
          thing, found, SEND_SRC |SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction(
          "^b$n fills ^g$N ^bfrom itself (bright as a bubble, that one).",   
          thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
      } else {
        /* perform the fill */
        transfer = maxFound - containFound;
        if (containDest>=0) {
          MAXSET(transfer, containDest);
          containDest -= transfer;
          OBJECTSETFIELD(dest, OF_DRINKCON_CONTAIN, containDest);
        }
        containFound+=transfer;
        OBJECTSETFIELD(found, OF_DRINKCON_CONTAIN, containFound);
        /* Poison accordingly */
        if (poisonDest > poisonFound) {
          poisonFound = poisonDest;
          OBJECTSETFIELD(found, OF_DRINKCON_POISON, poisonFound);
        }
  
        SendAction("^bYou fill your ^g$N", 
          thing, found, SEND_SRC |SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n fills $s ^g$N",   
          thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction(" ^bfrom the ^g$N\n", 
          thing, dest, SEND_SRC|SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE);
      }    
    } else {
      SendAction("^bYou cant fill your $N",
        thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^bfrom the $N!\n",
        thing, dest, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
    }
    
    /* 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--;
  }
}


CMDPROC(CmdEmpty) {    /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  BYTE   dstKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  LWORD  dstOffset;
  LWORD  contain;
  THING *found;
  THING *search;
  
  cmd = StrOneWord(cmd, NULL); /* lose the command at the start */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, dstKey, &dstOffset);
  
  search = thing;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJINV, &srcOffset);
  if (!found)
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
  
  while (found && srcNum!=0) {
    if (Obj(found)->oTemplate->oType == OTYPE_DRINKCON) {
      contain = OBJECTGETFIELD(found, OF_DRINKCON_CONTAIN);
      if (contain>0) {
        /* full container */
        SendAction("^bYou empty your ^g$N ^bon the floor\n", 
             thing, found, SEND_SRC |SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n empties $s ^g$N ^bon the floor\n",   
             thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        OBJECTSETFIELD(found, OF_DRINKCON_CONTAIN, 0);
        OBJECTSETFIELD(found, OF_DRINKCON_POISON,  0);
      } else if (contain==0) {
        /* empty container */
        SendAction("^bYou hold your ^g$N ^bupside down and shake, but nothing comes out\n", 
             thing, found, SEND_SRC |SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n holds $s ^g$N ^bupside down and shakes it, but nothing comes out\n",   
             thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
      } else {
        /* infinite liquid source */
        SendAction("^bYou hold your ^g$N ^bupside down and spray liquid all over the floor\n", 
             thing, found, SEND_SRC |SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
        SendAction("^b$n holds $s ^g$N ^bupside down and sprays liquid all over the floor\n",   
             thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
      }
    } else {
      SendAction("^bYou empty your ^g$N\n", 
                thing, found, SEND_SRC |SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^b$n empties $s ^g$N\n",   
                thing, found, SEND_ROOM|SEND_AUDIBLE|SEND_VISIBLE|SEND_CAPFIRST);
    }
    while(found->tContain)
      ThingTo(found->tContain, Base(found)->bInside);
    
    
    /* 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--;
  }
}

CMDPROC(CmdRead) {    /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE      srcKey[256];
  LWORD     srcNum;
  LWORD     srcOffset;
  THING    *found;
  LWORD     i;
  LWORD     board;
  BYTE     *origCmd;

  origCmd = cmd;
  cmd = StrOneWord(cmd, NULL);
  if (!*cmd) {
    SendThing("^rTry Read <Object>\n", thing);
    return;
  }
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);
  
  found = CharThingFind(thing, srcKey, -1, thing, TF_OBJ, &srcOffset);
  if (!found)
    found = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_OBJ, &srcOffset);
  if (!found) {
    /* SendThing("^bThere doesnt appear to be anything like that around\n", thing); */
    CmdLook(thing, origCmd);
    return;
  }
  if (Obj(found)->oTemplate->oType!=OTYPE_BOARD) {
    /* SendThing("^bThat sort of thing cant have anything written on it.\n", thing); */
    CmdLook(thing, origCmd);
    return;
  }
  board = BoardOf(OBJECTGETFIELD(found, OF_BOARD_BVIRTUAL));
  if (board == -1) {
    SendThing("^wTell whoever created this thing that the virtual # is invalid\n", thing);
    return;
  }

  /* List of message titles */
  if (!*cmd) {
    BoardShow(board, thing);
    SendHint("^;HINT: Try ^<Read ^;<object> <msg#> to read a message\n", thing);
    return;
  }
  
  i = -1;
  sscanf(cmd, " %ld", &i);
  i -= 1;
  if (i<0 || i>= boardList[board].bIndex.iNum) {
    SendThing("^wThere is no message with that number\n", thing);
    return;
  }

  BoardShowMessage(board, i, thing);
}

CMDPROC(CmdEdit) {
  LWORD     board;
  BYTE      strName[256];
  BOARDMSG *boardMsg;
  LWORD     i;
  BYTE      srcKey[256];
  LWORD     srcNum;
  LWORD     srcOffset;
  THING    *found;

  if (thing->tType!=TTYPE_PLR) {
    SendThing("^rMobs cant edit messages\n", thing);
    return;
  }

  cmd = StrOneWord(cmd, NULL);
  if (!*cmd) {
    SendThing("^rTry Edit <Object> <msg #>\n", thing);
    return;
  }
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);

  found = CharThingFind(thing, srcKey, -1, thing, TF_OBJ, &srcOffset);
  if (!found)
    found = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_OBJ, &srcOffset);
  if (!found) {
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
    return;
  }
  if (Obj(found)->oTemplate->oType!=OTYPE_BOARD) {
    SendThing("^bThat sort of thing can have anything written on it.\n", thing);
    return;
  }
  board = BoardOf(OBJECTGETFIELD(found, OF_BOARD_BVIRTUAL));
  if (board == -1) {
    SendThing("^wTell whoever created this thing that the virtual # is invalid\n", thing);
    return;
  }

  /* check virtual # */
  i = -1;
  sscanf(cmd, " %ld", &i);
  i -= 1;
  if (i<0 || i>= boardList[board].bIndex.iNum) {
    SendThing("^wThere is no message with that number\n", thing);
    return;
  }
  boardMsg = BoardMsg(boardList[board].bIndex.iThing[i]);

  if (  (Character(thing)->cLevel<LEVEL_CODER) 
      ||(!StrExact(thing->tSDesc->sText, boardMsg->bAuthor->sText)) ) {
    SendThing("^rYou can only edit your own messages\n", thing);
    return;
  }

  sprintf(strName, "Board [%s]- Edit", boardList[board].bFileName);
  EDITSTR(thing, boardMsg->bText, 2048, strName, EP_ENDLF|EP_IMMNEW);
  EDITFLAG(thing, &boardList[board].bFlag, B_UNSAVED);
}


CMDPROC(CmdWrite) {
  LWORD     board;
  BYTE      strName[256];
  BOARDMSG *boardMsg;
  BYTE      srcKey[256];
  LWORD     srcNum;
  LWORD     srcOffset;
  THING    *found;

  cmd = StrOneWord(cmd, NULL);
  if (!*cmd) {
    SendThing("^rTry Write <Object> <Message Title>\n", thing);
    return;
  }
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);

  found = CharThingFind(thing, srcKey, -1, thing, TF_OBJ, &srcOffset);
  if (!found)
    found = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_OBJ, &srcOffset);
  if (!found) {
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
    return;
  }
  if (Obj(found)->oTemplate->oType!=OTYPE_BOARD) {
    SendThing("^bThat sort of thing can have anything written on it.\n", thing);
    return;
  }
  board = BoardOf(OBJECTGETFIELD(found, OF_BOARD_BVIRTUAL));
  if (board == -1) {
    SendThing("^wTell whoever created this thing that the virtual # is invalid\n", thing);
    return;
  }

  /* chuck virtual # */
  if (!*cmd)
    boardMsg = BoardMsgCreate(board, thing, "^Y<No Title>", BOARD_NOTREPLY);
  else
    boardMsg = BoardMsgCreate(board, thing, cmd, BOARD_NOTREPLY);

  if (!boardMsg) {
    SendThing("^rNot good, critical error aborting message\n", thing);
    return;
  }
  sprintf(strName, "Board [%s] - Write", boardList[board].bFileName);
  EDITSTR(thing, boardMsg->bText, 2048, strName, EP_ENDLF|EP_IMMNEW);
  EDITFLAG(thing, &boardList[board].bFlag, B_UNSAVED);
}

CMDPROC(CmdReply) {
  LWORD     board;
  BYTE      titleBuf[50];
  BYTE      strName[256];
  BOARDMSG *boardMsg;
  LWORD     i;
  BYTE      srcKey[256];
  LWORD     srcNum;
  LWORD     srcOffset;
  THING    *found;

  cmd = StrOneWord(cmd, NULL);
  if (!*cmd) {
    SendThing("^rTry Reply <Object> <msg #> [<msg title>]\n", thing);
    return;
  }
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);

  found = CharThingFind(thing, srcKey, -1, thing, TF_OBJ, &srcOffset);
  if (!found)
    found = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_OBJ, &srcOffset);
  if (!found) {
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
    return;
  }
  if (Obj(found)->oTemplate->oType!=OTYPE_BOARD) {
    SendThing("^bThat sort of thing cant have anything written on it.\n", thing);
    return;
  }
  board = BoardOf(OBJECTGETFIELD(found, OF_BOARD_BVIRTUAL));
  if (board == -1) {
    SendThing("^wTell whoever created this thing that the virtual # is invalid\n", thing);
    return;
  }

  /* check msg # */
  i = -1;
  sscanf(cmd, " %ld", &i);
  i -= 1;
  if (i<0 || i>= boardList[board].bIndex.iNum) {
    SendThing("^wThere is no message with that number\n", thing);
    return;
  }
  boardMsg = BoardMsg(boardList[board].bIndex.iThing[i]);

  cmd = StrOneWord(cmd, NULL);
  if (!*cmd) {
    strcpy(titleBuf, "Re:");
    strncpy(titleBuf+3, boardMsg->bTitle->sText, sizeof(titleBuf)-3);
    titleBuf[sizeof(titleBuf)-1] = 0;
    boardMsg = BoardMsgCreate(board, thing, titleBuf, i);
  } else
    boardMsg = BoardMsgCreate(board, thing, cmd, i);

  if (!boardMsg) {
    SendThing("^rNot good, critical error aborting message\n", thing);
    return;
  }
  sprintf(strName, "Board [%s] - Reply", boardList[board].bFileName);
  EDITSTR(thing, boardMsg->bText, 2048, strName, EP_ENDLF|EP_IMMNEW);
  EDITFLAG(thing, &boardList[board].bFlag, B_UNSAVED);
}

CMDPROC(CmdErase) {
  LWORD     board;
  BYTE      buf[256];
  BOARDMSG *boardMsg;
  LWORD     i;
  BYTE      srcKey[256];
  LWORD     srcNum;
  LWORD     srcOffset;
  THING    *found;

  cmd = StrOneWord(cmd, NULL);
  if (!*cmd) {
    SendThing("^rTry Erase <object> <msg #>\n", thing);
    return;
  }
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);

  found = CharThingFind(thing, srcKey, -1, thing, TF_OBJ, &srcOffset);
  if (!found)
    found = CharThingFind(thing, srcKey, -1, Base(thing)->bInside, TF_OBJ, &srcOffset);
  if (!found) {
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
    return;
  }
  if (Obj(found)->oTemplate->oType!=OTYPE_BOARD) {
    SendThing("^bThat sort of thing can have anything written on it.\n", thing);
    return;
  }
  board = BoardOf(OBJECTGETFIELD(found, OF_BOARD_BVIRTUAL));
  if (board == -1) {
    SendThing("^wTell whoever created this thing that the virtual # is invalid\n", thing);
    return;
  }

  /* check msg # */
  i = -1;
  sscanf(cmd, " %ld", &i);
  i -= 1;
  if (i<0 || i>= boardList[board].bIndex.iNum) {
    SendThing("^wThere is no message with that number\n", thing);
    return;
  }
  boardMsg = BoardMsg(boardList[board].bIndex.iThing[i]);

  SendThing("^wErasing:\n", thing);
  sprintf(buf, "^gMessage Number: ^G[^b%ld/%ld^G]\n", i+1, boardList[board].bIndex.iNum); 
  SendThing(buf, thing);
  sprintf(buf, "^gAuthor:         ^G[^b%s^G]\n", boardMsg->bAuthor->sText);
  SendThing(buf, thing);
  SendThing(   "^gMessage Title:  ^G[^g", thing);
  SendThing(boardMsg->bTitle->sText, thing);
  SendThing("^G]\n", thing);

  BoardMsgDelete(board, i);
}

int InvScan(THING *thing, THING *scanner, BYTE *cmd) {
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *found;
  THING *search;
  FLAG   cFlag;
  LWORD  cValue;
  FLAG   sFlag;
  LWORD  sBio;
  LWORD  sMax;
  LWORD  sChip;
  LWORD  sLeft;
  BYTE   buf[256];
  THING *world;

  if (!*cmd) {
    SendThing("^wPerhaps you should specify something to scan\n", thing);
    return TRUE;
  }

  /* Scan, yes fine but What? */
  cmd = ParseFind(cmd, srcKey, &srcOffset, &srcNum, NULL, NULL);

  search = Base(thing)->bInside;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJ, &srcOffset);
  if (!found) {
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
    return TRUE;
  }

  while (found && srcNum!=0) {
    /* Scan Found */
    while(1) {
      if (found->tType != TTYPE_OBJ
        ||Obj(found)->oTemplate->oType != OTYPE_CONTAINER) {
        SendThing("^pYou detect nothing of any particular interest\n", thing);
        break;
      } 
      cFlag  = OBJECTGETFIELD(found, OF_CONTAINER_CFLAG);
      cValue = OBJECTGETFIELD(found, OF_CONTAINER_SVALUE);
      if (!BIT(cFlag, OCF_CORPSE)) {
        SendThing("^CYou detect nothing of any particular interest\n", thing);
        break;
      }
      /* Check out their scanner */
      sFlag = OBJECTGETFIELD(scanner, OF_SCANNER_SFLAG);
      sMax  = OBJECTGETFIELD(scanner, OF_SCANNER_MAX);
      sBio  = OBJECTGETFIELD(scanner, OF_SCANNER_BIO);
      sChip = OBJECTGETFIELD(scanner, OF_SCANNER_CHIP);
      sLeft = sMax - sBio - sChip;

      /* Check if they can do that */
      if (BIT(cFlag, OCF_ELECTRONIC)) {
        if (!BIT(sFlag, OSF_SCANCHIP)) {
          SendThing("^wI'm afraid your scanner isnt capable of scanning that\n", thing);
          break;
        }
      } else {
        if (!BIT(sFlag, OSF_SCANBIO)) {
          SendThing("^wI'm afraid your scanner isnt capable of scanning that\n", thing);
          break;
        }
      }

      /* Check if they have room */
      if (sLeft < cValue) {
        SendThing("^wI'm afraid your scanner doesnt have enough memory free to scan that\n", thing);
        break;
      }

      SendAction("^wYou scan ^g$N\n",
        thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^C$n scans ^g$N\n",
        thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);

      /* guard against no gain zones etc here */
      world = Base(thing)->bInside;

      OBJECTSETFIELD(found, OF_CONTAINER_SVALUE, 0);
      if (BIT(cFlag, OCF_ELECTRONIC)) {
        sChip += cValue;
        if (world->tType==TTYPE_WLD 
         && BIT(areaList[Wld(world)->wArea].aResetFlag, RF_NOMONEY)) {
          sprintf(buf, "^YYou ^rwould ^Yhave obtained ^y%ld ^Ycredits worth of chip technology\n", cValue);
        } else {
          OBJECTSETFIELD(scanner, OF_SCANNER_CHIP, sChip);
          sprintf(buf, "^YYou obtain ^y%ld ^Ycredits worth of chip technology\n", cValue);
        }
      } else {
        sBio += cValue;
        if (world->tType==TTYPE_WLD 
         && BIT(areaList[Wld(world)->wArea].aResetFlag, RF_NOMONEY)) {
          sprintf(buf, "^YYou ^rwould ^Yhave obtained ^y%ld ^Ycredits worth of biological data\n", cValue);
        } else {
          OBJECTSETFIELD(scanner, OF_SCANNER_BIO, sBio);
          sprintf(buf, "^YYou obtain ^y%ld ^Ycredits worth of biological data\n", cValue);
        }
      }
      SendThing(buf, thing);

      if (!cValue) {
        SendThing("^wArgh! Nothing left worth scanning, someone beat you to it\n", thing);
      }
      break;
    }
    
    /* see if there is more (will not find successive matches unless offset is TF_ALLMATCH) */
    found = CharThingFind(thing, srcKey, -1, search, TF_OBJ|TF_CONTINUE, &srcOffset);
    if (srcNum>0) srcNum--;
  }
  return TRUE;
}

/* for now we'll just make it so ya gotta hold it ta use it... */
CMDPROC(CmdUse) {    /* void CmdProc(THING *thing, BYTE* cmd) */
  BYTE   srcKey[256];
  LWORD  srcNum;
  LWORD  srcOffset;
  THING *found;
  THING *search;
  LWORD  apply;
  LWORD  aType;
  LWORD  aValue;
  THING *ammo = NULL;
  LWORD  ammoType;
  LWORD  ammoUse;
  LWORD  ammoLeft;
  LWORD  success;

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

  search = thing;
  found = CharThingFind(thing, srcKey, -1, search, TF_OBJ, &srcOffset);
  if (!found) {
    search = Base(thing)->bInside;
    found = CharThingFind(thing, srcKey, -1, search, TF_OBJ, &srcOffset);
  }
  if (!found) {
    SendThing("^bThere doesnt appear to be anything like that around\n", thing);
    return;
  }

  while (found && srcNum!=0) {
    ammo = ObjectGetAmmo(found, &ammoType, &ammoUse, &ammoLeft);

    /* Block if this is carry2use and we're not carrying it */
    if (BIT(Obj(found)->oAct, OA_CARRY2USE) && search != thing) {
      SendAction("^wI'm afraid you must be carrying that to use it.\n",
        thing, found, SEND_SRC|SEND_CAPFIRST);
    }

    /* Block if we are out of ammo */
    else if (ammoType && !ammo) {
      SendAction("^wI'm afraid ^g$N is unloaded\n",
        thing, found, SEND_SRC|SEND_CAPFIRST);
    }

    else if (ammoUse > ammoLeft) {
      SendAction("^wI'm afraid ^g$N just ran outta steam\n",
        thing, found, SEND_SRC|SEND_CAPFIRST);
    }

    /* Give code Parser a crack at this */
    else if (!CodeParseUse(thing, found)) {

      /* Send they use the item message */
      SendAction("^bYou use ^g$N\n", 
        thing, found, SEND_SRC |SEND_VISIBLE|SEND_CAPFIRST);
      SendAction("^b$n uses ^g$N\n",   
        thing, found, SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);

      success = FALSE;
      /* Perform the objects actions */
      for (apply=0; apply < OBJECT_MAX_APPLY; apply++) {
        aType  = Obj(found)->oApply[apply].aType;
        aValue = Obj(found)->oApply[apply].aValue;
        success |= Effect(applyList[aType].aEffect, applyList[aType].aTarget, thing, cmd, aValue);
      }
      /* Special actions due to the object type */
      switch (Obj(found)->oTemplate->oType) {
      case OTYPE_SCANNER:
        /* Find the target etc, should I do this with an effect? */
        success |= InvScan(thing, found, cmd);
        break;
      case OTYPE_DRUG:
        if (thing->tType == TTYPE_PLR) {
          Plr(thing)->pIntox += OBJECTGETFIELD(found, OF_DRUG_INTOX);
          MAXSET(Plr(thing)->pIntox, raceList[Plr(thing)->pRace].rMaxIntox);
          success = TRUE;
        }
        break;
      }
      /* after the fact script code */
      success |= CodeParseAfterUse(thing, found);

      /* affect align if good or evil */
      if (success && thing->tType==TTYPE_PLR) {
        if (BIT(Obj(found)->oAct, OA_EVIL)) {
          if (Character(thing)->cAura > 400) {
            Character(thing)->cAura -=1;
          }
        }
        if (BIT(Obj(found)->oAct, OA_GOOD)) {
          if (Character(thing)->cAura < -400) {
            Character(thing)->cAura +=1;
          }
        }
      }

      /* tweak ammo / destroy object */
      if (!success) {
        SendAction("^wBut nothing much seems to happen\n", 
          thing, found, SEND_SRC|SEND_ROOM|SEND_VISIBLE|SEND_CAPFIRST);
      } else if (!ammo) {
      /* Destroy object or decrement ammo */
        if (ammoUse>=0) THINGFREE(found);
      } else {
        ObjectUseAmmo(found);
      }
    }

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