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