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