//////////////////////////////////////////////////////////////////////// // OpenTibia - an opensource roleplaying game //////////////////////////////////////////////////////////////////////// // 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, either version 3 of the License, or // (at your option) any later version. // // 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, see . //////////////////////////////////////////////////////////////////////// #ifndef __ITEM__ #define __ITEM__ #include "otsystem.h" #include #include #include "thing.h" #include "items.h" #include "raids.h" class Creature; class Player; class Container; class Depot; class Teleport; class TrashHolder; class Mailbox; class Door; class MagicField; class BedItem; enum ITEMPROPERTY { BLOCKSOLID = 0, HASHEIGHT, BLOCKPROJECTILE, BLOCKPATH, ISVERTICAL, ISHORIZONTAL, MOVEABLE, IMMOVABLEBLOCKSOLID, IMMOVABLEBLOCKPATH, IMMOVABLENOFIELDBLOCKPATH, NOFIELDBLOCKPATH, SUPPORTHANGABLE }; enum TradeEvents_t { ON_TRADE_TRANSFER, ON_TRADE_CANCEL, }; enum ItemDecayState_t { DECAYING_FALSE = 0, DECAYING_TRUE, DECAYING_PENDING }; enum AttrTypes_t { ATTR_END = 0, //ATTR_DESCRIPTION = 1, //ATTR_EXT_FILE = 2, ATTR_TILE_FLAGS = 3, ATTR_ACTION_ID = 4, ATTR_UNIQUE_ID = 5, ATTR_TEXT = 6, ATTR_DESC = 7, ATTR_TELE_DEST = 8, ATTR_ITEM = 9, ATTR_DEPOT_ID = 10, //ATTR_EXT_SPAWN_FILE = 11, ATTR_RUNE_CHARGES = 12, //ATTR_EXT_HOUSE_FILE = 13, ATTR_HOUSEDOORID = 14, ATTR_COUNT = 15, ATTR_DURATION = 16, ATTR_DECAYING_STATE = 17, ATTR_WRITTENDATE = 18, ATTR_WRITTENBY = 19, ATTR_SLEEPERGUID = 20, ATTR_SLEEPSTART = 21, ATTR_CHARGES = 22, ATTR_CONTAINER_ITEMS = 23, ATTR_NAME = 30, ATTR_PLURALNAME = 31, ATTR_ATTACK = 33, ATTR_EXTRAATTACK = 34, ATTR_DEFENSE = 35, ATTR_EXTRADEFENSE = 36, ATTR_ARMOR = 37, ATTR_ATTACKSPEED = 38, ATTR_HITCHANCE = 39, ATTR_SHOOTRANGE = 40, ATTR_ARTICLE = 41, ATTR_SCRIPTPROTECTED = 42 }; enum Attr_ReadValue { ATTR_READ_CONTINUE, ATTR_READ_ERROR, ATTR_READ_END }; // from iomap.h #pragma pack(1) struct TeleportDest { uint16_t _x, _y; uint8_t _z; }; #pragma pack() typedef std::list ItemList; class ItemAttributes { public: ItemAttributes() { m_attributes = 0; m_firstAttr = NULL; } virtual ~ItemAttributes() { if(m_firstAttr) deleteAttrs(m_firstAttr); } ItemAttributes(const ItemAttributes &i) { m_attributes = i.m_attributes; if(i.m_firstAttr) m_firstAttr = new Attribute(*i.m_firstAttr); } void setDuration(int32_t time) {setIntAttr(ATTR_ITEM_DURATION, time);} void decreaseDuration(int32_t time) {increaseIntAttr(ATTR_ITEM_DURATION, -time);} int32_t getDuration() const {return getIntAttr(ATTR_ITEM_DURATION);} void setSpecialDescription(const std::string& desc) {setStrAttr(ATTR_ITEM_DESC, desc);} void resetSpecialDescription() {removeAttribute(ATTR_ITEM_DESC);} const std::string& getSpecialDescription() const {return getStrAttr(ATTR_ITEM_DESC);} void setText(const std::string& text) {setStrAttr(ATTR_ITEM_TEXT, text);} void resetText() {removeAttribute(ATTR_ITEM_TEXT);} const std::string& getText() const {return getStrAttr(ATTR_ITEM_TEXT);} void setDate(uint64_t n) {setIntAttr(ATTR_ITEM_WRITTENDATE, n);} void resetDate() {removeAttribute(ATTR_ITEM_WRITTENDATE);} time_t getDate() const {return (time_t)getIntAttr(ATTR_ITEM_WRITTENDATE);} void setWriter(std::string _writer) {setStrAttr(ATTR_ITEM_WRITTENBY, _writer);} void resetWriter() {removeAttribute(ATTR_ITEM_WRITTENBY);} const std::string& getWriter() const {return getStrAttr(ATTR_ITEM_WRITTENBY);} void setActionId(uint16_t n) {setIntAttr(ATTR_ITEM_ACTIONID, (uint16_t)std::max((uint16_t)100, n));} void resetActionId() {removeAttribute(ATTR_ITEM_ACTIONID);} uint16_t getActionId() const {return getIntAttr(ATTR_ITEM_ACTIONID);} void setUniqueId(uint16_t n) {setIntAttr(ATTR_ITEM_UNIQUEID, (uint16_t)std::max((uint16_t)1000, n));} uint16_t getUniqueId() const {return getIntAttr(ATTR_ITEM_UNIQUEID);} void setCharges(uint16_t n) {setIntAttr(ATTR_ITEM_CHARGES, n);} uint16_t getCharges() const {return getIntAttr(ATTR_ITEM_CHARGES);} void setFluidType(uint16_t n) {setIntAttr(ATTR_ITEM_FLUIDTYPE, n);} uint16_t getFluidType() const {return getIntAttr(ATTR_ITEM_FLUIDTYPE);} void setOwner(uint32_t _owner) {setIntAttr(ATTR_ITEM_OWNER, _owner);} uint32_t getOwner() const {return getIntAttr(ATTR_ITEM_OWNER);} void setCorpseOwner(uint32_t _corpseOwner) {setIntAttr(ATTR_ITEM_CORPSEOWNER, _corpseOwner);} uint32_t getCorpseOwner() {return getIntAttr(ATTR_ITEM_CORPSEOWNER);} void setDecaying(ItemDecayState_t decayState) {setIntAttr(ATTR_ITEM_DECAYING, decayState);} uint32_t getDecaying() const {return getIntAttr(ATTR_ITEM_DECAYING);} protected: enum itemAttrTypes { ATTR_ITEM_ACTIONID = 1 << 0, ATTR_ITEM_UNIQUEID = 1 << 1, ATTR_ITEM_DESC = 1 << 2 , ATTR_ITEM_TEXT = 1 << 3, ATTR_ITEM_WRITTENDATE = 1 << 4, ATTR_ITEM_WRITTENBY = 1 << 5, // basic item modifiers ATTR_ITEM_NAME = 1 << 6, ATTR_ITEM_PLURALNAME = 1 << 7, ATTR_ITEM_ATTACK = 1 << 8, ATTR_ITEM_EXTRAATTACK = 1 << 9, ATTR_ITEM_DEFENSE = 1 << 10, ATTR_ITEM_EXTRADEFENSE = 1 << 11, ATTR_ITEM_ARMOR = 1 << 12, ATTR_ITEM_HITCHANCE = 1 << 13, ATTR_ITEM_SHOOTRANGE = 1 << 14, ATTR_ITEM_SCRIPTPROTECTED = 1 << 15, // compatibility with previous versions ATTR_ITEM_OWNER = 1 << 16, ATTR_ITEM_DURATION = 1 << 17, ATTR_ITEM_DECAYING = 1 << 18, ATTR_ITEM_CORPSEOWNER = 1 << 19, ATTR_ITEM_CHARGES = 1 << 20, ATTR_ITEM_FLUIDTYPE = 1 << 21, ATTR_ITEM_DOORID = 1 << 22, // advanced item modifiers ATTR_ITEM_ARTICLE = 1 << 23, ATTR_ITEM_ATTACKSPEED = 1 << 24 }; bool hasAttribute(itemAttrTypes type) const; void removeAttribute(itemAttrTypes type); protected: static std::string emptyString; class Attribute { public: itemAttrTypes type; void* value; Attribute* next; Attribute(itemAttrTypes _type) { type = _type; value = NULL; next = NULL; } Attribute(const Attribute &i) { type = i.type; if(ItemAttributes::validateIntAttrType(type)) value = i.value; else if(ItemAttributes::validateStrAttrType(type)) value = (void*)new std::string( *((std::string*)i.value) ); else value = NULL; next = NULL; if(i.next) next = new Attribute(*i.next); } }; uint32_t m_attributes; Attribute* m_firstAttr; uint32_t getIntAttr(itemAttrTypes type) const; void increaseIntAttr(itemAttrTypes type, int32_t value); void setIntAttr(itemAttrTypes type, int32_t value); const std::string& getStrAttr(itemAttrTypes type) const; void setStrAttr(itemAttrTypes type, const std::string& value); static bool validateIntAttrType(itemAttrTypes type); static bool validateStrAttrType(itemAttrTypes type); void addAttr(Attribute* attr); Attribute* getAttrConst(itemAttrTypes type) const; Attribute* getAttr(itemAttrTypes type); void deleteAttrs(Attribute* attr); }; class Item : virtual public Thing, public ItemAttributes { public: static Items items; //Factory member to create item of right type based on type static Item* CreateItem(const uint16_t _type, uint16_t _count = 1); static Item* CreateItem(PropStream& propStream); static bool loadItem(xmlNodePtr node, Container* parent); static bool loadContainer(xmlNodePtr node, Container* parent); // Constructor for items Item(const uint16_t _type, uint16_t _count = 0); Item(const Item &i); virtual ~Item() {} virtual Item* clone() const; virtual void copyAttributes(Item* item); virtual Item* getItem() {return this;} virtual const Item* getItem() const {return this;} virtual Container* getContainer() {return NULL;} virtual const Container* getContainer() const {return NULL;} virtual Teleport* getTeleport() {return NULL;} virtual const Teleport* getTeleport() const {return NULL;} virtual TrashHolder* getTrashHolder() {return NULL;} virtual const TrashHolder* getTrashHolder() const {return NULL;} virtual Mailbox* getMailbox() {return NULL;} virtual const Mailbox* getMailbox() const {return NULL;} virtual Door* getDoor() {return NULL;} virtual const Door* getDoor() const {return NULL;} virtual MagicField* getMagicField() {return NULL;} virtual const MagicField* getMagicField() const {return NULL;} virtual BedItem* getBed() {return NULL;} virtual const BedItem* getBed() const {return NULL;} static std::string getDescription(const ItemType& it, int32_t lookDistance, const Item* item = NULL, int32_t subType = -1, bool addArticle = true); static std::string getNameDescription(const ItemType& it, const Item* item = NULL, int32_t subType = -1, bool addArticle = true); static std::string getWeightDescription(const ItemType& it, double weight, uint32_t count = 1); virtual std::string getDescription(int32_t lookDistance) const {return getDescription(items[id], lookDistance, this);} std::string getNameDescription() const {return getNameDescription(items[id], this);} std::string getWeightDescription() const; //serialization virtual Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream); virtual bool unserializeAttr(PropStream& propStream); virtual bool serializeAttr(PropWriteStream& propWriteStream) const; virtual bool unserializeItemNode(FileLoader& f, NODE node, PropStream& propStream) {return unserializeAttr(propStream);} uint16_t getID() const {return id;} uint16_t getClientID() const {return items[id].clientId;} void setID(uint16_t newid); const std::string& getName() const {return getStrAttr(ATTR_ITEM_NAME) != "" ? getStrAttr(ATTR_ITEM_NAME) : items[id].name;} void setName(std::string name) {setStrAttr(ATTR_ITEM_NAME, name);} const std::string& getPluralName() const {return getStrAttr(ATTR_ITEM_PLURALNAME) != "" ? getStrAttr(ATTR_ITEM_PLURALNAME) : items[id].pluralName;} void setPluralName(std::string pluralname) {setStrAttr(ATTR_ITEM_PLURALNAME, pluralname);} int32_t getAttack() const {return hasAttribute(ATTR_ITEM_ATTACK) ? getIntAttr(ATTR_ITEM_ATTACK) : items[id].attack;} void setAttack(int32_t attack) {setIntAttr(ATTR_ITEM_ATTACK, attack);} int32_t getExtraAttack() const {return hasAttribute(ATTR_ITEM_EXTRAATTACK) ? getIntAttr(ATTR_ITEM_EXTRAATTACK) : items[id].extraAttack;} void setExtraAttack(int32_t extraattack) {setIntAttr(ATTR_ITEM_EXTRAATTACK, extraattack);} int32_t getDefense() const {return hasAttribute(ATTR_ITEM_DEFENSE) ? getIntAttr(ATTR_ITEM_DEFENSE) : items[id].defense;} void setDefense(int32_t defense) {setIntAttr(ATTR_ITEM_DEFENSE, defense);} int32_t getExtraDefense() const {return hasAttribute(ATTR_ITEM_EXTRADEFENSE) ? getIntAttr(ATTR_ITEM_EXTRADEFENSE) : items[id].extraDefense;} void setExtraDefense(int32_t extradefense) {setIntAttr(ATTR_ITEM_EXTRADEFENSE, extradefense);} int32_t getArmor() const {return hasAttribute(ATTR_ITEM_ARMOR) ? getIntAttr(ATTR_ITEM_ARMOR) : items[id].armor;} void setArmor(int32_t armor) {setIntAttr(ATTR_ITEM_ARMOR, armor);} uint32_t getAttackSpeed() const {return hasAttribute(ATTR_ITEM_ATTACKSPEED) ? getIntAttr(ATTR_ITEM_ATTACKSPEED) : items[id].attackSpeed;} void setAttackSpeed(int32_t attackspeed) {setIntAttr(ATTR_ITEM_ATTACKSPEED, attackspeed);} int32_t getHitChance() const {return hasAttribute(ATTR_ITEM_HITCHANCE) ? getIntAttr(ATTR_ITEM_HITCHANCE) : items[id].hitChance;} void setHitChance(int32_t hitchance) {setIntAttr(ATTR_ITEM_HITCHANCE, hitchance);} int32_t getShootRange() const {return hasAttribute(ATTR_ITEM_SHOOTRANGE) ? getIntAttr(ATTR_ITEM_SHOOTRANGE) : items[id].shootRange;} void setShootRange(int32_t shootrange) {setIntAttr(ATTR_ITEM_HITCHANCE, shootrange);} const std::string& getArticle() const {return getStrAttr(ATTR_ITEM_ARTICLE) != "" ? getStrAttr(ATTR_ITEM_ARTICLE) : items[id].article;} void setArticle(std::string article) {setStrAttr(ATTR_ITEM_ARTICLE, article);} bool isScriptProtected() const {return hasAttribute(ATTR_ITEM_SCRIPTPROTECTED) ? (bool)getIntAttr(ATTR_ITEM_SCRIPTPROTECTED) : false;} void setScriptProtected(bool value) {setIntAttr(ATTR_ITEM_SCRIPTPROTECTED, value ? 1 : 0);} int32_t getSlotPosition() const {return items[id].slotPosition;} int32_t getWieldPosition() const {return items[id].wieldPosition;} WeaponType_t getWeaponType() const {return items[id].weaponType;} Ammo_t getAmmoType() const {return items[id].ammoType;} virtual double getWeight() const; virtual int32_t getThrowRange() const {return (isPickupable() ? 15 : 2);} int32_t getWorth() const {return getItemCount() * items[id].worth;} void getLight(LightInfo& lightInfo); int32_t getMaxWriteLength() const {return items[id].maxTextLen;} bool canWriteText() const {return items[id].canWriteText;} bool forceSerialize() const {return items[id].forceSerialize || canWriteText() || isContainer() || isBed() || isDoor();} bool hasProperty(enum ITEMPROPERTY prop) const; bool hasSubType() const {return items[id].hasSubType();} bool hasCharges() const {return items[id].charges != 0;} virtual bool isPushable() const {return !isNotMoveable();} bool isGroundTile() const {return items[id].isGroundTile();} bool isContainer() const {return items[id].isContainer();} bool isSplash() const {return items[id].isSplash();} bool isFluidContainer() const {return (items[id].isFluidContainer());} bool isDoor() const {return items[id].isDoor();} bool isMagicField() const {return items[id].isMagicField();} bool isTeleport() const {return items[id].isTeleport();} bool isKey() const {return items[id].isKey();} bool isDepot() const {return items[id].isDepot();} bool isMailbox() const {return items[id].isMailbox();} bool isTrashHolder() const {return items[id].isTrashHolder();} bool isBed() const {return items[id].isBed();} bool isRune() const {return items[id].isRune();} bool isBlocking() const {return items[id].blockSolid;} bool isStackable() const {return items[id].stackable;} bool isAlwaysOnTop() const {return items[id].alwaysOnTop;} bool isNotMoveable() const {return !items[id].moveable;} bool isMoveable() const {return items[id].moveable;} bool isPickupable() const {return items[id].pickupable;} bool isUseable() const {return items[id].useable;} bool isHangable() const {return items[id].isHangable;} bool isRoteable() const {const ItemType& it = items[id]; return it.rotable && it.rotateTo;} bool isWeapon() const {return (items[id].weaponType != WEAPON_NONE);} bool isReadable() const {return items[id].canReadText;} bool floorChange(FloorChange_t change = CHANGE_NONE) const; uint16_t getItemCount() const {return count;} void setItemCount(uint16_t n) {count = n;} Player* getHoldingPlayer(); const Player* getHoldingPlayer() const; uint16_t getSubType() const; void setSubType(uint16_t n); bool isLoadedFromMap() const {return loadedFromMap;} void setLoadedFromMap(bool value) {loadedFromMap = value;} Raid* getRaid() {return raid;} void setRaid(Raid* _raid) {raid = _raid;} void setDefaultSubtype(); void setUniqueId(uint16_t n); bool canDecay(); virtual void __startDecaying(); uint32_t getDefaultDuration() const {return items[id].decayTime * 1000;} void setDefaultDuration() { uint32_t duration = getDefaultDuration(); if(duration != 0) setDuration(duration); } virtual bool canRemove() const {return true;} virtual bool canTransform() const {return true;} virtual void onRemoved(); virtual bool onTradeEvent(TradeEvents_t event, Player* owner, Player* seller) {return true;} static uint32_t countByType(const Item* item, int32_t checkType, bool multiCount); protected: std::string getWeightDescription(double weight) const {return getWeightDescription(Item::items[id], weight, count);} uint16_t id; uint8_t count; Raid* raid; bool loadedFromMap; }; inline uint32_t Item::countByType(const Item* item, int32_t checkType, bool multiCount) { if(checkType != -1 && checkType != (int32_t)item->getSubType()) return 0; if(multiCount) return item->getItemCount(); if(item->isRune()) return item->getCharges(); return item->getItemCount(); } #endif