/*
* 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 .
*
*/
#include "StdAfx.h"
DynamicObject::DynamicObject(uint32 high, uint32 low)
{
m_objectTypeId = TYPEID_DYNAMICOBJECT;
m_valuesCount = DYNAMICOBJECT_END;
m_uint32Values = _fields;
memset(m_uint32Values, 0,(DYNAMICOBJECT_END)*sizeof(uint32));
m_updateMask.SetCount(DYNAMICOBJECT_END);
m_uint32Values[OBJECT_FIELD_TYPE] = TYPE_DYNAMICOBJECT|TYPE_OBJECT;
m_uint32Values[OBJECT_FIELD_GUID] = low;
m_uint32Values[OBJECT_FIELD_GUID+1] = high;
m_wowGuid.Init(GetGUID());
m_floatValues[OBJECT_FIELD_SCALE_X] = 1;
m_parentSpell=NULL;
m_aliveDuration = 0;
u_caster = 0;
m_spellProto = 0;
p_caster = 0;
}
DynamicObject::~DynamicObject()
{
// remove aura from all targets
DynamicObjectList::iterator jtr = targets.begin();
DynamicObjectList::iterator jend = targets.end();
Unit * target;
while(jtr != jend)
{
target = *jtr;
++jtr;
target->RemoveAura(m_spellProto->Id);
}
if(u_caster->dynObj == this)
u_caster->dynObj = 0;
}
void DynamicObject::Create(Unit * caster, Spell * pSpell, float x, float y, float z, uint32 duration, float radius)
{
Object::_Create(caster->GetMapId(),x, y, z, 0);
if(pSpell->g_caster)
{
m_parentSpell = pSpell;
}
p_caster = pSpell->p_caster;
m_spellProto = pSpell->m_spellInfo;
SetUInt64Value(DYNAMICOBJECT_CASTER, caster->GetGUID());
m_uint32Values[OBJECT_FIELD_ENTRY] = m_spellProto->Id;
m_uint32Values[DYNAMICOBJECT_BYTES] = 0x01eeeeee;
m_uint32Values[DYNAMICOBJECT_SPELLID] = m_spellProto->Id;
m_floatValues[DYNAMICOBJECT_RADIUS] = radius;
m_floatValues[DYNAMICOBJECT_POS_X] = x;
m_floatValues[DYNAMICOBJECT_POS_Y] = y;
m_floatValues[DYNAMICOBJECT_POS_Z] = z;
m_aliveDuration = duration;
u_caster = caster;
m_faction = caster->m_faction;
m_factionDBC = caster->m_factionDBC;
if(caster->dynObj != 0)
{
// expire next update
caster->dynObj->m_aliveDuration = 1;
caster->dynObj->UpdateTargets();
}
caster->dynObj = this;
if(pSpell->g_caster)
{
PushToWorld(pSpell->g_caster->GetMapMgr());
}else
PushToWorld(caster->GetMapMgr());
sEventMgr.AddEvent(this, &DynamicObject::UpdateTargets, EVENT_DYNAMICOBJECT_UPDATE, 100, 0,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
}
void DynamicObject::AddInRangeObject(Object* pObj)
{
if(pObj->IsUnit())
{
bool attackable;
if(p_caster)
attackable = isAttackable(p_caster, pObj);
else
attackable = isAttackable(this, pObj);
if(attackable)
m_inRangeOppFactions.insert(((Unit*)pObj));
}
Object::AddInRangeObject(pObj);
}
void DynamicObject::OnRemoveInRangeObject(Object* pObj)
{
if(pObj->IsUnit())
{
m_inRangeOppFactions.erase(((Unit*)pObj));
targets.erase(((Unit*)pObj));
}
Object::OnRemoveInRangeObject(pObj);
}
void DynamicObject::UpdateTargets()
{
if(m_aliveDuration == 0)
return;
if(m_aliveDuration >= 100)
{
FactionRangeList::iterator itr = m_inRangeOppFactions.begin();
FactionRangeList::iterator iend = m_inRangeOppFactions.end();
Unit * target;
Aura * pAura;
float radius = powf(m_floatValues[DYNAMICOBJECT_RADIUS], 2);
while(itr != iend)
{
target = *itr;
++itr;
// skip units already hit, their range will be tested later
if(targets.find(target) != targets.end())
continue;
if(GetDistanceSq(target) <= radius)
{
pAura = new Aura(m_spellProto, m_aliveDuration, u_caster, target);
for(uint32 i = 0; i < 3; ++i)
{
if(m_spellProto->Effect[i] == 27)
{
pAura->AddMod(m_spellProto->EffectApplyAuraName[i],
m_spellProto->EffectBasePoints[i]+1, m_spellProto->EffectMiscValue[i], i);
}
}
target->AddAura(pAura);
if(p_caster)
{
p_caster->HandleProc(PROC_ON_CAST_SPECIFIC_SPELL | PROC_ON_CAST_SPELL,target, m_spellProto);
p_caster->m_procCounter = 0;
}
// add to target list
targets.insert(target);
}
}
// loop the targets, check the range of all of them
DynamicObjectList::iterator jtr = targets.begin();
DynamicObjectList::iterator jtr2;
DynamicObjectList::iterator jend = targets.end();
while(jtr != jend)
{
target = *jtr;
jtr2 = jtr;
++jtr;
if(GetDistanceSq(target) > radius)
{
targets.erase(jtr2);
target->RemoveAura(m_spellProto->Id);
}
}
m_aliveDuration -= 100;
}
else
{
m_aliveDuration = 0;
}
if(m_aliveDuration == 0)
{
DynamicObjectList::iterator jtr = targets.begin();
DynamicObjectList::iterator jend = targets.end();
Unit * target;
while(jtr != jend)
{
target = *jtr;
++jtr;
target->RemoveAura(m_spellProto->Id);
}
Remove();
}
}
void DynamicObject::Remove()
{
if(IsInWorld())
RemoveFromWorld();
delete this;
}