diff options
Diffstat (limited to 'src/game/GameObject.cpp')
-rw-r--r-- | src/game/GameObject.cpp | 559 |
1 files changed, 367 insertions, 192 deletions
diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index d50c2698759..106c41f720e 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * - * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.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 @@ -22,15 +22,14 @@ #include "QuestDef.h" #include "GameObject.h" #include "ObjectMgr.h" +#include "PoolHandler.h" #include "SpellMgr.h" #include "Spell.h" #include "UpdateMask.h" #include "Opcodes.h" #include "WorldPacket.h" -#include "WorldSession.h" #include "World.h" #include "Database/DatabaseEnv.h" -#include "MapManager.h" #include "LootMgr.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" @@ -41,12 +40,12 @@ #include "OutdoorPvPMgr.h" #include "BattleGroundAV.h" -GameObject::GameObject() : WorldObject() +GameObject::GameObject() : WorldObject(), m_goValue(new GameObjectValue) { m_objectType |= TYPEMASK_GAMEOBJECT; m_objectTypeId = TYPEID_GAMEOBJECT; // 2.3.2 - 0x58 - m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HASPOSITION); + m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION); m_valuesCount = GAMEOBJECT_END; m_respawnTime = 0; @@ -58,15 +57,16 @@ GameObject::GameObject() : WorldObject() m_charges = 5; m_cooldownTime = 0; m_goInfo = NULL; + m_goData = NULL; m_DBTableGuid = 0; } GameObject::~GameObject() { - if(m_uint32Values) // field array can be not exist if GameOBject not loaded + /*if(m_uint32Values) // field array can be not exist if GameOBject not loaded { - // crash possible at access to deleted GO in Unit::m_gameobj + // Possible crash at access to deleted GO in Unit::m_gameobj uint64 owner_guid = GetOwnerGUID(); if(owner_guid) { @@ -76,7 +76,7 @@ GameObject::~GameObject() else if(!IS_PLAYER_GUID(owner_guid)) sLog.outError("Delete GameObject (GUID: %u Entry: %u ) that have references in not found creature %u GO list. Crash possible later.",GetGUIDLow(),GetGOInfo()->id,GUID_LOPART(owner_guid)); } - } + }*/ } void GameObject::AddToWorld() @@ -84,6 +84,9 @@ void GameObject::AddToWorld() ///- Register the gameobject for guid lookup if(!IsInWorld()) { + if(m_zoneScript) + m_zoneScript->OnGameObjectCreate(this, true); + ObjectAccessor::Instance().AddObject(this); WorldObject::AddToWorld(); } @@ -94,23 +97,33 @@ void GameObject::RemoveFromWorld() ///- Remove the gameobject from the accessor if(IsInWorld()) { - if(Map *map = FindMap()) - if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) - ((InstanceMap*)map)->GetInstanceData()->OnObjectRemove(this); - ObjectAccessor::Instance().RemoveObject(this); + if(m_zoneScript) + m_zoneScript->OnGameObjectCreate(this, false); + + // Possible crash at access to deleted GO in Unit::m_gameobj + if(uint64 owner_guid = GetOwnerGUID()) + { + Unit* owner = ObjectAccessor::GetUnit(*this,owner_guid); + if(owner) + owner->RemoveGameObject(this,false); + else if(!IS_PLAYER_GUID(owner_guid)) + sLog.outError("Delete GameObject (GUID: %u Entry: %u ) that have references in not found creature %u GO list. Crash possible later.",GetGUIDLow(),GetGOInfo()->id,GUID_LOPART(owner_guid)); + } WorldObject::RemoveFromWorld(); + ObjectAccessor::Instance().RemoveObject(this); } } -bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, uint32 go_state, uint32 ArtKit) +bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 ArtKit) { Relocate(x,y,z,ang); SetMapId(map->GetId()); SetInstanceId(map->GetInstanceId()); + SetPhaseMask(phaseMask,false); if(!IsPositionValid()) { - sLog.outError("ERROR: Gameobject (GUID: %u Entry: %u ) not created. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,name_id,x,y); + sLog.outError("Gameobject (GUID: %u Entry: %u ) not created. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,name_id,x,y); return false; } @@ -134,19 +147,18 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, float x, float SetFloatValue(GAMEOBJECT_POS_X, x); SetFloatValue(GAMEOBJECT_POS_Y, y); SetFloatValue(GAMEOBJECT_POS_Z, z); - SetFloatValue(GAMEOBJECT_FACING, ang); //this is not facing angle - SetFloatValue (GAMEOBJECT_ROTATION, rotation0); - SetFloatValue (GAMEOBJECT_ROTATION+1, rotation1); - SetFloatValue (GAMEOBJECT_ROTATION+2, rotation2); - SetFloatValue (GAMEOBJECT_ROTATION+3, rotation3); + SetFloatValue(GAMEOBJECT_PARENTROTATION+0, rotation0); + SetFloatValue(GAMEOBJECT_PARENTROTATION+1, rotation1); + + UpdateRotationFields(rotation2,rotation3); // GAMEOBJECT_FACING, GAMEOBJECT_ROTATION, GAMEOBJECT_PARENTROTATION+2/3 SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size); SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction); SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags); - SetUInt32Value(OBJECT_FIELD_ENTRY, goinfo->id); + SetEntry(goinfo->id); SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId); @@ -155,20 +167,20 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, float x, float SetGoAnimProgress(animprogress); - SetUInt32Value (GAMEOBJECT_ARTKIT, ArtKit); - - // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22) - if (goinfo->type == GAMEOBJECT_TYPE_SPELLCASTER) - m_charges = goinfo->spellcaster.charges; + SetByteValue(GAMEOBJECT_BYTES_1, 2, ArtKit); - //Notify the map's instance data. - //Only works if you create the object in it, not if it is moves to that map. - //Normally non-players do not teleport to other maps. - if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) + switch(goinfo->type) { - ((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this); + case GAMEOBJECT_TYPE_SPELLCASTER: + m_charges = goinfo->spellcaster.charges; + break; + case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING: + m_goValue->building.health = goinfo->building.intactNumHits + goinfo->building.damagedNumHits; + break; } + SetZoneScript(); + return true; } @@ -190,7 +202,7 @@ void GameObject::Update(uint32 /*p_time*/) { // Arming Time for GAMEOBJECT_TYPE_TRAP (6) Unit* owner = GetOwner(); - if (owner && ((Player*)owner)->isInCombat()) + if (owner && owner->isInCombat()) m_cooldownTime = time(NULL) + GetGOInfo()->trap.startDelay; m_lootState = GO_READY; break; @@ -204,7 +216,7 @@ void GameObject::Update(uint32 /*p_time*/) Unit* caster = GetOwner(); if(caster && caster->GetTypeId()==TYPEID_PLAYER) { - SetGoState(0); + SetGoState(GO_STATE_ACTIVE); SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); UpdateData udata; @@ -213,10 +225,7 @@ void GameObject::Update(uint32 /*p_time*/) udata.BuildPacket(&packet); ((Player*)caster)->GetSession()->SendPacket(&packet); - WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4); - data << GetGUID(); - data << (uint32)(0); - ((Player*)caster)->SendMessageToSet(&data,true); + SendCustomAnim(); } m_lootState = GO_READY; // can be successfully open with some chance @@ -262,18 +271,22 @@ void GameObject::Update(uint32 /*p_time*/) case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: //we need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for battlegrounds) - if( !GetGoState() ) - SwitchDoorOrButton(false); + if (GetGoState() != GO_STATE_READY) + ResetDoorOrButton(); //flags in AB are type_button and we need to add them here so no break! default: - if(!m_spawnedByDefault) // despawn timer + if (!m_spawnedByDefault) // despawn timer { // can be despawned or destroyed SetLootState(GO_JUST_DEACTIVATED); return; } // respawn timer - MapManager::Instance().GetMap(GetMapId(), this)->Add(this); + uint16 poolid = poolhandler.IsPartOfAPool(GetGUIDLow(), TYPEID_GAMEOBJECT); + if (poolid) + poolhandler.UpdatePool(poolid, GetGUIDLow(), TYPEID_GAMEOBJECT); + else + GetMap()->Add(this); break; } } @@ -293,17 +306,13 @@ void GameObject::Update(uint32 /*p_time*/) bool IsBattleGroundTrap = false; //FIXME: this is activation radius (in different casting radius that must be selected from spell data) //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state - float radius = 0.0f; - const SpellEntry *spellEntry = sSpellStore.LookupEntry(m_spellId); - if(spellEntry) - radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEntry->EffectRadiusIndex[0])); - else - radius = goInfo->trap.radius; + float radius = goInfo->trap.radius; + if(!radius) // i think this is a hack, spell radius is determined by trap radius (spell itself does not have radius) + if(const SpellEntry *spellEntry = sSpellStore.LookupEntry(m_spellId)) + radius = goInfo->trap.radius; if(!radius) { - if(goInfo->trap.cooldown != 3) // cast in other case (at some triggering/linked go/etc explicit call) - return; - else + if(goInfo->trap.cooldown == 3) // cast in other case (at some triggering/linked go/etc explicit call) { if(m_respawnTime > 0) break; @@ -311,58 +320,44 @@ void GameObject::Update(uint32 /*p_time*/) radius = goInfo->trap.cooldown; // battlegrounds gameobjects has data2 == 0 && data5 == 3 IsBattleGroundTrap = true; } + if(!radius) + return; } - bool NeedDespawn = (goInfo->trap.charges != 0); - - CellPair p(Trinity::ComputeCellPair(GetPositionX(),GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - // Note: this hack with search required until GO casting not implemented // search unfriendly creature - if(owner && NeedDespawn) // hunter trap + if(owner) // hunter trap { - Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck u_check(this, owner, radius); - Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> checker(ok, u_check); - - CellLock<GridReadGuard> cell_lock(cell, p); - - TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck>, GridTypeMapContainer > grid_object_checker(checker); - cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); - - // or unfriendly player/pet - if(!ok) - { - TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker); - cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); - } + Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius); + Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, ok, checker); + VisitNearbyGridObject(radius, searcher); + if(!ok) VisitNearbyWorldObject(radius, searcher); } else // environmental trap { // environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support - // affect only players - Player* p_ok = NULL; - Trinity::AnyPlayerInObjectRangeCheck p_check(this, radius); - Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> checker(p_ok, p_check); - - CellLock<GridReadGuard> cell_lock(cell, p); - - TypeContainerVisitor<Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker); - cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); - ok = p_ok; + Player* player = NULL; + MaNGOS::AnyPlayerInObjectRangeCheck checker(this, radius); + MaNGOS::PlayerSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> searcher(this, player, checker); + VisitNearbyWorldObject(radius, searcher); + ok = player; } if (ok) { + // some traps do not have spell but should be triggered + if(goInfo->trap.spellId) + CastSpell(ok, goInfo->trap.spellId); //Unit *caster = owner ? owner : ok; + //caster->CastSpell(ok, goInfo->trap.spellId, true, 0, 0, GetGUID()); - //caster->CastSpell(ok, goInfo->trap.spellId, true); - CastSpell(ok, goInfo->trap.spellId); - m_cooldownTime = time(NULL) + 4; // 4 seconds + if(goInfo->trap.cooldown) + m_cooldownTime = time(NULL) + goInfo->trap.cooldown; + else + m_cooldownTime = time(NULL) + 4; // 4 seconds - if(NeedDespawn) + if(owner) SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed if(IsBattleGroundTrap && ok->GetTypeId() == TYPEID_PLAYER) @@ -386,11 +381,8 @@ void GameObject::Update(uint32 /*p_time*/) { case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: - if(GetAutoCloseTime() && (m_cooldownTime < time(NULL))) - { - SwitchDoorOrButton(false); - SetLootState(GO_JUST_DEACTIVATED); - } + if (GetAutoCloseTime() && (m_cooldownTime < time(NULL))) + ResetDoorOrButton(); break; } break; @@ -404,11 +396,13 @@ void GameObject::Update(uint32 /*p_time*/) if(spellId) { - std::set<uint32>::iterator it = m_unique_users.begin(); - std::set<uint32>::iterator end = m_unique_users.end(); + std::set<uint32>::const_iterator it = m_unique_users.begin(); + std::set<uint32>::const_iterator end = m_unique_users.end(); for (; it != end; it++) { Unit* owner = Unit::GetUnit(*this, uint64(*it)); + // For now we do not support go cast + //if (owner) owner->CastSpell(owner, spellId, false, 0, 0, GetGUID()); if (owner) owner->CastSpell(owner, spellId, false); } @@ -420,7 +414,10 @@ void GameObject::Update(uint32 /*p_time*/) if(GetOwnerGUID()) { - m_respawnTime = 0; + if(Unit* owner = GetOwner()) + owner->RemoveGameObject(this, false); + + SetRespawnTime(0); Delete(); return; } @@ -428,7 +425,7 @@ void GameObject::Update(uint32 /*p_time*/) //burning flags in some battlegrounds, if you find better condition, just add it if (GetGoAnimProgress() > 0) { - SendObjectDeSpawnAnim(this->GetGUID()); + SendObjectDeSpawnAnim(GetGUID()); //reset flags SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags); } @@ -465,7 +462,7 @@ void GameObject::Refresh() return; if(isSpawned()) - MapManager::Instance().GetMap(GetMapId(), this)->Add(this); + GetMap()->Add(this); } void GameObject::AddUniqueUse(Player* player) @@ -478,24 +475,29 @@ void GameObject::Delete() { SendObjectDeSpawnAnim(GetGUID()); - SetGoState(1); + SetGoState(GO_STATE_READY); SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags); - AddObjectToRemoveList(); + uint16 poolid = poolhandler.IsPartOfAPool(GetGUIDLow(), TYPEID_GAMEOBJECT); + if (poolid) + poolhandler.UpdatePool(poolid, GetGUIDLow(), TYPEID_GAMEOBJECT); + else + AddObjectToRemoveList(); } -void GameObject::getFishLoot(Loot *fishloot) +void GameObject::getFishLoot(Loot *fishloot, Player* loot_owner) { fishloot->clear(); - uint32 subzone = GetAreaId(); + uint32 zone, subzone; + GetZoneAndAreaId(zone,subzone); // if subzone loot exist use it if(LootTemplates_Fishing.HaveLootFor(subzone)) - fishloot->FillLoot(subzone, LootTemplates_Fishing, NULL); + fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner,true); // else use zone loot else - fishloot->FillLoot(GetZoneId(), LootTemplates_Fishing, NULL); + fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner,true); } void GameObject::SaveToDB() @@ -509,10 +511,10 @@ void GameObject::SaveToDB() return; } - SaveToDB(GetMapId(), data->spawnMask); + SaveToDB(GetMapId(), data->spawnMask, data->phaseMask); } -void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask) +void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) { const GameObjectInfo *goI = GetGOInfo(); @@ -527,38 +529,40 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask) // data->guid = guid don't must be update at save data.id = GetEntry(); data.mapid = mapid; + data.phaseMask = phaseMask; data.posX = GetFloatValue(GAMEOBJECT_POS_X); data.posY = GetFloatValue(GAMEOBJECT_POS_Y); data.posZ = GetFloatValue(GAMEOBJECT_POS_Z); data.orientation = GetFloatValue(GAMEOBJECT_FACING); - data.rotation0 = GetFloatValue(GAMEOBJECT_ROTATION+0); - data.rotation1 = GetFloatValue(GAMEOBJECT_ROTATION+1); - data.rotation2 = GetFloatValue(GAMEOBJECT_ROTATION+2); - data.rotation3 = GetFloatValue(GAMEOBJECT_ROTATION+3); + data.rotation0 = GetFloatValue(GAMEOBJECT_PARENTROTATION+0); + data.rotation1 = GetFloatValue(GAMEOBJECT_PARENTROTATION+1); + data.rotation2 = GetFloatValue(GAMEOBJECT_PARENTROTATION+2); + data.rotation3 = GetFloatValue(GAMEOBJECT_PARENTROTATION+3); data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime; data.animprogress = GetGoAnimProgress(); data.go_state = GetGoState(); data.spawnMask = spawnMask; - data.ArtKit = GetUInt32Value (GAMEOBJECT_ARTKIT); + data.ArtKit = GetGoArtKit(); // updated in DB std::ostringstream ss; ss << "INSERT INTO gameobject VALUES ( " << m_DBTableGuid << ", " - << GetUInt32Value (OBJECT_FIELD_ENTRY) << ", " + << GetEntry() << ", " << mapid << ", " - << (uint32)spawnMask << ", " + << uint32(spawnMask) << "," // cast to prevent save as symbol + << uint16(GetPhaseMask()) << "," // prevent out of range error << GetFloatValue(GAMEOBJECT_POS_X) << ", " << GetFloatValue(GAMEOBJECT_POS_Y) << ", " << GetFloatValue(GAMEOBJECT_POS_Z) << ", " << GetFloatValue(GAMEOBJECT_FACING) << ", " - << GetFloatValue(GAMEOBJECT_ROTATION) << ", " - << GetFloatValue(GAMEOBJECT_ROTATION+1) << ", " - << GetFloatValue(GAMEOBJECT_ROTATION+2) << ", " - << GetFloatValue(GAMEOBJECT_ROTATION+3) << ", " + << GetFloatValue(GAMEOBJECT_PARENTROTATION) << ", " + << GetFloatValue(GAMEOBJECT_PARENTROTATION+1) << ", " + << GetFloatValue(GAMEOBJECT_PARENTROTATION+2) << ", " + << GetFloatValue(GAMEOBJECT_PARENTROTATION+3) << ", " << m_respawnDelayTime << ", " - << GetGoAnimProgress() << ", " - << GetGoState() << ")"; + << uint32(GetGoAnimProgress()) << ", " + << uint32(GetGoState()) << ")"; WorldDatabase.BeginTransaction(); WorldDatabase.PExecuteLog("DELETE FROM gameobject WHERE guid = '%u'", m_DBTableGuid); @@ -572,12 +576,13 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map) if( !data ) { - sLog.outErrorDb("ERROR: Gameobject (GUID: %u) not found in table `gameobject`, can't load. ",guid); + sLog.outErrorDb("Gameobject (GUID: %u) not found in table `gameobject`, can't load. ",guid); return false; } uint32 entry = data->id; - uint32 map_id = data->mapid; + //uint32 map_id = data->mapid; // already used before call + uint32 phaseMask = data->phaseMask; float x = data->posX; float y = data->posY; float z = data->posZ; @@ -589,48 +594,47 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map) float rotation3 = data->rotation3; uint32 animprogress = data->animprogress; - uint32 go_state = data->go_state; + GOState go_state = data->go_state; uint32 ArtKit = data->ArtKit; m_DBTableGuid = guid; if (map->GetInstanceId() != 0) guid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT); - if (!Create(guid,entry, map, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, ArtKit) ) + if (!Create(guid,entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, ArtKit) ) return false; - switch(GetGOInfo()->type) + if(!GetDespawnPossibility()) { - case GAMEOBJECT_TYPE_DOOR: - case GAMEOBJECT_TYPE_BUTTON: - /* this code (in comment) isn't correct because in battlegrounds we need despawnable doors and buttons, pls remove - SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); + SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); + m_spawnedByDefault = true; + m_respawnDelayTime = 0; + m_respawnTime = 0; + } + else + { + if(data->spawntimesecs >= 0) + { m_spawnedByDefault = true; - m_respawnDelayTime = 0; - m_respawnTime = 0; - break;*/ - default: - if(data->spawntimesecs >= 0) - { - m_spawnedByDefault = true; - m_respawnDelayTime = data->spawntimesecs; - m_respawnTime = objmgr.GetGORespawnTime(m_DBTableGuid, map->GetInstanceId()); + m_respawnDelayTime = data->spawntimesecs; + m_respawnTime = objmgr.GetGORespawnTime(m_DBTableGuid, map->GetInstanceId()); - // ready to respawn - if(m_respawnTime && m_respawnTime <= time(NULL)) - { - m_respawnTime = 0; - objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0); - } - } - else + // ready to respawn + if(m_respawnTime && m_respawnTime <= time(NULL)) { - m_spawnedByDefault = false; - m_respawnDelayTime = -data->spawntimesecs; m_respawnTime = 0; + objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0); } - break; + } + else + { + m_spawnedByDefault = false; + m_respawnDelayTime = -data->spawntimesecs; + m_respawnTime = 0; + } } + m_goData = data; + return true; } @@ -644,12 +648,7 @@ void GameObject::DeleteFromDB() GameObject* GameObject::GetGameObject(WorldObject& object, uint64 guid) { - return ObjectAccessor::GetGameObject(object,guid); -} - -GameObjectInfo const *GameObject::GetGOInfo() const -{ - return m_goInfo; + return object.GetMap()->GetGameObject(guid); } uint32 GameObject::GetLootId(GameObjectInfo const* ginfo) @@ -710,7 +709,7 @@ Unit* GameObject::GetOwner() const void GameObject::SaveRespawnTime() { - if(m_respawnTime > time(NULL) && m_spawnedByDefault) + if(m_goData && m_goData->dbData && m_respawnTime > time(NULL) && m_spawnedByDefault) objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime); } @@ -738,14 +737,10 @@ bool GameObject::isVisibleForInState(Player const* u, bool inVisibleList) const if(owner && u->IsHostileTo(owner) && !canDetectTrap(u, GetDistance(u))) return false; } - - // Smuggled Mana Cell required 10 invisibility type detection/state - if(GetEntry()==187039 && ((u->m_detectInvisibilityMask | u->m_invisibilityMask) & (1<<10))==0) - return false; } // check distance - return IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject() + + return IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); } @@ -824,7 +819,20 @@ void GameObject::TriggeringLinkedGameObject( uint32 trapEntry, Unit* target) if(!trapSpell) // checked at load already return; - float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(trapSpell->rangeIndex)); + float range; + SpellRangeEntry const * srentry = sSpellRangeStore.LookupEntry(trapSpell->rangeIndex); + //get owner to check hostility of GameObject + if (GetSpellMaxRangeForHostile(srentry) == GetSpellMaxRangeForHostile(srentry)) + range = GetSpellMaxRangeForHostile(srentry); + else + { + Unit * owner=GetOwner(); + if (owner) + range = owner->GetSpellMaxRangeForTarget(target, srentry); + else + //if no owner assume that object is hostile to target + range = GetSpellMaxRangeForHostile(srentry); + } // search nearest linked GO GameObject* trapGO = NULL; @@ -834,18 +842,18 @@ void GameObject::TriggeringLinkedGameObject( uint32 trapEntry, Unit* target) Cell cell(p); cell.data.Part.reserved = ALL_DISTRICT; - Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*target,trapEntry,range); - Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(trapGO,go_check); + MaNGOS::NearestGameObjectEntryInObjectRangeCheck go_check(*target,trapEntry,range); + MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> checker(this, trapGO,go_check); TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker); CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); + cell_lock->Visit(cell_lock, object_checker, *GetMap()); } // found correct GO // FIXME: when GO casting will be implemented trap must cast spell to target if(trapGO) - target->CastSpell(target,trapSpell,true); + target->CastSpell(target,trapSpell,true, 0, 0, GetGUID()); } GameObject* GameObject::LookupFishingHoleAround(float range) @@ -855,18 +863,28 @@ GameObject* GameObject::LookupFishingHoleAround(float range) CellPair p(Trinity::ComputeCellPair(GetPositionX(),GetPositionY())); Cell cell(p); cell.data.Part.reserved = ALL_DISTRICT; - Trinity::NearestGameObjectFishingHole u_check(*this, range); - Trinity::GameObjectSearcher<Trinity::NearestGameObjectFishingHole> checker(ok, u_check); + MaNGOS::NearestGameObjectFishingHole u_check(*this, range); + MaNGOS::GameObjectSearcher<MaNGOS::NearestGameObjectFishingHole> checker(this, ok, u_check); CellLock<GridReadGuard> cell_lock(cell, p); TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::NearestGameObjectFishingHole>, GridTypeMapContainer > grid_object_checker(checker); - cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); + cell_lock->Visit(cell_lock, grid_object_checker, *GetMap()); return ok; } -void GameObject::UseDoorOrButton(uint32 time_to_restore) +void GameObject::ResetDoorOrButton() +{ + if (m_lootState == GO_READY || m_lootState == GO_JUST_DEACTIVATED) + return; + + SwitchDoorOrButton(false); + SetLootState(GO_JUST_DEACTIVATED); + m_cooldownTime = 0; +} + +void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */) { if(m_lootState != GO_READY) return; @@ -874,32 +892,31 @@ void GameObject::UseDoorOrButton(uint32 time_to_restore) if(!time_to_restore) time_to_restore = GetAutoCloseTime(); - SwitchDoorOrButton(true); + SwitchDoorOrButton(true,alternative); SetLootState(GO_ACTIVATED); m_cooldownTime = time(NULL) + time_to_restore; - } -void GameObject::SetGoArtKit(uint32 kit) +void GameObject::SetGoArtKit(uint8 kit) { - SetUInt32Value(GAMEOBJECT_ARTKIT, kit); + SetByteValue(GAMEOBJECT_BYTES_1, 2, kit); GameObjectData *data = const_cast<GameObjectData*>(objmgr.GetGOData(m_DBTableGuid)); if(data) data->ArtKit = kit; } -void GameObject::SwitchDoorOrButton(bool activate) +void GameObject::SwitchDoorOrButton(bool activate, bool alternative /* = false */) { if(activate) SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); else RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - if(GetGoState()) //if closed -> open - SetGoState(0); + if(GetGoState() == GO_STATE_READY) //if closed -> open + SetGoState(alternative ? GO_STATE_ACTIVE_ALTERNATIVE : GO_STATE_ACTIVE); else //if open -> close - SetGoState(1); + SetGoState(GO_STATE_READY); } void GameObject::Use(Unit* user) @@ -907,6 +924,7 @@ void GameObject::Use(Unit* user) // by default spell caster is user Unit* spellCaster = user; uint32 spellId = 0; + bool triggered = false; switch(GetGoType()) { @@ -956,7 +974,7 @@ void GameObject::Use(Unit* user) // every slot will be on that straight line float orthogonalOrientation = GetOrientation()+M_PI*0.5f; // find nearest slot - for(uint32 i=0; i<info->chair.slots; i++) + for(uint32 i=0; i<info->chair.slots; ++i) { // the distance between this slot and the center of the go - imagine a 1D space float relativeDistance = (info->size*i)-(info->size*(info->chair.slots-1)/2.0f); @@ -988,7 +1006,7 @@ void GameObject::Use(Unit* user) // fallback, will always work player->TeleportTo(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(),TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET); } - player->SetStandState(PLAYER_STATE_SIT_LOW_CHAIR+info->chair.height); + player->SetStandState(UNIT_STAND_STATE_SIT_LOW_CHAIR+info->chair.height); return; } //big gun, its a spell/aura @@ -1010,6 +1028,9 @@ void GameObject::Use(Unit* user) // possible quest objective for active quests player->CastedCreatureOrGO(info->id, GetGUID(), 0); + + if (info->goober.eventId) + sWorld.ScriptsStart(sEventScripts, info->goober.eventId, player, this); } // cast this spell later if provided @@ -1028,12 +1049,12 @@ void GameObject::Use(Unit* user) Player* player = (Player*)user; - if(info->camera.cinematicId) - { - WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4); - data << info->camera.cinematicId; - player->GetSession()->SendPacket(&data); - } + if (info->camera.cinematicId) + player->SendCinematicStart(info->camera.cinematicId); + + if (info->camera.eventID) + sWorld.ScriptsStart(sEventScripts, info->camera.eventID, player, this); + return; } //fishing bobber @@ -1055,11 +1076,12 @@ void GameObject::Use(Unit* user) // 2) if skill == base_zone_skill => 5% chance // 3) chance is linear dependence from (base_zone_skill-skill) - uint32 subzone = GetAreaId(); + uint32 zone, subzone; + GetZoneAndAreaId(zone,subzone); int32 zone_skill = objmgr.GetFishingBaseSkillLevel( subzone ); if(!zone_skill) - zone_skill = objmgr.GetFishingBaseSkillLevel( GetZoneId() ); + zone_skill = objmgr.GetFishingBaseSkillLevel( zone ); //provide error, no fishable zone or area should be 0 if(!zone_skill) @@ -1067,7 +1089,7 @@ void GameObject::Use(Unit* user) int32 skill = player->GetSkillValue(SKILL_FISHING); int32 chance = skill - zone_skill + 5; - int32 roll = GetMap()->irand(1,100); + int32 roll = irand(1,100); DEBUG_LOG("Fishing check (skill: %i zone min skill: %i chance %i roll: %i",skill,zone_skill,chance,roll); @@ -1084,6 +1106,7 @@ void GameObject::Use(Unit* user) if (ok) { player->SendLoot(ok->GetGUID(),LOOT_FISHINGHOLE); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT, ok->GetGOInfo()->id); SetLootState(GO_JUST_DEACTIVATED); } else @@ -1150,6 +1173,13 @@ void GameObject::Use(Unit* user) return; spellId = info->summoningRitual.spellId; + if(spellId==62330) // GO store not existed spell, replace by expected + { + // spell have reagent and mana cost but it not expected use its + // it triggered spell in fact casted at currently channeled GO + spellId = 61993; + triggered = true; + } // finish spell caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0); @@ -1207,7 +1237,10 @@ void GameObject::Use(Unit* user) if (level < info->meetingstone.minLevel || level > info->meetingstone.maxLevel) return; - spellId = 23598; + if(info->id==194097) + spellId = 61994; // Ritual of Summoning + else + spellId = 59782; // Summoning Stone Effect break; } @@ -1219,7 +1252,7 @@ void GameObject::Use(Unit* user) Player* player = (Player*)user; - if( player->isAllowUseBattleGroundObject() ) + if( player->CanUseBattleGroundObject() ) { // in battleground check BattleGround *bg = player->GetBattleGround(); @@ -1244,7 +1277,7 @@ void GameObject::Use(Unit* user) Player* player = (Player*)user; - if( player->isAllowUseBattleGroundObject() ) + if( player->CanUseBattleGroundObject() ) { // in battleground check BattleGround *bg = player->GetBattleGround(); @@ -1282,6 +1315,26 @@ void GameObject::Use(Unit* user) } break; } + case GAMEOBJECT_TYPE_BARBER_CHAIR: //32 + { + GameObjectInfo const* info = GetGOInfo(); + if(!info) + return; + + if(user->GetTypeId()!=TYPEID_PLAYER) + return; + + Player* player = (Player*)user; + + // fallback, will always work + player->TeleportTo(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(),TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET); + + WorldPacket data(SMSG_ENABLE_BARBER_SHOP, 0); + player->GetSession()->SendPacket(&data); + + player->SetStandState(UNIT_STAND_STATE_SIT_LOW_CHAIR+info->barberChair.chairheight); + return; + } default: sLog.outDebug("Unknown Object Type %u", GetGoType()); break; @@ -1300,7 +1353,7 @@ void GameObject::Use(Unit* user) return; } - Spell *spell = new Spell(spellCaster, spellInfo, false); + Spell *spell = new Spell(spellCaster, spellInfo, triggered); // spell target is user of GO SpellCastTargets targets; @@ -1309,8 +1362,29 @@ void GameObject::Use(Unit* user) spell->prepare(&targets); } -void GameObject::CastSpell(Unit* target, uint32 spell) +void GameObject::CastSpell(Unit* target, uint32 spellId) { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if(!spellInfo) + return; + + bool self = false; + for(int i = 0; i < 3; ++i) + { + if(spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_CASTER) + { + self = true; + break; + } + } + + if(self) + { + if(target) + target->CastSpell(target, spellInfo, true); + return; + } + //summon world trigger Creature *trigger = SummonTrigger(GetPositionX(), GetPositionY(), GetPositionZ(), 0, 1); if(!trigger) return; @@ -1319,17 +1393,96 @@ void GameObject::CastSpell(Unit* target, uint32 spell) if(Unit *owner = GetOwner()) { trigger->setFaction(owner->getFaction()); - trigger->CastSpell(target, spell, true, 0, 0, owner->GetGUID()); + trigger->CastSpell(target, spellInfo, true, 0, 0, owner->GetGUID()); } else { trigger->setFaction(14); - trigger->CastSpell(target, spell, true, 0, 0, target->GetGUID()); + trigger->CastSpell(target, spellInfo, true); } //trigger->setDeathState(JUST_DIED); //trigger->RemoveCorpse(); } +void GameObject::SendCustomAnim() +{ + WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4); + data << GetGUID(); + data << (uint32)0; + SendMessageToSet(&data, true); +} + +bool GameObject::IsInRange(float x, float y, float z, float radius) const +{ + GameObjectDisplayInfoEntry const * info = sGameObjectDisplayInfoStore.LookupEntry(GetUInt32Value(GAMEOBJECT_DISPLAYID)); + if(!info) + return IsWithinDist3d(x, y, z, radius); + + float sinA = sin(GetOrientation()); + float cosA = cos(GetOrientation()); + float dx = x - GetPositionX(); + float dy = y - GetPositionY(); + float dz = z - GetPositionZ(); + float dist = sqrt(dx*dx + dy*dy); + float sinB = dx / dist; + float cosB = dy / dist; + dx = dist * (cosA * cosB + sinA * sinB); + dy = dist * (cosA * sinB - sinA * cosB); + return dx < info->maxX + radius && dx > info->minX - radius + && dy < info->maxY + radius && dy > info->minY - radius + && dz < info->maxZ + radius && dz > info->minZ - radius; +} + +void GameObject::TakenDamage(uint32 damage) +{ + if(!m_goValue->building.health) + return; + + if(m_goValue->building.health > damage) + m_goValue->building.health -= damage; + else + m_goValue->building.health = 0; + + if(HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED)) // from damaged to destroyed + { + if(!m_goValue->building.health) + { + RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED); + + SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); + SetUInt32Value(GAMEOBJECT_DISPLAYID, m_goInfo->building.destroyedDisplayId); + EventInform(m_goInfo->building.damagedEvent); + } + } + else // from intact to damaged + { + if(m_goValue->building.health <= m_goInfo->building.damagedNumHits) + { + if(!m_goInfo->building.destroyedDisplayId) + m_goValue->building.health = 0; + else if(!m_goValue->building.health) + m_goValue->building.health = 1; + + SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED); + SetUInt32Value(GAMEOBJECT_DISPLAYID, m_goInfo->building.damagedDisplayId); + EventInform(m_goInfo->building.intactEvent); + } + } +} + +void GameObject::Rebuild() +{ + RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED + GO_FLAG_DESTROYED); + SetUInt32Value(GAMEOBJECT_DISPLAYID, m_goInfo->displayId); + m_goValue->building.health = m_goInfo->building.intactNumHits + m_goInfo->building.damagedNumHits; +} + +void GameObject::EventInform(uint32 eventId) +{ + if(eventId && m_zoneScript) + m_zoneScript->ProcessEvent(this, eventId); +} + // overwrite WorldObject function for proper name localization const char* GameObject::GetNameForLocaleIdx(int32 loc_idx) const { @@ -1346,3 +1499,25 @@ const char* GameObject::GetNameForLocaleIdx(int32 loc_idx) const return GetName(); } +void GameObject::UpdateRotationFields(float rotation2 /*=0.0f*/, float rotation3 /*=0.0f*/) +{ + static double const atan_pow = atan(pow(2.0f, -20.0f)); + + SetFloatValue(GAMEOBJECT_FACING, GetOrientation()); + + double f_rot1 = sin(GetOrientation() / 2.0f); + double f_rot2 = cos(GetOrientation() / 2.0f); + + int64 i_rot1 = int64(f_rot1 / atan_pow *(f_rot2 >= 0 ? 1.0f : -1.0f)); + int64 rotation = (i_rot1 << 43 >> 43) & 0x00000000001FFFFF; + SetUInt64Value(GAMEOBJECT_ROTATION, rotation); + + if(rotation2==0.0f && rotation3==0.0f) + { + rotation2 = f_rot1; + rotation3 = f_rot2; + } + + SetFloatValue(GAMEOBJECT_PARENTROTATION+2, rotation2); + SetFloatValue(GAMEOBJECT_PARENTROTATION+3, rotation3); +} |