circlemud_squared_0.5.153/cnf/
circlemud_squared_0.5.153/etc/
circlemud_squared_0.5.153/etc/etc/
circlemud_squared_0.5.153/etc/house/
circlemud_squared_0.5.153/etc/misc/
circlemud_squared_0.5.153/etc/plralias/A-E/
circlemud_squared_0.5.153/etc/plralias/F-J/
circlemud_squared_0.5.153/etc/plralias/K-O/
circlemud_squared_0.5.153/etc/plralias/P-T/
circlemud_squared_0.5.153/etc/plralias/U-Z/
circlemud_squared_0.5.153/etc/plralias/ZZZ/
circlemud_squared_0.5.153/etc/plrobjs/
circlemud_squared_0.5.153/etc/plrobjs/A-E/
circlemud_squared_0.5.153/etc/plrobjs/F-J/
circlemud_squared_0.5.153/etc/plrobjs/K-O/
circlemud_squared_0.5.153/etc/plrobjs/P-T/
circlemud_squared_0.5.153/etc/plrobjs/U-Z/
circlemud_squared_0.5.153/etc/plrobjs/ZZZ/
circlemud_squared_0.5.153/etc/text/
circlemud_squared_0.5.153/etc/text/help/
circlemud_squared_0.5.153/src/util/
circlemud_squared_0.5.153/src/util/worldconv/
/**
 * @file item.c
 * @ingroup item
 *
 * Item based code
 *
 * @author Geoff Davis <geoff@circlemudsquared.org>
 * @author Greg Buxton <greg@circlemudsquared.org>
 *
 * @par Copyright:
 *   Copyright (C) 2006 Geoff Davis <geoff@circlemudsquared.org><br>
 *                      Greg Buxton <greg@circlemudsquared.org>
 *
 * @par
 *   Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University<br>
 *   CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.
 *
 * @par
 *   All rights reserved.  See license.doc for complete information.
 *
 * @package cs
 * @version 1.0
 */

#define __ITEM_C__

#include "base.h"
#include "structs.h"
#include "utils.h"

#include "comm.h"
#include "constants.h"
#include "dao.h"
#include "db.h"
#include "handler.h"
#include "log.h"
#include "interpreter.h"
#include "spells.h"
#include "extraDesc.h"
#include "zone.h"
#include "room.h"
#include "item.h"

/*
 * External variables.
 */
extern const char *item_types[];

/*
 * Local functions
 */
void itemData_freePrototype(void *i);
void itemData_addItemFromDao(zoneData_t *zone, daoData_t *itemDao);
itemData_t *itemData_findPrototypeInZone(zoneData_t *zone, itemVnum_t iVnum);

/**
 * Convert an item to its DAO representation.
 * @param parentDao the container DAO to contain the item's DAO
 * @param item the item to be converted
 * @return none
 */
