/*
* Ascent Serveur MMORPG
* Copyright (C) 2005-2008 Ascent Team
* Copyright (C) 2007-2008 AscentFR Team
*
* Ce programme est un logiciel libre: vous pouvez le redistribuer ou le modifier.
*Selon les termes de la GNU General Public License Affero tel que publi par
* la Software Foundation, soit la version 3 de la licence, ou
* toute version ultrieure.
*
* Ce programme est distribu dans l'espoir qu'il sera utile,
* Mais SANS AUCUNE GARANTIE; sans mme la garantie implicite de
* Marchande ou d'adquation un usage particulier. Voir le
* Affero GNU General Public License pour plus de dtails.
*
* Vous devez avoir reu une copie de la GNU General Public License Affero
* Avec ce programme. Si non, voir .
*
*/
#include "StdAfx.h"
GameObject::GameObject(uint64 guid)
{
m_objectTypeId = TYPEID_GAMEOBJECT;
m_valuesCount = GAMEOBJECT_END;
m_uint32Values = _fields;
memset(m_uint32Values, 0,(GAMEOBJECT_END)*sizeof(uint32));
m_updateMask.SetCount(GAMEOBJECT_END);
SetUInt32Value( OBJECT_FIELD_TYPE,TYPE_GAMEOBJECT|TYPE_OBJECT);
SetUInt64Value( OBJECT_FIELD_GUID,guid);
SetByte(GAMEOBJECT_BYTES_1, 3, 100);
m_wowGuid.Init(GetGUID());
SetFloatValue( OBJECT_FIELD_SCALE_X, 1);//info->Size );
SetByte(GAMEOBJECT_BYTES_1, 3, 100);
counter=0;//not needed at all but to prevent errors that var was not inited, can be removed in release
bannerslot = bannerauraslot = -1;
m_summonedGo = false;
invisible = false;
invisibilityFlag = INVIS_FLAG_NORMAL;
spell = 0;
m_summoner = NULL;
charges = -1;
m_ritualcaster = 0;
m_ritualtarget = 0;
m_ritualmembers = NULL;
m_ritualspell = 0;
m_quests = NULL;
pInfo = NULL;
myScript = NULL;
m_spawn = 0;
loot.gold = 0;
m_deleted = false;
usage_remaining = 1;
m_respawnCell=NULL;
m_battleground = NULL;
}
GameObject::~GameObject()
{
sEventMgr.RemoveEvents(this);
if(m_ritualmembers) {
delete[] m_ritualmembers;
m_ritualmembers = NULL;
}
uint32 guid = GetUInt32Value(OBJECT_FIELD_CREATED_BY);
if(guid)
{
Player *plr = objmgr.GetPlayer(guid);
if(plr && plr->GetSummonedObject() == this)
plr->SetSummonedObject(NULL);
if(plr == m_summoner)
m_summoner = 0;
}
if(m_respawnCell!=NULL)
hashmap64_remove(m_respawnCell->_respawnObjects, GetGUID());
if (m_summonedGo && m_summoner)
for(int i = 0; i < 4; i++)
if (m_summoner->m_ObjectSlots[i] == GetLowGUID())
m_summoner->m_ObjectSlots[i] = 0;
if( m_battleground != NULL && m_battleground->GetType() == BATTLEGROUND_ARATHI_BASIN )
{
if( bannerslot >= 0 && static_cast(m_battleground)->m_controlPoints[bannerslot] == this )
static_cast(m_battleground)->m_controlPoints[bannerslot] = NULL;
if( bannerauraslot >= 0 && static_cast(m_battleground)->m_controlPointAuras[bannerauraslot] == this )
static_cast(m_battleground)->m_controlPointAuras[bannerauraslot] = NULL;
}
}
bool GameObject::CreateFromProto(uint32 entry,uint32 mapid, float x, float y, float z, float ang)
{
pInfo= GameObjectNameStorage.LookupEntry(entry);
if(!pInfo)return false;
Object::_Create( mapid, x, y, z, ang );
SetUInt32Value( OBJECT_FIELD_ENTRY, entry );
SetFloatValue( GAMEOBJECT_POS_X, x );
SetFloatValue( GAMEOBJECT_POS_Y, y );
SetFloatValue( GAMEOBJECT_POS_Z, z );
SetFloatValue( GAMEOBJECT_FACING, ang );
SetRotation(ang);
//SetUInt32Value( GAMEOBJECT_TIMESTAMP, (uint32)UNIXTIME);
// SetUInt32Value( GAMEOBJECT_ARTKIT, 0 ); //these must be from wdb somewhere i guess
SetByte( GAMEOBJECT_BYTES_1, 3, 0 );
SetByte( GAMEOBJECT_BYTES_1, 0, 1 );
SetUInt32Value( GAMEOBJECT_DISPLAYID, pInfo->DisplayID );
SetByte( GAMEOBJECT_BYTES_1, 1, pInfo->Type );
InitAI();
return true;
/*
original_flags = m_uint32Values[GAMEOBJECT_FLAGS];
original_state = m_uint32Values[GAMEOBJECT_BYTES_1, 0];
*/
}
/*
void GameObject::Create(uint32 mapid, float x, float y, float z, float ang)
{
Object::_Create( mapid, x, y, z, ang);
SetFloatValue( GAMEOBJECT_POS_X, x);
SetFloatValue( GAMEOBJECT_POS_Y, y );
SetFloatValue( GAMEOBJECT_POS_Z, z );
SetFloatValue( GAMEOBJECT_FACING, ang );
//SetUInt32Value( GAMEOBJECT_TIMESTAMP, (uint32)time(NULL));
}
void GameObject::Create( uint32 guidlow, uint32 guidhigh,uint32 displayid, uint8 state, uint32 entryid, float scale,uint32 typeId, uint32 type,uint32 flags, uint32 mapid, float x, float y, float z, float ang )
{
Object::_Create( mapid, x, y, z, ang);
SetUInt32Value( OBJECT_FIELD_ENTRY, entryid );
SetFloatValue( OBJECT_FIELD_SCALE_X, scale );
SetUInt32Value( GAMEOBJECT_DISPLAYID, displayid );
SetByte( GAMEOBJECT_BYTES_1, 0, state );
SetByte( GAMEOBJECT_BYTES_1, 1, typeId );
SetUInt32Value( GAMEOBJECT_FLAGS, flags );
}*/
void GameObject::EventCastSpell(uint32 guid, uint32 sp, bool triggered)
{
Spell * spp =SpellPool.PooledNew();
spp->Init((Object*)this,dbcSpell.LookupEntry(sp),false,NULL);
SpellCastTargets tars( guid);
spp->prepare(&tars);
}
void GameObject::TrapSearchTarget()
{
Update(100);
}
void GameObject::Update(uint32 p_time)
{
if(m_event_Instanceid != m_instanceId)
{
event_Relocate();
return;
}
if(!IsInWorld())
return;
if(m_deleted)
return;
if(spell && (GetByte(GAMEOBJECT_BYTES_1, 0) == 1))
{
if(checkrate > 1)
{
if(counter++%checkrate)
return;
}
ObjectSet::iterator itr = GetInRangeSetBegin();
ObjectSet::iterator it2 = itr;
ObjectSet::iterator iend = GetInRangeSetEnd();
Unit * pUnit;
float dist;
this->AquireInrangeLock(); //make sure to release lock before exit function !
for(; it2 != iend;)
{
itr = it2;
++it2;
dist = GetDistanceSq((*itr));
if( (*itr) != m_summoner && (*itr)->IsUnit() && dist <= range)
{
pUnit = static_cast(*itr);
if(m_summonedGo)
{
if(!m_summoner)
{
ExpireAndDelete();
return;
}
if(!isAttackable(m_summoner,pUnit))continue;
}
Spell * sp=SpellPool.PooledNew();
sp->Init((Object*)this,spell,true,NULL);
SpellCastTargets tgt((*itr)->GetGUID());
tgt.m_destX = GetPositionX();
tgt.m_destY = GetPositionY();
tgt.m_destZ = GetPositionZ();
sp->prepare(&tgt);
// proc on trap trigger
if( pInfo->Type == GAMEOBJECT_TYPE_TRAP )
{
if( m_summoner != NULL )
m_summoner->HandleProc( PROC_ON_TRAP_TRIGGER, pUnit, spell );
}
if(m_summonedGo)
{
ExpireAndDelete();
this->ReleaseInrangeLock();
return;
}
if(spell->EffectImplicitTargetA[0] == 16 ||
spell->EffectImplicitTargetB[0] == 16)
{
this->ReleaseInrangeLock();
return; // on area dont continue.
}
}
}
this->ReleaseInrangeLock();
}
}
void GameObject::Spawn(MapMgr * m)
{
PushToWorld(m);
CALL_GO_SCRIPT_EVENT(this, OnSpawn)();
}
void GameObject::Despawn(uint32 time)
{
if(!IsInWorld())
return;
loot.items.clear();
//This is for go get deleted while looting
if(m_spawn)
{
SetByte(GAMEOBJECT_BYTES_1, 0, m_spawn->state);
SetUInt32Value(GAMEOBJECT_FLAGS, m_spawn->flags);
}
CALL_GO_SCRIPT_EVENT(this, OnDespawn)();
if(time)
{
/* Get our originiating mapcell */
MapCell * pCell = m_mapCell;
ASSERT(pCell);
hashmap64_put(pCell->_respawnObjects, GetGUID(), NULL);
sEventMgr.RemoveEvents(this);
sEventMgr.AddEvent(m_mapMgr, &MapMgr::EventRespawnGameObject, this, pCell, EVENT_GAMEOBJECT_ITEM_SPAWN, time, 1, 0);
Object::RemoveFromWorld(false);
m_respawnCell=pCell;
}
else
{
Object::RemoveFromWorld(true);
ExpireAndDelete();
}
}
void GameObject::SaveToDB()
{
std::stringstream ss;
ss << "REPLACE INTO gameobject_spawns VALUES("
<< ((m_spawn == NULL) ? 0 : m_spawn->id) << ","
<< GetEntry() << ","
<< GetMapId() << ","
<< GetPositionX() << ","
<< GetPositionY() << ","
<< GetPositionZ() << ","
<< GetOrientation() << ","
<< GetUInt64Value(GAMEOBJECT_ROTATION) << ","
<< GetFloatValue(GAMEOBJECT_PARENTROTATION) << ","
<< GetFloatValue(GAMEOBJECT_PARENTROTATION_02) << ","
<< GetFloatValue(GAMEOBJECT_PARENTROTATION_03) << ","
<< (unsigned short)GetByte(GAMEOBJECT_BYTES_1, 0) << ","
<< GetUInt32Value(GAMEOBJECT_FLAGS) << ","
<< GetUInt32Value(GAMEOBJECT_FACTION) << ","
<< GetFloatValue(OBJECT_FIELD_SCALE_X) << ","
<< "0)";
WorldDatabase.Execute(ss.str().c_str());
/* std::stringstream ss;
if (!m_sqlid)
m_sqlid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
ss << "DELETE FROM gameobjects WHERE id=" << m_sqlid;
sDatabase.Execute(ss.str().c_str());
ss.rdbuf()->str("");
ss << "INSERT INTO gameobjects VALUES ( "
<< m_sqlid << ", "
<< m_position.x << ", "
<< m_position.y << ", "
<< m_position.z << ", "
<< m_position.o << ", "
<< GetZoneId() << ", "
<< GetMapId() << ", '";
for( uint32 index = 0; index < m_valuesCount; index ++ )
ss << GetUInt32Value(index) << " ";
ss << "', ";
ss << GetEntry() << ", 0, 0)";
sDatabase.Execute( ss.str( ).c_str( ) );*/
}
void GameObject::SaveToFile(std::stringstream & name)
{
std::stringstream ss;
ss << "REPLACE INTO gameobject_spawns VALUES("
<< ((m_spawn == NULL) ? 0 : m_spawn->id) << ","
<< GetEntry() << ","
<< GetMapId() << ","
<< GetPositionX() << ","
<< GetPositionY() << ","
<< GetPositionZ() << ","
<< GetOrientation() << ","
<< GetUInt64Value(GAMEOBJECT_ROTATION) << ","
<< GetFloatValue(GAMEOBJECT_PARENTROTATION) << ","
<< GetFloatValue(GAMEOBJECT_PARENTROTATION_02) << ","
<< GetFloatValue(GAMEOBJECT_PARENTROTATION_03) << ","
<< (unsigned short)GetByte(GAMEOBJECT_BYTES_1, 0) << ","
<< GetUInt32Value(GAMEOBJECT_FLAGS) << ","
<< GetUInt32Value(GAMEOBJECT_FACTION) << ","
<< GetFloatValue(OBJECT_FIELD_SCALE_X) << ","
<< "0)";
FILE * OutFile;
OutFile = fopen(name.str().c_str(), "wb");
if (!OutFile) return;
fwrite(ss.str().c_str(),1,ss.str().size(),OutFile);
fclose(OutFile);
}
void GameObject::InitAI()
{
if(!pInfo)
return;
// this fixes those fuckers in booty bay
if(pInfo->SpellFocus == 0 &&
pInfo->sound1 == 0 &&
pInfo->sound2 == 0 &&
pInfo->sound3 != 0 &&
pInfo->sound5 != 3 &&
pInfo->sound9 == 1)
return;
if(pInfo->DisplayID == 1027)//Shaman Shrine
{
if(pInfo->ID != 177964 && pInfo->ID != 153556)
{
//Deactivate
//SetUInt32Value(GAMEOBJECT_DYNAMIC, 0);
}
}
uint32 spellid = 0;
if(pInfo->Type==GAMEOBJECT_TYPE_TRAP)
{
spellid = pInfo->sound3;
}
else if(pInfo->Type == GAMEOBJECT_TYPE_SPELL_FOCUS)
{
// get spellid from attached gameobject - by sound2 field
if( pInfo->sound2 == 0 )
return;
if( GameObjectNameStorage.LookupEntry( pInfo->sound2 ) == NULL )
return;
spellid = GameObjectNameStorage.LookupEntry( pInfo->sound2 )->sound3;
}
else if(pInfo->Type == GAMEOBJECT_TYPE_RITUAL)
{
m_ritualmembers = new uint32[pInfo->SpellFocus];
memset(m_ritualmembers,0,sizeof(uint32)*pInfo->SpellFocus);
}
else if(pInfo->Type == GAMEOBJECT_TYPE_CHEST)
{
Lock *pLock = dbcLock.LookupEntry(GetInfo()->SpellFocus);
if(pLock)
{
for(uint32 i=0; i < 5; i++)
{
if(pLock->locktype[i])
{
if(pLock->locktype[i] == 2) //locktype;
{
//herbalism and mining;
if(pLock->lockmisc[i] == LOCKTYPE_MINING || pLock->lockmisc[i] == LOCKTYPE_HERBALISM)
{
CalcMineRemaining(true);
}
}
}
}
}
}
else if ( pInfo->Type == GAMEOBJECT_TYPE_FISHINGHOLE )
{
CalcFishRemaining( true );
}
myScript = sScriptMgr.CreateAIScriptClassForGameObject(GetEntry(), this);
// hackfix for bad spell in BWL
if(!spellid || spellid == 22247)
return;
SpellEntry *sp= dbcSpell.LookupEntry(spellid);
if(!sp)
{
spell = NULL;
return;
}
else
{
spell = sp;
}
//ok got valid spell that will be casted on target when it comes close enough
//get the range for that
float r = 0;
for(uint32 i=0;i<3;i++)
{
if(sp->Effect[i])
{
float t = GetRadius(dbcSpellRadius.LookupEntry(sp->EffectRadiusIndex[i]));
if(t > r)
r = t;
}
}
if(r < 0.1)//no range
r = GetMaxRange(dbcSpellRange.LookupEntry(sp->rangeIndex));
range = r*r;//square to make code faster
checkrate = 20;//once in 2 seconds
}
bool GameObject::Load(GOSpawn *spawn)
{
if(!CreateFromProto(spawn->entry,0,spawn->x,spawn->y,spawn->z,spawn->facing))
return false;
m_spawn = spawn;
SetRotation(spawn->o);
SetUInt32Value(GAMEOBJECT_FLAGS,spawn->flags);
// SetUInt32Value(GAMEOBJECT_LEVEL,spawn->level);
SetByte(GAMEOBJECT_BYTES_1, 0,spawn->state);
if(spawn->faction)
{
SetUInt32Value(GAMEOBJECT_FACTION,spawn->faction);
m_faction = dbcFactionTemplate.LookupEntry(spawn->faction);
if(m_faction)
m_factionDBC = dbcFaction.LookupEntry(m_faction->Faction);
}
SetFloatValue(OBJECT_FIELD_SCALE_X,spawn->scale);
_LoadQuests();
CALL_GO_SCRIPT_EVENT(this, OnCreate)();
CALL_GO_SCRIPT_EVENT(this, OnSpawn)();
InitAI();
_LoadQuests();
return true;
}
void GameObject::DeleteFromDB()
{
if( m_spawn != NULL )
WorldDatabase.Execute("DELETE FROM gameobject_spawns WHERE id=%u", m_spawn->id);
}
void GameObject::EventCloseDoor()
{
// gameobject_flags +1 closedoor animate restore the pointer flag.
// by cebernic
SetByte(GAMEOBJECT_BYTES_1, 0, 1);
SetUInt32Value(GAMEOBJECT_FLAGS, GetUInt32Value( GAMEOBJECT_FLAGS ) & ~1);
}
void GameObject::UseFishingNode(Player *player)
{
sEventMgr.RemoveEvents( this );
if( GetUInt32Value( GAMEOBJECT_FLAGS ) != 32 ) // Clicking on the bobber before something is hooked
{
player->GetSession()->OutPacket( SMSG_FISH_NOT_HOOKED );
EndFishing( player, true );
return;
}
/* Unused code: sAreaStore.LookupEntry(GetMapMgr()->GetAreaID(GetPositionX(),GetPositionY()))->ZoneId*/
uint32 zone = player->GetAreaID();
if( zone == 0 ) // If the player's area ID is 0, use the zone ID instead
zone = player->GetZoneId();
FishingZoneEntry *entry = FishingZoneStorage.LookupEntry( zone );
if( entry == NULL ) // No fishing information found for area or zone, log an error, and end fishing
{
sLog.outError( "ERREUR : Information de la zone de pche pour la zone %d introuvable!", zone );
EndFishing( player, true );
return;
}
uint32 maxskill = entry->MaxSkill;
uint32 minskill = entry->MinSkill;
if( player->_GetSkillLineCurrent( SKILL_FISHING, false ) < maxskill )
player->_AdvanceSkillLine( SKILL_FISHING, float2int32( 1.0f * sWorld.getRate( RATE_SKILLRATE ) ) );
GameObject * school = NULL;
this->AquireInrangeLock(); //make sure to release lock before exit function !
for ( InRangeSet::iterator it = GetInRangeSetBegin(); it != GetInRangeSetEnd(); ++it )
{
if ( (*it) == NULL || (*it)->GetTypeId() != TYPEID_GAMEOBJECT || (*it)->GetByte(GAMEOBJECT_BYTES_1, 1) != GAMEOBJECT_TYPE_FISHINGHOLE)
continue;
school = static_cast( *it );
if ( !isInRange( school, (float)school->GetInfo()->sound1 ) )
{
school = NULL;
continue;
}
else
break;
}
this->ReleaseInrangeLock();
if ( school != NULL ) // open school loot if school exists
{
lootmgr.FillGOLoot( &school->loot, school->GetEntry(), school->GetMapMgr() ? ( school->GetMapMgr()->iInstanceMode ? true : false ) : false );
player->SendLoot( school->GetGUID(), LOOT_FISHING );
EndFishing( player, false );
school->CatchFish();
if ( !school->CanFish() )
sEventMgr.AddEvent( school, &GameObject::Despawn, ( 1800000 + RandomUInt( 3600000 ) ), EVENT_GAMEOBJECT_EXPIRE, 10000, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT ); // respawn in 30 - 90 minutes
}
else if( Rand( ( ( player->_GetSkillLineCurrent( SKILL_FISHING, true ) - minskill ) * 100 ) / maxskill ) ) // Open loot on success, otherwise FISH_ESCAPED.
{
lootmgr.FillFishingLoot( &loot, zone );
player->SendLoot( GetGUID(), LOOT_FISHING );
EndFishing( player, false );
}
else // Failed
{
player->GetSession()->OutPacket( SMSG_FISH_ESCAPED );
EndFishing( player, true );
}
}
void GameObject::EndFishing(Player* player, bool abort )
{
Spell * spell = player->GetCurrentSpell();
if(spell)
{
if(abort) // abort becouse of a reason
{
//FIXME: here 'failed' should appear over progress bar
spell->SendChannelUpdate(0);
//spell->cancel();
spell->finish();
}
else // spell ended
{
spell->SendChannelUpdate(0);
spell->finish();
}
}
if(!abort)
sEventMgr.AddEvent(this, &GameObject::ExpireAndDelete, EVENT_GAMEOBJECT_EXPIRE, 10000, 1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
else
ExpireAndDelete();
}
void GameObject::FishHooked(Player * player)
{
WorldPacket data(12);
data.Initialize(SMSG_GAMEOBJECT_CUSTOM_ANIM);
data << GetGUID();
data << (uint32)(0); // value < 4
player->GetSession()->SendPacket(&data);
//SetByte(GAMEOBJECT_BYTES_1, 0, 0);
//BuildFieldUpdatePacket(player, GAMEOBJECT_FLAGS, 32);
SetUInt32Value(GAMEOBJECT_FLAGS, 32);
}
/////////////
/// Quests
void GameObject::AddQuest(QuestRelation *Q)
{
m_quests->push_back(Q);
}
void GameObject::DeleteQuest(QuestRelation *Q)
{
list::iterator it;
for( it = m_quests->begin(); it != m_quests->end(); ++it )
{
if( ( (*it)->type == Q->type ) && ( (*it)->qst == Q->qst ) )
{
delete (*it);
m_quests->erase(it);
break;
}
}
}
Quest* GameObject::FindQuest(uint32 quest_id, uint8 quest_relation)
{
list< QuestRelation* >::iterator it;
for( it = m_quests->begin(); it != m_quests->end(); ++it )
{
QuestRelation* ptr = (*it);
if( ( ptr->qst->id == quest_id ) && ( ptr->type & quest_relation ) )
{
return ptr->qst;
}
}
return NULL;
}
uint16 GameObject::GetQuestRelation(uint32 quest_id)
{
uint16 quest_relation = 0;
list< QuestRelation* >::iterator it;
for( it = m_quests->begin(); it != m_quests->end(); ++it )
{
if( (*it) != NULL && (*it)->qst->id == quest_id )
{
quest_relation |= (*it)->type;
}
}
return quest_relation;
}
uint32 GameObject::NumOfQuests()
{
return (uint32)m_quests->size();
}
void GameObject::_LoadQuests()
{
sQuestMgr.LoadGOQuests(this);
}
/////////////////
// Summoned Go's
void GameObject::_Expire()
{
sEventMgr.RemoveEvents(this);
if(IsInWorld())
RemoveFromWorld(true);
//sEventMgr.AddEvent(World::getSingletonPtr(), &World::DeleteObject, ((Object*)this), EVENT_DELETE_TIMER, 1000, 1);
delete this;
}
void GameObject::ExpireAndDelete()
{
if(m_deleted)
return;
m_deleted = true;
/* remove any events */
sEventMgr.RemoveEvents(this);
sEventMgr.AddEvent(this, &GameObject::_Expire, EVENT_GAMEOBJECT_EXPIRE, 1, 1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
}
void GameObject::Deactivate()
{
SetUInt32Value(GAMEOBJECT_DYNAMIC, 0);
}
void GameObject::CallScriptUpdate()
{
ASSERT(myScript);
myScript->AIUpdate();
}
void GameObject::OnPushToWorld()
{
Object::OnPushToWorld();
}
void GameObject::OnRemoveInRangeObject(Object* pObj)
{
Object::OnRemoveInRangeObject(pObj);
if(m_summonedGo && m_summoner == pObj)
{
for(int i = 0; i < 4; i++)
if (m_summoner->m_ObjectSlots[i] == GetLowGUID())
m_summoner->m_ObjectSlots[i] = 0;
m_summoner = 0;
ExpireAndDelete();
}
}
void GameObject::RemoveFromWorld(bool free_guid)
{
WorldPacket data(SMSG_GAMEOBJECT_DESPAWN_ANIM, 8);
data << GetGUID();
SendMessageToSet(&data,true);
sEventMgr.RemoveEvents(this, EVENT_GAMEOBJECT_TRAP_SEARCH_TARGET);
Object::RemoveFromWorld(free_guid);
}
bool GameObject::HasLoot()
{
int count=0;
for(vector<__LootItem>::iterator itr = loot.items.begin(); itr != loot.items.end(); ++itr)
{
if( itr->item.itemproto->Bonding == ITEM_BIND_QUEST || itr->item.itemproto->Bonding == ITEM_BIND_QUEST2 )
continue;
count += (itr)->iItemsCount;
}
return (count>0);
}
uint32 GameObject::GetGOReqSkill()
{
if(GetEntry() == 180215) return 300;
if(GetInfo() == NULL)
return 0;
Lock *lock = dbcLock.LookupEntry( GetInfo()->SpellFocus );
if(!lock) return 0;
for(uint32 i=0;i<5;i++)
if(lock->locktype[i] == 2 && lock->minlockskill[i])
{
return lock->minlockskill[i];
}
return 0;
}
void GameObject::SetRotation(float rad)
{
if (rad > (float)M_PI)
rad -= 2*(float)M_PI;
else if (rad < -(float)M_PI)
rad += 2*(float)M_PI;
float sin = sinf(rad/2.f);
if(sin >= 0)
rad = 1.f + 0.125f * sin;
else
rad = 1.25f + 0.125f * sin;
SetFloatValue(GAMEOBJECT_ROTATION, rad);