/* * Ascent MMORPG Server * Copyright (C) 2005-2007 Ascent Team * * 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 * 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 _OBJECT_H #define _OBJECT_H class Unit; enum HIGHGUID { HIGHGUID_PLAYER = 0x00000000, HIGHGUID_UNIT = 0x00000001, HIGHGUID_GAMEOBJECT = 0x00000002, //0x1FAA0000, //0x1FA70000, elevators 0x1FAA0000 for trams(only this one works for elevators but not for trams lol) HIGHGUID_CORPSE = 0x00000003, HIGHGUID_DYNAMICOBJECT = 0x00000004, HIGHGUID_ITEM = 0x00000005, HIGHGUID_CONTAINER = 0x00000006, HIGHGUID_WAYPOINT = 0x00000007, HIGHGUID_TRANSPORTER = 0x00000008, HIGHGUID_PET = 0x00000009, }; // TODO: fix that type mess enum TYPE { TYPE_OBJECT = 1, TYPE_ITEM = 2, TYPE_CONTAINER = 4, TYPE_UNIT = 8, TYPE_PLAYER = 16, TYPE_GAMEOBJECT = 32, TYPE_DYNAMICOBJECT = 64, TYPE_CORPSE = 128, TYPE_AIGROUP = 256, TYPE_AREATRIGGER = 512, }; enum TYPEID { TYPEID_OBJECT = 0, TYPEID_ITEM = 1, TYPEID_CONTAINER = 2, TYPEID_UNIT = 3, TYPEID_PLAYER = 4, TYPEID_GAMEOBJECT = 5, TYPEID_DYNAMICOBJECT = 6, TYPEID_CORPSE = 7, TYPEID_AIGROUP = 8, TYPEID_AREATRIGGER = 9, TYPEID_UNUSED = 10,//used to signal invalid reference (object dealocated but someone is still using it) }; enum OBJECT_UPDATE_TYPE { UPDATETYPE_VALUES = 0, // 8 bytes - GUID // Goto Update Block UPDATETYPE_MOVEMENT = 1, // 8 bytes - GUID // Goto Position Update UPDATETYPE_CREATE_OBJECT = 2, // 8 bytes - GUID // 1 byte - Object Type (*) // Goto Position Update // Goto Update Block UPDATETYPE_CREATE_YOURSELF = 3, // looks like 3 & 4 do the same thing // 4 bytes - Count // Loop Count Times: // 8 bytes - GUID UPDATETYPE_OUT_OF_RANGE_OBJECTS = 4 // <- this is correct, not sure about 3 // 4 bytes - Count // Loop Count Times: // 8 bytes - GUID }; class WorldPacket; class ByteBuffer; class WorldSession; class Player; class MapCell; class MapMgr; //==================================================================== // Object // Base object for every item, unit, player, corpse, container, etc //==================================================================== class SERVER_DECL Object : public EventableObject { public: typedef std::set InRangeSet; virtual ~Object ( ); virtual void Update ( uint32 time ) { } //! True if object exists in world inline bool IsInWorld() { return m_mapMgr != NULL; } virtual void AddToWorld(); void PushToWorld(MapMgr*); virtual void OnPushToWorld() { } virtual void RemoveFromWorld(); // guid always comes first #ifndef USING_BIG_ENDIAN inline const uint64& GetGUID() const { return *((uint64*)m_uint32Values); } #else inline const uint64 GetGUID() const { return GetUInt64Value(0); } #endif inline const WoWGuid& GetNewGUID() const { return m_wowGuid; } inline uint32 GetEntry(){return m_uint32Values[3];} inline const uint32& GetGUIDLow() const { return m_uint32Values[0]; } inline const uint32& GetGUIDHigh() const { return m_uint32Values[1]; } // type inline const uint8& GetTypeId() const { return m_objectTypeId; } inline bool IsPlayer() { return m_objectTypeId == TYPEID_PLAYER; } //! This includes any nested objects we have, inventory for example. virtual uint32 __fastcall BuildCreateUpdateBlockForPlayer( ByteBuffer *data, Player *target ); uint32 __fastcall BuildValuesUpdateBlockForPlayer( ByteBuffer *buf, Player *target ); uint32 __fastcall BuildValuesUpdateBlockForPlayer( ByteBuffer * buf, UpdateMask * mask ); uint32 __fastcall BuildOutOfRangeUpdateBlock( ByteBuffer *buf ); WorldPacket* BuildFieldUpdatePacket(uint32 index,uint32 value); void BuildFieldUpdatePacket(Player* Target, uint32 Index, uint32 Value); void BuildFieldUpdatePacket(ByteBuffer * buf, uint32 Index, uint32 Value); void DealDamage(Unit *pVictim, uint32 damage, uint32 targetEvent, uint32 unitEvent, uint32 spellId, bool no_remove_auras = false); virtual void DestroyForPlayer( Player *target ) const; void BuildHeartBeatMsg( WorldPacket *data ) const; WorldPacket * BuildTeleportAckMsg( const LocationVector & v); bool IsBeingTeleported() { return mSemaphoreTeleport; } void SetSemaphoreTeleport(bool semphsetting) { mSemaphoreTeleport = semphsetting; } bool SetPosition( float newX, float newY, float newZ, float newOrientation, bool allowPorting = false ); bool SetPosition( const LocationVector & v, bool allowPorting = false); void SetRotation( uint64 guid ); inline const float& GetPositionX( ) const { return m_position.x; } inline const float& GetPositionY( ) const { return m_position.y; } inline const float& GetPositionZ( ) const { return m_position.z; } inline const float& GetOrientation( ) const { return m_position.o; } inline void SetOrientation( float &o ) { m_position.o = o; } inline const float& GetSpawnX( ) const { return m_spawnLocation.x; } inline const float& GetSpawnY( ) const { return m_spawnLocation.y; } inline const float& GetSpawnZ( ) const { return m_spawnLocation.z; } inline const float& GetSpawnO( ) const { return m_spawnLocation.o; } inline const LocationVector & GetPosition() { return m_position; } //Distance Calculation float CalcDistance(Object* Ob); float CalcDistance(float ObX, float ObY, float ObZ); float CalcDistance(Object *Oa, Object *Ob); float CalcDistance(Object *Oa, float ObX, float ObY, float ObZ); float CalcDistance(float OaX, float OaY, float OaZ, float ObX, float ObY, float ObZ); //! Only for MapMgr use inline MapCell* GetMapCell() const { return m_mapCell; } //! Only for MapMgr use inline void SetMapCell(MapCell* cell) { m_mapCell = cell; } //! Only for MapMgr use inline MapMgr* GetMapMgr() const { return m_mapMgr; } inline void SetMapId(uint32 newMap) { m_mapId = newMap; } void SetZoneId(uint32 newZone); inline const uint32 GetMapId( ) const { return m_mapId; } inline const uint32& GetZoneId( ) const { return m_zoneId; } //! Get uint32 property inline const uint32& GetUInt32Value( uint32 index ) const { ASSERT( index < m_valuesCount ); return m_uint32Values[ index ]; } //! Get uint64 property #ifdef USING_BIG_ENDIAN __inline const uint64 GetUInt64Value( uint32 index ) const #else inline const uint64& GetUInt64Value( uint32 index ) const #endif { ASSERT( index + uint32(1) < m_valuesCount ); #ifdef USING_BIG_ENDIAN /* these have to be swapped here :< */ return uint64((uint64(m_uint32Values[index+1]) << 32) | m_uint32Values[index]); #else return *((uint64*)&(m_uint32Values[ index ])); #endif } //! Get float property inline const float& GetFloatValue( uint32 index ) const { ASSERT( index < m_valuesCount ); return m_floatValues[ index ]; } void __fastcall ModFloatValue(const uint32 index, const float value ); void ModPFloatValue(const uint32 index, const float value, bool apply); void ModUInt32Value(uint32 index, int32 value); // void ModPUInt32Value(const uint32 index, const int32 value, bool apply); uint32 GetModPUInt32Value(const uint32 index, const int32 value); //! Set uint32 property void SetByte(uint32 index, uint32 index1,uint8 value); inline uint8 GetByte(uint32 i,uint32 i1) { ASSERT( i < m_valuesCount); ASSERT(i1 < 4); return ((uint8*)m_uint32Values)[i*4+i1]; } inline void SetNewGuid(uint32 Guid) { SetUInt32Value(OBJECT_FIELD_GUID, Guid); m_wowGuid.Init(GetGUID()); } void __fastcall SetUInt32Value( const uint32 index, const uint32 value ); //! Set uint64 property void __fastcall SetUInt64Value( const uint32 index, const uint64 value ); //! Set float property void __fastcall SetFloatValue( const uint32 index, const float value ); void __fastcall SetFlag( const uint32 index, uint32 newFlag ); void __fastcall RemoveFlag( const uint32 index, uint32 oldFlag ); inline bool HasFlag( const uint32 index, uint32 flag ) const { ASSERT( index < m_valuesCount ); return (m_uint32Values[ index ] & flag) != 0; } //////////////////////////////////////// void ClearUpdateMask( ) { m_updateMask.Clear(); m_objectUpdated = false; } bool HasUpdateField(uint32 index) { ASSERT( index < m_valuesCount); return m_updateMask.GetBit(index); } //use it to check if a object is in range of another bool isInRange(Object* target, float range); // Use it to Check if a object is in front of another one bool isInFront(Object* target); bool isInBack(Object* target); /* Calculates the angle between two Positions */ float calcAngle( float Position1X, float Position1Y, float Position2X, float Position2Y ); float calcRadAngle( float Position1X, float Position1Y, float Position2X, float Position2Y ); /* converts to 360 > x > 0 */ float getEasyAngle( float angle ); inline const float GetDistanceSq(Object* obj) { if(obj->GetMapId() != m_mapId) return 40000.0f; //enough for out of range return m_position.DistanceSq(obj->GetPosition()); } inline float GetDistanceSq(LocationVector & comp) { return comp.DistanceSq(m_position); } inline float CalcDistance(LocationVector & comp) { return comp.Distance(m_position); } inline const float GetDistanceSq(float x, float y, float z) { return m_position.DistanceSq(x, y, z); } inline const float GetDistance2dSq(Object* obj) { if(obj->GetMapId() != m_mapId) return 40000.0f; //enough for out of range return m_position.Distance2DSq(obj->m_position); } // In-range object management, not sure if we need it inline bool IsInRangeSet(Object* pObj) { return !(m_objectsInRange.find(pObj) == m_objectsInRange.end()); } virtual void AddInRangeObject(Object* pObj) { if(!pObj) return; m_objectsInRange.insert(pObj); if(pObj->GetTypeId() == TYPEID_PLAYER) m_inRangePlayers.insert( ((Player*)pObj) ); } inline void RemoveInRangeObject(Object* pObj) { if(!pObj) return; OnRemoveInRangeObject(pObj); m_objectsInRange.erase(pObj); } inline bool HasInRangeObjects() { return (m_objectsInRange.size() > 0); } virtual void OnRemoveInRangeObject(Object * pObj) { if(pObj->GetTypeId() == TYPEID_PLAYER) ASSERT(m_inRangePlayers.erase( ((Player*)pObj) ) == 1); } virtual void ClearInRangeSet() { m_objectsInRange.clear(); m_inRangePlayers.clear(); m_oppFactsInRange.clear(); } inline uint32 GetInRangeCount() { return m_objectsInRange.size(); } inline InRangeSet::iterator GetInRangeSetBegin() { return m_objectsInRange.begin(); } inline InRangeSet::iterator GetInRangeSetEnd() { return m_objectsInRange.end(); } inline InRangeSet::iterator FindInRangeSet(Object * obj) { return m_objectsInRange.find(obj); } void RemoveInRangeObject(InRangeSet::iterator itr) { OnRemoveInRangeObject(*itr); m_objectsInRange.erase(itr); } inline bool RemoveIfInRange(Object * obj) { InRangeSet::iterator itr = m_objectsInRange.find(obj); if(obj->GetTypeId() == TYPEID_PLAYER) m_inRangePlayers.erase(((Player*)obj)); if(itr == m_objectsInRange.end()) return false; m_objectsInRange.erase(itr); return true; } inline void AddInRangePlayer(Object * obj) { m_inRangePlayers.insert(((Player*)obj)); } inline void RemoveInRangePlayer(Object * obj) { m_inRangePlayers.erase(((Player*)obj)); } bool IsInRangeOppFactSet(Object* pObj) { return (m_oppFactsInRange.count(pObj) > 0); } void UpdateOppFactionSet(); inline std::set::iterator GetInRangeOppFactsSetBegin() { return m_oppFactsInRange.begin(); } inline std::set::iterator GetInRangeOppFactsSetEnd() { return m_oppFactsInRange.end(); } inline std::set::iterator GetInRangePlayerSetBegin() { return m_inRangePlayers.begin(); } inline std::set::iterator GetInRangePlayerSetEnd() { return m_inRangePlayers.end(); } inline std::set * GetInRangePlayerSet() { return &m_inRangePlayers; }; void __fastcall SendMessageToSet(WorldPacket *data, bool self,bool myteam_only=false); inline void SendMessageToSet(StackBufferBase * data, bool self) { OutPacketToSet(data->GetOpcode(), data->GetSize(), data->GetBufferPointer(), self); } void OutPacketToSet(uint16 Opcode, uint16 Len, const void * Data, bool self); //! Fill values with data from a space seperated string of uint32s. void LoadValues(const char* data); inline uint16 GetValuesCount() const { return m_valuesCount; } //! Blizzard seem to send those for all object types. weird. float m_walkSpeed; float m_runSpeed; float m_backWalkSpeed; float m_swimSpeed; float m_backSwimSpeed; float m_turnRate; float m_flySpeed; float m_backFlySpeed; inline bool IsUnit()//creature or player { return ( m_objectTypeId == TYPEID_UNIT || m_objectTypeId == TYPEID_PLAYER); } void EventSpellDamage(uint64 Victim, uint32 SpellID, uint32 Damage); void SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool allowProc, bool no_remove_auras = false); //***************************************************************************************** //* SpellLog packets just to keep the code cleaner and better to read //***************************************************************************************** void SendSpellLog(Object *Caster, Object *Target,uint32 Ability, uint8 SpellLogType); void SendSpellNonMeleeDamageLog(Object * Caster, Object * Target,uint32 SpellID,uint32 Damage, uint8 Damage_Type,uint32 AbsorbedDamage, uint32 ResistedDamage,bool PhysicalDamage, uint32 BlockedDamage, bool CriticalHit, bool bToSet); bool IsPet(); //object faction void _setFaction(); uint32 _getFaction(){return m_faction->Faction;} FactionTemplateDBC *m_faction; FactionDBC *m_factionDBC; inline void SetInstanceID(int32 instance) { m_instanceId = instance; } inline int32 GetInstanceID() { return m_instanceId; } int32 event_GetInstanceID(); bool Active; bool CanActivate(); void Activate(MapMgr * mgr); void Deactivate(MapMgr * mgr); bool m_inQueue; inline void SetMapMgr(MapMgr * mgr) { m_mapMgr = mgr; } void Delete() { if(IsInWorld()) RemoveFromWorld(); delete this; } void GMScriptEvent(void * function, uint32 argc, uint32 * argv, uint32 * argt); inline uint32 GetInRangeOppFactCount() { return m_oppFactsInRange.size(); } protected: Object ( ); //void _Create (uint32 guidlow, uint32 guidhigh); void _Create( uint32 mapid, float x, float y, float z, float ang); //! Mark values that need updating for specified player. virtual void _SetUpdateBits(UpdateMask *updateMask, Player *target) const; //! Mark values that player should get when he/she/it sees object for first time. virtual void _SetCreateBits(UpdateMask *updateMask, Player *target) const; void _BuildMovementUpdate( ByteBuffer *data, uint8 flags, uint32 flags2, Player* target ); void _BuildValuesUpdate( ByteBuffer *data, UpdateMask *updateMask, Player* target ); /* Main Function called by isInFront(); */ bool inArc(float Position1X, float Position1Y, float FOV, float Orientation, float Position2X, float Position2Y ); //! WoWGuid class WoWGuid m_wowGuid; //! Type id. uint8 m_objectTypeId; //! Zone id. uint32 m_zoneId; //! Continent/map id. uint32 m_mapId; //! Map manager MapMgr *m_mapMgr; //! Current map cell MapCell *m_mapCell; LocationVector m_position; LocationVector m_spawnLocation; // Semaphores - needed to forbid two operations on the same object at the same very time (may cause crashing\lack of data) bool mSemaphoreTeleport; //! Object properties. union { uint32 *m_uint32Values; float *m_floatValues; }; //! Number of properties uint32 m_valuesCount; //! List of object properties that need updating. UpdateMask m_updateMask; //! True if object was updated bool m_objectUpdated; //! Set of Objects in range. //! TODO: that functionality should be moved into WorldServer. std::set m_objectsInRange; std::set m_inRangePlayers; std::set m_oppFactsInRange; //! Remove object from map void _RemoveFromMap(); int32 m_instanceId; }; #endif