void itemData_toDao(daoData_t *parentDao, itemData_t *item) {
  if (parentDao == NULL) {
    log("itemData_toDao(): invalid 'parentDao' daoData_t.");
  } else if (item == NULL) {
    log("itemData_toDao(): invalid 'item' itemData_t.");
  } else {
    /* Declare some temporary buffer space. */
    char temp[MAX_STRING_LENGTH] = {'\0'};

    /* Declare some working DAO pointers. */
    daoData_t *itemDao = NULL, *subContainerDao = NULL, *flagsDao = NULL;

    /* Declare an iterator variable. */
    register int i = 0;

    itemDao = dao_newChild(parentDao, "%d", item->vnum);

    if (item->name && *(item->name) != '\0') {
      dao_newScalar(itemDao, "keywords", "%s", item->name);
    }
    if (item->description && *(item->description) != '\0') {
      dao_newScalar(itemDao, "description", "%s", item->description);
    }
    if (item->shortDescription && *(item->shortDescription) != '\0') {
      dao_newScalar(itemDao, "shortDescription", "%s", item->shortDescription);
    }
    if (item->actionDescription && *(item->actionDescription) != '\0') {
      dao_newScalar(itemDao, "actionDescription", "%s", item->actionDescription);
    }
    if (item->exDescription) {
      extraDescData_listToDao(itemDao, item->exDescription);
    }

    flagsDao = dao_newChild(itemDao, "flags");
    sprinttype(item->typeFlag, item_types, temp, sizeof(temp));
    dao_newScalar(flagsDao, "type", "%s", temp);
    dao_newScalar(flagsDao, "weight", "%d", item->weight);
    dao_newScalar(flagsDao, "cost", "%d", item->cost);
    dao_newScalar(flagsDao, "costPerDay", "%d", item->costPerDay);
    dao_newScalar(flagsDao, "timer", "%d", item->timer);

    subContainerDao = dao_newChild(flagsDao, "values");
    for (i = 0; i < 4; i++) {
      snprintf(temp, sizeof(temp), "value%d", i + 1);
      dao_newScalar(subContainerDao, temp, "%d", item->value[i]);
    }

    subContainerDao = NULL;
    if (item->wearFlags != 0UL) {
      subContainerDao = dao_newChild(flagsDao, "wearFlags");
      dao_newScalar(subContainerDao, "take", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_TAKE)));
      dao_newScalar(subContainerDao, "finger", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_FINGER)));
      dao_newScalar(subContainerDao, "neck", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_NECK)));
      dao_newScalar(subContainerDao, "body", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_BODY)));
      dao_newScalar(subContainerDao, "head", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_HEAD)));
      dao_newScalar(subContainerDao, "legs", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_LEGS)));
      dao_newScalar(subContainerDao, "feet", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_FEET)));
      dao_newScalar(subContainerDao, "hands", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_HANDS)));
      dao_newScalar(subContainerDao, "arms", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_ARMS)));
      dao_newScalar(subContainerDao, "shield", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_SHIELD)));
      dao_newScalar(subContainerDao, "about", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_ABOUT)));
      dao_newScalar(subContainerDao, "waist", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_WAIST)));
      dao_newScalar(subContainerDao, "wrist", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_WRIST)));
      dao_newScalar(subContainerDao, "wield", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_WIELD)));
      dao_newScalar(subContainerDao, "hold", YESNO(IS_SET(item->wearFlags, ITEM_WEAR_HOLD)));
    }

    subContainerDao = NULL;
    if (item->extraFlags != 0UL) {
      subContainerDao = dao_newChild(flagsDao, "extraFlags");
      dao_newScalar(subContainerDao, "glow", YESNO(IS_SET(item->extraFlags, ITEM_GLOW)));
      dao_newScalar(subContainerDao, "hum", YESNO(IS_SET(item->extraFlags, ITEM_HUM)));
      dao_newScalar(subContainerDao, "noRent", YESNO(IS_SET(item->extraFlags, ITEM_NORENT)));
      dao_newScalar(subContainerDao, "noDonate", YESNO(IS_SET(item->extraFlags, ITEM_NODONATE)));
      dao_newScalar(subContainerDao, "noInvis", YESNO(IS_SET(item->extraFlags, ITEM_NOINVIS)));
      dao_newScalar(subContainerDao, "invisible", YESNO(IS_SET(item->extraFlags, ITEM_INVISIBLE)));
      dao_newScalar(subContainerDao, "magic", YESNO(IS_SET(item->extraFlags, ITEM_MAGIC)));
      dao_newScalar(subContainerDao, "noDrop", YESNO(IS_SET(item->extraFlags, ITEM_NODROP)));
      dao_newScalar(subContainerDao, "blessed", YESNO(IS_SET(item->extraFlags, ITEM_BLESS)));
      dao_newScalar(subContainerDao, "antiGood", YESNO(IS_SET(item->extraFlags, ITEM_ANTI_GOOD)));
      dao_newScalar(subContainerDao, "antiEvil", YESNO(IS_SET(item->extraFlags, ITEM_ANTI_EVIL)));
      dao_newScalar(subContainerDao, "antiNeutral", YESNO(IS_SET(item->extraFlags, ITEM_ANTI_NEUTRAL)));
      dao_newScalar(subContainerDao, "antiMagicUser", YESNO(IS_SET(item->extraFlags, ITEM_ANTI_MAGIC_USER)));
      dao_newScalar(subContainerDao, "antiCleric", YESNO(IS_SET(item->extraFlags, ITEM_ANTI_CLERIC)));
      dao_newScalar(subContainerDao, "antiThief", YESNO(IS_SET(item->extraFlags, ITEM_ANTI_THIEF)));
      dao_newScalar(subContainerDao, "antiWarrior", YESNO(IS_SET(item->extraFlags, ITEM_ANTI_WARRIOR)));
      dao_newScalar(subContainerDao, "noSell", YESNO(IS_SET(item->extraFlags, ITEM_NOSELL)));
    }
  }
}

/* ************************************************************************ */
/*  Load Item Data from DAO                                                 */
/* ************************************************************************ */

/**
 * Load all items in zone
 *
 * @param zone Zone to load items into
 * @param itemListDao daoData_t of items to load
 * @return none
 */
