Backed out changeset 8fba4a7e4268

--HG--
branch : trunk
This commit is contained in:
KingPin
2008-11-17 22:07:07 -06:00
parent 18dff69c55
commit ba0ef6ffc5
4 changed files with 8390 additions and 8448 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,496 +1,488 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* Copyright (C) 2008 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
* the Free Software Foundation; either version 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "Database/DBCStores.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "World.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Log.h"
#include "Opcodes.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "BattleGround.h"
#include "MapManager.h"
#include "ScriptCalls.h"
#include "Totem.h"
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
{
// TODO: add targets.read() check
CHECK_PACKET_SIZE(recvPacket,1+1+1+1+8);
Player* pUser = _player;
uint8 bagIndex, slot;
uint8 spell_count; // number of spells at item, not used
uint8 cast_count; // next cast if exists (single or not)
uint64 item_guid;
recvPacket >> bagIndex >> slot >> spell_count >> cast_count >> item_guid;
Item *pItem = pUser->GetItemByPos(bagIndex, slot);
if(!pItem)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
return;
}
sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, spell_count: %u , cast_count: %u, Item: %u, data length = %i", bagIndex, slot, spell_count, cast_count, pItem->GetEntry(), recvPacket.size());
ItemPrototype const *proto = pItem->GetProto();
if(!proto)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL );
return;
}
// some item classes can be used only in equipped state
if(proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped())
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL );
return;
}
uint8 msg = pUser->CanUseItem(pItem);
if( msg != EQUIP_ERR_OK )
{
pUser->SendEquipError( msg, pItem, NULL );
return;
}
// only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
if( proto->Class == ITEM_CLASS_CONSUMABLE &&
!(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) &&
pUser->InArena())
{
pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL);
return;
}
if (pUser->isInCombat())
{
for(int i = 0; i < 5; ++i)
{
if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId))
{
if (IsNonCombatSpell(spellInfo))
{
pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL);
return;
}
}
}
}
// check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
if( pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM )
{
if (!pItem->IsSoulBound())
{
pItem->SetState(ITEM_CHANGED, pUser);
pItem->SetBinding( true );
}
}
SpellCastTargets targets;
if(!targets.read(&recvPacket, pUser))
return;
//Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
if(!Script->ItemUse(pUser,pItem,targets))
{
// no script or script not process request by self
// special learning case
if(pItem->GetProto()->Spells[0].SpellId==SPELL_ID_GENERIC_LEARN)
{
uint32 learning_spell_id = pItem->GetProto()->Spells[1].SpellId;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(SPELL_ID_GENERIC_LEARN);
if(!spellInfo)
{
sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, SPELL_ID_GENERIC_LEARN);
pUser->SendEquipError(EQUIP_ERR_NONE,pItem,NULL);
return;
}
Spell *spell = new Spell(pUser, spellInfo, false);
spell->m_CastItem = pItem;
spell->m_cast_count = cast_count; //set count of casts
spell->m_currentBasePoints[0] = learning_spell_id;
spell->prepare(&targets);
return;
}
// use triggered flag only for items with many spell casts and for not first cast
int count = 0;
for(int i = 0; i < 5; ++i)
{
_Spell const& spellData = pItem->GetProto()->Spells[i];
// no spell
if(!spellData.SpellId)
continue;
// wrong triggering type
if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_NO_DELAY_USE)
continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId);
if(!spellInfo)
{
sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, spellData.SpellId);
continue;
}
Spell *spell = new Spell(pUser, spellInfo, (count > 0));
spell->m_CastItem = pItem;
spell->m_cast_count = cast_count; //set count of casts
spell->prepare(&targets);
++count;
}
}
}
#define OPEN_CHEST 11437
#define OPEN_SAFE 11535
#define OPEN_CAGE 11792
#define OPEN_BOOTY_CHEST 5107
#define OPEN_STRONGBOX 8517
void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,1+1);
sLog.outDetail("WORLD: CMSG_OPEN_ITEM packet, data length = %i",recvPacket.size());
Player* pUser = _player;
uint8 bagIndex, slot;
recvPacket >> bagIndex >> slot;
sLog.outDetail("bagIndex: %u, slot: %u",bagIndex,slot);
Item *pItem = pUser->GetItemByPos(bagIndex, slot);
if(!pItem)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
return;
}
ItemPrototype const *proto = pItem->GetProto();
if(!proto)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL );
return;
}
// locked item
uint32 lockId = proto->LockID;
if(lockId)
{
LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
if (!lockInfo)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL );
sLog.outError( "WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", pItem->GetGUIDLow() , lockId);
return;
}
// required picklocking
if(lockInfo->requiredlockskill || lockInfo->requiredminingskill)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL );
return;
}
}
if(pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))// wrapped?
{
QueryResult *result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow());
if (result)
{
Field *fields = result->Fetch();
uint32 entry = fields[0].GetUInt32();
uint32 flags = fields[1].GetUInt32();
pItem->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, 0);
pItem->SetUInt32Value(OBJECT_FIELD_ENTRY, entry);
pItem->SetUInt32Value(ITEM_FIELD_FLAGS, flags);
pItem->SetState(ITEM_CHANGED, pUser);
delete result;
}
else
{
sLog.outError("Wrapped item %u don't have record in character_gifts table and will deleted", pItem->GetGUIDLow());
pUser->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
return;
}
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow());
}
else
pUser->SendLoot(pItem->GetGUID(),LOOT_CORPSE);
}
void WorldSession::HandleGameObjectUseOpcode( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data,8);
uint64 guid;
uint32 spellId = OPEN_CHEST;
recv_data >> guid;
sLog.outDebug( "WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid));
GameObject *obj = ObjectAccessor::GetGameObject(*_player, guid);
if(!obj)
return;
if (Script->GOHello(_player, obj))
return;
obj->Use(_player);
}
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,4+1+2);
uint32 spellId;
uint8 cast_count;
recvPacket >> spellId;
recvPacket >> cast_count;
sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u data length = %i",
spellId, cast_count, recvPacket.size());
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
if(!spellInfo)
{
sLog.outError("WORLD: unknown spell id %u", spellId);
return;
}
// not have spell or spell passive and not casted by client
if ( !_player->HasSpell (spellId) || IsPassiveSpell(spellId) )
{
//cheater? kick? ban?
return;
}
// can't use our own spells when we're in possession of another unit,
if(_player->isPossessing())
return;
// client provided targets
SpellCastTargets targets;
if(!targets.read(&recvPacket,_player))
return;
// auto-selection buff level base at target level (in spellInfo)
if(targets.getUnitTarget())
{
SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(spellInfo,targets.getUnitTarget()->getLevel());
// if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message
if(actualSpellInfo)
spellInfo = actualSpellInfo;
}
Spell *spell = new Spell(_player, spellInfo, false);
spell->m_cast_count = cast_count; //set count of casts
spell->prepare(&targets);
}
void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,4);
uint32 spellId;
recvPacket >> spellId;
//FIXME: hack, ignore unexpected client cancel Deadly Throw cast
if(spellId==26679)
return;
if(_player->IsNonMeleeSpellCasted(false))
_player->InterruptNonMeleeSpells(false,spellId);
}
void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,4);
uint32 spellId;
recvPacket >> spellId;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
if (!spellInfo)
return;
// Remove possess/charm/sight aura from the possessed/charmed as well
// TODO: Remove this once the ability to cancel aura sets at once is implemented
if(_player->GetCharm() || _player->GetFarsightTarget())
{
for (int i = 0; i < 3; ++i)
{
if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS ||
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS_PET ||
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_CHARM ||
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_BIND_SIGHT)
{
_player->RemoveAurasDueToSpellByCancel(spellId);
if (_player->GetCharm())
_player->GetCharm()->RemoveAurasDueToSpellByCancel(spellId);
else if (_player->GetFarsightTarget()->GetTypeId() != TYPEID_DYNAMICOBJECT)
((Unit*)_player->GetFarsightTarget())->RemoveAurasDueToSpellByCancel(spellId);
return;
}
}
}
// not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL
if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL))
return;
// channeled spell case (it currently casted then)
if(IsChanneledSpell(spellInfo))
{
if(Spell* spell = _player->m_currentSpells[CURRENT_CHANNELED_SPELL])
{
if(spell->m_spellInfo->Id==spellId)
{
spell->cancel();
spell->SetReferencedFromCurrent(false);
_player->m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL;
}
}
return;
}
// non channeled case
_player->RemoveAurasDueToSpellByCancel(spellId);
}
void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket, 8+4);
uint64 guid;
uint32 spellId;
recvPacket >> guid;
recvPacket >> spellId;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
if(!spellInfo)
{
sLog.outError("WORLD: unknown PET spell id %u", spellId);
return;
}
Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid);
if(!pet)
{
sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid)) );
return;
}
if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
{
sLog.outError( "HandlePetCancelAura.Pet %u isn't pet of player %s", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
return;
}
if(!pet->isAlive())
{
pet->SendPetActionFeedback(FEEDBACK_PET_DEAD);
return;
}
pet->RemoveAurasDueToSpell(spellId);
pet->AddCreatureSpellCooldown(spellId);
}
void WorldSession::HandleCancelGrowthAuraOpcode( WorldPacket& /*recvPacket*/)
{
// nothing do
}
void WorldSession::HandleCancelAutoRepeatSpellOpcode( WorldPacket& /*recvPacket*/)
{
// may be better send SMSG_CANCEL_AUTO_REPEAT?
// cancel and prepare for deleting
_player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
}
/// \todo Complete HandleCancelChanneling function
void WorldSession::HandleCancelChanneling( WorldPacket & /*recv_data */)
{
/*
CHECK_PACKET_SIZE(recv_data, 4);
uint32 spellid;
recv_data >> spellid;
*/
}
void WorldSession::HandleTotemDestroy( WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket, 1);
uint8 slotId;
recvPacket >> slotId;
if (slotId >= MAX_TOTEM)
return;
if(!_player->m_TotemSlot[slotId])
return;
Creature* totem = ObjectAccessor::GetCreature(*_player,_player->m_TotemSlot[slotId]);
// Don't unsummon sentry totem
if(totem && totem->isTotem() && totem->GetEntry() != SENTRY_TOTEM_ENTRY)
((Totem*)totem)->UnSummon();
}
void WorldSession::HandleSelfResOpcode( WorldPacket & /*recv_data*/ )
{
sLog.outDebug("WORLD: CMSG_SELF_RES"); // empty opcode
if(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL))
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL));
if(spellInfo)
_player->CastSpell(_player,spellInfo,false,0);
_player->SetUInt32Value(PLAYER_SELF_RES_SPELL, 0);
}
}
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* Copyright (C) 2008 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
* the Free Software Foundation; either version 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "Database/DBCStores.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "World.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Log.h"
#include "Opcodes.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "BattleGround.h"
#include "MapManager.h"
#include "ScriptCalls.h"
#include "Totem.h"
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
{
// TODO: add targets.read() check
CHECK_PACKET_SIZE(recvPacket,1+1+1+1+8);
Player* pUser = _player;
uint8 bagIndex, slot;
uint8 spell_count; // number of spells at item, not used
uint8 cast_count; // next cast if exists (single or not)
uint64 item_guid;
recvPacket >> bagIndex >> slot >> spell_count >> cast_count >> item_guid;
Item *pItem = pUser->GetItemByPos(bagIndex, slot);
if(!pItem)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
return;
}
sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, spell_count: %u , cast_count: %u, Item: %u, data length = %i", bagIndex, slot, spell_count, cast_count, pItem->GetEntry(), recvPacket.size());
ItemPrototype const *proto = pItem->GetProto();
if(!proto)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL );
return;
}
// some item classes can be used only in equipped state
if(proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped())
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL );
return;
}
uint8 msg = pUser->CanUseItem(pItem);
if( msg != EQUIP_ERR_OK )
{
pUser->SendEquipError( msg, pItem, NULL );
return;
}
// only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
if( proto->Class == ITEM_CLASS_CONSUMABLE &&
!(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) &&
pUser->InArena())
{
pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL);
return;
}
if (pUser->isInCombat())
{
for(int i = 0; i < 5; ++i)
{
if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId))
{
if (IsNonCombatSpell(spellInfo))
{
pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL);
return;
}
}
}
}
// check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
if( pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM )
{
if (!pItem->IsSoulBound())
{
pItem->SetState(ITEM_CHANGED, pUser);
pItem->SetBinding( true );
}
}
SpellCastTargets targets;
if(!targets.read(&recvPacket, pUser))
return;
//Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
if(!Script->ItemUse(pUser,pItem,targets))
{
// no script or script not process request by self
// special learning case
if(pItem->GetProto()->Spells[0].SpellId==SPELL_ID_GENERIC_LEARN)
{
uint32 learning_spell_id = pItem->GetProto()->Spells[1].SpellId;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(SPELL_ID_GENERIC_LEARN);
if(!spellInfo)
{
sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, SPELL_ID_GENERIC_LEARN);
pUser->SendEquipError(EQUIP_ERR_NONE,pItem,NULL);
return;
}
Spell *spell = new Spell(pUser, spellInfo, false);
spell->m_CastItem = pItem;
spell->m_cast_count = cast_count; //set count of casts
spell->m_currentBasePoints[0] = learning_spell_id;
spell->prepare(&targets);
return;
}
// use triggered flag only for items with many spell casts and for not first cast
int count = 0;
for(int i = 0; i < 5; ++i)
{
_Spell const& spellData = pItem->GetProto()->Spells[i];
// no spell
if(!spellData.SpellId)
continue;
// wrong triggering type
if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_NO_DELAY_USE)
continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId);
if(!spellInfo)
{
sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, spellData.SpellId);
continue;
}
Spell *spell = new Spell(pUser, spellInfo, (count > 0));
spell->m_CastItem = pItem;
spell->m_cast_count = cast_count; //set count of casts
spell->prepare(&targets);
++count;
}
}
}
#define OPEN_CHEST 11437
#define OPEN_SAFE 11535
#define OPEN_CAGE 11792
#define OPEN_BOOTY_CHEST 5107
#define OPEN_STRONGBOX 8517
void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,1+1);
sLog.outDetail("WORLD: CMSG_OPEN_ITEM packet, data length = %i",recvPacket.size());
Player* pUser = _player;
uint8 bagIndex, slot;
recvPacket >> bagIndex >> slot;
sLog.outDetail("bagIndex: %u, slot: %u",bagIndex,slot);
Item *pItem = pUser->GetItemByPos(bagIndex, slot);
if(!pItem)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
return;
}
ItemPrototype const *proto = pItem->GetProto();
if(!proto)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL );
return;
}
// locked item
uint32 lockId = proto->LockID;
if(lockId)
{
LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
if (!lockInfo)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL );
sLog.outError( "WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", pItem->GetGUIDLow() , lockId);
return;
}
// required picklocking
if(lockInfo->requiredlockskill || lockInfo->requiredminingskill)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL );
return;
}
}
if(pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))// wrapped?
{
QueryResult *result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow());
if (result)
{
Field *fields = result->Fetch();
uint32 entry = fields[0].GetUInt32();
uint32 flags = fields[1].GetUInt32();
pItem->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, 0);
pItem->SetUInt32Value(OBJECT_FIELD_ENTRY, entry);
pItem->SetUInt32Value(ITEM_FIELD_FLAGS, flags);
pItem->SetState(ITEM_CHANGED, pUser);
delete result;
}
else
{
sLog.outError("Wrapped item %u don't have record in character_gifts table and will deleted", pItem->GetGUIDLow());
pUser->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
return;
}
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow());
}
else
pUser->SendLoot(pItem->GetGUID(),LOOT_CORPSE);
}
void WorldSession::HandleGameObjectUseOpcode( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data,8);
uint64 guid;
uint32 spellId = OPEN_CHEST;
recv_data >> guid;
sLog.outDebug( "WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid));
GameObject *obj = ObjectAccessor::GetGameObject(*_player, guid);
if(!obj)
return;
if (Script->GOHello(_player, obj))
return;
obj->Use(_player);
}
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,4+1+2);
uint32 spellId;
uint8 cast_count;
recvPacket >> spellId;
recvPacket >> cast_count;
sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u data length = %i",
spellId, cast_count, recvPacket.size());
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
if(!spellInfo)
{
sLog.outError("WORLD: unknown spell id %u", spellId);
return;
}
// not have spell or spell passive and not casted by client
if ( !_player->HasSpell (spellId) || IsPassiveSpell(spellId) )
{
//cheater? kick? ban?
return;
}
// can't use our own spells when we're in possession of another unit,
if(_player->isPossessing())
return;
// client provided targets
SpellCastTargets targets;
if(!targets.read(&recvPacket,_player))
return;
// auto-selection buff level base at target level (in spellInfo)
if(targets.getUnitTarget())
{
SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(spellInfo,targets.getUnitTarget()->getLevel());
// if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message
if(actualSpellInfo)
spellInfo = actualSpellInfo;
}
Spell *spell = new Spell(_player, spellInfo, false);
spell->m_cast_count = cast_count; //set count of casts
spell->prepare(&targets);
}
void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,4);
uint32 spellId;
recvPacket >> spellId;
//FIXME: hack, ignore unexpected client cancel Deadly Throw cast
if(spellId==26679)
return;
if(_player->IsNonMeleeSpellCasted(false))
_player->InterruptNonMeleeSpells(false,spellId);
}
void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,4);
uint32 spellId;
recvPacket >> spellId;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
if (!spellInfo)
return;
// Remove possess/charm/sight aura from the possessed/charmed as well
// TODO: Remove this once the ability to cancel aura sets at once is implemented
if(_player->GetCharm() || _player->GetFarsightTarget())
{
for (int i = 0; i < 3; ++i)
{
if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS ||
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS_PET ||
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_CHARM ||
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_BIND_SIGHT)
{
_player->RemoveAurasDueToSpellByCancel(spellId);
if (_player->GetCharm())
_player->GetCharm()->RemoveAurasDueToSpellByCancel(spellId);
else if (_player->GetFarsightTarget()->GetTypeId() != TYPEID_DYNAMICOBJECT)
((Unit*)_player->GetFarsightTarget())->RemoveAurasDueToSpellByCancel(spellId);
return;
}
}
}
// not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL
if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL))
return;
_player->RemoveAurasDueToSpellByCancel(spellId);
if (spellId == 2584) // Waiting to resurrect spell cancel, we must remove player from resurrect queue
{
BattleGround *bg = _player->GetBattleGround();
if(!bg)
return;
bg->RemovePlayerFromResurrectQueue(_player->GetGUID());
}
}
void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket, 8+4);
uint64 guid;
uint32 spellId;
recvPacket >> guid;
recvPacket >> spellId;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
if(!spellInfo)
{
sLog.outError("WORLD: unknown PET spell id %u", spellId);
return;
}
Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid);
if(!pet)
{
sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid)) );
return;
}
if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
{
sLog.outError( "HandlePetCancelAura.Pet %u isn't pet of player %s", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
return;
}
if(!pet->isAlive())
{
pet->SendPetActionFeedback(FEEDBACK_PET_DEAD);
return;
}
pet->RemoveAurasDueToSpell(spellId);
pet->AddCreatureSpellCooldown(spellId);
}
void WorldSession::HandleCancelGrowthAuraOpcode( WorldPacket& /*recvPacket*/)
{
// nothing do
}
void WorldSession::HandleCancelAutoRepeatSpellOpcode( WorldPacket& /*recvPacket*/)
{
// may be better send SMSG_CANCEL_AUTO_REPEAT?
// cancel and prepare for deleting
_player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
}
/// \todo Complete HandleCancelChanneling function
void WorldSession::HandleCancelChanneling( WorldPacket & /*recv_data */)
{
/*
CHECK_PACKET_SIZE(recv_data, 4);
uint32 spellid;
recv_data >> spellid;
*/
}
void WorldSession::HandleTotemDestroy( WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket, 1);
uint8 slotId;
recvPacket >> slotId;
if (slotId >= MAX_TOTEM)
return;
if(!_player->m_TotemSlot[slotId])
return;
Creature* totem = ObjectAccessor::GetCreature(*_player,_player->m_TotemSlot[slotId]);
// Don't unsummon sentry totem
if(totem && totem->isTotem() && totem->GetEntry() != SENTRY_TOTEM_ENTRY)
((Totem*)totem)->UnSummon();
}
void WorldSession::HandleSelfResOpcode( WorldPacket & /*recv_data*/ )
{
sLog.outDebug("WORLD: CMSG_SELF_RES"); // empty opcode
if(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL))
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL));
if(spellInfo)
_player->CastSpell(_player,spellInfo,false,0);
_player->SetUInt32Value(PLAYER_SELF_RES_SPELL, 0);
}
}

