/* * psitem.h * * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation (version 2 of the License) * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __PSITEM_H__ #define __PSITEM_H__ #include #include #include #include "util/stringarray.h" #include "util/psconst.h" #include "../iserver/idal.h" #include "util/poolallocator.h" #include "psskills.h" #include "psitemstats.h" #include "util/scriptvar.h" #include "util/gameevent.h" #include "gem.h" class csMutex; class psString; // Note: The following 2 options require a clean rebuild when changed. /// Enable this to be notified of all item saving activity #define SAVE_DEBUG 0 /// Enable this to keep track of the initial caller of Save() (when used with SAVE_DEBUG, will print full trace) #define SAVE_TRACER 0 /// These two define how long an item will stay in the world before being auto-removed, in seconds. #define REMOVAL_INTERVAL_RANGE 300 #define REMOVAL_INTERVAL_MINIMUM 1200 /// This indicates that the item has been deleted from the database and should not be updated #define ID_DONT_SAVE_ITEM 0xffffffff /// The crafter ID field contains the id of the character that made this item #define PSITEM_FLAG_CRAFTER_ID_IS_VALID 0x00000001 /// The guild ID field contains the id of a guild that certified this item #define PSITEM_FLAG_GUILD_ID_IS_VALID 0x00000002 /// This item uses its own unique psItemStats data (in the database), and modifications to the data are OK as they will reflect solely on this item #define PSITEM_FLAG_UNIQUE_ITEM 0x00000004 /** This item is solely based on a basic item template. It has no modifiers. * When this flag is set and all effects on this item expire, if the current_stats is not the same as the base_stats pointer, * then the object referenced by current_stats is deleted and current_stats is set to point at the base_stats pointer. * This allows item stats for base items to use a single area in memory most of the time. When effects are applied a new copy * of the base stats can be made and modified with the effect data. When all effects fade the new copy can be released back to * the pool. * This flag is not intended to be directly manipulated. All objects starting from a basic item will have this set to begin with. * If a modifier is applied, or if the item is forced to take over unique status, this flag is cleared. */ #define PSITEM_FLAG_USES_BASIC_ITEM 0x00000008 /// Flags used for glyphs #define PSITEM_FLAG_PURIFIED 0x00000010 #define PSITEM_FLAG_PURIFYING 0x00000020 /// Flags for locked status (as in a locked container) #define PSITEM_FLAG_LOCKED 0x00000040 #define PSITEM_FLAG_LOCKABLE 0x00000080 /// Flag for an un-pickupable item (remains fixed) #define PSITEM_FLAG_NOPICKUP 0x00000100 /// Flag defines any item as a key to a locked object #define PSITEM_FLAG_KEY 0x00000200 /// Transient items are removed from the world approx 3hrs after creation, if not picked up by someone #define PSITEM_FLAG_TRANSIENT 0x00000400 #define KEY_SKELETON (unsigned int)-1 typedef unsigned int PSITEM_FLAGS; /// The maximum number of modifiers that can be applied to a single instance of an item on top of the base item #define PSITEM_MAX_MODIFIERS 10 class psContainerIterator; class psItem; class psCharacter; class gemItem; class psSectorInfo; struct psItemCategory; class psScheduledItem; class psWorkGameEvent; ///** A list of the possible errors when placing an item in a container. /// Positive numbers indicate the number of items remaining during a stack operation enum PS_CONTAINER_ERROR { PS_CONT_OK = 0, PS_CONT_ERR_OUT_RANGE = -1, PS_CONT_ERR_NO_ITEM = -2, PS_CONT_ERR_SELF = -3, PS_CONT_ERR_TO_BIG = -4, PS_CONT_ERR_NOT_OWNER = -5, PS_CONT_ERR_NO_STACK = -6 }; enum ITEM_ORIGIN { ITEM_DB_LOAD = 1, //loaded from DB ITEM_CLONE, //created from a Copy(), as in purchasing something ITEM_CACHE, //created by CacheManager ITEM_MONEY, //created by psserverchar::MakeMoneyItem ITEM_BASIC //created by psitemstats::instantiateBasicItem }; /** This class iterates through sub objects in a container object. * * */ class psContainerIterator { public: psContainerIterator(psItem *container); ~psContainerIterator(); bool HasNext(); psItem *Next(); void UseContainerItem(psItem *container); private: psItem *current_container; unsigned int next_position; }; #define ITEM_DECAY_FACTOR_PARRY 0.75F // If the target parries the blow, how much is his weapon damaged by blocking the attacker #define ITEM_DECAY_FACTOR_BLOCKED 1.25F // If the target parries the blow, how much is the attacker's weapon damaged by getting blocked /** This class embodies item instances in the game. * Every item that can be picked up, dropped, traded, equiped, bought or sold is a psitem. * * This class has some specific design philosophy. * * First, each item instance has a unique 32 bit identifier. The database ensures that there can be only one entry * per item identifier. This means if an item is truly duped it will not persist between world resets since the next * load from the database will find only one entry for that item. * In order to make this mean anything, certain situations must be carefully coded to avoid bypassing this protection. * In any case where 1 item becomes multiple items (such as splitting a stack) the logic should be well defined and located * in just one place (preferably within the psItem class). If a bug does arise, it should require a fix to a single location. * Any instance where an item is legitimately duped will need to do more work to actually copy the item. The code will be required * to basically reconstruct the item from the ground up. The new item will be a truly new item. Do not take this lightly. * * ----The only time an item instance should be duplicated is for Game Master level functions.---- * * Items are built from statistic entries (item stats). Most items will have a base item stat entry and 0 or more item stat * entries that act as modifiers. Modifiers are permanent additions to an item instance. For example, you may be able to buy * a normal 'short sword' from a merchant. This would be the base stat of the item. If you use a trade skill to sharpen the * short sword, that may add the 'sharpened' modifier to the sword. The resulting item instance will still (and always) have * the base stat of 'short sword'. In addition it will have the modifier of 'sharpened'. It may gain or lose modifiers through * other actions. Temporary effects such as spells, poisons, etc are NOT modifiers. They should be handled differently. * At this time there is no code to handle effects on items, but it should not be difficult to add once the parameters of effects * are defined. * The other type of item instance is a unique item. Unique items are truely unique. The unique item has its own entry for its * stats in the database. Only one item instance will ever refer to this entry. If the item instance is destroyed, so is the entry. * In some situations the item stats may be altered - either through an extremely difficult quest, or GM intervention. These alterations * to the stats will alter the entries of the unique item stats. In addition, normal modifiers may also be applied. * * ----Unique items should be very difficult to obtain as they are a larger drain on server resources---- * * An item instance has four persistant-state related operations: * Load() - Translates data from a database item instance entry into a usable psItem * Save() - Saves a psItem. This creates a new Unique Identifier (UID) for the item instance if needed (if the UID is 0). * DeleteItem() - (Called from psCharacterLoader) Destroys the item instance entry from the database. The psItem entry in memory should also * be destroyed promptly. * * Hierarchy: * psItem uses a fairly straightforward hierarchy system. psItems may contain other psItems. The maximum amount of items a psItem may contain * is defined by the compile time constant PSITEM_MAX_CONTAINER_SLOTS. Hierarchy linkage is stored in both the child and the parent in memory. * Only container items may store other items. Container items MUST NOT be stackable. The base stats (and modifiers) control wether an item instance * is a container or not. * The following functions should be used to add and remove items from containers, and ONLY these functions. These functions should contain all logic * about ensuring hierarchy linkage and constraints (size, weight, etc) and updating data throughout the hierarchy (such as sum weight propagated to * parent containers) * bool TakeOutOfContainer(); * int AddItemToContainer(psItem *addme); * int AddItemToContainer(psItem *addme,unsigned int slot); * * Weight Rules: * TODO: Containers will have a maximum carrying weight. * Weight of stacks is a the count of the stack multiplied by the weight of the base item stat. * * Size Rules: * Size is single number (unsigned short) that relates to the length of the longest dimension measured in centimeters. * Stacks do not affect size. * Containers have a maximum content size. Containers themselves have a size just like every other item as well, this tells wether containers can fit inside other containers. * 65535 = infinite size. Items with 65535 cannot be put into any containers. Containers with 65535 max content size can contain any item except items with 65535 size. * * TODO: Add effect data - such as spell effects or poision or whatever. * TODO: Merge various mutually exclusive stats into unions to save space. The container stats and modifiers may be able to be merged (or maybe not). */ class psItem : public iScriptableVar, public iDeleteObjectCallback, public CS::WeakReferenced { public: /** Constructs a psItem. Does not assign a UID. * After construction the caller should set the location in the world or place the item into a container * with the parent's AddItemToContainer() member function. It should then call Save() to save the instance * to the database. */ psItem (); /** Destructs the psItem, and, if this is a container, all contained items. Does NOT remove any items from the database. */ virtual ~psItem (); /** Return a string identifying this object as an Item */ virtual const char * GetItemType() { return "Item"; } gemItem* GetGemObject() { return gItem; } void SetGemObject( gemItem* object ); psWorkGameEvent* GetTransformationEvent() { return transformationEvent; } void SetTransformationEvent(psWorkGameEvent* t) { transformationEvent = t; } /// Identify what methods were used to create this object for debugging /// rather religious looking void SetCreator(int origin){ creator=origin;} char * GetCreatorName(); /// Handles deleted gem objects. virtual void DeleteObjectCallback(iDeleteNotificationObject * object); private: /// The 32 bit Unique Identifier of this item. uint32 uid; /// Debug info, used to determine where this came from int creator; /// This flag is true when the item cannot be moved around in inventory, during repairs for example. bool item_in_use; /// If set, this is a pointer to the item that is currently being trade skill transformed. psWorkGameEvent* transformationEvent; /// Container specific data struct { /// The array of psItems contained in this psItem. Only valid if this is a container. NULL for slot empty. psItem *contained_item_ptr[PSITEM_MAX_CONTAINER_SLOTS]; } container_data; /// Location in the game world. Only valid if this item is not being carried by a player (directly or indirectly) struct { psSectorInfo *loc_sectorinfo; float loc_x,loc_y,loc_z; float loc_yrot; } location; /// The total weight of this item and all contained items. Adjusted during AddItemToContainer(), TakeOutOfContainer() and RecalculateFullWeight() float sum_weight; /// 0% means item does not reduce decay at all. 100% means item does not decay. float decay_resistance; // percent 3.2 float item_quality; ///< Current quality of item float crafted_quality; ///< The crafted max quality of the item. /// Original quality of item, used to detect save requirements float item_quality_original; /// The number of items in this stack if this is a stackable item. unsigned short stack_count; protected: /** Flags for this item instance. Flags are described at the top of this file. * Note that psItemStats also has flags that are stored separately. * If you're looking for a flag that you think should be here, check psItemStats to be sure * it's not a stat flag instead of an instance flag. * Flags are indicated in the database as text, e.g. "NOPICKUP" in the flags column */ PSITEM_FLAGS flags; private: /** This field stores the UID of the character that crafted this item if it was crafted. * In this way we can add recognition to crafters as their items traverse the game. */ unsigned int crafter_id; /** This field stores the guild UID of a guild that has CERTIFIED this item. * The concept of this is that a guild as an entity can certify certain works from any crafter. * This gives the ability to mark items after some kind of inspection through a method not based * on guild membership. I.E. a crafter in a guild that crafts an item will not automatically have * his wares marked with guild id. Rather someone of sufficient rank will need to mark the item. */ unsigned int guild_id; /* Container Hierarchy Data * * The following field allows objects-within-objects (containers) to be described. * */ /// Points to the object that contains this object, or NULL if there is none. psItem *container_parent; /** Dual use. Indicates either the slot within the parent item if contained, or the slot in the player's inventory/equipment/bulk if appropriate. * If the item is on the ground in the world and not inside of a container item this field should be ignored. */ unsigned int loc_in_parent; /** Pointer to the psCharacter that holds this item * The character can hold the item either directly in their inventory/bank/equipment or in a container they hold. * NULL if this item is on the ground or in another item that is on the ground. * */ psCharacter *owning_character; /** The owner of the item may not be infact online so have to store the ID since the above may be undefined in some cases. */ unsigned int owningCharacterID; /** The basic stats of this item. * This can point to a common shared entry from the basic stats list, or a unique entry. * Check for the PSITEM_FLAG_UNIQUE_ITEM flag to see which. */ psItemStats *base_stats; /** The current stats of this item. This value should be used for pretty much everything. * Initially this points to the same entry as the base_stats. If modifiers or effects are applied * this will point to an allocated temporary stats entry that contains the result of all modifiers * and effects on top of the base. */ psItemStats *current_stats; /** The list of modifiers for this item. * We could keep just the base and current, but then we wouldn't be able to track what kinds of modifiers * had been applied to this item instance, and it would be difficult to find where to add the modifiers in * the database. */ psItemStats *modifiers[PSITEM_MAX_MODIFIERS]; // Lock stuff unsigned int lockStrength; PSSKILL lockpickSkill; // A key can open multiple locks csArray openableLocks; psScheduledItem* schedule; /** Saves this item to the database. Generates an item ID if necessary. * This creates a new UID for the item and creates appropriate database entries if necessary. * Otherwise it updates the existing entry. * This calls a database function directly. */ void Commit(bool children = false); /** * ItemQuality for items that decay changes so often, writing every change to the db * is overly onerous. Also, any loss of data due to server crashes benefits the player * rather than hurting him, so it isn't too bad if it is never updated. This function * is called by the dtor to make sure quality is only updated minimal times. */ void UpdateItemQuality(uint32 id, float qual); /// Commit() is called primarily from psDelaySave::Trigger() friend class psDelaySave; public: /** Loads data from a database row into the current psItem. * This is used only by the character loader. * On return parentid is set to the UID of the parent item. UID 0 is reserved for no parent. */ virtual bool Load(iResultRow& row,uint32 &parentid); /** Queues this item to be saved to the database. (DB action will be executed after 500ms) * Call this after EVERY change of a persistant property, and the system * will ensure that any sequence of changes will result in only one DB hit. */ void Save(bool children = false); /// Saves this item now if it hasn't been saved before, to force the generation of a UID void ForceSaveIfNew(); /** Flags that this item has been fully loaded, and is allowed to be saved on changes. * This MUST be called after this item is constructed AND it's initial * properties are set. (includes normal loading, InstantiateBasicItem(), etc.) */ void SetLoaded() { loaded = true; } /** Check to see if the character meets the requirements for this item. */ bool CheckRequirements( psCharacter* character, csString& resp ); /** Database assist function. Fills the passed psStringArray with values for the fields in the database. * Helper function for saving and updating. */ void GetFieldArray(psStringArray& fields); /** Returns the UID of this item instance. * 0 is reserved for no UID assigned yet. * Items are initially created with a UID of 0. Save() generates a unique item id. */ uint32 GetUID() { return uid; } /** Sets the Unique ID of this item. DO NOT CALL THIS. * This should ONLY be called internally or from psCharacterLoader. */ void SetUID(uint32 v); /// Returns true if the crafter character ID is valid bool GetIsCrafterIDValid(); /// Set wether the crafter ID is valid. SetCrafterID() sets this to true for you. void SetIsCrafterIDValid(bool v); /// Returns true if the certifying guild ID is valid bool GetIsGuildIDValid(); /// Set wether the guild ID is valid. SetGuildID() sets this to true for you. void SetIsGuildIDValid(bool v); /// Returns the UID for the crafter of this item. Be sure to check GetIsCrafterIDValid()! unsigned int GetCrafterID() const { return crafter_id; } /// Sets the UID for the cracter of this item. Generally used immediately after completing the crafting work. void SetCrafterID(unsigned int v); /// Returns the UID for the guild who has certified this item. Be sure to check GetIsGuildIDValid()! unsigned int GetGuildID() const { return guild_id; } /// Sets the UID for the guild certifying this item. void SetGuildID(unsigned int v); /// Gets the maximum possible quality of the item by reading the item_stat. float GetMaxItemQuality(); /// Sets the maximum allowed quality of the item by changing the item_stat. void SetMaxItemQuality(float v); /// Gets the quality of the item. float GetItemQuality(); /// Sets the quality of the item. void SetItemQuality(float v); /// Returns item_stats id of repair tool required to fix this item, or 0. int GetRequiredRepairTool(); /// Returns the is_consumed flag of repair tool required to fix this item. bool GetRequiredRepairToolConsumed(); /// Set the decay resistance percentage for the item void SetDecayResistance(float v); /// Set the item decay factor void SetItemDecayRate(float v); /// Get the item decay factor float GetItemDecayRate() { return base_stats->GetDecayRate(); } /// Adjust the item quality by an amount of decay float AddDecay(float severityFactor); bool IsInUse() { return item_in_use; } void SetInUse(bool flag) { item_in_use = flag; } /** Returns true if this item is based off of unique statistics. * Items with unique statistics will be especially rare. Some special operations are * possible on unique items */ bool GetIsUnique() const; /** Returns true if this item has this modifier in its modifier list. * This can be used to make sure an item doesn't get the same modifier multiple times or if an * item needs to have a specific modifier to be used for something. * * TODO: In the future we may expand this to functions that check for "similar" modifiers to a given * modifier. */ bool HasModifier(psItemStats *modifier); /** Adds a modifier to this item instance if there is space available. * Current stats are automaticaly updated. * * TODO: A DeleteModifier() function may be warranted in the future. */ bool AddModifier(psItemStats *modifier); /** Returns the modifier at a specific index 0 through PSITEM_MAX_MODIFIERS-1 * */ psItemStats *GetModifier(int index); /** Creates a new blank instance of it's class (i.e. psItem or its subclass) */ virtual psItem *CreateNew() { return new psItem(); } /** Duplicates an item instance. * The parameter is the stack count of the new item. * The return value must be checked for NULL. * The returned item will not have a valid location nor a valid UID. The location in the world or * on an owning player must be set first, and then Save() called to generate a UID and save to the database. */ virtual psItem *Copy(unsigned short newstackcount); /** Copies values of its attributes to item 'target'. */ virtual void Copy(psItem * target); /** Splits an item instance representing a stack into two smaller stacks. * The parameter is the size of the new stack. * The return value must be checked for NULL. * The returned item will not have a valid location nor a valid UID. The location in the world or * on an owning player must be set first, and then Save() called to generate a UID and save to the database. */ psItem* SplitStack(unsigned short newstackcount); /** Attempts to stack 'stackme' with this item. * Setting test to true tests for the number of items that will remain unstacked but does not change anything. * * Returns the number of items that remains unstacked. Returns -1 if stacking is not possible. */ int CombineStack(psItem *& stackme, bool test); /** TODO: Comment me with something more than "Gets the attack animation ID" * */ int GetAttackAnimID(psCharacter *pschar,iCelEntity *entity); /// Returns the decay value of the item. See the decay member for a description of what this is. float GetDecay(); /// Sets the decay value of the item. See the decay member for a description of what this is. void SetDecay(float v); /// Returns the stack count. Be sure to call GetIsStackable() first! unsigned short GetStackCount() { return stack_count; } /** Sets the stack count. Be sure to call GetIsStackable() first! * Don't call this to try and combine or split stacks! That logic is done in CombineStack() * ,FindStackableAndStack() and SplitStack(). */ void SetStackCount(unsigned short v); /** Returns a pointer to the character who is holding this item directly or indirectly (including containers and bank slots) or NULL if none. * Returns NULL if on the ground or in a container on the ground. * * This should always be valid since items should be destroyed when the character logs off */ psCharacter *GetOwningCharacter() { return owning_character; } /** Get the ID of the owning character. This is required in cases where the owning * character may not be online and the above pointer is undefined. */ unsigned int GetOwningCharacterID() { return owningCharacterID; } /** Alters the owning character of this item and all contained items (if this is a container). DO NOT USE! * This is automatically called from the functions that remove items from inventory (or add items). * There shouldn't be any reason to call this from anywhere else, and it can really mess things up if you do! */ virtual void SetOwningCharacter(psCharacter *owner); /// Returns true if this is not a container or if it's a container that's empty. bool GetIsContainerEmpty(); /// Returns the total size of the items within a container. unsigned short GetContainedSize(); /// Returns the item that contains this item, or NULL if it's not contained by another item. psItem *GetParentItem() { return container_parent; } void SetParent( psItem* item ); /** Returns the UID of the item that contains this item. DO NOT USE! * There's no danger in using this, but you probably want to use GetParentItem() instead. * The UID isn't really useful outside of the database and maybe sending to clients as an ID. */ uint32 GetParentID() { if (container_parent!=NULL) return container_parent->GetUID(); return 0; } /** Returns the location of this item in it's parent item or in the players equipment, bulk or bank as appropriate. * */ unsigned int GetLocInParent() { return loc_in_parent; } /** DO NOT USE! DO NOT USE! DO NOT USE! * This is used at load time and as a helper function for setting the location within the parent AFTER all checks * have been performed. It does NOT do two way linkage. * Look at TakeOutOfContainer() and AddItemToContainer() to do what you want to do. */ void SetLocInParent(unsigned int location); /** Returns the item in the specific slot of this container. * Returns NULL if this is not a container or if there is no item in the requested slot. */ psItem *GetItemInSlot(unsigned int slot); /** Takes this item out of any container it's in. * This function adjusts the two way linkage, the owning player, and properties such as sum_weight of the parents. * Returns false if this item is not in a container. */ bool TakeOutOfContainer(); /** Put an item into this container item in any spot where it will fit, or any container within this container where it will fit. * This function adjusts the two way linkage, the owning player, and properties such as sum_weight of the parents. * Returns false if the item will not fit or this is not a container. * * @param addme The item to add into the container. * @param useOwner If NULL then use the owner of this container. Otherwise use the owner passed in. * NOTE: This does NOT stack items of the same type. addme is guaranteed to be valid when this function completes. */ bool AddItemToContainer(psItem *addme, bool test = false, psCharacter* useOwner = NULL); /** Put an item into this container item in a specified slot. * This function adjusts the two way linkage, the owning player, and properties such as sum_weight of the parents. * Returns false if the item will not fit or this is not a container. * * NOTE: This does NOT stack items of the same type. addme is guaranteed to be valid when this function completes. */ bool AddItemToContainer(psItem *addme, unsigned int slot, bool test = false); /** Swaps, moves, removes, and puts based on count in a container. * For drag and drop mostly. Different from and take and add in that you can split counts. */ bool SwapItemsInContainer(unsigned int fromSlot, unsigned int toSlot); bool MoveItemsInContainer(unsigned int fromSlot, unsigned int toSlot, int count); psItem *RemoveItemsInContainer(unsigned int fromSlot, int count); int PutItemsInContainer(unsigned int toSlot, psItem *item, psCharacter* owner, bool test = false); /// Returns the sum weight of this item and all contained items float GetSumWeight() { return sum_weight; } /** DO NOT USE! HELPER FUNCTION! * Item weights are stored as a property of the basic item stats. If weight reduction items are desired they should be * described within the item stats and the logic for that weight reduction should be implemented in the various weight * adjusting functions here in psItem. * This function is used to help recursively adjust the weight of this item and all parent items. */ float AdjustSumWeight(float delta); /** Recalculates the sum weight of this item from the top down. * Starts at this item and sets its own weight, recursively calls itself for each contained item. * Adds the sum weight of the children to its own weight for its own sum. * Returns the sum weight calculated. */ float RecalculateFullWeight(); /** Used to set the UNIQUE flag in addition to setting base stats pointer * TODO: This is pretty much untested at this point. * */ void SetUniqueStats(psItemStats *statptr); /** Alters the base stats of this item instance. * If called on a unique item it revokes the unique item status of this item! * If called on a unique item the unique item stats should be destroyed elsewhere. * */ void SetBaseStats(psItemStats *statptr); /** Returns the base stats for this item instance. You may want to use this only to see this item instance is a specific type of item * Do not use for retrieval of values for calculations (such as damage). */ psItemStats *GetBaseStats() const { return base_stats; } /** Sets the current item stats. DO NOT USE! * This is used mostly internally. The current stats either point to the same entry as the base stats or a stats entry that * is the sum of the base stats plus modifiers and effects. */ void SetCurrentStats(psItemStats *statptr); /** Gets a pointer to the current stats. You probably dont want to use this. * Use the functions below which may apply additional logic to determine what value to return. * */ psItemStats *GetCurrentStats() const { return current_stats; } /** In some cases some modifiers or effects may be difficult to reverse (for example percent bonuses applied and removed in different orders). * In these cases it should be safe to call RecalcCurrentStats() which takes a bit longer, but builds the current stats back up from the base. */ void RecalcCurrentStats(); PSITEM_FLAGS GetFlags() { return flags; } void SetFlags(int f) { flags = f; } virtual int GetPurifyStatus() const { return 0; } /* These next two functions provide the means for unique item id numbering. * The first will be used constantly as items are created. * The second should be used rarely since unique items will be rare, but a guaranteed unique number is still needed * */ /** Returns a unique ID that can be assigned to an item instance being created. * * This should be called during setup of initial item data. This function guarantees that the number returned will * be unique among all item instances in memory and the database. * * @return A 32 bit unsigned unique ID number for items. 0 on failure (lock failed). */ static uint32 GetNextItemUID(); /** Returns a unique ID that can be assigned to a new Unique ItemStats entry being created. * * This should be called during setup of unique item stats. This function guarantees that the number returned will * be unique among all unique item stats entries in memory and the database. * * @return A 32 bit unsigned unique ID number for items. 0 on failure (lock failed). */ static uint32 GetNextUniqueItemStatsUID(); // Interface to itemstats /* The following functions mostly call into the current stats to return the requested values. * In the future additional logic about value modification may be added to these functions. * For this reason these functions should ALWAYS be used rather than calling GetCurrentStats()->Get*() * unless you REALLY know what you're doing and REALLY mean to bypass the intended value of the item instance. */ bool GetIsMeleeWeapon(); bool GetIsRangeWeapon(); bool GetIsAmmo(); bool GetIsShield(); bool GetIsContainer(); bool GetCanTransform(); bool GetUsesAmmo(); bool GetIsStackable() const; const char *GetName(); const char *GetDescription(); PSITEMSTATS_WEAPONTYPE GetWeaponType(); PSSKILL GetWeaponSkill(PSITEMSTATS_WEAPONSKILL_INDEX index); float GetLatency(); float GetDamage(PSITEMSTATS_DAMAGETYPE dmgtype); float GetExtraDamagePercent(PSITEMSTATS_DAMAGETYPE dmgtype); PSITEMSTATS_AMMOTYPE GetAmmoType(); float GetPenetration(); float GetUntargetedBlockValue(); float GetTargetedBlockValue(); float GetCounterBlockValue(); PSITEMSTATS_ARMORTYPE GetArmorType(); float GetDamageProtection(PSITEMSTATS_DAMAGETYPE dmgtype); float GetHardness(); float GetWeaponAttributeBonus(PSITEMSTATS_STAT stat); PSITEMSTATS_STAT GetWeaponAttributeBonusType(PSITEMSTATS_STAT_BONUS_INDEX index); float GetWeaponAttributeBonusMax(PSITEMSTATS_STAT_BONUS_INDEX index); float GetWeight(); unsigned short GetSize(); /// Gets the total size of the items in the stack. float GetSumSize() { return (float)GetSize()*stack_count; } unsigned short GetContainerMaxSize(); PSITEMSTATS_SLOTLIST GetValidSlots(); bool FitsInSlots(PSITEMSTATS_SLOTLIST slotmask); float GetDecayResistance(); psMoney& GetPrice(); psMoney GetSellPrice(); ///< Merchants want a percentage psItemCategory* GetCategory(); float GetVisibleDistance(); void GetLocationInWorld(psSectorInfo **sectorinfo,float &loc_x,float &loc_y,float &loc_z,float &loc_yrot); void SetLocationInWorld(psSectorInfo *sectorinfo,float loc_x,float loc_y,float loc_z,float loc_yrot); /** Get the Mesh Name for the item. * * Used for standalone or weilded mesh. */ const char *GetMeshName(); /** Get the Texture Name for the item. * * Used when worn and attached to the mesh given by part name. */ const char *GetTextureName(); /** Get the Part Name for the item. * * This is the name of the part that the texture should be attached to * if no change of mesh. */ const char *GetPartName(); /** Get the Part Mesh Name for the item. * * This is the new mesh to be attached to the location given * by the pattern Part Name. */ const char *GetPartMeshName(); /** Get the Image Name for the item. * * Used in inventory and other location where item has to be presented * by a 2D image. */ const char *GetImageName(); csString GetQuantityName(); // returns the quantity and plural name in a string static csString GetQuantityName(psString name, int stack_count); // For future use, see notes for mesh_index variables, etc. /* unsigned int GetMeshIndex(); unsigned int GetTextureIndex(); unsigned int GetTexturePartIndex(); unsigned int GetImageIndex(); */ bool CheckStackableWith(const psItem& otheritem) const; const char *GetSound(); /// This is used by the math scripting engine to get various values. double GetProperty(const char *ptr); bool GetIsLocked() { return ((flags & PSITEM_FLAG_LOCKED)? true : false); } void SetIsLocked(bool v); bool GetIsLockable() { return ((flags & PSITEM_FLAG_LOCKABLE)? true : false); } void SetIsLockable(bool v); bool GetIsKey() { return ((flags & PSITEM_FLAG_KEY)? true : false); } void SetIsKey(bool v); bool IsTransient() { return ((flags & PSITEM_FLAG_TRANSIENT) ? true : false); } void SetIsTransient(bool v); void SetIsPickupable(bool v); PSSKILL GetLockpickSkill() { return lockpickSkill; } void SetLockpickSkill(PSSKILL v); unsigned int GetLockStrength() { return lockStrength; } void SetLockStrength(unsigned int v); bool CanOpenLock(uint32 id); void AddOpenableLock(uint32 v); void RemoveOpenableLock(uint32 v); void ClearOpenableLocks(); void MakeSkeleton(bool b); bool GetIsSkeleton(); psScheduledItem* GetScheduledItem() { return schedule; } void SetScheduledItem(psScheduledItem* item) { schedule = item; } void ScheduleRespawn(); void ItemAboutToMove(); ///< This is called before item is moved to another place /// Checks if the 'item' parameter is direct or indirect parent of our item bool IsIndirectParent(psItem * item); /// Gets the reduction of this weapon against the armor given float GetArmorVSWeaponResistance(psItemStats* armor); /** Called when an item is completely destroyed from the persistant world * * Persistant refers to the item existing through a reset of the server. This definition can affect when an item * should be "destroyed" (removed from the database). * For example, if items dropped on the ground will be forever lost if the server goes down, then when an item * is dropped on the group, DestroyItem() should be used instead of UpdateItem(). When the item is picked up * again, CreateItem() should be called. * */ bool Destroy(); /** * This function handles creating an event manager event at the right time * to get transient objects removed from the world automatically. */ void ScheduleRemoval(); bool Delete(); /* Objects of this class utilize a pool allocator. The pool allocator can be found in poolallocator.h in the psutil library. * The pool allocator allows us to avoid allocating memory from and releasing memory to the heap over and over for things that are * constantly shifting in the number of allocations (such as items in the game). It also reduces memory usage overhead slightly. * * It should be possible to debug memory leaks from a specific pool easier as well since you can analyze allocations solely from that pool * without getting flooded with allocations from everywhere else. */ /// The new operator is overriden to call PoolAllocator template functions void *operator new(size_t); /// The delete operator is overriden to call PoolAllocator template functions void operator delete(void *); private: /// Static reference to the pool for all psItem objects static PoolAllocator itempool; friend class psContainerIterator; /// Mutex to restrict access to the global itemid static csRef global_itemid_mutex; /// global item id counter. This value is always at least 1 higher than the highest itemid assigned to an item. static uint32 global_itemid; /// Mutex to restrict access to the global incrementing id of unique itemstats static csRef global_uniqueitemid_mutex; /// global unique itemstats id counter. This value is always at least 1 higher than the highest id assigned to a unique itemstats entry. static uint32 global_uniqueitemid; gemItem* gItem; bool loaded; bool pendingsave; #if SAVE_TRACER private: csString last_save_queued_from; #endif }; class psScheduledItem { public: psScheduledItem(int spawnID,uint32 itemID,csVector3& position, psSectorInfo* sector, int interval,int maxrnd); psItem* CreateItem(); uint32 GetItemID() { return itemID;} psSectorInfo* GetSector() { return sector; } csVector3& GetPosition() { return pos; } int MakeInterval(); ///< This will return a randomized interval int GetInterval() { return interval; } int GetMaxModifier() { return maxrnd; } csTicks GetLastSpawn() { return lastSpawn; } void UpdatePosition(csVector3& positon, const char *sector); void ChangeIntervals(int newint, int newrand); void Remove(); ///< Deletes from the DB and everything bool WantToDie() { return wantToDie; } private: bool wantToDie; int spawnID; ///< database id uint32 itemID; ///< Item csVector3 pos; ///< Position psSectorInfo* sector; ///< Sector int interval; ///< Interval in msecs int maxrnd; ///< Maximum random interval modifier in msecs csTicks lastSpawn; ///< When we last spawned it, good for something perhaps? :) }; class psItemSet { protected: csArray set; csArray parents; public: ~psItemSet(); /// Adds a psitem to this set. The parentid must be specified since this function is used at load time. void Add(psItem *item,uint32 parentid); bool ResolveAllParents(); void Release(); psItem* Get(size_t n); size_t GetSize() { return set.Length(); } }; #endif