void itemData_loadItemsInZone(zoneData_t *zone, daoData_t *itemListDao) {

  if (zone == NULL) {
    log("itemData_loadItemsInZone(): invalid 'zone'zoneData_t.");
  } else {
    if (itemListDao != NULL) {
      daoData_t *entDao = NULL;

      for (entDao = itemListDao->children; entDao; entDao = entDao->next) {
        itemData_addItemFromDao(zone, entDao);
      }
    }
  }
}

/**
 * Load a single item from it's dao entry
 *
 * @param zone Zone to load item into
 * @param itemDao daoData_t of item to load
 * @return none
 */
void itemData_addItemFromDao(zoneData_t *zone, daoData_t *itemDao) {
  if (zone == NULL) {
    log("itemData_addItemFromDao(): invalid 'zone'zoneData_t.");
  } else if (itemDao == NULL) {
    log("itemData_addItemFromDao(): invalid 'itemDao' daoData_t.");
  } else {
    /* Declare the new item var, and initialize it */
    itemData_t *item = itemData_newPrototype(zone, dao_keyInt(itemDao, -1));
    daoData_t *flagsDao = NULL, *subDao = NULL;

    if (item != NULL) {
      /* Let's load the item's information */

      /* Name (keywords) */
      itemData_setName(item, (char *)dao_queryString(itemDao, "keywords", "item new keyword"));

      /* Description (long) */
      itemData_setDescription(item, (char *)dao_queryString(itemDao, "description", "A new item lies here."));

      /* Short Description */
      itemData_setShortDescription(item, (char *)dao_queryString(itemDao, "shortDescription", "a new item"));

      /* Action Description -- This one can be NULL */
      itemData_setActionDescription(item, (char *)dao_queryString(itemDao, "actionDescription", NULL));

      /* Look for exDescList */
      subDao = dao_query(itemDao, "extraDescriptions");
      if (subDao) {
        item->exDescription = extraDescData_listFromDao(subDao);
      }
      subDao = NULL;

      /* Load the bits in the flags container. */
      /* These should be moved up to the main object level */
      flagsDao = dao_query(itemDao, "flags");
      if (flagsDao != NULL) {
        /* Read the type code from the flags DOA. */
        item->typeFlag = dao_queryType(flagsDao, "type", item_types, 0);
        /* Read the weight value from the flags DAO. */
        item->weight = dao_queryInt(flagsDao, "weight", 0);
        /* Read the cost value from the flags DAO. */
        item->cost = dao_queryInt(flagsDao, "cost", 0);
        /* Read the cost-per-day value from the flags DAO. */
        item->costPerDay = dao_queryInt(flagsDao, "costPerDay", 0);
        /* Read the timer value from the flags DAO. */
        item->timer = dao_queryInt(flagsDao, "timer", 0);
        /* Read the value1 value from the flags DAO. */
        item->value[0] = dao_queryInt(flagsDao, "values/value1", 0);
        /* Read the value2 value from the flags DAO. */
        item->value[1] = dao_queryInt(flagsDao, "values/value2", 0);
        /* Read the value3 value from the flags DAO. */
        item->value[2] = dao_queryInt(flagsDao, "values/value3", 0);
        /* Read the value4 value from the flags DAO. */
        item->value[3] = dao_queryInt(flagsDao, "values/value4", 0);
        /* Read the wear flags from the flags DAO. */
        item->wearFlags = dao_queryBits(flagsDao, "wearFlags", wear_bits, 0);
        /* Read the extra flags from the flags DAO. */
        item->extraFlags = dao_queryBits(flagsDao, "extraFlags", extra_bits, 0);
      }

      item->number = 0;
      /* Done! */
    }
  }
}

/* ************************************************************************ */
/*  General item functions                                                  */
/* ************************************************************************ */

/**
 * Create a new object prototype in a zone, by VNum
 *
 * @param zone Zone in which to create item
 * @param iVnum VNum of item to create
 * @return pointer to itemData_t for new item
 */