View File

@@ -4094,17 +4094,12 @@ void Unit::RemoveNotOwnSingleTargetAuras()
void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
{
Aura* Aur = i->second;
SpellEntry const* AurSpellInfo = Aur->GetSpellProto();
Unit* caster = NULL;
if (IsSingleTargetSpell(AurSpellInfo))
if (IsSingleTargetSpell((*i).second->GetSpellProto()))
{
caster = Aur->GetCaster();
if(caster)
if(Unit* caster = (*i).second->GetCaster())
{
AuraList& scAuras = caster->GetSingleCastAuras();
scAuras.remove(Aur);
scAuras.remove((*i).second);
}
else
{
@@ -4113,19 +4108,20 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
}
}
// remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
if ((*i).second->GetModifier()->m_auraname < TOTAL_AURAS)
{
m_modAuras[Aur->GetModifier()->m_auraname].remove(Aur);
if(Aur->GetSpellProto()->AuraInterruptFlags)
m_modAuras[(*i).second->GetModifier()->m_auraname].remove((*i).second);
if((*i).second->GetSpellProto()->AuraInterruptFlags)
{
m_interruptableAuras.remove(Aur);
m_interruptableAuras.remove((*i).second);
UpdateInterruptMask();
}
if(Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE)
m_ccAuras.remove(Aur);
if((*i).second->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE)
m_ccAuras.remove((*i).second);
}
// remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
Aura* Aur = i->second;
// Set remove mode
Aur->SetRemoveMode(mode);
// some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
@@ -4133,22 +4129,12 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
m_Auras.erase(i);
++m_removedAuras; // internal count used by unit update
// Statue unsummoned at aura remove
// Status unsummoned at aura remove
Totem* statue = NULL;
bool caster_channeled = false;
if(IsChanneledSpell(AurSpellInfo))
{
if(!caster) // can be already located for IsSingleTargetSpell case
caster = Aur->GetCaster();
if(caster)
{
if(IsChanneledSpell(Aur->GetSpellProto()))
if(Unit* caster = Aur->GetCaster())
if(caster->GetTypeId()==TYPEID_UNIT && ((Creature*)caster)->isTotem() && ((Totem*)caster)->GetTotemType()==TOTEM_STATUE)
statue = ((Totem*)caster);
else
caster_channeled = caster==this;
}
}
if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(-(int32)Aur->GetSpellProto()->Id))
@@ -4167,9 +4153,6 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
Aur->_RemoveAura();
delete Aur;
if(caster_channeled)
RemoveAurasAtChanneledTarget (AurSpellInfo);
if(statue)
statue->UnSummon();
@@ -4595,10 +4578,8 @@ void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchool
ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType);
}
bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * /*procSpell*/, uint32 /*procFlag*/, uint32 cooldown)
bool Unit::HandleHasteAuraProc(Unit *pVictim, SpellEntry const *hasteSpell, uint32 /*effIndex*/, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 cooldown)
{
SpellEntry const *hasteSpell = triggeredByAura->GetSpellProto();
Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
@@ -4658,11 +4639,8 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return true;
}
bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 cooldown)
bool Unit::HandleDummyAuraProc(Unit *pVictim, SpellEntry const *dummySpell, uint32 effIndex, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 cooldown)
{
SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
uint32 effIndex = triggeredByAura->GetEffIndex ();
Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
@@ -6480,10 +6458,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return true;
}
bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown)
bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, int32 scriptId, uint32 damage, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown)
{
int32 scriptId = triggeredByAura->GetModifier()->m_miscvalue;
if(!pVictim || !pVictim->isAlive())
return false;
@@ -9947,15 +9923,17 @@ bool Unit::isFrozen() const
struct ProcTriggeredData
{
ProcTriggeredData(Aura* _triggeredByAura, uint32 _cooldown)
: triggeredByAura(_triggeredByAura),
ProcTriggeredData(SpellEntry const * _spellInfo, uint32 _spellParam, Aura* _triggeredByAura, uint32 _cooldown)
: spellInfo(_spellInfo), spellParam(_spellParam), triggeredByAura(_triggeredByAura),
triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex())),
cooldown(_cooldown)
{}
{}
Aura* triggeredByAura; // triggred aura, can be invalidate at triggered aura proccessing
Unit::spellEffectPair triggeredByAura_SpellPair; // spell pair, used for re-find aura (by pointer comparison in range)
uint32 cooldown; // possible hidden cooldown
SpellEntry const * spellInfo;
uint32 spellParam;
Aura* triggeredByAura;
Unit::spellEffectPair triggeredByAura_SpellPair;
uint32 cooldown;
};
typedef std::list< ProcTriggeredData > ProcTriggeredList;
@@ -9972,13 +9950,87 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
{
next = i; ++next;
Aura* i_aura = *i;
uint32 cooldown; // returned at next line
if(!IsTriggeredAtSpellProcEvent(i_aura->GetSpellProto(), procSpell, procFlag,attType,isVictim,cooldown))
SpellEntry const *spellProto = (*i)->GetSpellProto();
if(!spellProto)
continue;
procTriggered.push_back( ProcTriggeredData(i_aura, cooldown) );
SpellProcEventEntry const *spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);
if(!spellProcEvent)
{
// used to prevent spam in log about same non-handled spells
static std::set<uint32> nonHandledSpellProcSet;
if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
{
sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's"));
nonHandledSpellProcSet.insert(spellProto->Id);
}
// spell.dbc use totally different flags, that only can create problems if used.
continue;
}
// Check spellProcEvent data requirements
if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag))
continue;
// Check if current equipment allows aura to proc
if(!isVictim && GetTypeId() == TYPEID_PLAYER )
{
if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
{
Item *item = ((Player*)this)->GetWeaponForAttack(attType,true);
if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
continue;
}
else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
{
// Check if player is wearing shield
Item *item = ((Player*)this)->GetShield(true);
if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
continue;
}
}
float chance = (float)spellProto->procChance;
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
if(!isVictim && spellProcEvent->ppmRate != 0)
{
uint32 WeaponSpeed = GetAttackTime(attType);
chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
}
if(roll_chance_f(chance))
{
uint32 cooldown = spellProcEvent->cooldown;
uint32 i_spell_eff = (*i)->GetEffIndex();
int32 i_spell_param;
switch(*aur)
{
case SPELL_AURA_PROC_TRIGGER_SPELL:
i_spell_param = procFlag;
break;
case SPELL_AURA_DUMMY:
case SPELL_AURA_PRAYER_OF_MENDING:
case SPELL_AURA_MOD_HASTE:
i_spell_param = i_spell_eff;
break;
case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
i_spell_param = (*i)->GetModifier()->m_miscvalue;
break;
default:
i_spell_param = (*i)->GetModifier()->m_amount;
break;
}
procTriggered.push_back( ProcTriggeredData(spellProto,i_spell_param,*i, cooldown) );
}
}
// Handle effects proceed this time
@@ -10011,66 +10063,106 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
}
}
// this is aura triggering code call
Aura* triggeredByAura = i->triggeredByAura;
// save charges existence before processing to prevent crash at access to deleted triggered aura after
bool triggeredByAuraWithCharges = triggeredByAura->m_procCharges > 0;
bool triggeredByAuraWithCharges = i->triggeredByAura->m_procCharges > 0;
bool casted = false;
switch(*aur)
{
case SPELL_AURA_PROC_TRIGGER_SPELL:
{
sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
casted = HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, attType, i->cooldown);
sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
casted = HandleProcTriggerSpell(pTarget, damage, i->triggeredByAura, procSpell,i->spellParam,attType,i->cooldown);
break;
}
case SPELL_AURA_PROC_TRIGGER_DAMAGE:
{
uint32 triggered_damage = triggeredByAura->GetModifier()->m_amount;
sLog.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
triggered_damage, (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
SpellNonMeleeDamageLog(pTarget, triggeredByAura->GetId(), triggered_damage, true, true);
sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i->spellParam, i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
uint32 damage = i->spellParam;
SpellNonMeleeDamageLog(pTarget, i->spellInfo->Id, damage, true, true);
casted = true;
break;
}
case SPELL_AURA_DUMMY:
{
uint32 effect = triggeredByAura->GetEffIndex();
sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
(isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
casted = HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag,i->cooldown);
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
casted = HandleDummyAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag,i->cooldown);
break;
}
case SPELL_AURA_PRAYER_OF_MENDING:
{
sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
(isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
sLog.outDebug("ProcDamageAndSpell(mending): casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
casted = HandleMeandingAuraProc(triggeredByAura);
// aura can be deleted at casts
int32 heal = i->triggeredByAura->GetModifier()->m_amount;
uint64 caster_guid = i->triggeredByAura->GetCasterGUID();
// jumps
int32 jumps = i->triggeredByAura->m_procCharges-1;
// current aura expire
i->triggeredByAura->m_procCharges = 1; // will removed at next charges decrease
// next target selection
if(jumps > 0 && GetTypeId()==TYPEID_PLAYER && IS_PLAYER_GUID(caster_guid))
{
Aura* aura = i->triggeredByAura;
SpellEntry const* spellProto = aura->GetSpellProto();
uint32 effIdx = aura->GetEffIndex();
float radius;
if (spellProto->EffectRadiusIndex[effIdx])
radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx]));
else
radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellProto->rangeIndex));
if(Player* caster = ((Player*)aura->GetCaster()))
{
caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL);
if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius))
{
// aura will applied from caster, but spell casted from current aura holder
SpellModifier *mod = new SpellModifier;
mod->op = SPELLMOD_CHARGES;
mod->value = jumps-5; // negative
mod->type = SPELLMOD_FLAT;
mod->spellId = spellProto->Id;
mod->effectId = effIdx;
mod->lastAffected = NULL;
mod->mask = spellProto->SpellFamilyFlags;
mod->charges = 0;
caster->AddSpellMod(mod, true);
CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,aura,caster->GetGUID());
caster->AddSpellMod(mod, false);
}
}
}
// heal
CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid);
casted = true;
break;
}
case SPELL_AURA_MOD_HASTE:
{
sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
(isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
casted = HandleHasteAuraProc(pTarget, damage, i->triggeredByAura, procSpell, procFlag,i->cooldown);
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
casted = HandleHasteAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag,i->cooldown);
break;
}
case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
{
// nothing do, just charges counter
// but count only in case appropriate school damage
casted = triggeredByAura->GetModifier()->m_miscvalue & damageSchoolMask;
casted = i->triggeredByAura->GetModifier()->m_miscvalue & damageSchoolMask;
break;
}
case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
{
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s class script aura of spell %u)",
(isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
casted = HandleOverrideClassScriptAuraProc(pTarget, i->triggeredByAura, procSpell,i->cooldown);
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
casted = HandleOverrideClassScriptAuraProc(pTarget, i->spellParam, damage, i->triggeredByAura, procSpell,i->cooldown);
break;
}
default:
@@ -10718,132 +10810,3 @@ Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id)
return pet;
}
bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry const* spellProto, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, bool isVictim, uint32& cooldown )
{
SpellProcEventEntry const * spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);
if(!spellProcEvent)
{
// used to prevent spam in log about same non-handled spells
static std::set<uint32> nonHandledSpellProcSet;
if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
{
sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's"));
nonHandledSpellProcSet.insert(spellProto->Id);
}
// spell.dbc use totally different flags, that only can create problems if used.
return false;
}
// Check spellProcEvent data requirements
if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag))
return false;
// Check if current equipment allows aura to proc
if(!isVictim && GetTypeId() == TYPEID_PLAYER )
{
if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
{
Item *item = ((Player*)this)->GetWeaponForAttack(attType,true);
if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
return false;
}
else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
{
// Check if player is wearing shield
Item *item = ((Player*)this)->GetShield(true);
if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
return false;
}
}
float chance = (float)spellProto->procChance;
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
{
uint32 WeaponSpeed = GetAttackTime(attType);
chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
}
cooldown = spellProcEvent ? spellProcEvent->cooldown : 0;
return roll_chance_f(chance);
}
bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura )
{
// aura can be deleted at casts
SpellEntry const* spellProto = triggeredByAura->GetSpellProto();
uint32 effIdx = triggeredByAura->GetEffIndex();
int32 heal = triggeredByAura->GetModifier()->m_amount;
uint64 caster_guid = triggeredByAura->GetCasterGUID();
// jumps
int32 jumps = triggeredByAura->m_procCharges-1;
// current aura expire
triggeredByAura->m_procCharges = 1; // will removed at next charges decrease
// next target selection
if(jumps > 0 && GetTypeId()==TYPEID_PLAYER && IS_PLAYER_GUID(caster_guid))
{
float radius;
if (spellProto->EffectRadiusIndex[effIdx])
radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx]));
else
radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellProto->rangeIndex));
if(Player* caster = ((Player*)triggeredByAura->GetCaster()))
{
caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL);
if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius))
{
// aura will applied from caster, but spell casted from current aura holder
SpellModifier *mod = new SpellModifier;
mod->op = SPELLMOD_CHARGES;
mod->value = jumps-5; // negative
mod->type = SPELLMOD_FLAT;
mod->spellId = spellProto->Id;
mod->effectId = effIdx;
mod->lastAffected = NULL;
mod->mask = spellProto->SpellFamilyFlags;
mod->charges = 0;
caster->AddSpellMod(mod, true);
CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,triggeredByAura,caster->GetGUID());
caster->AddSpellMod(mod, false);
}
}
}
// heal
CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid);
return true;
}
void Unit::RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo)
{
uint64 target_guid = GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT);
if(!IS_UNIT_GUID(target_guid))
return;
Unit* target = ObjectAccessor::GetUnit(*this, target_guid);
if(!target)
return;
for (AuraMap::iterator iter = target->GetAuras().begin(); iter != target->GetAuras().end(); )
{
if (iter->second->GetId() == spellInfo->Id && iter->second->GetCasterGUID()==GetGUID())
target->RemoveAura(iter);
else
++iter;
}
}

File diff suppressed because it is too large Load Diff