itemData_t *itemData_newPrototype(zoneData_t *zone, itemVnum_t iVnum) {
  itemData_t *item = NULL;

  if (zone == NULL) {
    log("itemData_newPrototype(): invalid 'zone' zoneData_t.");
  } else if (iVnum < 0) {
    log("itemData_newPrototype(): invalid 'iVnum' itemVnum_t.");
  } else {
    /* If the zone's items hashMap doesn't exist, create it */
    if (zone->items == NULL) {
      zone->items = hashMap_create(0, hashVnum, NULL, itemData_freePrototype);
      if (zone->items == NULL) {
        log("itemData_newPrototype(): NULL returned from hashMap_create().  Aborting.");
        exit(1);
      }
    }

    /* Attempt to get an item with that VNum from the zone */
    item = itemData_findPrototypeInZone(zone, iVnum);

    /* If we don't have an item returned, create one.  Otherwise free it out */
    if (item == NULL) {
      CREATE(item, itemData_t, 1);

      /* Set the VNum */
      item->vnum = iVnum;

      /* Since it wasn't in the hashMap, add it */
      hashMap_insert(zone->items, &item->vnum, item);
    } else {
      if (item->name)
        free(item->name);
      if (item->description)
        free(item->description);
      if (item->shortDescription)
        free(item->shortDescription);
      if (item->actionDescription)
        free(item->actionDescription);
      if (item->exDescription)
        free_extra_descriptions(item->exDescription);
    }

    /* Sanity's Sake */

    item->prototype = NULL;
    item->name = NULL;
    item->description = NULL;
    item->shortDescription = NULL;
    item->actionDescription = NULL;
    item->exDescription = NULL;

    item->typeFlag = 0;
    item->wearFlags = 0;
    item->extraFlags = 0;
    item->number = 0;

    item->zone = zone;
  }

  return (item);
}

/**
 * Set a item's name
 *
 * @param item Item that's being changed
 * @param name New name for item
 * @return none
 */
void itemData_setName(itemData_t *item, char *name) {

  if (item == NULL) {
    log("itemData_set(): invalid 'item' itemData_t.");
  } else if (name == NULL || *name == '\0') {
    log("itemData_set(): invalid 'name' char.");
  } else {
    if (itemData_isPrototype(item) || 
        (item->prototype && item->prototype->name &&
         item->prototype->name != item->name)) {
      if (item->name)
        free(item->name);
    }

    item->name = strdup(name);
  }
}

/**
 * Set a item's description
 *
 * @param item Item that's being changed
 * @param description New description for item
 * @return none
 */
void itemData_setDescription(itemData_t *item, char *description) {

  if (item == NULL) {
    log("itemData_set(): invalid 'item' itemData_t.");
  } else if (description == NULL || *description == '\0') {
    log("itemData_set(): invalid 'description' char.");
  } else {
    if (itemData_isPrototype(item) || 
        (item->prototype && item->prototype->description &&
         item->prototype->description != item->description)) {
      if (item->description)
        free(item->description);
    }

    item->description = strdup(description);
  }
}

/**
 * Set a item's shortDescription
 *
 * @param item Item that's being changed
 * @param shortDescription New shortDescription for item
 * @return none
 */
void itemData_setShortDescription(itemData_t *item, char *shortDescription) {

  if (item == NULL) {
    log("itemData_set(): invalid 'item' itemData_t.");
  } else if (shortDescription == NULL || *shortDescription == '\0') {
    log("itemData_set(): invalid 'shortDescription' char.");
  } else {
    if (itemData_isPrototype(item) || 
        (item->prototype && item->prototype->shortDescription &&
         item->prototype->shortDescription != item->shortDescription)) {
      if (item->shortDescription)
        free(item->shortDescription);
    }

    item->shortDescription = strdup(shortDescription);
  }
}

/**
 * Set a item's actionDescription
 *
 * @param item Item that's being changed
 * @param actionDescription New actionDescription for item
 * @return none
 */
void itemData_setActionDescription(itemData_t *item, char *actionDescription) {

  if (item == NULL) {
    log("itemData_set(): invalid 'item' itemData_t.");
  } else if (actionDescription == NULL || *actionDescription == '\0') {
    if (itemData_isPrototype(item) || 
        (item->prototype && item->prototype->actionDescription &&
         item->prototype->actionDescription != item->actionDescription)) {
      if (item->actionDescription)
        free(item->actionDescription);
    }

    item->actionDescription = NULL;
  } else {
    if (itemData_isPrototype(item) || 
        (item->prototype && item->prototype->actionDescription &&
         item->prototype->actionDescription != item->actionDescription)) {
      if (item->actionDescription)
        free(item->actionDescription);
    }

    item->actionDescription = strdup(actionDescription);
  }
}

/**
 * Free an item prototype
 *
 * This function takes a void pointer and casts back to a itemData_t so
 * that it will work with the hashMap code.
 *
 * @param i Item entry to be freed (void pointer)
 * @return none
 */
void itemData_freePrototype(void *i) {
  itemData_t *item = (itemData_t *)(i);

  if (item != NULL) {
    if (item->name)
      free(item->name);
    if (item->description)
      free(item->description);
    if (item->shortDescription)
      free(item->shortDescription);
    if (item->actionDescription)
      free(item->actionDescription);
    if (item->exDescription)
      free_extra_descriptions(item->exDescription);

    free(item);
    item = NULL;
  }
}

/**
 * Find an item prototype by vnum in a zone's items hashMap
 *
 * @param zone Zone to look for the item in
 * @param iVnum VNum of the item to find
 * @return pointer to itemData_t for the Item with matching VNum
 */
itemData_t *itemData_findPrototypeInZone(zoneData_t *zone, itemVnum_t iVnum) {
  return (itemData_t*) hashMap_getValue(zone->items, &iVnum, NULL);
}

/**
 * Check to see if a itemData_t is a prototype or not
 *
 * @param item Item to check
 * @return TRUE or FALSE
 */
bool itemData_isPrototype(itemData_t *item) {
  return (item->prototype == NULL &&
          item == itemData_findPrototypeInZone(item->zone, item->vnum));
}

/**
 * Find the prototype of a given item
 *
 * @param item Item to find the prototype of
 * @return Pointer to the prototype
 */
itemData_t *itemData_findPrototype(itemData_t *item) {
  if (item == NULL) {
    return NULL;
  } else if (item->prototype) {
    return (item->prototype);
  }
  return itemData_findPrototypeInZone(item->zone, item->vnum);
}

/**
 * Find an item in the world by segmented "vnum"
 *
 * This is the function which whill be used the most, as it gives a referece
 * to the zone by keyword and the item by number
 *
 * @param vnumString Segemented vnum string
 * @return pointer to the item or NULL
 */
itemData_t *itemData_find(char *vnumString) {
  itemData_t *item = NULL;

  if (vnumString == NULL || *vnumString == '\0') {
    log("itemData_find(): Invalid char 'vnumString'.");
  } else {
    zoneData_t *zone = NULL;
    char *z = NULL, *s = NULL;
    char *holder = strdup(vnumString);
    itemVnum_t iv = 0;

    z = holder;
    s = strstr(holder, ":");

    if (s) {
      *s = '\0';
      s++;
      iv = atoi(s);
    }

    if (z) {
      zone = zoneData_find(z);
      if (zone && zone->items) {
        item = itemData_findPrototypeInZone(zone, iv);
      }
    }

    if (holder)
      free(holder);
  }

  return item;
}

/**
 * Find an item prototype for a character.
 *
 * This function does some processing to let the user "drop" the zone if they want
 * to reference an item in the current zone.
 *
 * @param ch Character to look up an item for
 * @param vnumString vnum string which might be segmented or not
 */
itemData_t *itemData_findForChar(charData_t *ch, char *vnumString) {
  itemData_t *item = NULL;

  if (vnumString == NULL || *vnumString == '\0') {
    log("itemData_findForChar(): Invalid char 'vnumString'.");
  } else if (ch == NULL) {
    log("itemData_findForChar(): Invalid charData_t 'ch'.");
  } else {
    char segmented[MAX_INPUT_LENGTH] = { '\0' };

    if (!strstr(vnumString, ":")) {
      snprintf(segmented, sizeof(segmented), "%s:%s", ch->room->zone->keyword, vnumString);
      item = itemData_find(segmented);
    } else {
      item = itemData_find(vnumString);
    }
  }
  return item;
}

/**
 * Search a list of items for an instance of an item, by prototype
 *
 * This replaces get_item_in_list_num()
 *
 * @param list List of items to search
 * @param itemProto Prototype of the item to look for
 * @return pointer to instance of item
 */
itemData_t *itemData_getInList(itemData_t *list, itemData_t *itemProto) {

  if (itemProto == NULL) {
    log("itemData_getInList(): Invalid itemData_t 'itemProto'.  NULL.");
  } else if (itemData_isPrototype(itemProto) == FALSE) {
    log("itemData_getInList(): Invalid itemData_t 'itemProto.'  Not a prototype.");
  } else {
    itemData_t *item = NULL;

    for (item = list; item; item = item->nextContent)
      if (item->prototype && item->prototype == itemProto)
        return (item);
  }

  return (NULL);
}

/**
 * Search the world for an instance of an item, by prototype
 *
 * This replaces get_item_num()
 *
 * @param itemProto Prototype of the item to look for
 * @return pointer to instance of item
 */
itemData_t *itemData_getInWorld(itemData_t *itemProto) {

  if (itemProto == NULL) {
    log("itemData_getInWorld(): Invalid itemData_t 'itemProto'.  NULL.");
  } else if (itemData_isPrototype(itemProto) == FALSE) {
    log("itemData_getInWorld(): Invalid itemData_t 'itemProto.'  Not a prototype.");
  } else {
    itemData_t *item = NULL;

    for (item = object_list; item; item = item->next)
      if (item->prototype && item->prototype == itemProto)
        return (item);
  }

  return (NULL);
}