From e2ee47fb355c3ff59c54cd1bd3f2c8b329c8a108 Mon Sep 17 00:00:00 2001 From: megamage Date: Sun, 28 Dec 2008 12:10:31 -0600 Subject: *Update to Mangos 6963. --HG-- branch : trunk --- src/game/Chat.cpp | 10 +- src/game/Chat.h | 2 +- src/game/Guild.cpp | 15 +- src/game/Language.h | 4 +- src/game/Level1.cpp | 34 + src/game/Level3.cpp | 8 - src/game/ObjectMgr.cpp | 9 +- src/game/Player.cpp | 22 +- src/game/Player.h | 4 +- src/game/Spell.cpp | 77 - src/game/SpellEffects.cpp | 2 - src/game/SpellMgr.cpp | 74 +- src/game/SpellMgr.h | 12 +- src/game/Unit.cpp | 6601 +++++++++++++++++---------------------------- src/game/Unit.h | 1 - src/shared/revision_nr.h | 2 +- 16 files changed, 2566 insertions(+), 4311 deletions(-) (limited to 'src') diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index c05fd2b35c6..1f352a16cba 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -110,6 +110,7 @@ ChatCommand * ChatHandler::getCommandTable() { "hp", SEC_MODERATOR, false, &ChatHandler::HandleModifyHPCommand, "", NULL }, { "mana", SEC_MODERATOR, false, &ChatHandler::HandleModifyManaCommand, "", NULL }, { "rage", SEC_MODERATOR, false, &ChatHandler::HandleModifyRageCommand, "", NULL }, + { "runicpower", SEC_MODERATOR, false, &ChatHandler::HandleModifyRunicPowerCommand, "", NULL }, { "energy", SEC_MODERATOR, false, &ChatHandler::HandleModifyEnergyCommand, "", NULL }, { "money", SEC_MODERATOR, false, &ChatHandler::HandleModifyMoneyCommand, "", NULL }, { "speed", SEC_MODERATOR, false, &ChatHandler::HandleModifySpeedCommand, "", NULL }, @@ -301,7 +302,6 @@ ChatCommand * ChatHandler::getCommandTable() { "locales_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesQuestCommand, "", NULL }, { "waypoint_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadWpScriptsCommand, "", NULL }, - { "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; @@ -753,9 +753,9 @@ void ChatHandler::PSendSysMessage(int32 entry, ...) { const char *format = GetTrinityString(entry); va_list ap; - char str [1024]; + char str [2048]; va_start(ap, entry); - vsnprintf(str,1024,format, ap ); + vsnprintf(str,2048,format, ap ); va_end(ap); SendSysMessage(str); } @@ -763,9 +763,9 @@ void ChatHandler::PSendSysMessage(int32 entry, ...) void ChatHandler::PSendSysMessage(const char *format, ...) { va_list ap; - char str [1024]; + char str [2048]; va_start(ap, format); - vsnprintf(str,1024,format, ap ); + vsnprintf(str,2048,format, ap ); va_end(ap); SendSysMessage(str); } diff --git a/src/game/Chat.h b/src/game/Chat.h index b324d2d5f5e..b5d9de4faf7 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -163,6 +163,7 @@ class ChatHandler bool HandleModifyHPCommand(const char* args); bool HandleModifyManaCommand(const char* args); bool HandleModifyRageCommand(const char* args); + bool HandleModifyRunicPowerCommand(const char* args); bool HandleModifyEnergyCommand(const char* args); bool HandleModifyMoneyCommand(const char* args); bool HandleModifyASpeedCommand(const char* args); @@ -202,7 +203,6 @@ class ChatHandler bool HandleNpcWhisperCommand(const char* args); bool HandleNpcYellCommand(const char* args); - bool HandleReloadCommand(const char* args); bool HandleReloadAllCommand(const char* args); bool HandleReloadAllAreaCommand(const char* args); bool HandleReloadAllItemCommand(const char* args); diff --git a/src/game/Guild.cpp b/src/game/Guild.cpp index 55ad071a74b..a34d4bee524 100644 --- a/src/game/Guild.cpp +++ b/src/game/Guild.cpp @@ -1213,18 +1213,19 @@ void Guild::LoadGuildBankFromDB() delete result; - // 0 1 2 3 - result = CharacterDatabase.PQuery("SELECT TabId, SlotId, item_guid, item_entry FROM guild_bank_item WHERE guildid='%u' ORDER BY TabId", Id); + // data needs to be at first place for Item::LoadFromDB + // 0 1 2 3 4 + result = CharacterDatabase.PQuery("SELECT data, TabId, SlotId, item_guid, item_entry FROM guild_bank_item JOIN item_instance ON item_guid = guid WHERE guildid='%u' ORDER BY TabId", Id); if(!result) return; do { Field *fields = result->Fetch(); - uint8 TabId = fields[0].GetUInt8(); - uint8 SlotId = fields[1].GetUInt8(); - uint32 ItemGuid = fields[2].GetUInt32(); - uint32 ItemEntry = fields[3].GetUInt32(); + uint8 TabId = fields[1].GetUInt8(); + uint8 SlotId = fields[2].GetUInt8(); + uint32 ItemGuid = fields[3].GetUInt32(); + uint32 ItemEntry = fields[4].GetUInt32(); if (TabId >= purchased_tabs || TabId >= GUILD_BANK_MAX_TABS) { @@ -1247,7 +1248,7 @@ void Guild::LoadGuildBankFromDB() } Item *pItem = NewItemOrBag(proto); - if(!pItem->LoadFromDB(ItemGuid, 0)) + if(!pItem->LoadFromDB(ItemGuid, 0, result)) { CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", Id, uint32(TabId), uint32(SlotId)); sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid); diff --git a/src/game/Language.h b/src/game/Language.h index c7115ce9248..06f9d0b1ed1 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -170,7 +170,9 @@ enum TrinityStrings LANG_SOUND_NOT_EXIST = 170, LANG_TELEPORTED_TO_BY_CONSOLE = 171, LANG_CONSOLE_COMMAND = 172, - // Room for more level 1 173-199 not used + LANG_YOU_CHANGE_RUNIC_POWER = 173, + LANG_YOURS_RUNIC_POWER_CHANGED = 174, + // Room for more level 1 175-199 not used // level 2 chat LANG_NO_SELECTION = 200, diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index e1373d8e8fb..462d2864621 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -874,6 +874,40 @@ bool ChatHandler::HandleModifyRageCommand(const char* args) return true; } +// Edit Player Runic Power +bool ChatHandler::HandleModifyRunicPowerCommand(const char* args) +{ + if(!*args) + return false; + + int32 rune = atoi((char*)args)*10; + int32 runem = atoi((char*)args)*10; + + if (rune <= 0 || runem <= 0 || runem < rune) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_RUNIC_POWER, chr->GetName(), rune/10, runem/10); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_RUNIC_POWER_CHANGED, GetName(), rune/10, runem/10); + + chr->SetMaxPower(POWER_RUNIC_POWER,runem ); + chr->SetPower(POWER_RUNIC_POWER, rune ); + + return true; +} + //Edit Player Faction bool ChatHandler::HandleModifyFactionCommand(const char* args) { diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index ae0ea508308..aef91bf1e9c 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -54,14 +54,6 @@ #include "InstanceData.h" //reload commands -bool ChatHandler::HandleReloadCommand(const char* arg) -{ - // this is error catcher for wrong table name in .reload commands - PSendSysMessage("Db table with name starting from '%s' not found and can't be reloaded.",arg); - SetSentErrorMessage(true); - return false; -} - bool ChatHandler::HandleReloadAllCommand(const char*) { HandleReloadAreaTriggerTeleportCommand(""); diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index add9fa793af..5ae6b5b63e0 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -1987,7 +1987,8 @@ void ObjectMgr::LoadItemPrototypes() void ObjectMgr::LoadAuctionItems() { - QueryResult *result = CharacterDatabase.Query( "SELECT itemguid,item_template FROM auctionhouse" ); + // data needs to be at first place for Item::LoadFromDB + QueryResult *result = CharacterDatabase.Query( "SELECT data,itemguid,item_template FROM auctionhouse JOIN item_instance ON itemguid = guid" ); if( !result ) return; @@ -2002,8 +2003,8 @@ void ObjectMgr::LoadAuctionItems() bar.step(); fields = result->Fetch(); - uint32 item_guid = fields[0].GetUInt32(); - uint32 item_template = fields[1].GetUInt32(); + uint32 item_guid = fields[1].GetUInt32(); + uint32 item_template = fields[2].GetUInt32(); ItemPrototype const *proto = GetItemPrototype(item_template); @@ -2015,7 +2016,7 @@ void ObjectMgr::LoadAuctionItems() Item *item = NewItemOrBag(proto); - if(!item->LoadFromDB(item_guid,0)) + if(!item->LoadFromDB(item_guid,0, result)) { delete item; continue; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 8fbc26ed9eb..adf5a5ab167 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -3666,15 +3666,16 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC MailItemsInfo mi; if(has_items) { - QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", mail_id); + // data needs to be at first place for Item::LoadFromDB + QueryResult *resultItems = CharacterDatabase.PQuery("SELECT data,item_guid,item_template FROM mail_items JOIN item_instance ON item_guid = guid WHERE mail_id='%u'", mail_id); if(resultItems) { do { Field *fields2 = resultItems->Fetch(); - uint32 item_guidlow = fields2[0].GetUInt32(); - uint32 item_template = fields2[1].GetUInt32(); + uint32 item_guidlow = fields2[1].GetUInt32(); + uint32 item_template = fields2[2].GetUInt32(); ItemPrototype const* itemProto = objmgr.GetItemPrototype(item_template); if(!itemProto) @@ -3684,7 +3685,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC } Item *pItem = NewItemOrBag(itemProto); - if(!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER))) + if(!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER),resultItems)) { pItem->FSetState(ITEM_REMOVED); pItem->SaveToDB(); // it also deletes item object ! @@ -6416,13 +6417,13 @@ void Player::UpdateZone(uint32 newZone) if(zone->flags & AREA_FLAG_SANCTUARY) // in sanctuary { - SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY); + SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); if(sWorld.IsFFAPvPRealm()) RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP); } else { - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY); + RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); } if(zone->flags & AREA_FLAG_CAPITAL) // in capital city @@ -14979,15 +14980,16 @@ void Player::_LoadInventory(QueryResult *result, uint32 timediff) // load mailed item which should receive current player void Player::_LoadMailedItems(Mail *mail) { - QueryResult* result = CharacterDatabase.PQuery("SELECT item_guid, item_template FROM mail_items WHERE mail_id='%u'", mail->messageID); + // data needs to be at first place for Item::LoadFromDB + QueryResult* result = CharacterDatabase.PQuery("SELECT data, item_guid, item_template FROM mail_items JOIN item_instance ON item_guid = guid WHERE mail_id='%u'", mail->messageID); if(!result) return; do { Field *fields = result->Fetch(); - uint32 item_guid_low = fields[0].GetUInt32(); - uint32 item_template = fields[1].GetUInt32(); + uint32 item_guid_low = fields[1].GetUInt32(); + uint32 item_template = fields[2].GetUInt32(); mail->AddItem(item_guid_low, item_template); @@ -15003,7 +15005,7 @@ void Player::_LoadMailedItems(Mail *mail) Item *item = NewItemOrBag(proto); - if(!item->LoadFromDB(item_guid_low, 0)) + if(!item->LoadFromDB(item_guid_low, 0, result)) { sLog.outError( "Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", mail->messageID, item_guid_low); CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low); diff --git a/src/game/Player.h b/src/game/Player.h index ef111762efa..e40e3859bdc 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -428,8 +428,8 @@ enum PlayerFlags PLAYER_FLAGS_UNK1 = 0x00001000, // played long time PLAYER_FLAGS_UNK2 = 0x00002000, // played too long time PLAYER_FLAGS_UNK3 = 0x00008000, // strange visual effect (2.0.1), looks like PLAYER_FLAGS_GHOST flag - PLAYER_FLAGS_SANCTUARY = 0x00010000, // player entered sanctuary - PLAYER_FLAGS_UNK4 = 0x00020000, // taxi benchmark mode (on/off) (2.0.1) + PLAYER_FLAGS_UNK4 = 0x00010000, // pre-3.0.3 PLAYER_FLAGS_SANCTUARY flag for player entered sanctuary + PLAYER_FLAGS_UNK5 = 0x00020000, // taxi benchmark mode (on/off) (2.0.1) PLAYER_FLAGS_PVP_TIMER = 0x00040000, // 3.0.2, pvp timer active (after you disable pvp manually) }; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index e515c592c50..d78db70b653 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -850,83 +850,6 @@ void Spell::AddItemTarget(Item* pitem, uint32 effIndex) target.effectMask = 1<GetTypeId()== TYPEID_PLAYER) - ((Player*)m_caster)->UpdateWeaponSkill(BASE_ATTACK); - - m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_MISS, m_spellInfo, m_IsTriggeredSpell); - break; - case SPELL_MISS_RESIST: - m_caster->ProcDamageAndSpell(unitTarget, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, damageSchoolMask, m_spellInfo, m_IsTriggeredSpell); - break; - case SPELL_MISS_DODGE: - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->UpdateDefense(); - - // Overpower - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARRIOR) - { - ((Player*) m_caster)->AddComboPoints(unitTarget, 1); - m_caster->StartReactiveTimer( REACTIVE_OVERPOWER ); - } - - // Riposte - if (unitTarget->getClass() != CLASS_ROGUE) - { - unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); - unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); - } - - m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_DODGE, m_spellInfo, m_IsTriggeredSpell); - break; - case SPELL_MISS_PARRY: - // Update victim defense ? - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->UpdateDefense(); - // Mongoose bite - set only Counterattack here - if (unitTarget->getClass() == CLASS_HUNTER) - { - unitTarget->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); - unitTarget->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); - } - else - { - unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); - unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); - } - m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_PARRY, m_spellInfo, m_IsTriggeredSpell); - break; - case SPELL_MISS_BLOCK: - unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); - unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); - - m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_BLOCK, m_spellInfo, m_IsTriggeredSpell); - break; - // Trigger from this events not supported - case SPELL_MISS_EVADE: - case SPELL_MISS_IMMUNE: - case SPELL_MISS_IMMUNE2: - case SPELL_MISS_DEFLECT: - case SPELL_MISS_ABSORB: - // Trigger from reflects need do after get reflect result - case SPELL_MISS_REFLECT: - break; - default: - break; - } - } -}*/ void Spell::DoAllEffectOnTarget(TargetInfo *target) { diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index af17bf0f97e..20924d1ef56 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -5398,8 +5398,6 @@ void Spell::EffectApplyGlyph(uint32 i) player->CastSpell(m_caster, gp->SpellId, true); player->SetGlyph(m_glyphIndex, glyph); - if(m_CastItem) - player->DestroyItemCount(m_CastItem->GetEntry(), 1, true); } } } diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 12689654310..2e0d25d4c6a 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -1073,80 +1073,10 @@ void SpellMgr::LoadSpellProcEvents() sLog.outString(); if (customProc) - sLog.outString( ">> Loaded %u custom spell proc event conditions +%u custom", count, customProc ); + sLog.outString( ">> Loaded %u extra spell proc event conditions +%u custom", count, customProc ); else - sLog.outString( ">> Loaded %u spell proc event conditions", count ); - - /* - // Commented for now, as it still produces many errors (still quite many spells miss spell_proc_event) - for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(id); - if (!spellInfo) - continue; - - bool found = false; - for (int effectId = 0; effectId < 3; ++effectId) - { - // at this moment check only SPELL_AURA_PROC_TRIGGER_SPELL - if( spellInfo->EffectApplyAuraName[effectId] == SPELL_AURA_PROC_TRIGGER_SPELL ) - { - found = true; - break; - } - } - - if(!found) - continue; - - if(GetSpellProcEvent(id)) - continue; - - sLog.outErrorDb("Spell %u (%s) misses spell_proc_event",id,spellInfo->SpellName[sWorld.GetDBClang()]); - } - */ -} - -/* -bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags ) -{ - if((procFlags & spellProcEvent->procFlags) == 0) - return false; - - // Additional checks in case spell cast/hit/crit is the event - // Check (if set) school, category, skill line, spell talent mask - if(spellProcEvent->schoolMask && (!procSpell || (GetSpellSchoolMask(procSpell) & spellProcEvent->schoolMask) == 0)) - return false; - if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category)) - return false; - if(spellProcEvent->skillId) - { - if (!procSpell) - return false; - - SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(procSpell->Id); - SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(procSpell->Id); - - bool found = false; - for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) - { - if(_spell_idx->second->skillId == spellProcEvent->skillId) - { - found = true; - break; - } - } - if (!found) - return false; - } - if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName)) - return false; - if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0)) - return false; - - return true; + sLog.outString( ">> Loaded %u extra spell proc event conditions", count ); } -*/ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active) { diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 5322f3fa16d..a37d219743f 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -482,14 +482,14 @@ enum ProcFlags PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor PROC_FLAG_KILL_AND_GET_XP = 0x00000002, // 01 Kill that yields experience or honor - PROC_FLAG_SUCCESSFUL_MILEE_HIT = 0x00000004, // 02 Successful melee attack - PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee strike hit + PROC_FLAG_SUCCESSFUL_MILEE_HIT = 0x00000004, // 02 Successful melee auto attack + PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee auto attack hit PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT = 0x00000010, // 04 Successful attack by Spell that use melee weapon PROC_FLAG_TAKEN_MELEE_SPELL_HIT = 0x00000020, // 05 Taken damage by Spell that use melee weapon - PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged attack (all ranged attack deal as spell so newer set :( ) - PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged attack (all ranged attack deal as spell so newer set :( ) + PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged auto attack + PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged auto attack PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT = 0x00000100, // 08 Successful Ranged attack by Spell that use ranged weapon PROC_FLAG_TAKEN_RANGED_SPELL_HIT = 0x00000200, // 09 Taken damage by Spell that use ranged weapon @@ -540,12 +540,12 @@ enum ProcFlagsEx PROC_EX_DEFLECT = 0x0000200, PROC_EX_ABSORB = 0x0000400, PROC_EX_REFLECT = 0x0000800, - PROC_EX_INTERRUPT = 0x0001000, // Melle hit result can be Interrupt (not used) + PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used) PROC_EX_RESERVED1 = 0x0002000, PROC_EX_RESERVED2 = 0x0004000, PROC_EX_RESERVED3 = 0x0008000, PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always ( no matter another flags) used for drop charges - PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000 // If set trigger always but only one time + PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000 // If set trigger always but only one time (not used) }; struct SpellProcEventEntry diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 5a2503f99fe..289bfb963ad 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -63,72 +63,14 @@ float baseMoveSpeed[MAX_MOVE_TYPE] = 3.14f // MOVE_PITCH_RATE }; -void InitTriggerAuraData(); - -// auraTypes contains attacker auras capable of proc'ing cast auras -static Unit::AuraTypeSet GenerateAttakerProcCastAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_DUMMY); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL); - auraTypes.insert(SPELL_AURA_MOD_HASTE); - auraTypes.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - return auraTypes; -} - -// auraTypes contains victim auras capable of proc'ing cast auras -static Unit::AuraTypeSet GenerateVictimProcCastAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_DUMMY); - auraTypes.insert(SPELL_AURA_PRAYER_OF_MENDING); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL); - return auraTypes; -} - -// auraTypes contains auras capable of proc effect/damage (but not cast) for attacker -static Unit::AuraTypeSet GenerateAttakerProcEffectAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_MOD_DAMAGE_DONE); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE); - auraTypes.insert(SPELL_AURA_MOD_CASTING_SPEED); - auraTypes.insert(SPELL_AURA_MOD_RATING); - return auraTypes; -} - -// auraTypes contains auras capable of proc effect/damage (but not cast) for victim -static Unit::AuraTypeSet GenerateVictimProcEffectAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_MOD_RESISTANCE); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE); - auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT); - auraTypes.insert(SPELL_AURA_MOD_BLOCK_PERCENT); - auraTypes.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); - return auraTypes; -} - -static Unit::AuraTypeSet attackerProcCastAuraTypes = GenerateAttakerProcCastAuraTypes(); -static Unit::AuraTypeSet attackerProcEffectAuraTypes = GenerateAttakerProcEffectAuraTypes(); - -static Unit::AuraTypeSet victimProcCastAuraTypes = GenerateVictimProcCastAuraTypes(); -static Unit::AuraTypeSet victimProcEffectAuraTypes = GenerateVictimProcEffectAuraTypes(); - -// auraTypes contains auras capable of proc'ing for attacker and victim -static Unit::AuraTypeSet GenerateProcAuraTypes() -{ - InitTriggerAuraData(); - - Unit::AuraTypeSet auraTypes; - auraTypes.insert(attackerProcCastAuraTypes.begin(),attackerProcCastAuraTypes.end()); - auraTypes.insert(attackerProcEffectAuraTypes.begin(),attackerProcEffectAuraTypes.end()); - auraTypes.insert(victimProcCastAuraTypes.begin(),victimProcCastAuraTypes.end()); - auraTypes.insert(victimProcEffectAuraTypes.begin(),victimProcEffectAuraTypes.end()); - return auraTypes; -} - -static Unit::AuraTypeSet procAuraTypes = GenerateProcAuraTypes(); +// Used for prepare can/can`t triggr aura +static bool InitTriggerAuraData(); +// Define can trigger auras +static bool isTriggerAura[TOTAL_AURAS]; +// Define can`t trigger auras (need for disable second trigger) +static bool isNonTriggerAura[TOTAL_AURAS]; +// Prepare lists +static bool procPrepared = InitTriggerAuraData(); bool IsPassiveStackableSpell( uint32 spellId ) { @@ -138,12 +80,8 @@ bool IsPassiveStackableSpell( uint32 spellId ) SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId); if(!spellProto) return false; - - for(int j = 0; j < 3; ++j) - { - if(std::find(procAuraTypes.begin(),procAuraTypes.end(),spellProto->EffectApplyAuraName[j])!=procAuraTypes.end()) - return false; - } + if (spellProto->procFlags) + return false; return true; } @@ -722,6 +660,169 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa { DEBUG_LOG("DealDamage: victim just died"); Kill(pVictim, durabilityLoss); + + /*// find player: owner of controlled `this` or `this` itself maybe + Player *player = GetCharmerOrOwnerPlayerOrPlayerItself(); + + if(pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->GetLootRecipient()) + player = ((Creature*)pVictim)->GetLootRecipient(); + // Reward player, his pets, and group/raid members + // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop) + if(player && player!=pVictim) + { + if(player->RewardPlayerAndGroupAtKill(pVictim)) + player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL_AND_GET_XP, PROC_FLAG_KILLED, PROC_EX_NONE, 0); + else + player->ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_KILLED,PROC_EX_NONE, 0); + } + + DEBUG_LOG("DealDamageAttackStop"); + + // stop combat + pVictim->CombatStop(); + pVictim->getHostilRefManager().deleteReferences(); + + bool damageFromSpiritOfRedemtionTalent = spellProto && spellProto->Id == 27795; + + // if talent known but not triggered (check priest class for speedup check) + Aura* spiritOfRedemtionTalentReady = NULL; + if( !damageFromSpiritOfRedemtionTalent && // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION + pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST ) + { + AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr) + { + if((*itr)->GetSpellProto()->SpellIconID==1654) + { + spiritOfRedemtionTalentReady = *itr; + break; + } + } + } + + DEBUG_LOG("SET JUST_DIED"); + if(!spiritOfRedemtionTalentReady) + pVictim->setDeathState(JUST_DIED); + + DEBUG_LOG("DealDamageHealth1"); + + if(spiritOfRedemtionTalentReady) + { + // save value before aura remove + uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL); + if(!ressSpellId) + ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId(); + + //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers) + pVictim->RemoveAllAurasOnDeath(); + + // restore for use at real death + pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL,ressSpellId); + + // FORM_SPIRITOFREDEMPTION and related auras + pVictim->CastSpell(pVictim,27827,true,NULL,spiritOfRedemtionTalentReady); + } + else + pVictim->SetHealth(0); + + // remember victim PvP death for corpse type and corpse reclaim delay + // at original death (not at SpiritOfRedemtionTalent timeout) + if( pVictim->GetTypeId()==TYPEID_PLAYER && !damageFromSpiritOfRedemtionTalent ) + ((Player*)pVictim)->SetPvPDeath(player!=NULL); + + // Call KilledUnit for creatures + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) + ((Creature*)this)->AI()->KilledUnit(pVictim); + + // achievement stuff + if ( pVictim->GetTypeId() == TYPEID_PLAYER) + { + if(GetTypeId() == TYPEID_UNIT) + ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry()); + else if(GetTypeId() == TYPEID_PLAYER) + ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1); + } + + // 10% durability loss on death + // clean InHateListOf + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + // only if not player and not controlled by player pet. And not at BG + if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround()) + { + DEBUG_LOG("We are dead, loosing 10 percents durability"); + ((Player*)pVictim)->DurabilityLossAll(0.10f,false); + // durability lost message + WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); + ((Player*)pVictim)->GetSession()->SendPacket(&data); + } + } + else // creature died + { + DEBUG_LOG("DealDamageNotPlayer"); + Creature *cVictim = (Creature*)pVictim; + + if(!cVictim->isPet()) + { + cVictim->DeleteThreatList(); + cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + // Call creature just died function + if (cVictim->AI()) + cVictim->AI()->JustDied(this); + + // Dungeon specific stuff, only applies to players killing creatures + if(cVictim->GetInstanceId()) + { + Map *m = cVictim->GetMap(); + Player *creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself(); + // TODO: do instance binding anyway if the charmer/owner is offline + + if(m->IsDungeon() && creditedPlayer) + { + if(m->IsRaid() || m->IsHeroic()) + { + if(cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) + ((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer); + } + else + { + // the reset time is set but not added to the scheduler + // until the players leave the instance + time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR; + if(InstanceSave *save = sInstanceSaveManager.GetInstanceSave(cVictim->GetInstanceId())) + if(save->GetResetTime() < resettime) save->SetResetTime(resettime); + } + } + } + } + + // last damage from non duel opponent or opponent controlled creature + if(duel_hasEnded) + { + assert(pVictim->GetTypeId()==TYPEID_PLAYER); + Player *he = (Player*)pVictim; + + assert(he->duel); + + he->duel->opponent->CombatStopWithPets(true); + he->CombatStopWithPets(true); + + he->DuelComplete(DUEL_INTERUPTED); + } + + // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill) + if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->InBattleGround()) + { + Player *killed = ((Player*)pVictim); + if(BattleGround *bg = killed->GetBattleGround()) + if(player) + bg->HandleKillPlayer(killed, player); + //later we can add support for creature->player kills here i'm + //not sure, but i guess those kills also get counted in av + //else if(GetTypeId() == TYPEID_UNIT) + // bg->HandleKillPlayer(killed,(Creature*)this); + }*/ } else // if (health <= damage) { @@ -752,7 +853,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa //if (!spellProto || !(spellProto->AuraInterruptFlags&AURA_INTERRUPT_FLAG_DIRECT_DAMAGE)) pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0); } - if (pVictim->GetTypeId() != TYPEID_PLAYER) { if(spellProto && IsDamageToThreatSpell(spellProto)) @@ -1061,569 +1161,473 @@ void Unit::CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castI spell->prepare(&targets, triggeredByAura); } -/* -void Unit::DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell) +// Obsolete func need remove, here only for comotability vs another patches +uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); + SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask); + CalculateSpellDamage(&damageInfo, damage, spellInfo); + SendSpellNonMeleeDamageLog(&damageInfo); + DealSpellDamage(&damageInfo, true); + return damageInfo.damage; +} + +void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType) { - // TODO this in only generic way, check for exceptions - DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage); + SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask); + Unit *pVictim = damageInfo->target; + + if (damage < 0) + return; + + if(!this || !pVictim) + return; + if(!this->isAlive() || !pVictim->isAlive()) + return; - // Per-damage class calculation + uint32 crTypeMask = pVictim->GetCreatureTypeMask(); + // Check spell crit chance + bool crit = isSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType); + bool blocked = false; + // Per-school calc switch (spellInfo->DmgClass) { // Melee and Ranged Spells case SPELL_DAMAGE_CLASS_RANGED: case SPELL_DAMAGE_CLASS_MELEE: { - // Calculate physical outcome - MeleeHitOutcome outcome = RollPhysicalOutcomeAgainst(pVictim, BASE_ATTACK, spellInfo); - - //Used to store the Hit Outcome - cleanDamage->hitOutCome = outcome; - - // Return miss/evade first (sends miss message) - switch(outcome) - { - case MELEE_HIT_EVADE: - { - SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_EVADES,0); - *damage = 0; - return; - } - case MELEE_HIT_MISS: - { - SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_NORMAL,0); - *damage = 0; - - if(GetTypeId()== TYPEID_PLAYER) - ((Player*)this)->UpdateWeaponSkill(BASE_ATTACK); - - CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,MELEE_HIT_MISS,spellInfo,isTriggeredSpell); - return; - } - } - - // Hitinfo, Victimstate - uint32 hitInfo = HITINFO_NORMALSWING; - VictimState victimState = VICTIMSTATE_NORMAL; - // Physical Damage - if ( GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NORMAL ) + if ( damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL ) { - // apply spellmod to Done damage - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_DAMAGE, *damage); - //Calculate armor mitigation - uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage); - - // random durability for main hand weapon (ABSORB) - if(damageAfterArmor < *damage) - if(pVictim->GetTypeId() == TYPEID_PLAYER) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK))); - - cleanDamage->damage += *damage - damageAfterArmor; - *damage = damageAfterArmor; + damage = CalcArmorReducedDamage(pVictim, damage); + // Get blocked status + blocked = isSpellBlocked(pVictim, spellInfo, attackType); } // Magical Damage else { // Calculate damage bonus - *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE); + damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE); } - - // Classify outcome - switch (outcome) + if (crit) { - case MELEE_HIT_BLOCK_CRIT: - case MELEE_HIT_CRIT: - { - uint32 bonusDmg = *damage; + damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT; - // Apply crit_damage bonus - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, bonusDmg); + // Calculate crit bonus + uint32 crit_bonus = damage; + // Apply crit_damage bonus for melee spells + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); + damage += crit_bonus; - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS); - for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - bonusDmg = uint32(bonusDmg * ((*i)->GetModifierValue()+100.0f)/100.0f); + // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE + int32 critPctDamageMod=0; + if(attackType == RANGED_ATTACK) + critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); + else + { + critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); + critPctDamageMod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE); + } + // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS + critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask); - *damage += bonusDmg; + if (critPctDamageMod!=0) + damage = int32((damage) * float((100.0f + critPctDamageMod)/100.0f)); - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - { - uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage); - cleanDamage->damage += resilienceReduction; - *damage -= resilienceReduction; - } + // Resilience - reduce crit damage + if (pVictim->GetTypeId()==TYPEID_PLAYER) + damage -= ((Player*)pVictim)->GetMeleeCritDamageReduction(damage); + } + // Spell weapon based damage CAN BE crit & blocked at same time + if (blocked) + { + damageInfo->blocked = uint32(pVictim->GetShieldBlockValue()); + if (damage < damageInfo->blocked) + damageInfo->blocked = damage; + damage-=damageInfo->blocked; + } + } + break; + // Magical Attacks + case SPELL_DAMAGE_CLASS_NONE: + case SPELL_DAMAGE_CLASS_MAGIC: + { + // Calculate damage bonus + damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE); + // If crit add critical bonus + if (crit) + { + damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT; + damage = SpellCriticalBonus(spellInfo, damage, pVictim); + // Resilience - reduce crit damage + if (pVictim->GetTypeId()==TYPEID_PLAYER) + damage -= ((Player*)pVictim)->GetSpellCritDamageReduction(damage); + } + } + break; + } - *crit = true; - hitInfo |= HITINFO_CRITICALHIT; + // Calculate absorb resist + if(damage > 0) + { + CalcAbsorbResist(pVictim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist); + damage-= damageInfo->absorb + damageInfo->resist; + } + else + damage = 0; + damageInfo->damage = damage; +} - ModifyAuraState(AURA_STATE_CRIT, true); - StartReactiveTimer( REACTIVE_CRIT ); +void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss) +{ + if (damageInfo==0) + return; - if(getClass()==CLASS_HUNTER) - { - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true); - StartReactiveTimer( REACTIVE_HUNTER_CRIT ); - } + Unit *pVictim = damageInfo->target; - if ( outcome == MELEE_HIT_BLOCK_CRIT ) - { - uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue()); - if (blocked_amount >= *damage) - { - hitInfo |= HITINFO_SWINGNOHITSOUND; - victimState = VICTIMSTATE_BLOCKS; - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - } - else - { - // To Help Calculate Rage - cleanDamage->damage += blocked_amount; - *damage = *damage - blocked_amount; - } + if(!this || !pVictim) + return; - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + return; - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); + SpellEntry const *spellProto = sSpellStore.LookupEntry(damageInfo->SpellID); + if (spellProto == NULL) + { + sLog.outDebug("Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", damageInfo->SpellID); + return; + } - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - } - break; - } - case MELEE_HIT_PARRY: - { - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - victimState = VICTIMSTATE_PARRY; - - // Counter-attack ( explained in Unit::DoAttackDamage() ) - if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN) ) - { - // Get attack timers - float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); - float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); - - // Reduce attack time - if (pVictim->haveOffhandWeapon() && offtime < basetime) - { - float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20; - float percent60 = 3 * percent20; - if(offtime > percent20 && offtime <= percent60) - { - pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20)); - } - else if(offtime > percent60) - { - offtime -= 2 * percent20; - pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime)); - } - } - else - { - float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20; - float percent60 = 3 * percent20; - if(basetime > percent20 && basetime <= percent60) - { - pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20)); - } - else if(basetime > percent60) - { - basetime -= 2 * percent20; - pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime)); - } - } - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update victim defense ? - ((Player*)pVictim)->UpdateDefense(); + //You don't lose health from damage taken from another player while in a sanctuary + //You still see it in the combat log though + if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + { + const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); + if(area && area->flags & 0x800) //sanctuary + return; + } - // random durability for main hand weapon (PARRY) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND); - } + // update at damage Judgement aura duration that applied by attacker at victim + if(damageInfo->damage && spellProto->Id == 35395) + { + AuraMap& vAuras = pVictim->GetAuras(); + for(AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr) + { + SpellEntry const *spellInfo = (*itr).second->GetSpellProto(); + if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID())) + { + (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration()); + (*itr).second->SendAuraUpdate(false); + } + } + } + // Call default DealDamage + CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL); + DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss); +} - // Set parry flags - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); +//TODO for melee need create structure as in +void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType) +{ + damageInfo->attacker = this; + damageInfo->target = pVictim; + damageInfo->damageSchoolMask = GetMeleeDamageSchoolMask(); + damageInfo->attackType = attackType; + damageInfo->damage = 0; + damageInfo->cleanDamage = 0; + damageInfo->absorb = 0; + damageInfo->resist = 0; + damageInfo->blocked_amount = 0; - // Mongoose bite - set only Counterattack here - if (pVictim->getClass() == CLASS_HUNTER) - { - pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); - pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); - } - else - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - break; - } - case MELEE_HIT_DODGE: - { - if(pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateDefense(); + damageInfo->TargetState = 0; + damageInfo->HitInfo = 0; + damageInfo->procAttacker = PROC_FLAG_NONE; + damageInfo->procVictim = PROC_FLAG_NONE; + damageInfo->procEx = PROC_EX_NONE; + damageInfo->hitOutCome = MELEE_HIT_EVADE; - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - hitInfo |= HITINFO_SWINGNOHITSOUND; - victimState = VICTIMSTATE_DODGE; + if(!this || !pVictim) + return; + if(!this->isAlive() || !pVictim->isAlive()) + return; - // Set dodge flags - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + // Select HitInfo/procAttacker/procVictim flag based on attack type + switch (attackType) + { + case BASE_ATTACK: + damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT; + damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT; + damageInfo->HitInfo = HITINFO_NORMALSWING2; + break; + case OFF_ATTACK: + damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT; + damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used + damageInfo->HitInfo = HITINFO_LEFTSWING; + break; + case RANGED_ATTACK: + damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT; + damageInfo->procVictim = PROC_FLAG_TAKEN_RANGED_HIT; + damageInfo->HitInfo = 0x08;// test + break; + default: + break; + } - // Overpower - if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) - { - ((Player*)this)->AddComboPoints(pVictim, 1); - StartReactiveTimer( REACTIVE_OVERPOWER ); - } + // Physical Immune check + if(damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask),true)) + { + damageInfo->HitInfo |= HITINFO_NORMALSWING; + damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE; - // Riposte - if (pVictim->getClass() != CLASS_ROGUE) - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - break; - } - case MELEE_HIT_BLOCK: - { - uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue()); - if (blocked_amount >= *damage) - { - hitInfo |= HITINFO_SWINGNOHITSOUND; - victimState = VICTIMSTATE_BLOCKS; - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - } - else - { - // To Help Calculate Rage - cleanDamage->damage += blocked_amount; - *damage = *damage - blocked_amount; - } + damageInfo->procEx |=PROC_EX_IMMUNE; + damageInfo->damage = 0; + damageInfo->cleanDamage = 0; + return; + } + damage += CalculateDamage (damageInfo->attackType, false); + // Add melee damage bonus + MeleeDamageBonus(damageInfo->target, &damage, damageInfo->attackType); + // Calculate armor reduction + damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage); + damageInfo->cleanDamage += damage - damageInfo->damage; - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType); - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); + // Disable parry or dodge for ranged attack + if(damageInfo->attackType == RANGED_ATTACK) + { + if (damageInfo->hitOutCome == MELEE_HIT_PARRY) damageInfo->hitOutCome = MELEE_HIT_NORMAL; + if (damageInfo->hitOutCome == MELEE_HIT_DODGE) damageInfo->hitOutCome = MELEE_HIT_MISS; + } - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - break; - } - case MELEE_HIT_EVADE: // already processed early - case MELEE_HIT_MISS: // already processed early - case MELEE_HIT_GLANCING: - case MELEE_HIT_CRUSHING: - case MELEE_HIT_NORMAL: - break; - } + switch(damageInfo->hitOutCome) + { + case MELEE_HIT_EVADE: + { + damageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND; + damageInfo->TargetState = VICTIMSTATE_EVADES; - // do all damage=0 cases here - if(*damage == 0) - CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,outcome,spellInfo,isTriggeredSpell); + damageInfo->procEx|=PROC_EX_EVADE; + damageInfo->damage = 0; + damageInfo->cleanDamage = 0; + return; + } + case MELEE_HIT_MISS: + { + damageInfo->HitInfo |= HITINFO_MISS; + damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->procEx|=PROC_EX_MISS; + damageInfo->damage = 0; + damageInfo->cleanDamage = 0; break; } - // Magical Attacks - case SPELL_DAMAGE_CLASS_NONE: - case SPELL_DAMAGE_CLASS_MAGIC: + case MELEE_HIT_NORMAL: + damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->procEx|=PROC_EX_NORMAL_HIT; + break; + case MELEE_HIT_CRIT: { - // Calculate damage bonus - *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE); + damageInfo->HitInfo |= HITINFO_CRITICALHIT; + damageInfo->TargetState = VICTIMSTATE_NORMAL; - *crit = isSpellCrit(pVictim, spellInfo, GetSpellSchoolMask(spellInfo), BASE_ATTACK); - if (*crit) + damageInfo->procEx|=PROC_EX_CRITICAL_HIT; + // Crit bonus calc + damageInfo->damage += damageInfo->damage; + int32 mod=0; + // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE + if(damageInfo->attackType == RANGED_ATTACK) + mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); + else { - *damage = SpellCriticalBonus(spellInfo, *damage, pVictim); + mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); + mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE); + } - // Resilience - reduce crit damage - if (pVictim && pVictim->GetTypeId()==TYPEID_PLAYER) - { - uint32 damage_reduction = ((Player *)pVictim)->GetSpellCritDamageReduction(*damage); - if(*damage > damage_reduction) - *damage -= damage_reduction; - else - *damage = 0; - } + uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask(); - cleanDamage->hitOutCome = MELEE_HIT_CRIT; - } - // spell proc all magic damage==0 case in this function - if(*damage == 0) - { - // Procflags - uint32 procAttacker = PROC_FLAG_HIT_SPELL; - uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE); + // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS + mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask); + if (mod!=0) + damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod)/100.0f)); - ProcDamageAndSpell(pVictim, procAttacker, procVictim, 0, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell); + // Resilience - reduce crit damage + if (pVictim->GetTypeId()==TYPEID_PLAYER) + { + uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(damageInfo->damage); + damageInfo->damage -= resilienceReduction; + damageInfo->cleanDamage += resilienceReduction; } - break; } - } - - // TODO this in only generic way, check for exceptions - DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage); -} - -uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage) -{ - if(!this || !pVictim) - return 0; - if(!isAlive() || !pVictim->isAlive()) - return 0; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); - if(!spellInfo) - return 0; - - CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL); - bool crit = false; - - if (useSpellDamage) - DealFlatDamage(pVictim, spellInfo, &damage, &cleanDamage, &crit, isTriggeredSpell); - - // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage) - if(damage > 0) - { - // Calculate absorb & resists - uint32 absorb = 0; - uint32 resist = 0; - - CalcAbsorbResist(pVictim,GetSpellSchoolMask(spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); + case MELEE_HIT_PARRY: + damageInfo->TargetState = VICTIMSTATE_PARRY; + damageInfo->procEx|=PROC_EX_PARRY; + damageInfo->cleanDamage += damageInfo->damage; + damageInfo->damage = 0; + break; - //No more damage left, target absorbed and/or resisted all damage - if (damage > absorb + resist) - damage -= absorb + resist; //Remove Absorbed and Resisted from damage actually dealt - else + case MELEE_HIT_DODGE: + damageInfo->TargetState = VICTIMSTATE_DODGE; + damageInfo->procEx|=PROC_EX_DODGE; + damageInfo->cleanDamage += damageInfo->damage; + damageInfo->damage = 0; + break; + case MELEE_HIT_BLOCK: { - uint32 HitInfo = HITINFO_SWINGNOHITSOUND; - - if (absorb) - HitInfo |= HITINFO_ABSORB; - if (resist) + damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->HitInfo |= HITINFO_BLOCK; + damageInfo->procEx|=PROC_EX_BLOCK; + damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue(); + if (damageInfo->blocked_amount >= damageInfo->damage) { - HitInfo |= HITINFO_RESIST; - ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, GetSpellSchoolMask(spellInfo), spellInfo,isTriggeredSpell); + damageInfo->TargetState = VICTIMSTATE_BLOCKS; + damageInfo->blocked_amount = damageInfo->damage; } - - //Send resist - SendAttackStateUpdate(HitInfo, pVictim, 1, GetSpellSchoolMask(spellInfo), damage, absorb,resist,VICTIMSTATE_NORMAL,0); - return 0; + damageInfo->damage -= damageInfo->blocked_amount; + damageInfo->cleanDamage += damageInfo->blocked_amount; + break; } - - // Deal damage done - damage = DealDamage(pVictim, damage, &cleanDamage, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellInfo), spellInfo, true); - - // Send damage log - sLog.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u", - GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist); - - // Actual log sent to client - SendSpellNonMeleeDamageLog(pVictim, spellID, damage + resist, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit); - - // Procflags - uint32 procAttacker = PROC_FLAG_HIT_SPELL; - uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE); - - if (crit) + case MELEE_HIT_GLANCING: { - procAttacker |= PROC_FLAG_CRIT_SPELL; - procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL; + damageInfo->HitInfo |= HITINFO_GLANCING; + damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->procEx|=PROC_EX_NORMAL_HIT; + int32 leveldif = int32(pVictim->getLevel()) - int32(getLevel()); + if (leveldif > 3) leveldif = 3; + float reducePercent = 1 - leveldif * 0.1f; + damageInfo->cleanDamage += damageInfo->damage-uint32(reducePercent * damageInfo->damage); + damageInfo->damage = uint32(reducePercent * damageInfo->damage); + break; } + case MELEE_HIT_CRUSHING: + { + damageInfo->HitInfo |= HITINFO_CRUSHING; + damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->procEx|=PROC_EX_NORMAL_HIT; + // 150% normal damage + damageInfo->damage += (damageInfo->damage / 2); + break; + } + default: - ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell); - - return damage; + break; } - else - { - // all spell proc for 0 normal and magic damage called in DealFlatDamage - //Check for rage - if(cleanDamage.damage) - // Rage from damage received. - if(pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE)) - ((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false); + // Calculate absorb resist + if(int32(damageInfo->damage) > 0) + { + damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE; + // Calculate absorb & resists + CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist); + damageInfo->damage-=damageInfo->absorb + damageInfo->resist; + if (damageInfo->absorb) + { + damageInfo->HitInfo|=HITINFO_ABSORB; + damageInfo->procEx|=PROC_EX_ABSORB; + } + if (damageInfo->resist) + damageInfo->HitInfo|=HITINFO_RESIST; - return 0; } -} -*/ - -// Obsolete func need remove, here only for comotability vs another patches -uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage) -{ - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); - SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask); - CalculateSpellDamage(&damageInfo, damage, spellInfo); - SendSpellNonMeleeDamageLog(&damageInfo); - DealSpellDamage(&damageInfo, true); - return damageInfo.damage; + else // Umpossible get negative result but.... + damageInfo->damage = 0; } -void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType) +void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) { - SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask); + if (damageInfo==0) return; Unit *pVictim = damageInfo->target; - if (damage < 0) - return; - if(!this || !pVictim) return; - if(!this->isAlive() || !pVictim->isAlive()) + + if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) return; - uint32 crTypeMask = pVictim->GetCreatureTypeMask(); - // Check spell crit chance - bool crit = isSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType); - bool blocked = false; - // Per-school calc - switch (spellInfo->DmgClass) + //You don't lose health from damage taken from another player while in a sanctuary + //You still see it in the combat log though + if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) { - // Melee and Ranged Spells - case SPELL_DAMAGE_CLASS_RANGED: - case SPELL_DAMAGE_CLASS_MELEE: - { - // Physical Damage - if ( damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL ) - { - //Calculate armor mitigation - damage = CalcArmorReducedDamage(pVictim, damage); - // Get blocked status - blocked = isSpellBlocked(pVictim, spellInfo, attackType); - } - // Magical Damage - else - { - // Calculate damage bonus - damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE); - } - if (crit) - { - damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT; - - // Calculate crit bonus - uint32 crit_bonus = damage; - // Apply crit_damage bonus for melee spells - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); - damage += crit_bonus; - - // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE - int32 critPctDamageMod=0; - if(attackType == RANGED_ATTACK) - critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); - else - { - critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); - critPctDamageMod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE); - } - // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS - critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask); + const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); + if(area && area->flags & 0x800) //sanctuary + return; + } - if (critPctDamageMod!=0) - damage = int32((damage) * float((100.0f + critPctDamageMod)/100.0f)); + // Hmmmm dont like this emotes cloent must by self do all animations + if (damageInfo->HitInfo&HITINFO_CRITICALHIT) + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL); + if(damageInfo->blocked_amount && damageInfo->TargetState!=VICTIMSTATE_BLOCKS) + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - damage -= ((Player*)pVictim)->GetMeleeCritDamageReduction(damage); + if(damageInfo->TargetState == VICTIMSTATE_PARRY) + { + // Get attack timers + float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); + float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); + // Reduce attack time + if (pVictim->haveOffhandWeapon() && offtime < basetime) + { + float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20; + float percent60 = 3 * percent20; + if(offtime > percent20 && offtime <= percent60) + { + pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20)); } - // Spell weapon based damage CAN BE crit & blocked at same time - if (blocked) + else if(offtime > percent60) { - damageInfo->blocked = uint32(pVictim->GetShieldBlockValue()); - if (damage < damageInfo->blocked) - damageInfo->blocked = damage; - damage-=damageInfo->blocked; + offtime -= 2 * percent20; + pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime)); } } - break; - // Magical Attacks - case SPELL_DAMAGE_CLASS_NONE: - case SPELL_DAMAGE_CLASS_MAGIC: + else { - // Calculate damage bonus - damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE); - // If crit add critical bonus - if (crit) + float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20; + float percent60 = 3 * percent20; + if(basetime > percent20 && basetime <= percent60) { - damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT; - damage = SpellCriticalBonus(spellInfo, damage, pVictim); - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - damage -= ((Player*)pVictim)->GetSpellCritDamageReduction(damage); + pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20)); + } + else if(basetime > percent60) + { + basetime -= 2 * percent20; + pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime)); } } - break; } - // Calculate absorb resist - if(damage > 0) - { - CalcAbsorbResist(pVictim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist); - damage-= damageInfo->absorb + damageInfo->resist; - } - else - damage = 0; - damageInfo->damage = damage; -} + // Call default DealDamage + CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->attackType,damageInfo->hitOutCome); + DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss); -void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss) -{ - if (damageInfo==0) - return; + // If this is a creature and it attacks from behind it has a probability to daze it's victim + if( (damageInfo->hitOutCome==MELEE_HIT_CRIT || damageInfo->hitOutCome==MELEE_HIT_CRUSHING || damageInfo->hitOutCome==MELEE_HIT_NORMAL || damageInfo->hitOutCome==MELEE_HIT_GLANCING) && + GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) ) + { + // -probability is between 0% and 40% + // 20% base chance + float Probability = 20; - Unit *pVictim = damageInfo->target; + //there is a newbie protection, at level 10 just 7% base chance; assuming linear function + if( pVictim->getLevel() < 30 ) + Probability = 0.65f*pVictim->getLevel()+0.5; - if(!this || !pVictim) - return; + uint32 VictimDefense=pVictim->GetDefenseSkillValue(); + uint32 AttackerMeleeSkill=GetUnitMeleeSkill(); - if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) - return; + Probability *= AttackerMeleeSkill/(float)VictimDefense; - SpellEntry const *spellProto = sSpellStore.LookupEntry(damageInfo->SpellID); - if (spellProto == NULL) - { - sLog.outDebug("Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", damageInfo->SpellID); - return; - } + if(Probability > 40) + Probability = 40; - //You don't lose health from damage taken from another player while in a sanctuary - //You still see it in the combat log though - if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) - { - const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); - if(area && area->flags & 0x800) //sanctuary - return; + if(roll_chance_f(Probability)) + CastSpell(pVictim, 1604, true); } // update at damage Judgement aura duration that applied by attacker at victim - if(damageInfo->damage && spellProto->Id == 35395) + if(damageInfo->damage) { AuraMap& vAuras = pVictim->GetAuras(); for(AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr) @@ -1636,422 +1640,107 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss) } } } - // Call default DealDamage - CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss); -} - -//TODO for melee need create structure as in -void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType) -{ - damageInfo->attacker = this; - damageInfo->target = pVictim; - damageInfo->damageSchoolMask = GetMeleeDamageSchoolMask(); - damageInfo->attackType = attackType; - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - damageInfo->absorb = 0; - damageInfo->resist = 0; - damageInfo->blocked_amount = 0; - - damageInfo->TargetState = 0; - damageInfo->HitInfo = 0; - damageInfo->procAttacker = PROC_FLAG_NONE; - damageInfo->procVictim = PROC_FLAG_NONE; - damageInfo->procEx = PROC_EX_NONE; - damageInfo->hitOutCome = MELEE_HIT_EVADE; - if(!this || !pVictim) - return; - if(!this->isAlive() || !pVictim->isAlive()) - return; - - // Select HitInfo/procAttacker/procVictim flag based on attack type - switch (attackType) + // If not miss + if (!(damageInfo->HitInfo & HITINFO_MISS)) { - case BASE_ATTACK: - damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT; - damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT; - damageInfo->HitInfo = HITINFO_NORMALSWING2; - break; - case OFF_ATTACK: - damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT; - damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used - damageInfo->HitInfo = HITINFO_LEFTSWING; - break; - case RANGED_ATTACK: - damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT; - damageInfo->procVictim = PROC_FLAG_TAKEN_RANGED_HIT; - damageInfo->HitInfo = 0x08;// test - break; - default: - break; - } - - // Physical Immune check - if(damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask),true)) - { - damageInfo->HitInfo |= HITINFO_NORMALSWING; - damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE; - - damageInfo->procEx |=PROC_EX_IMMUNE; - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - return; - } - damage += CalculateDamage (damageInfo->attackType, false); - // Add melee damage bonus - MeleeDamageBonus(damageInfo->target, &damage, damageInfo->attackType); - // Calculate armor reduction - damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage); - damageInfo->cleanDamage += damage - damageInfo->damage; + if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive()) + { + for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) + ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i), pVictim, damageInfo->attackType); + } - damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType); + // victim's damage shield + std::set alreadyDone; + uint32 removedAuras = pVictim->m_removedAuras; + AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD); + for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next) + { + next++; + if (alreadyDone.find(*i) == alreadyDone.end()) + { + alreadyDone.insert(*i); + uint32 damage=(*i)->GetModifier()->m_amount; + SpellEntry const *spellProto = sSpellStore.LookupEntry((*i)->GetId()); + if(!spellProto) + continue; + //Calculate absorb resist ??? no data in opcode for this possibly unable to absorb or resist? + //uint32 absorb; + //uint32 resist; + //CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); + //damage-=absorb + resist; - // Disable parry or dodge for ranged attack - if(damageInfo->attackType == RANGED_ATTACK) - { - if (damageInfo->hitOutCome == MELEE_HIT_PARRY) damageInfo->hitOutCome = MELEE_HIT_NORMAL; - if (damageInfo->hitOutCome == MELEE_HIT_DODGE) damageInfo->hitOutCome = MELEE_HIT_MISS; - } + WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4+4+4)); + data << uint64(pVictim->GetGUID()); + data << uint64(GetGUID()); + data << uint32(spellProto->Id); + data << uint32(damage); // Damage + data << uint32(0); // Overkill + data << uint32(spellProto->SchoolMask); + pVictim->SendMessageToSet(&data, true ); - switch(damageInfo->hitOutCome) - { - case MELEE_HIT_EVADE: - { - damageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND; - damageInfo->TargetState = VICTIMSTATE_EVADES; + pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true); - damageInfo->procEx|=PROC_EX_EVADE; - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - return; + if (pVictim->m_removedAuras > removedAuras) + { + removedAuras = pVictim->m_removedAuras; + next = vDamageShields.begin(); + } + } } - case MELEE_HIT_MISS: - { - damageInfo->HitInfo |= HITINFO_MISS; - damageInfo->TargetState = VICTIMSTATE_NORMAL; + } +} - damageInfo->procEx|=PROC_EX_MISS; - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - break; - } - case MELEE_HIT_NORMAL: - damageInfo->TargetState = VICTIMSTATE_NORMAL; - damageInfo->procEx|=PROC_EX_NORMAL_HIT; - break; - case MELEE_HIT_CRIT: - { - damageInfo->HitInfo |= HITINFO_CRITICALHIT; - damageInfo->TargetState = VICTIMSTATE_NORMAL; - damageInfo->procEx|=PROC_EX_CRITICAL_HIT; - // Crit bonus calc - damageInfo->damage += damageInfo->damage; - int32 mod=0; - // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE - if(damageInfo->attackType == RANGED_ATTACK) - mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); - else - { - mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); - mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE); - } +void Unit::HandleEmoteCommand(uint32 anim_id) +{ + WorldPacket data( SMSG_EMOTE, 12 ); + data << uint32(anim_id); + data << uint64(GetGUID()); + SendMessageToSet(&data, true); +} - uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask(); +uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage) +{ + uint32 newdamage = 0; + float armor = pVictim->GetArmor(); + // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura + armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); - // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS - mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask); - if (mod!=0) - damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod)/100.0f)); + // Apply Player CR_ARMOR_PENETRATION rating + if (GetTypeId()==TYPEID_PLAYER) + armor *= 1.0f - ((Player*)this)->GetRatingBonusValue(CR_ARMOR_PENETRATION) / 100.0f; - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - { - uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(damageInfo->damage); - damageInfo->damage -= resilienceReduction; - damageInfo->cleanDamage += resilienceReduction; - } - break; - } - case MELEE_HIT_PARRY: - damageInfo->TargetState = VICTIMSTATE_PARRY; - damageInfo->procEx|=PROC_EX_PARRY; - damageInfo->cleanDamage += damageInfo->damage; - damageInfo->damage = 0; - break; + if (armor < 0.0f) armor=0.0f; - case MELEE_HIT_DODGE: - damageInfo->TargetState = VICTIMSTATE_DODGE; - damageInfo->procEx|=PROC_EX_DODGE; - damageInfo->cleanDamage += damageInfo->damage; - damageInfo->damage = 0; - break; - case MELEE_HIT_BLOCK: - { - damageInfo->TargetState = VICTIMSTATE_NORMAL; - damageInfo->procEx|=PROC_EX_BLOCK; - damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue(); - if (damageInfo->blocked_amount >= damageInfo->damage) - { - damageInfo->TargetState = VICTIMSTATE_BLOCKS; - damageInfo->blocked_amount = damageInfo->damage; - } - damageInfo->damage -= damageInfo->blocked_amount; - damageInfo->cleanDamage += damageInfo->blocked_amount; - break; - } - case MELEE_HIT_GLANCING: - { - damageInfo->HitInfo |= HITINFO_GLANCING; - damageInfo->TargetState = VICTIMSTATE_NORMAL; - damageInfo->procEx|=PROC_EX_NORMAL_HIT; - int32 leveldif = int32(pVictim->getLevel()) - int32(getLevel()); - if (leveldif > 3) leveldif = 3; - float reducePercent = 1 - leveldif * 0.1f; - damageInfo->cleanDamage += damageInfo->damage-uint32(reducePercent * damageInfo->damage); - damageInfo->damage = uint32(reducePercent * damageInfo->damage); - break; - } - case MELEE_HIT_CRUSHING: - { - damageInfo->HitInfo |= HITINFO_CRUSHING; - damageInfo->TargetState = VICTIMSTATE_NORMAL; - damageInfo->procEx|=PROC_EX_NORMAL_HIT; - // 150% normal damage - damageInfo->damage += (damageInfo->damage / 2); - break; - } - default: + float levelModifier = getLevel(); + if ( levelModifier > 59 ) + levelModifier = levelModifier + (4.5f * (levelModifier-59)); - break; - } + float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40); + tmpvalue = tmpvalue/(1.0f + tmpvalue); - // Calculate absorb resist - if(int32(damageInfo->damage) > 0) - { - damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE; - // Calculate absorb & resists - CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist); - damageInfo->damage-=damageInfo->absorb + damageInfo->resist; - if (damageInfo->absorb) - { - damageInfo->HitInfo|=HITINFO_ABSORB; - damageInfo->procEx|=PROC_EX_ABSORB; - } - if (damageInfo->resist) - damageInfo->HitInfo|=HITINFO_RESIST; + if(tmpvalue < 0.0f) + tmpvalue = 0.0f; + if(tmpvalue > 0.75f) + tmpvalue = 0.75f; + newdamage = uint32(damage - (damage * tmpvalue)); - } - else // Umpossible get negative result but.... - damageInfo->damage = 0; + return (newdamage > 1) ? newdamage : 1; } -void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) +void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist) { - if (damageInfo==0) return; - Unit *pVictim = damageInfo->target; - - if(!this || !pVictim) - return; - - if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + if(!pVictim || !pVictim->isAlive() || !damage) return; - //You don't lose health from damage taken from another player while in a sanctuary - //You still see it in the combat log though - if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + // Magic damage, check for resists + if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL)==0) { - const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); - if(area && area->flags & 0x800) //sanctuary - return; - } - - // Hmmmm dont like this emotes cloent must by self do all animations - if (damageInfo->HitInfo&HITINFO_CRITICALHIT) - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL); - if(damageInfo->blocked_amount && damageInfo->TargetState!=VICTIMSTATE_BLOCKS) - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); - - if(damageInfo->TargetState == VICTIMSTATE_PARRY) - { - // Get attack timers - float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); - float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); - // Reduce attack time - if (pVictim->haveOffhandWeapon() && offtime < basetime) - { - float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20; - float percent60 = 3 * percent20; - if(offtime > percent20 && offtime <= percent60) - { - pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20)); - } - else if(offtime > percent60) - { - offtime -= 2 * percent20; - pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime)); - } - } - else - { - float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20; - float percent60 = 3 * percent20; - if(basetime > percent20 && basetime <= percent60) - { - pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20)); - } - else if(basetime > percent60) - { - basetime -= 2 * percent20; - pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime)); - } - } - } - - // Call default DealDamage - CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->attackType,damageInfo->hitOutCome); - DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss); - - // If this is a creature and it attacks from behind it has a probability to daze it's victim - if( (damageInfo->hitOutCome==MELEE_HIT_CRIT || damageInfo->hitOutCome==MELEE_HIT_CRUSHING || damageInfo->hitOutCome==MELEE_HIT_NORMAL || damageInfo->hitOutCome==MELEE_HIT_GLANCING) && - GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) ) - { - // -probability is between 0% and 40% - // 20% base chance - float Probability = 20; - - //there is a newbie protection, at level 10 just 7% base chance; assuming linear function - if( pVictim->getLevel() < 30 ) - Probability = 0.65f*pVictim->getLevel()+0.5; - - uint32 VictimDefense=pVictim->GetDefenseSkillValue(); - uint32 AttackerMeleeSkill=GetUnitMeleeSkill(); - - Probability *= AttackerMeleeSkill/(float)VictimDefense; - - if(Probability > 40) - Probability = 40; - - if(roll_chance_f(Probability)) - CastSpell(pVictim, 1604, true); - } - - // update at damage Judgement aura duration that applied by attacker at victim - if(damageInfo->damage) - { - AuraMap& vAuras = pVictim->GetAuras(); - for(AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr) - { - SpellEntry const *spellInfo = (*itr).second->GetSpellProto(); - if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID())) - { - (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration()); - (*itr).second->SendAuraUpdate(false); - } - } - } - - // If not miss - if (!(damageInfo->HitInfo & HITINFO_MISS)) - { - if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive()) - { - for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) - ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i), pVictim, damageInfo->attackType); - } - - // victim's damage shield - std::set alreadyDone; - uint32 removedAuras = pVictim->m_removedAuras; - AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD); - for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next) - { - next++; - if (alreadyDone.find(*i) == alreadyDone.end()) - { - alreadyDone.insert(*i); - uint32 damage=(*i)->GetModifier()->m_amount; - SpellEntry const *spellProto = sSpellStore.LookupEntry((*i)->GetId()); - if(!spellProto) - continue; - //Calculate absorb resist ??? no data in opcode for this possibly unable to absorb or resist? - //uint32 absorb; - //uint32 resist; - //CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - //damage-=absorb + resist; - - WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4)); - data << uint64(pVictim->GetGUID()); - data << uint64(GetGUID()); - data << uint32(spellProto->SchoolMask); - data << uint32(damage); - pVictim->SendMessageToSet(&data, true ); - - pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true); - - if (pVictim->m_removedAuras > removedAuras) - { - removedAuras = pVictim->m_removedAuras; - next = vDamageShields.begin(); - } - } - } - } -} - - -void Unit::HandleEmoteCommand(uint32 anim_id) -{ - WorldPacket data( SMSG_EMOTE, 12 ); - data << anim_id << GetGUID(); - WPAssert(data.size() == 12); - - SendMessageToSet(&data, true); -} - -uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage) -{ - uint32 newdamage = 0; - float armor = pVictim->GetArmor(); - // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura - armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); - - // Apply Player CR_ARMOR_PENETRATION rating - if (GetTypeId()==TYPEID_PLAYER) - armor *= 1.0f - ((Player*)this)->GetRatingBonusValue(CR_ARMOR_PENETRATION) / 100.0f; - - if (armor < 0.0f) armor=0.0f; - - float levelModifier = getLevel(); - if ( levelModifier > 59 ) - levelModifier = levelModifier + (4.5f * (levelModifier-59)); - - float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40); - tmpvalue = tmpvalue/(1.0f + tmpvalue); - - if(tmpvalue < 0.0f) - tmpvalue = 0.0f; - if(tmpvalue > 0.75f) - tmpvalue = 0.75f; - newdamage = uint32(damage - (damage * tmpvalue)); - - return (newdamage > 1) ? newdamage : 1; -} - -void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist) -{ - if(!pVictim || !pVictim->isAlive() || !damage) - return; - - // Magic damage, check for resists - if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL)==0) - { - // Get base victim resistance for school - float tmpvalue2 = (float)pVictim->GetResistance(GetFirstSchoolInMask(schoolMask)); - // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura - tmpvalue2 += (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask); + // Get base victim resistance for school + float tmpvalue2 = (float)pVictim->GetResistance(GetFirstSchoolInMask(schoolMask)); + // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura + tmpvalue2 += (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask); tmpvalue2 *= (float)(0.15f / getLevel()); if (tmpvalue2 < 0.0f) @@ -2116,7 +1805,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe int32 currentAbsorb; - //Reflective Shield + // Reflective Shield if ((pVictim != this) && (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && (*i)->GetSpellProto()->SpellFamilyFlags == 0x1) { if(Unit* caster = (*i)->GetCaster()) @@ -2262,1271 +1951,771 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe *absorb = damage - RemainingDamage - *resist; } -/* -void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell) +void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra ) { - MeleeHitOutcome outcome; - - // If is casted Melee spell, calculate like physical - if(!spellCasted) - outcome = RollMeleeOutcomeAgainst (pVictim, attType); - else - outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted); - - if(outcome == MELEE_HIT_MISS ||outcome == MELEE_HIT_DODGE ||outcome == MELEE_HIT_BLOCK ||outcome == MELEE_HIT_PARRY) - pVictim->AddThreat(this, 0.0f); - switch(outcome) - { - case MELEE_HIT_EVADE: - { - *hitInfo |= HITINFO_MISS; - *damage = 0; - cleanDamage->damage = 0; - return; - } - case MELEE_HIT_MISS: - { - *hitInfo |= HITINFO_MISS; - *damage = 0; - cleanDamage->damage = 0; - if(GetTypeId()== TYPEID_PLAYER) - ((Player*)this)->UpdateWeaponSkill(attType); - return; - } - } - - /// If this is a creature and it attacks from behind it has a probability to daze it's victim - if( (outcome==MELEE_HIT_CRIT || outcome==MELEE_HIT_CRUSHING || outcome==MELEE_HIT_NORMAL || outcome==MELEE_HIT_GLANCING) && - GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) - && pVictim->GetTypeId() == TYPEID_PLAYER) - { - // -probability is between 0% and 40% - // 20% base chance - float Probability = 20; - - //there is a newbie protection, at level 10 just 7% base chance; assuming linear function - if( pVictim->getLevel() < 30 ) - Probability = 0.65f*pVictim->getLevel()+0.5; + if(hasUnitState(UNIT_STAT_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) ) + return; - uint32 VictimDefense=pVictim->GetDefenseSkillValue(this); - uint32 AttackerMeleeSkill=GetUnitMeleeSkill(pVictim); + if (!pVictim->isAlive()) + return; - Probability *= AttackerMeleeSkill/(float)VictimDefense; + CombatStart(pVictim); + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ATTACK); - if(Probability > 40.0f) - Probability = 40.0f; + uint32 hitInfo; + if (attType == BASE_ATTACK) + hitInfo = HITINFO_NORMALSWING2; + else if (attType == OFF_ATTACK) + hitInfo = HITINFO_LEFTSWING; + else + return; // ignore ranged case - if(roll_chance_f(Probability)) - CastSpell(pVictim, 1604, true); - } + uint32 extraAttacks = m_extraAttacks; - //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL - if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) + // melee attack spell casted at main hand attack only + if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL]) { - uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage); + m_currentSpells[CURRENT_MELEE_SPELL]->cast(); - // random durability for main hand weapon (ABSORB) - if(damageAfterArmor < *damage) - if(pVictim->GetTypeId() == TYPEID_PLAYER) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK))); + // not recent extra attack only at any non extra attack (melee spell case) + if(!extra && extraAttacks) + { + while(m_extraAttacks) + { + AttackerStateUpdate(pVictim, BASE_ATTACK, true); + if(m_extraAttacks > 0) + --m_extraAttacks; + } + } - cleanDamage->damage += *damage - damageAfterArmor; - *damage = damageAfterArmor; + return; } - if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER ) - ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false); + CalcDamageInfo damageInfo; + CalculateMeleeDamage(pVictim, 0, &damageInfo, attType); + // Send log damage message to client + SendAttackStateUpdate(&damageInfo); + ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType); + DealMeleeDamage(&damageInfo,true); - if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true); + if (GetTypeId() == TYPEID_PLAYER) + DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", + GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); + else + DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", + GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); - switch (outcome) + // extra attack only at any non extra attack (normal case) + if(!extra && extraAttacks) { - case MELEE_HIT_BLOCK_CRIT: - case MELEE_HIT_CRIT: + while(m_extraAttacks) { - *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | HITINFO_UNK2; + AttackerStateUpdate(pVictim, BASE_ATTACK, true); + if(m_extraAttacks > 0) + --m_extraAttacks; + } + } +} - // Crit bonus calc - uint32 crit_bonus; - crit_bonus = *damage; +MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackType attType) const +{ + // This is only wrapper - // Apply crit_damage bonus for melee spells - if (spellCasted) - { - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellCasted->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); + // Miss chance based on melee + //float miss_chance = MeleeMissChanceCalc(pVictim, attType); + float miss_chance = MeleeSpellMissChance(pVictim, attType, int32(GetWeaponSkillValue(attType,pVictim)) - int32(pVictim->GetDefenseSkillValue(this)), 0); - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS); - for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i) - if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) - crit_bonus = uint32(crit_bonus * ((*i)->GetModifierValue()+100.0f)/100.0f); - } - - *damage += crit_bonus; - - uint32 resilienceReduction = 0; - - if(attType == RANGED_ATTACK) - { - int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); - *damage = int32((*damage) * float((100.0f + mod)/100.0f)); - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - resilienceReduction = ((Player*)pVictim)->GetRangedCritDamageReduction(*damage); - } - else - { - int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); - mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE); - *damage = int32((*damage) * float((100.0f + mod)/100.0f)); - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage); - } - - *damage -= resilienceReduction; - cleanDamage->damage += resilienceReduction; - - if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER ) - ((Player*)this)->UpdateWeaponSkill(attType); - - ModifyAuraState(AURA_STATE_CRIT, true); - StartReactiveTimer( REACTIVE_CRIT ); - - if(getClass()==CLASS_HUNTER) - { - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true); - StartReactiveTimer( REACTIVE_HUNTER_CRIT ); - } + // Critical hit chance + float crit_chance = GetUnitCriticalChance(attType, pVictim); - if ( outcome == MELEE_HIT_BLOCK_CRIT ) - { - *blocked_amount = pVictim->GetShieldBlockValue(); + // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case) + float dodge_chance = pVictim->GetUnitDodgeChance(); + float block_chance = pVictim->GetUnitBlockChance(); + float parry_chance = pVictim->GetUnitParryChance(); - if (pVictim->GetUnitBlockChance()) - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); - else - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + // Useful if want to specify crit & miss chances for melee, else it could be removed + DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance,crit_chance,dodge_chance,parry_chance,block_chance); - //Only set VICTIMSTATE_BLOCK on a full block - if (*blocked_amount >= uint32(*damage)) - { - *victimState = VICTIMSTATE_BLOCKS; - *blocked_amount = uint32(*damage); - } + return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), false); +} - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); +MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const +{ + if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + return MELEE_HIT_EVADE; - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } + int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(pVictim); + int32 victimMaxSkillValueForLevel = pVictim->GetMaxSkillValueForLevel(this); - pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - break; - } + int32 attackerWeaponSkill = GetWeaponSkillValue(attType,pVictim); + int32 victimDefenseSkill = pVictim->GetDefenseSkillValue(this); - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL); - break; - } - case MELEE_HIT_PARRY: - { - if(attType == RANGED_ATTACK) //range attack - no parry - { - outcome = MELEE_HIT_NORMAL; - break; - } + // bonus from skills is 0.04% + int32 skillBonus = 4 * ( attackerWeaponSkill - victimMaxSkillValueForLevel ); + int32 skillBonus2 = 4 * ( attackerMaxSkillValueForLevel - victimDefenseSkill ); + int32 sum = 0, tmp = 0; + int32 roll = urand (0, 10000); - cleanDamage->damage += *damage; - *damage = 0; - *victimState = VICTIMSTATE_PARRY; + DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus); + DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d", + roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance); - // instant (maybe with small delay) counter attack - { - float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); - float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); + tmp = miss_chance; - // after parry nearest next attack time will reduced at %40 from full attack time. - // The delay cannot be reduced to less than 20% of your weapon base swing delay. - if (pVictim->haveOffhandWeapon() && offtime < basetime) - { - float percent20 = pVictim->GetAttackTime(OFF_ATTACK)*0.20; - float percent60 = 3*percent20; - // set to 20% if in range 20%...20+40% of full time - if(offtime > percent20 && offtime <= percent60) - { - pVictim->setAttackTimer(OFF_ATTACK,uint32(percent20)); - } - // decrease at %40 from full time - else if(offtime > percent60) - { - offtime -= 2*percent20; - pVictim->setAttackTimer(OFF_ATTACK,uint32(offtime)); - } - // ELSE not changed - } - else - { - float percent20 = pVictim->GetAttackTime(BASE_ATTACK)*0.20; - float percent60 = 3*percent20; - // set to 20% if in range 20%...20+40% of full time - if(basetime > percent20 && basetime <= percent60) - { - pVictim->setAttackTimer(BASE_ATTACK,uint32(percent20)); - } - // decrease at %40 from full time - else if(basetime > percent60) - { - basetime -= 2*percent20; - pVictim->setAttackTimer(BASE_ATTACK,uint32(basetime)); - } - // ELSE not changed - } - } + if (tmp > 0 && roll < (sum += tmp )) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS"); + return MELEE_HIT_MISS; + } - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update victim defense ? - ((Player*)pVictim)->UpdateDefense(); + // always crit against a sitting target (except 0 crit chance) + if( pVictim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !pVictim->IsStandState() ) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)"); + return MELEE_HIT_CRIT; + } - // random durability for main hand weapon (PARRY) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND); - } + // Dodge chance - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + // only players can't dodge if attacker is behind + if (pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->HasInArc(M_PI,this)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player."); + } + else + { + // Reduce dodge chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + dodge_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100); - if (pVictim->getClass() == CLASS_HUNTER) - { - pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); - pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); - } - else - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } + // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE + dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); - CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - return; - } - case MELEE_HIT_DODGE: + tmp = dodge_chance; + if ( (tmp > 0) // check if unit _can_ dodge + && ((tmp -= skillBonus) > 0) + && roll < (sum += tmp)) { - if(attType == RANGED_ATTACK) //range attack - no dodge - { - outcome = MELEE_HIT_NORMAL; - break; - } - - cleanDamage->damage += *damage; - *damage = 0; - *victimState = VICTIMSTATE_DODGE; - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateDefense(); - - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - if (pVictim->getClass() != CLASS_ROGUE) // Riposte - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - - // Overpower - if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) - { - ((Player*)this)->AddComboPoints(pVictim, 1); - StartReactiveTimer( REACTIVE_OVERPOWER ); - } - - CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - return; + DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum); + return MELEE_HIT_DODGE; } - case MELEE_HIT_BLOCK: - { - *blocked_amount = pVictim->GetShieldBlockValue(); + } - if (pVictim->GetUnitBlockChance()) - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); - else - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + // parry & block chances - //Only set VICTIMSTATE_BLOCK on a full block - if (*blocked_amount >= uint32(*damage)) - { - *victimState = VICTIMSTATE_BLOCKS; - *blocked_amount = uint32(*damage); - } + // check if attack comes from behind, nobody can parry or block if attacker is behind + if (!pVictim->HasInArc(M_PI,this)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind."); + } + else + { + // Reduce parry chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + parry_chance-= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100); - if(pVictim->GetTypeId() == TYPEID_PLAYER) + if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY) ) + { + int32 tmp = int32(parry_chance); + if ( (tmp > 0) // check if unit _can_ parry + && ((tmp -= skillBonus) > 0) + && (roll < (sum += tmp))) { - // Update defense - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); + DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum); + return MELEE_HIT_PARRY; } - - pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - - break; } - case MELEE_HIT_GLANCING: - { -<<<<<<< HEAD:src/game/Unit.cpp - int32 leveldif = int32(pVictim->getLevel()) - int32(getLevel()); - if (leveldif > 3) leveldif = 3; - *damage *= (1 - leveldif * 0.1f); - cleanDamage->damage = *damage; -======= - float reducePercent = 1.0f; //damage factor - - // calculate base values and mods - float baseLowEnd = 1.3; - float baseHighEnd = 1.2; - switch(getClass()) // lowering base values for casters - { - case CLASS_SHAMAN: - case CLASS_PRIEST: - case CLASS_MAGE: - case CLASS_WARLOCK: - case CLASS_DRUID: - baseLowEnd -= 0.7; - baseHighEnd -= 0.3; - break; - } - float maxLowEnd = 0.6; - switch(getClass()) // upper for melee classes + if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK) ) + { + tmp = block_chance; + if ( (tmp > 0) // check if unit _can_ block + && ((tmp -= skillBonus) > 0) + && (roll < (sum += tmp))) { - case CLASS_WARRIOR: - case CLASS_ROGUE: - case CLASS_DEATH_KNIGHT: - maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91 + // Critical chance + tmp = crit_chance + skillBonus2; + if ( GetTypeId() == TYPEID_PLAYER && SpellCasted && tmp > 0 ) + { + if ( roll_chance_i(tmp/100)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT"); + return MELEE_HIT_BLOCK_CRIT; + } + } + DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum); + return MELEE_HIT_BLOCK; } - - // calculate values - int32 diff = int32(pVictim->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType,pVictim)); - float lowEnd = baseLowEnd - ( 0.05f * diff ); - float highEnd = baseHighEnd - ( 0.03f * diff ); - - // apply max/min bounds - if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f - lowEnd = 0.01f; - else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end - lowEnd = maxLowEnd; - - if ( highEnd < 0.2f ) //high end limits - highEnd = 0.2f; - if ( highEnd > 0.99f ) - highEnd = 0.99f; - - if(lowEnd > highEnd) // prevent negative range size - lowEnd = highEnd; - - reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd ); - - *damage = uint32(reducePercent * *damage); - cleanDamage->damage += *damage; ->>>>>>> upstream/master:src/game/Unit.cpp - *hitInfo |= HITINFO_GLANCING; - break; - } - case MELEE_HIT_CRUSHING: - { - // 150% normal damage - *damage += (*damage / 2); - cleanDamage->damage = *damage; - *hitInfo |= HITINFO_CRUSHING; - // TODO: victimState, victim animation? - break; } - default: - break; - } - - // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block - if(*victimState != VICTIMSTATE_BLOCKS) - { - MeleeDamageBonus(pVictim, damage,attType,spellCasted); - CalcAbsorbResist(pVictim, damageSchoolMask, DIRECT_DAMAGE, *damage-*blocked_amount, absorbDamage, resistDamage); } - if (*absorbDamage) *hitInfo |= HITINFO_ABSORB; - if (*resistDamage) *hitInfo |= HITINFO_RESIST; - - cleanDamage->damage += *blocked_amount; + // Critical chance + tmp = crit_chance + skillBonus2; - if (*damage <= *absorbDamage + *resistDamage + *blocked_amount) + if (tmp > 0 && roll < (sum += tmp)) { - //*hitInfo = 0x00010020; - //*hitInfo |= HITINFO_SWINGNOHITSOUND; - //*damageType = 0; - CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - return; + DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum); + return MELEE_HIT_CRIT; } - // update at damage Judgement aura duration that applied by attacker at victim - if(*damage) + // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon) + if( attType != RANGED_ATTACK && !SpellCasted && + (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet()) && + pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->isPet() && + getLevel() < pVictim->getLevelForTarget(this) ) { - AuraMap const& vAuras = pVictim->GetAuras(); - for(AuraMap::const_iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr) + // cap possible value (with bonuses > max skill) + int32 skill = attackerWeaponSkill; + int32 maxskill = attackerMaxSkillValueForLevel; + skill = (skill > maxskill) ? maxskill : skill; + + tmp = (10 + (victimDefenseSkill - skill)) * 100; + tmp = tmp > 4000 ? 4000 : tmp; + if (roll < (sum += tmp)) { - SpellEntry const *spellInfo = (*itr).second->GetSpellProto(); - if( (spellInfo->AttributesEx3 & 0x40000) && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && - ((*itr).second->GetCasterGUID() == GetGUID() && (!spellCasted || spellCasted->Id == 35395)) ) - { - (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration()); - (*itr).second->SendAuraUpdate(false); - } + DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum); + return MELEE_HIT_GLANCING; } } - CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);eld - // yet another hack to fix crashes related to the aura getting removed during iteration - std::set alreadyDone; - uint32 removedAuras = pVictim->m_removedAuras; - AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD); - for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next) + if(GetTypeId()!=TYPEID_PLAYER && !(((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH) && !((Creature*)this)->isPet() && !SpellCasted /*Only autoattack can be crushing blow*/ ) { - ++next; - if (alreadyDone.find(*i) == alreadyDone.end()) + // mobs can score crushing blows if they're 3 or more levels above victim + // or when their weapon skill is 15 or more above victim's defense skill + tmp = victimDefenseSkill; + int32 tmpmax = victimMaxSkillValueForLevel; + // having defense above your maximum (from items, talents etc.) has no effect + tmp = tmp > tmpmax ? tmpmax : tmp; + // tmp = mob's level * 5 - player's current defense skill + tmp = attackerMaxSkillValueForLevel - tmp; + if(tmp >= 15) { - alreadyDone.insert(*i); - pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifierValue(), false, false); - if (pVictim->m_removedAuras > removedAuras) + // add 2% chance per lacking skill point, min. is 15% + tmp = tmp * 200 - 1500; + if (roll < (sum += tmp)) { - removedAuras = pVictim->m_removedAuras; - next = vDamageShields.begin(); + DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum); + return MELEE_HIT_CRUSHING; } } } -}*/ -void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra ) -{ - if(hasUnitState(UNIT_STAT_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) ) - return; + DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL"); + return MELEE_HIT_NORMAL; +} - if (!pVictim->isAlive()) - return; - - CombatStart(pVictim); - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ATTACK); +uint32 Unit::CalculateDamage (WeaponAttackType attType, bool normalized) +{ + float min_damage, max_damage; - uint32 hitInfo; - if (attType == BASE_ATTACK) - hitInfo = HITINFO_NORMALSWING2; - else if (attType == OFF_ATTACK) - hitInfo = HITINFO_LEFTSWING; + if (normalized && GetTypeId()==TYPEID_PLAYER) + ((Player*)this)->CalculateMinMaxDamage(attType,normalized,min_damage, max_damage); else - return; // ignore ranged case - - uint32 extraAttacks = m_extraAttacks; - - // melee attack spell casted at main hand attack only - if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL]) { - m_currentSpells[CURRENT_MELEE_SPELL]->cast(); - - // not recent extra attack only at any non extra attack (melee spell case) - if(!extra && extraAttacks) + switch (attType) { - while(m_extraAttacks) - { - AttackerStateUpdate(pVictim, BASE_ATTACK, true); - if(m_extraAttacks > 0) - --m_extraAttacks; - } + case RANGED_ATTACK: + min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE); + max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE); + break; + case BASE_ATTACK: + min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE); + max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE); + break; + case OFF_ATTACK: + min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE); + max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE); + break; + // Just for good manner + default: + min_damage = 0.0f; + max_damage = 0.0f; + break; } + } - return; + if (min_damage > max_damage) + { + std::swap(min_damage,max_damage); } - CalcDamageInfo damageInfo; - CalculateMeleeDamage(pVictim, 0, &damageInfo, attType); - // Send log damage message to client - SendAttackStateUpdate(&damageInfo); - ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType); - DealMeleeDamage(&damageInfo,true); + if(max_damage == 0.0f) + max_damage = 5.0f; - if (GetTypeId() == TYPEID_PLAYER) - DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", - GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); - else - DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", - GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); + return urand((uint32)min_damage, (uint32)max_damage); +} - // extra attack only at any non extra attack (normal case) - if(!extra && extraAttacks) - { - while(m_extraAttacks) - { - AttackerStateUpdate(pVictim, BASE_ATTACK, true); - if(m_extraAttacks > 0) - --m_extraAttacks; - } - } +float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const +{ + if(spellProto->spellLevel <= 0) + return 1.0f; + + float LvlPenalty = 0.0f; + + if(spellProto->spellLevel < 20) + LvlPenalty = 20.0f - spellProto->spellLevel * 3.75f; + float LvlFactor = (float(spellProto->spellLevel) + 6.0f) / float(getLevel()); + if(LvlFactor > 1.0f) + LvlFactor = 1.0f; + + return (100.0f - LvlPenalty) * LvlFactor / 100.0f; } -/* -MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo) +void Unit::SendAttackStart(Unit* pVictim) { - // Miss chance based on melee - float miss_chance = MeleeMissChanceCalc(pVictim, attType); + WorldPacket data( SMSG_ATTACKSTART, 16 ); + data << uint64(GetGUID()); + data << uint64(pVictim->GetGUID()); - // Critical hit chance - float crit_chance = GetUnitCriticalChance(attType, pVictim); - // this is to avoid compiler issue when declaring variables inside if - float block_chance, parry_chance, dodge_chance; + SendMessageToSet(&data, true); + DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" ); +} - // cannot be dodged/parried/blocked - if(spellInfo->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) - { - block_chance = 0.0f; - parry_chance = 0.0f; - dodge_chance = 0.0f; - } - else - { - // parry can be avoided only by some abilities - parry_chance = pVictim->GetUnitParryChance(); - // block might be bypassed by it as well - block_chance = pVictim->GetUnitBlockChance(); - // stunned target cannot dodge and this is check in GetUnitDodgeChance() - dodge_chance = pVictim->GetUnitDodgeChance(); - } +void Unit::SendAttackStop(Unit* victim) +{ + if(!victim) + return; - // Only players can have Talent&Spell bonuses - if (GetTypeId() == TYPEID_PLAYER) + WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size + data.append(GetPackGUID()); + data.append(victim->GetPackGUID()); // can be 0x00... + data << uint32(0); // can be 0x1 + SendMessageToSet(&data, true); + sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow()); + + /*if(victim->GetTypeId() == TYPEID_UNIT) + ((Creature*)victim)->AI().EnterEvadeMode(this);*/ +} + +bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAttackType attackType) +{ + if (pVictim->HasInArc(M_PI,this)) { - // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura - crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, spellInfo->SchoolMask); - // Ignore combat result aura + // Ignore combat result aura (parry/dodge check on prepare) AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); for(AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) { - if (!(*i)->isAffectedOnSpell(spellInfo)) + if (!(*i)->isAffectedOnSpell(spellProto)) continue; - switch((*i)->GetModifier()->m_miscvalue) - { - case MELEE_HIT_DODGE: dodge_chance = 0.0f; break; - case MELEE_HIT_BLOCK: block_chance = 0.0f; break; - case MELEE_HIT_PARRY: parry_chance = 0.0f; break; - default: - DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetModifier()->m_miscvalue); - break; - } + if ((*i)->GetModifier()->m_miscvalue == MELEE_HIT_BLOCK) + return false; } + float blockChance = GetUnitBlockChance(); + blockChance += (GetWeaponSkillValue(attackType) - pVictim->GetMaxSkillValueForLevel() )*0.04; + if (roll_chance_f(blockChance)) + return true; } + return false; +} - // Spellmods - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); - - DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance,crit_chance,dodge_chance,parry_chance, block_chance); +// Melee based spells can be miss, parry or dodge on this step +// Crit or block - determined on damage calculation phase! (and can be both in some time) +/*float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell) +{ + // Calculate hit chance (more correct for chance mod) + int32 HitChance; - return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100),int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), true); -}*/ + // PvP - PvE melee chances + int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; + int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim); + if(leveldif < 3) + HitChance = 95 - leveldif; + else + HitChance = 93 - (leveldif - 2) * lchance; -MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackType attType) const -{ - // This is only wrapper + // Hit chance depends from victim auras + if(attType == RANGED_ATTACK) + HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); + else + HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); - // Miss chance based on melee - //float miss_chance = MeleeMissChanceCalc(pVictim, attType); - float miss_chance = MeleeSpellMissChance(pVictim, attType, int32(GetWeaponSkillValue(attType,pVictim)) - int32(pVictim->GetDefenseSkillValue(this)), 0); + // Spellmod from SPELLMOD_RESIST_MISS_CHANCE + if(Player *modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance); - // Critical hit chance - float crit_chance = GetUnitCriticalChance(attType, pVictim); + // Miss = 100 - hit + float miss_chance= 100.0f - HitChance; - // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case) - float dodge_chance = pVictim->GetUnitDodgeChance(); - float block_chance = pVictim->GetUnitBlockChance(); - float parry_chance = pVictim->GetUnitParryChance(); + // Bonuses from attacker aura and ratings + if (attType == RANGED_ATTACK) + miss_chance -= m_modRangedHitChance; + else + miss_chance -= m_modMeleeHitChance; - // Useful if want to specify crit & miss chances for melee, else it could be removed - DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance,crit_chance,dodge_chance,parry_chance,block_chance); + // bonus from skills is 0.04% + miss_chance -= skillDiff * 0.04f; - return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), false); -} + // Limit miss chance from 0 to 60% + if (miss_chance < 0.0f) + return 0.0f; + if (miss_chance > 60.0f) + return 60.0f; + return miss_chance; +}*/ -MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const +// Melee based spells hit result calculations +SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) { - if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) - return MELEE_HIT_EVADE; + WeaponAttackType attType = BASE_ATTACK; - int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(pVictim); - int32 victimMaxSkillValueForLevel = pVictim->GetMaxSkillValueForLevel(this); + if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED) + attType = RANGED_ATTACK; - int32 attackerWeaponSkill = GetWeaponSkillValue(attType,pVictim); - int32 victimDefenseSkill = pVictim->GetDefenseSkillValue(this); + // bonus from skills is 0.04% per skill Diff + int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim)); + int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this)); + int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this)); - // bonus from skills is 0.04% - int32 skillBonus = 4 * ( attackerWeaponSkill - victimMaxSkillValueForLevel ); - int32 skillBonus2 = 4 * ( attackerMaxSkillValueForLevel - victimDefenseSkill ); - int32 sum = 0, tmp = 0; - int32 roll = urand (0, 10000); + uint32 roll = urand (0, 10000); - DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus); - DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d", - roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance); + uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell->Id)*100.0f); + // Roll miss + uint32 tmp = missChance; + if (roll < tmp) + return SPELL_MISS_MISS; - tmp = miss_chance; + bool canDodge = true; + bool canParry = true; - if (tmp > 0 && roll < (sum += tmp )) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS"); - return MELEE_HIT_MISS; - } + // Same spells cannot be parry/dodge + if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) + return SPELL_MISS_NONE; - // always crit against a sitting target (except 0 crit chance) - if( pVictim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !pVictim->IsStandState() ) + // Ranged attack cannot be parry/dodge + if (attType == RANGED_ATTACK) + return SPELL_MISS_NONE; + + // Check for attack from behind + if (!pVictim->HasInArc(M_PI,this)) { - DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)"); - return MELEE_HIT_CRIT; + // Can`t dodge from behind in PvP (but its possible in PvE) + if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + canDodge = false; + // Can`t parry + canParry = false; } - // Dodge chance - - // only players can't dodge if attacker is behind - if (pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->HasInArc(M_PI,this)) + // Ignore combat result aura + AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); + for(AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) { - DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player."); + if (!(*i)->isAffectedOnSpell(spell)) + continue; + switch((*i)->GetModifier()->m_miscvalue) + { + case MELEE_HIT_DODGE: canDodge = false; break; + case MELEE_HIT_BLOCK: break; // Block check in hit step + case MELEE_HIT_PARRY: canParry = false; break; + default: + DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetModifier()->m_miscvalue); + break; + } } - else + + if (canDodge) { + // Roll dodge + int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4; + // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE + dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); // Reduce dodge chance by attacker expertise rating if (GetTypeId() == TYPEID_PLAYER) - dodge_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100); + dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); + if (dodgeChance < 0) + dodgeChance = 0; - // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE - dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); + tmp += dodgeChance; + if (roll < tmp) + return SPELL_MISS_DODGE; + } - tmp = dodge_chance; - if ( (tmp > 0) // check if unit _can_ dodge - && ((tmp -= skillBonus) > 0) - && roll < (sum += tmp)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum); - return MELEE_HIT_DODGE; - } - } - - // parry & block chances - - // check if attack comes from behind, nobody can parry or block if attacker is behind - if (!pVictim->HasInArc(M_PI,this)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind."); - } - else + if (canParry) { + // Roll parry + int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4; // Reduce parry chance by attacker expertise rating if (GetTypeId() == TYPEID_PLAYER) - parry_chance-= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100); - - if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY) ) - { - int32 tmp = int32(parry_chance); - if ( (tmp > 0) // check if unit _can_ parry - && ((tmp -= skillBonus) > 0) - && (roll < (sum += tmp))) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum); - return MELEE_HIT_PARRY; - } - } + parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); + if (parryChance < 0) + parryChance = 0; - if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK) ) - { - tmp = block_chance; - if ( (tmp > 0) // check if unit _can_ block - && ((tmp -= skillBonus) > 0) - && (roll < (sum += tmp))) - { - // Critical chance - tmp = crit_chance + skillBonus2; - if ( GetTypeId() == TYPEID_PLAYER && SpellCasted && tmp > 0 ) - { - if ( roll_chance_i(tmp/100)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT"); - return MELEE_HIT_BLOCK_CRIT; - } - } - DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum); - return MELEE_HIT_BLOCK; - } - } + tmp += parryChance; + if (roll < tmp) + return SPELL_MISS_PARRY; } - // Critical chance - tmp = crit_chance + skillBonus2; + return SPELL_MISS_NONE; +} - if (tmp > 0 && roll < (sum += tmp)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum); - return MELEE_HIT_CRIT; - } +// TODO need use unit spell resistances in calculations +SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell) +{ + // Can`t miss on dead target (on skinning for example) + if (!pVictim->isAlive()) + return SPELL_MISS_NONE; - // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon) - if( attType != RANGED_ATTACK && !SpellCasted && - (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet()) && - pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->isPet() && - getLevel() < pVictim->getLevelForTarget(this) ) - { - // cap possible value (with bonuses > max skill) - int32 skill = attackerWeaponSkill; - int32 maxskill = attackerMaxSkillValueForLevel; - skill = (skill > maxskill) ? maxskill : skill; + SpellSchoolMask schoolMask = GetSpellSchoolMask(spell); + // PvP - PvE spell misschances per leveldif > 2 + int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11; + int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim)); - tmp = (10 + (victimDefenseSkill - skill)) * 100; - tmp = tmp > 4000 ? 4000 : tmp; - if (roll < (sum += tmp)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum); - return MELEE_HIT_GLANCING; - } - } + // Base hit chance from attacker and victim levels + int32 modHitChance; + if(leveldif < 3) + modHitChance = 96 - leveldif; + else + modHitChance = 94 - (leveldif - 2) * lchance; - if(GetTypeId()!=TYPEID_PLAYER && !(((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH) && !((Creature*)this)->isPet() && !SpellCasted /*Only autoattack can be crushing blow*/ ) + // Spellmod from SPELLMOD_RESIST_MISS_CHANCE + if(Player *modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance); + // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras + modHitChance+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask); + // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras + modHitChance+= pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask); + // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura + if (IsAreaOfEffectSpell(spell)) + modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE); + // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST + if (IsDispelSpell(spell)) + modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST); + // Chance resist mechanic (select max value from every mechanic spell effect) + int32 resist_mech = 0; + // Get effects mechanic and chance + for(int eff = 0; eff < 3; ++eff) { - // mobs can score crushing blows if they're 3 or more levels above victim - // or when their weapon skill is 15 or more above victim's defense skill - tmp = victimDefenseSkill; - int32 tmpmax = victimMaxSkillValueForLevel; - // having defense above your maximum (from items, talents etc.) has no effect - tmp = tmp > tmpmax ? tmpmax : tmp; - // tmp = mob's level * 5 - player's current defense skill - tmp = attackerMaxSkillValueForLevel - tmp; - if(tmp >= 15) + int32 effect_mech = GetEffectMechanic(spell, eff); + if (effect_mech) { - // add 2% chance per lacking skill point, min. is 15% - tmp = tmp * 200 - 1500; - if (roll < (sum += tmp)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum); - return MELEE_HIT_CRUSHING; - } + int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech); + if (resist_mech < temp) + resist_mech = temp; } } + // Apply mod + modHitChance-=resist_mech; - DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL"); - return MELEE_HIT_NORMAL; + // Chance resist debuff + modHitChance-=pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)); + + int32 HitChance = modHitChance * 100; + // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings + HitChance += int32(m_modSpellHitChance*100.0f); + + // Decrease hit chance from victim rating bonus + if (pVictim->GetTypeId()==TYPEID_PLAYER) + HitChance -= int32(((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL)*100.0f); + + if (HitChance < 100) HitChance = 100; + if (HitChance > 9900) HitChance = 9900; + + uint32 rand = urand(0,10000); + if (rand > HitChance) + return SPELL_MISS_RESIST; + return SPELL_MISS_NONE; } -uint32 Unit::CalculateDamage (WeaponAttackType attType, bool normalized) +// Calculate spell hit result can be: +// Every spell can: Evade/Immune/Reflect/Sucesful hit +// For melee based spells: +// Miss +// Dodge +// Parry +// For spells +// Resist +SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool CanReflect) { - float min_damage, max_damage; + // Return evade for units in evade mode + if (pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + return SPELL_MISS_EVADE; - if (normalized && GetTypeId()==TYPEID_PLAYER) - ((Player*)this)->CalculateMinMaxDamage(attType,normalized,min_damage, max_damage); - else + // If Spel has this flag cannot be resisted/immuned/etc + if (spell->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) + return SPELL_MISS_NONE; + + // Check for immune (use charges) + if (pVictim->IsImmunedToSpell(spell,true)) + return SPELL_MISS_IMMUNE; + + // All positive spells can`t miss + // TODO: client not show miss log for this spells - so need find info for this in dbc and use it! + if (IsPositiveSpell(spell->Id) + &&(!IsHostileTo(pVictim))) //prevent from affecting enemy by "positive" spell + return SPELL_MISS_NONE; + + // Check for immune (use charges) + if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell),true)) + return SPELL_MISS_IMMUNE; + + if(this == pVictim) + return SPELL_MISS_NONE; + + // Try victim reflect spell + if (CanReflect) { - switch (attType) + int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS); + Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL); + for(Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i) + if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell)) + reflectchance = (*i)->GetModifierValue(); + if (reflectchance > 0 && roll_chance_i(reflectchance)) { - case RANGED_ATTACK: - min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE); - max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE); - break; - case BASE_ATTACK: - min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE); - max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE); - break; - case OFF_ATTACK: - min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE); - max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE); - break; - // Just for good manner - default: - min_damage = 0.0f; - max_damage = 0.0f; - break; + // Start triggers for remove charges if need (trigger only for victim, and mark as active spell) + ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 1, BASE_ATTACK, spell); + return SPELL_MISS_REFLECT; } } - if (min_damage > max_damage) + switch (spell->DmgClass) { - std::swap(min_damage,max_damage); + case SPELL_DAMAGE_CLASS_RANGED: + case SPELL_DAMAGE_CLASS_MELEE: + return MeleeSpellHitResult(pVictim, spell); + case SPELL_DAMAGE_CLASS_NONE: + return SPELL_MISS_NONE; + case SPELL_DAMAGE_CLASS_MAGIC: + return MagicSpellHitResult(pVictim, spell); } - - if(max_damage == 0.0f) - max_damage = 5.0f; - - return urand((uint32)min_damage, (uint32)max_damage); + return SPELL_MISS_NONE; } -float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const +/*float Unit::MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const { - if(spellProto->spellLevel <= 0) - return 1.0f; - - float LvlPenalty = 0.0f; - - if(spellProto->spellLevel < 20) - LvlPenalty = 20.0f - spellProto->spellLevel * 3.75f; - float LvlFactor = (float(spellProto->spellLevel) + 6.0f) / float(getLevel()); - if(LvlFactor > 1.0f) - LvlFactor = 1.0f; + if(!pVictim) + return 0.0f; - return (100.0f - LvlPenalty) * LvlFactor / 100.0f; -} + // Base misschance 5% + float misschance = 5.0f; -void Unit::SendAttackStart(Unit* pVictim) -{ - WorldPacket data( SMSG_ATTACKSTART, 16 ); - data << uint64(GetGUID()); - data << uint64(pVictim->GetGUID()); - - SendMessageToSet(&data, true); - DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" ); -} - -void Unit::SendAttackStop(Unit* victim) -{ - if(!victim) - return; - - WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size - data.append(GetPackGUID()); - data.append(victim->GetPackGUID()); // can be 0x00... - data << uint32(0); // can be 0x1 - SendMessageToSet(&data, true); - sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow()); - - /*if(victim->GetTypeId() == TYPEID_UNIT) - ((Creature*)victim)->AI().EnterEvadeMode(this);*/ -} - -bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAttackType attackType) -{ - if (pVictim->HasInArc(M_PI,this)) + // DualWield - Melee spells and physical dmg spells - 5% , white damage 24% + if (haveOffhandWeapon() && attType != RANGED_ATTACK) { - float blockChance = GetUnitBlockChance(); - blockChance += (GetWeaponSkillValue(attackType) - pVictim->GetMaxSkillValueForLevel() )*0.04; - if (roll_chance_f(blockChance)) - return true; + bool isNormal = false; + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) + { + if( m_currentSpells[i] && (GetSpellSchoolMask(m_currentSpells[i]->m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL) ) + { + isNormal = true; + break; + } + } + if (isNormal || m_currentSpells[CURRENT_MELEE_SPELL]) + { + misschance = 5.0f; + } + else + { + misschance = 24.0f; + } } - return false; -} -// Melee based spells can be miss, parry or dodge on this step -// Crit or block - determined on damage calculation phase! (and can be both in some time) -float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const -{ - // Calculate hit chance (more correct for chance mod) - int32 HitChance; + // PvP : PvE melee misschances per leveldif > 2 + int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; - // PvP - PvE melee chances - /*int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; - int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim); - if(leveldif < 3) - HitChance = 95 - leveldif; - else - HitChance = 93 - (leveldif - 2) * lchance;*/ - if (spellId || attType == RANGED_ATTACK || !haveOffhandWeapon()) - HitChance = 95.0f; + int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim)); + if(leveldif < 0) + leveldif = 0; + + // Hit chance from attacker based on ratings and auras + float m_modHitChance; + if (attType == RANGED_ATTACK) + m_modHitChance = m_modRangedHitChance; else - HitChance = 76.0f; + m_modHitChance = m_modMeleeHitChance; - // Hit chance depends from victim auras - if(attType == RANGED_ATTACK) - HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); + if(leveldif < 3) + misschance += (leveldif - m_modHitChance); else - HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); + misschance += ((leveldif - 2) * chance - m_modHitChance); - // Spellmod from SPELLMOD_RESIST_MISS_CHANCE - if(spellId) + // Hit chance for victim based on ratings + if (pVictim->GetTypeId()==TYPEID_PLAYER) { - if(Player *modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, HitChance); + if (attType == RANGED_ATTACK) + misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED); + else + misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE); } - // Miss = 100 - hit - float miss_chance= 100.0f - HitChance; - - // Bonuses from attacker aura and ratings - if (attType == RANGED_ATTACK) - miss_chance -= m_modRangedHitChance; + // Modify miss chance by victim auras + if(attType == RANGED_ATTACK) + misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); else - miss_chance -= m_modMeleeHitChance; + misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); - // bonus from skills is 0.04% - //miss_chance -= skillDiff * 0.04f; - int32 diff = -skillDiff; - if(pVictim->GetTypeId()==TYPEID_PLAYER) - miss_chance += diff > 0 ? diff * 0.04 : diff * 0.02; - else - miss_chance += diff > 10 ? 2 + (diff - 10) * 0.4 : diff * 0.1; + // Modify miss chance from skill difference ( bonus from skills is 0.04% ) + int32 skillBonus = int32(GetWeaponSkillValue(attType,pVictim)) - int32(pVictim->GetDefenseSkillValue(this)); + misschance -= skillBonus * 0.04f; // Limit miss chance from 0 to 60% - if (miss_chance < 0.0f) + if ( misschance < 0.0f) return 0.0f; - if (miss_chance > 60.0f) + if ( misschance > 60.0f) return 60.0f; - return miss_chance; -} - -// Melee based spells hit result calculations -SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) -{ - WeaponAttackType attType = BASE_ATTACK; - - if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED) - attType = RANGED_ATTACK; - - // bonus from skills is 0.04% per skill Diff - int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim)); - int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this)); - int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this)); - - uint32 roll = urand (0, 10000); - uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell->Id)*100.0f); - - // Roll miss - uint32 tmp = missChance; - if (roll < tmp) - return SPELL_MISS_MISS; - - // Same spells cannot be parry/dodge - if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) - return SPELL_MISS_NONE; - - // Ranged attack can`t miss too - if (attType == RANGED_ATTACK) - return SPELL_MISS_NONE; - - bool attackFromBehind = !pVictim->HasInArc(M_PI,this); - // Roll dodge - int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4; - // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE - dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); - - // Reduce dodge chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - if (dodgeChance < 0) - dodgeChance = 0; + return misschance; +}*/ - // Can`t dodge from behind in PvP (but its possible in PvE) - if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind) - dodgeChance = 0; +uint32 Unit::GetDefenseSkillValue(Unit const* target) const +{ + if(GetTypeId() == TYPEID_PLAYER) + { + // in PvP use full skill instead current skill value + uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER) + ? ((Player*)this)->GetMaxSkillValue(SKILL_DEFENSE) + : ((Player*)this)->GetSkillValue(SKILL_DEFENSE); + value += uint32(((Player*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL)); + return value; + } + else + return GetUnitMeleeSkill(target); +} - // Rogue talent`s cant be dodged - AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); - for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i) +float Unit::GetUnitDodgeChance() const +{ + if(hasUnitState(UNIT_STAT_STUNNED)) + return 0.0f; + if( GetTypeId() == TYPEID_PLAYER ) + return GetFloatValue(PLAYER_DODGE_PERCENTAGE); + else { - if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move + if(((Creature const*)this)->isTotem()) + return 0.0f; + else { - if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE)) - { - dodgeChance = 0; - break; - } + float dodge = 5.0f; + dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); + return dodge > 0.0f ? dodge : 0.0f; } } - - tmp += dodgeChance; - if (roll < tmp) - return SPELL_MISS_DODGE; - - // Roll parry - int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4; - // Reduce parry chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - // Can`t parry from behind - if (parryChance < 0 || attackFromBehind) - parryChance = 0; - - tmp += parryChance; - if (roll < tmp) - return SPELL_MISS_PARRY; - - return SPELL_MISS_NONE; } -// TODO need use unit spell resistances in calculations -SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell) +float Unit::GetUnitParryChance() const { - // Can`t miss on dead target (on skinning for example) - if (!pVictim->isAlive()) - return SPELL_MISS_NONE; + if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED)) + return 0.0f; - SpellSchoolMask schoolMask = GetSpellSchoolMask(spell); - // PvP - PvE spell misschances per leveldif > 2 - int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11; - int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim)); + float chance = 0.0f; - // Base hit chance from attacker and victim levels - int32 modHitChance; - if(leveldif < 3) - modHitChance = 96 - leveldif; - else - modHitChance = 94 - (leveldif - 2) * lchance; + if(GetTypeId() == TYPEID_PLAYER) + { + Player const* player = (Player const*)this; + if(player->CanParry() ) + { + Item *tmpitem = player->GetWeaponForAttack(BASE_ATTACK,true); + if(!tmpitem) + tmpitem = player->GetWeaponForAttack(OFF_ATTACK,true); - // Spellmod from SPELLMOD_RESIST_MISS_CHANCE - if(Player *modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance); - // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras - modHitChance+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask); - // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras - modHitChance+= pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask); - // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura - if (IsAreaOfEffectSpell(spell)) - modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE); - // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST - if (IsDispelSpell(spell)) - modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST); - // Chance resist mechanic (select max value from every mechanic spell effect) - int32 resist_mech = 0; - // Get effects mechanic and chance - for(int eff = 0; eff < 3; ++eff) + if(tmpitem) + chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE); + } + } + else if(GetTypeId() == TYPEID_UNIT) { - int32 effect_mech = GetEffectMechanic(spell, eff); - if (effect_mech) + if(GetCreatureType() == CREATURE_TYPE_HUMANOID) { - int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech); - if (resist_mech < temp) - resist_mech = temp; - } - } - // Apply mod - modHitChance-=resist_mech; - - // Chance resist debuff - modHitChance-=pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)); - - int32 HitChance = modHitChance * 100; - // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings - HitChance += int32(m_modSpellHitChance*100.0f); - - // Decrease hit chance from victim rating bonus - if (pVictim->GetTypeId()==TYPEID_PLAYER) - HitChance -= int32(((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL)*100.0f); - - if (HitChance < 100) HitChance = 100; - if (HitChance > 9900) HitChance = 9900; - - uint32 rand = urand(0,10000); - if (rand > HitChance) - return SPELL_MISS_RESIST; - return SPELL_MISS_NONE; -} - -// Calculate spell hit result can be: -// Every spell can: Evade/Immune/Reflect/Sucesful hit -// For melee based spells: -// Miss -// Dodge -// Parry -// For spells -// Resist -SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool CanReflect) -{ - // Return evade for units in evade mode - if (pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) - return SPELL_MISS_EVADE; - - // If Spel has this flag cannot be resisted/immuned/etc - if (spell->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) - return SPELL_MISS_NONE; - - // Check for immune (use charges) - if (pVictim->IsImmunedToSpell(spell,true)) - return SPELL_MISS_IMMUNE; - - // All positive spells can`t miss - // TODO: client not show miss log for this spells - so need find info for this in dbc and use it! - if (IsPositiveSpell(spell->Id) - &&(!IsHostileTo(pVictim))) //prevent from affecting enemy by "positive" spell - return SPELL_MISS_NONE; - - // Check for immune (use charges) - if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell),true)) - return SPELL_MISS_IMMUNE; - - if(this == pVictim) - return SPELL_MISS_NONE; - - // Try victim reflect spell - if (CanReflect) - { - int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS); - Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL); - for(Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i) - if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell)) - reflectchance = (*i)->GetModifierValue(); - if (reflectchance > 0 && roll_chance_i(reflectchance)) - { - // Start triggers for remove charges if need (trigger only for victim, and mark as active spell) - ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 1, BASE_ATTACK, spell); - return SPELL_MISS_REFLECT; - } - } - - switch (spell->DmgClass) - { - case SPELL_DAMAGE_CLASS_RANGED: - case SPELL_DAMAGE_CLASS_MELEE: - return MeleeSpellHitResult(pVictim, spell); - case SPELL_DAMAGE_CLASS_NONE: - return SPELL_MISS_NONE; - case SPELL_DAMAGE_CLASS_MAGIC: - return MagicSpellHitResult(pVictim, spell); - } - return SPELL_MISS_NONE; -} - -/*float Unit::MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const -{ - if(!pVictim) - return 0.0f; - - // Base misschance 5% - float misschance = 5.0f; - - // DualWield - Melee spells and physical dmg spells - 5% , white damage 24% - if (haveOffhandWeapon() && attType != RANGED_ATTACK) - { - bool isNormal = false; - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) - { - if( m_currentSpells[i] && (GetSpellSchoolMask(m_currentSpells[i]->m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL) ) - { - isNormal = true; - break; - } - } - if (isNormal || m_currentSpells[CURRENT_MELEE_SPELL]) - { - misschance = 5.0f; - } - else - { - misschance = 24.0f; - } - } - - // PvP : PvE melee misschances per leveldif > 2 - int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; - - int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim)); - if(leveldif < 0) - leveldif = 0; - - // Hit chance from attacker based on ratings and auras - float m_modHitChance; - if (attType == RANGED_ATTACK) - m_modHitChance = m_modRangedHitChance; - else - m_modHitChance = m_modMeleeHitChance; - - if(leveldif < 3) - misschance += (leveldif - m_modHitChance); - else - misschance += ((leveldif - 2) * chance - m_modHitChance); - - // Hit chance for victim based on ratings - if (pVictim->GetTypeId()==TYPEID_PLAYER) - { - if (attType == RANGED_ATTACK) - misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED); - else - misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE); - } - - // Modify miss chance by victim auras - if(attType == RANGED_ATTACK) - misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); - else - misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); - - // Modify miss chance from skill difference ( bonus from skills is 0.04% ) - int32 skillBonus = int32(GetWeaponSkillValue(attType,pVictim)) - int32(pVictim->GetDefenseSkillValue(this)); - misschance -= skillBonus * 0.04f; - - // Limit miss chance from 0 to 60% - if ( misschance < 0.0f) - return 0.0f; - if ( misschance > 60.0f) - return 60.0f; - - return misschance; -}*/ - -uint32 Unit::GetDefenseSkillValue(Unit const* target) const -{ - if(GetTypeId() == TYPEID_PLAYER) - { - // in PvP use full skill instead current skill value - uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER) - ? ((Player*)this)->GetMaxSkillValue(SKILL_DEFENSE) - : ((Player*)this)->GetSkillValue(SKILL_DEFENSE); - value += uint32(((Player*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL)); - return value; - } - else - return GetUnitMeleeSkill(target); -} - -float Unit::GetUnitDodgeChance() const -{ - if(hasUnitState(UNIT_STAT_STUNNED)) - return 0.0f; - if( GetTypeId() == TYPEID_PLAYER ) - return GetFloatValue(PLAYER_DODGE_PERCENTAGE); - else - { - if(((Creature const*)this)->isTotem()) - return 0.0f; - else - { - float dodge = 5.0f; - dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); - return dodge > 0.0f ? dodge : 0.0f; - } - } -} - -float Unit::GetUnitParryChance() const -{ - if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED)) - return 0.0f; - - float chance = 0.0f; - - if(GetTypeId() == TYPEID_PLAYER) - { - Player const* player = (Player const*)this; - if(player->CanParry() ) - { - Item *tmpitem = player->GetWeaponForAttack(BASE_ATTACK,true); - if(!tmpitem) - tmpitem = player->GetWeaponForAttack(OFF_ATTACK,true); - - if(tmpitem) - chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE); - } - } - else if(GetTypeId() == TYPEID_UNIT) - { - if(GetCreatureType() == CREATURE_TYPE_HUMANOID) - { - chance = 5.0f; - chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); + chance = 5.0f; + chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); } } @@ -4964,6 +4153,7 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log) data.append(log->attacker->GetPackGUID()); data << uint32(log->SpellID); data << uint32(log->damage); //damage amount + data << uint32(0); data << uint8 (log->schoolMask); //damage school data << uint32(log->absorb); //AbsorbedDamage data << uint32(log->resist); //resist @@ -5022,75 +4212,46 @@ void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo) void Unit::SendAttackStateUpdate(CalcDamageInfo *damageInfo) { - WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+84)); // we guess size + uint32 count = 1; + WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size data << (uint32)damageInfo->HitInfo; data.append(GetPackGUID()); data.append(damageInfo->target->GetPackGUID()); data << (uint32)(damageInfo->damage); // Full damage + data << uint32(0); // overkill value - data << (uint8)1; // Sub damage count - //=== Sub damage description - data << (uint32)(damageInfo->damageSchoolMask); // School of sub damage - data << (float)damageInfo->damage; // sub damage - data << (uint32)damageInfo->damage; // Sub Damage - data << (uint32)damageInfo->absorb; // Absorb - data << (uint32)damageInfo->resist; // Resist - //================================================= - data << (uint32)damageInfo->TargetState; - data << (uint32)0; - data << (uint32)0; - data << (uint32)damageInfo->blocked_amount; - SendMessageToSet( &data, true );/**/ -} - -void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount) -{ - sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE"); - - WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size - data << uint32(HitInfo); // flags - data.append(GetPackGUID()); - data.append(target->GetPackGUID()); - data << uint32(Damage-AbsorbDamage-Resist-BlockedAmount);// damage - data << uint32(0); // overkill value - - data << (uint8)SwingType; // count? + data << (uint8)count; // Sub damage count - // for(i = 0; i < SwingType; ++i) - data << (uint32)damageSchoolMask; - data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount); - data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); - // end loop + for(int i = 0; i < count; ++i) + { + data << (uint32)(damageInfo->damageSchoolMask); // School of sub damage + data << (float)damageInfo->damage; // sub damage + data << (uint32)damageInfo->damage; // Sub Damage + } - if(HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2)) + if(damageInfo->HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2)) { - // for(i = 0; i < SwingType; ++i) - data << uint32(AbsorbDamage); - // end loop + for(int i = 0; i < count; ++i) + data << (uint32)damageInfo->absorb; // Absorb } - if(HitInfo & (HITINFO_RESIST | HITINFO_RESIST2)) + if(damageInfo->HitInfo & (HITINFO_RESIST | HITINFO_RESIST2)) { - // for(i = 0; i < SwingType; ++i) - data << uint32(Resist); - // end loop + for(int i = 0; i < count; ++i) + data << (uint32)damageInfo->resist; // Resist } - data << (uint8)TargetState; + data << (uint32)damageInfo->TargetState; data << (uint32)0; data << (uint32)0; - if(HitInfo & HITINFO_BLOCK) - { - data << uint32(BlockedAmount); - } + if(damageInfo->HitInfo & HITINFO_BLOCK) + data << (uint32)damageInfo->blocked_amount; - if(HitInfo & HITINFO_UNK3) - { + if(damageInfo->HitInfo & HITINFO_UNK3) data << uint32(0); - } - if(HitInfo & HITINFO_UNK1) + if(damageInfo->HitInfo & HITINFO_UNK1) { data << uint32(0); data << float(0); @@ -5111,2030 +4272,1303 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SendMessageToSet( &data, true ); } -/* -void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellSchoolMask damageSchoolMask, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType) + +void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount) { - sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim); - if(procSpell) - sLog.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell->Id, (isTriggeredSpell?"(triggered)":"")); + sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE"); - // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities - // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect - // That is the question though if it's fully correct - if(procSpell && !isTriggeredSpell) - { - if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE) - { - if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_MELEE; - if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_MELEE; - if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_MELEE; - if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_MELEE; - attType = BASE_ATTACK; // Melee abilities are assumed to be dealt with mainhand weapon - } - else if (procSpell->DmgClass == SPELL_DAMAGE_CLASS_RANGED) - { - if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_RANGED; - if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_RANGED; - if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_RANGED; - if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_RANGED; - attType = RANGED_ATTACK; - } - } - if(damage && (procVictim & (PROC_FLAG_STRUCK_MELEE|PROC_FLAG_STRUCK_RANGED|PROC_FLAG_STRUCK_SPELL))) - procVictim |= (PROC_FLAG_TAKE_DAMAGE|PROC_FLAG_TOUCH); + WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size + data << uint32(HitInfo); // flags + data.append(GetPackGUID()); + data.append(target->GetPackGUID()); + data << uint32(Damage-AbsorbDamage-Resist-BlockedAmount);// damage + data << uint32(0); // overkill value - // Not much to do if no flags are set. - if (procAttacker) + data << (uint8)SwingType; // count? + + // for(i = 0; i < SwingType; ++i) + data << (uint32)damageSchoolMask; + data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount); + data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); + // end loop + + if(HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2)) { - // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set - ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcEffectAuraTypes,attType, procSpell, damage, damageSchoolMask); - ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcCastAuraTypes,attType, procSpell, damage, damageSchoolMask); + // for(i = 0; i < SwingType; ++i) + data << uint32(AbsorbDamage); + // end loop } - // Now go on with a victim's events'n'auras - // Not much to do if no flags are set or there is no victim - if(pVictim && pVictim->isAlive() && procVictim) + if(HitInfo & (HITINFO_RESIST | HITINFO_RESIST2)) { - // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set - pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcEffectAuraTypes,attType,procSpell, damage, damageSchoolMask); - pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcCastAuraTypes,attType,procSpell, damage, damageSchoolMask); + // for(i = 0; i < SwingType; ++i) + data << uint32(Resist); + // end loop } -} - -void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell) -{ - if(!pVictim) - return; - uint32 procAttacker = PROC_FLAG_NONE; - uint32 procVictim = PROC_FLAG_NONE; + data << (uint8)TargetState; + data << (uint32)0; + data << (uint32)0; - switch(outcome) + if(HitInfo & HITINFO_BLOCK) { - case MELEE_HIT_EVADE: - return; - case MELEE_HIT_MISS: - if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_MISS; - } - break; - case MELEE_HIT_BLOCK_CRIT: - case MELEE_HIT_CRIT: - if(spellCasted && attType == BASE_ATTACK) - { - procAttacker |= PROC_FLAG_CRIT_SPELL; - procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL; - if ( outcome == MELEE_HIT_BLOCK_CRIT ) - { - procVictim |= PROC_FLAG_BLOCK; - procAttacker |= PROC_FLAG_TARGET_BLOCK; - } - } - else if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE; - procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE; - } - else - { - procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED; - procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED; - } - break; - case MELEE_HIT_PARRY: - procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY; - procVictim = PROC_FLAG_PARRY; - break; - case MELEE_HIT_BLOCK: - procAttacker = PROC_FLAG_TARGET_BLOCK; - procVictim = PROC_FLAG_BLOCK; - break; - case MELEE_HIT_DODGE: - procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY; - procVictim = PROC_FLAG_DODGE; - break; - case MELEE_HIT_CRUSHING: - if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE; - procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE; - } - else - { - procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED; - procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED; - } - break; - default: - if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_HIT_MELEE; - procVictim = PROC_FLAG_STRUCK_MELEE; - } - else - { - procAttacker = PROC_FLAG_HIT_RANGED; - procVictim = PROC_FLAG_STRUCK_RANGED; - } - break; + data << uint32(BlockedAmount); } - if(damage > 0) - procVictim |= PROC_FLAG_TAKE_DAMAGE; - - if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE) - ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType); -}*/ - -bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown) -{ - SpellEntry const *hasteSpell = triggeredByAura->GetSpellProto(); - - Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER - ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; - - uint32 triggered_spell_id = 0; - Unit* target = pVictim; - int32 basepoints0 = 0; - - switch(hasteSpell->SpellFamilyName) + if(HitInfo & HITINFO_UNK3) { - case SPELLFAMILY_ROGUE: - { - switch(hasteSpell->Id) - { - // Blade Flurry - case 13877: - case 33735: - { - target = SelectNearbyTarget(); - if(!target) - return false; - basepoints0 = damage; - triggered_spell_id = 22482; - break; - } - } - break; - } + data << uint32(0); } - // processed charge only counting case - if(!triggered_spell_id) - return true; - - SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); - - if(!triggerEntry) + if(HitInfo & HITINFO_UNK1) { - sLog.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell->Id,triggered_spell_id); - return false; + data << uint32(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + for(uint8 i = 0; i < 5; ++i) + { + data << float(0); + data << float(0); + } + data << uint32(0); } - // default case - if(!target || target!=this && !target->isAlive()) - return false; - - if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; - - if(basepoints0) - CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - else - CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); - - if( cooldown && GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); - - return true; + SendMessageToSet( &data, true ); } -bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown) +bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown) { - SpellEntry const *dummySpell = triggeredByAura->GetSpellProto (); - uint32 effIndex = triggeredByAura->GetEffIndex (); + SpellEntry const *hasteSpell = triggeredByAura->GetSpellProto(); Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; - uint32 triggered_spell_id = 0; - Unit* target = pVictim; - int32 basepoints0 = 0; - - switch(dummySpell->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - switch (dummySpell->Id) - { - // Eye for an Eye - case 9799: - case 25988: - { - // prevent damage back from weapon special attacks - if (!procSpell || procSpell->DmgClass != SPELL_DAMAGE_CLASS_MAGIC ) - return false; - - // return damage % to attacker but < 50% own total health - basepoints0 = triggeredByAura->GetModifier()->m_amount*int32(damage)/100; - if(basepoints0 > GetMaxHealth()/2) - basepoints0 = GetMaxHealth()/2; - - triggered_spell_id = 25997; - break; - } - // Sweeping Strikes - case 12328: - case 18765: - case 35429: - { - // prevent chain of triggered spell from same triggered spell - if(procSpell && procSpell->Id==26654) - return false; - - target = SelectNearbyTarget(); - if(!target) - return false; - - triggered_spell_id = 26654; - break; - } - // Unstable Power - case 24658: - { - if (!procSpell || procSpell->Id == 24659) - return false; - // Need remove one 24659 aura - RemoveSingleAuraFromStack(24659, 0); - RemoveSingleAuraFromStack(24659, 1); - return true; - } - // Restless Strength - case 24661: - { - // Need remove one 24662 aura - RemoveSingleAuraFromStack(24662, 0); - return true; - } - // Adaptive Warding (Frostfire Regalia set) - case 28764: - { - if(!procSpell) - return false; - - // find Mage Armor - bool found = false; - AuraList const& mRegenInterupt = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT); - for(AuraList::const_iterator iter = mRegenInterupt.begin(); iter != mRegenInterupt.end(); ++iter) - { - if(SpellEntry const* iterSpellProto = (*iter)->GetSpellProto()) - { - if(iterSpellProto->SpellFamilyName==SPELLFAMILY_MAGE && (iterSpellProto->SpellFamilyFlags & 0x10000000)) - { - found=true; - break; - } - } - } - if(!found) - return false; - - switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) - { - case SPELL_SCHOOL_NORMAL: - case SPELL_SCHOOL_HOLY: - return false; // ignored - case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break; - case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break; - case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break; - case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break; - case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break; - default: - return false; - } - - target = this; - break; - } - // Obsidian Armor (Justice Bearer`s Pauldrons shoulder) - case 27539: - { - if(!procSpell) - return false; - - switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) - { - case SPELL_SCHOOL_NORMAL: - return false; // ignore - case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break; - case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break; - case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break; - case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break; - case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break; - case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break; - default: - return false; - } - - target = this; - break; - } - // Mana Leech (Passive) (Priest Pet Aura) - case 28305: - { - // Cast on owner - target = GetOwner(); - if(!target) - return false; - - basepoints0 = int32(damage * 2.5f); // manaregen - triggered_spell_id = 34650; - break; - } - // Mark of Malice - case 33493: - { - // Cast finish spell at last charge - if (triggeredByAura->m_procCharges > 1) - return false; - - target = this; - triggered_spell_id = 33494; - break; - } - // Twisted Reflection (boss spell) - case 21063: - triggered_spell_id = 21064; - break; - // Vampiric Aura (boss spell) - case 38196: - { - basepoints0 = 3 * damage; // 300% - if (basepoints0 < 0) - return false; - - triggered_spell_id = 31285; - target = this; - break; - } - // Aura of Madness (Darkmoon Card: Madness trinket) - //===================================================== - // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior) - // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid) - // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid) - // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin) - // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes) - // 41005 Manic: +35 haste (spell, melee and ranged) (All classes) - // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter) - // 41011 Martyr Complex: +35 stamina (All classes) - // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) - // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) - case 39446: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Select class defined buff - switch (getClass()) - { - case CLASS_PALADIN: // 39511,40997,40998,40999,41002,41005,41009,41011,41409 - case CLASS_DRUID: // 39511,40997,40998,40999,41002,41005,41009,41011,41409 - { - uint32 RandomSpell[]={39511,40997,40998,40999,41002,41005,41009,41011,41409}; - triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; - break; - } - case CLASS_ROGUE: // 39511,40997,40998,41002,41005,41011 - case CLASS_WARRIOR: // 39511,40997,40998,41002,41005,41011 - { - uint32 RandomSpell[]={39511,40997,40998,41002,41005,41011}; - triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; - break; - } - case CLASS_PRIEST: // 40999,41002,41005,41009,41011,41406,41409 - case CLASS_SHAMAN: // 40999,41002,41005,41009,41011,41406,41409 - case CLASS_MAGE: // 40999,41002,41005,41009,41011,41406,41409 - case CLASS_WARLOCK: // 40999,41002,41005,41009,41011,41406,41409 - { - uint32 RandomSpell[]={40999,41002,41005,41009,41011,41406,41409}; - triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; - break; - } - case CLASS_HUNTER: // 40997,40999,41002,41005,41009,41011,41406,41409 - { - uint32 RandomSpell[]={40997,40999,41002,41005,41009,41011,41406,41409}; - triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; - break; - } - default: - return false; - } - - target = this; - if (roll_chance_i(10)) - ((Player*)this)->Say("This is Madness!", LANG_UNIVERSAL); - break; - } - /* - // TODO: need find item for aura and triggered spells - // Sunwell Exalted Caster Neck (??? neck) - // cast ??? Light's Wrath if Exalted by Aldor - // cast ??? Arcane Bolt if Exalted by Scryers*/ - case 46569: - return false; // disable for while - /* - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = ??? - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = ??? - break; - } - return false; - }/**/ - // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck) - // cast 45479 Light's Wrath if Exalted by Aldor - // cast 45429 Arcane Bolt if Exalted by Scryers - case 45481: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45479; - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = 45429; - break; - } - return false; - } - // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck) - // cast 45480 Light's Strength if Exalted by Aldor - // cast 45428 Arcane Strike if Exalted by Scryers - case 45482: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45480; - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = 45428; - break; - } - return false; - } - // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck) - // cast 45431 Arcane Insight if Exalted by Aldor - // cast 45432 Light's Ward if Exalted by Scryers - case 45483: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45432; - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45431; - break; - } - return false; - } - // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck) - // cast 45478 Light's Salvation if Exalted by Aldor - // cast 45430 Arcane Surge if Exalted by Scryers - case 45484: - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45478; - break; - } - // Get Scryers reputation rank - if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = 45430; - break; - } - return false; - } - } - break; - } - case SPELLFAMILY_MAGE: - { - // Magic Absorption - if (dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura - { - if (getPowerType() != POWER_MANA) - return false; - - // mana reward - basepoints0 = (triggeredByAura->GetModifier()->m_amount * GetMaxPower(POWER_MANA) / 100); - target = this; - triggered_spell_id = 29442; - break; - } - // Master of Elements - if (dummySpell->SpellIconID == 1920) - { - if(!procSpell) - return false; - - // mana cost save - basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100; - if( basepoints0 <=0 ) - return false; - - target = this; - triggered_spell_id = 29077; - break; - } - // Incanter's Regalia set (add trigger chance to Mana Shield) - if (dummySpell->SpellFamilyFlags & 0x0000000000008000LL) - { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - target = this; - triggered_spell_id = 37436; - break; - } - switch(dummySpell->Id) - { - // Ignite - case 11119: - case 11120: - case 12846: - case 12847: - case 12848: - { - switch (dummySpell->Id) - { - case 11119: basepoints0 = int32(0.04f*damage); break; - case 11120: basepoints0 = int32(0.08f*damage); break; - case 12846: basepoints0 = int32(0.12f*damage); break; - case 12847: basepoints0 = int32(0.16f*damage); break; - case 12848: basepoints0 = int32(0.20f*damage); break; - default: - sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell->Id); - return false; - } - - triggered_spell_id = 12654; - break; - } - // Combustion - case 11129: - { - //last charge and crit - if (triggeredByAura->m_procCharges <= 1 && (procEx & PROC_EX_CRITICAL_HIT) ) - { - RemoveAurasDueToSpell(28682); //-> remove Combustion auras - return true; // charge counting (will removed) - } - - CastSpell(this, 28682, true, castItem, triggeredByAura); - return (procEx & PROC_EX_CRITICAL_HIT);// charge update only at crit hits, no hidden cooldowns - } - } - break; - } - case SPELLFAMILY_WARRIOR: - { - // Retaliation - if(dummySpell->SpellFamilyFlags==0x0000000800000000LL) - { - // check attack comes not from behind - if (!HasInArc(M_PI, pVictim)) - return false; - - triggered_spell_id = 22858; - break; - } - else if (dummySpell->SpellIconID == 1697) // Second Wind - { - // only for spells and hit/crit (trigger start always) and not start from self casted spells (5530 Mace Stun Effect for example) - if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == pVictim) - return false; - // Need stun or root mechanic - if (procSpell->Mechanic != MECHANIC_ROOT && procSpell->Mechanic != MECHANIC_STUN) - { - int32 i; - for (i=0; i<3; i++) - if (procSpell->EffectMechanic[i] == MECHANIC_ROOT || procSpell->EffectMechanic[i] == MECHANIC_STUN) - break; - if (i == 3) - return false; - } - - switch (dummySpell->Id) - { - case 29838: triggered_spell_id=29842; break; - case 29834: triggered_spell_id=29841; break; - default: - sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (SW)",dummySpell->Id); - return false; - } - - target = this; - break; - } - break; - } - case SPELLFAMILY_WARLOCK: - { - // Seed of Corruption - if (dummySpell->SpellFamilyFlags & 0x0000001000000000LL) - { - Modifier* mod = triggeredByAura->GetModifier(); - // if damage is more than need or target die from damage deal finish spell - if( mod->m_amount <= damage || GetHealth() <= damage ) - { - // remember guid before aura delete - uint64 casterGuid = triggeredByAura->GetCasterGUID(); - - // Remove aura (before cast for prevent infinite loop handlers) - RemoveAurasDueToSpell(triggeredByAura->GetId()); - - // Cast finish spell (triggeredByAura already not exist!) - if(Unit* caster = GetUnit(*this, casterGuid)) - caster->CastSpell(this, 27285, true, castItem); - return true; // no hidden cooldown - } - - // Damage counting - mod->m_amount-=damage; - return true; - } - // Seed of Corruption (Mobs cast) - no die req - if (dummySpell->SpellFamilyFlags == 0x00LL && dummySpell->SpellIconID == 1932) - { - Modifier* mod = triggeredByAura->GetModifier(); - // if damage is more than need deal finish spell - if( mod->m_amount <= damage ) - { - // remember guid before aura delete - uint64 casterGuid = triggeredByAura->GetCasterGUID(); - - // Remove aura (before cast for prevent infinite loop handlers) - RemoveAurasDueToSpell(triggeredByAura->GetId()); - - // Cast finish spell (triggeredByAura already not exist!) - if(Unit* caster = GetUnit(*this, casterGuid)) - caster->CastSpell(this, 32865, true, castItem); - return true; // no hidden cooldown - } - // Damage counting - mod->m_amount-=damage; - return true; - } - switch(dummySpell->Id) - { - // Nightfall - case 18094: - case 18095: - { - target = this; - triggered_spell_id = 17941; - break; - } - //Soul Leech - case 30293: - case 30295: - case 30296: - { - // health - basepoints0 = int32(damage*triggeredByAura->GetModifier()->m_amount/100); - target = this; - triggered_spell_id = 30294; - break; - } - // Shadowflame (Voidheart Raiment set bonus) - case 37377: - { - triggered_spell_id = 37379; - break; - } - // Pet Healing (Corruptor Raiment or Rift Stalker Armor) - case 37381: - { - target = GetPet(); - if(!target) - return false; - - // heal amount - basepoints0 = damage * triggeredByAura->GetModifier()->m_amount/100; - triggered_spell_id = 37382; - break; - } - // Shadowflame Hellfire (Voidheart Raiment set bonus) - case 39437: - { - triggered_spell_id = 37378; - break; - } - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Vampiric Touch - if( dummySpell->SpellFamilyFlags & 0x0000040000000000LL ) - { - if(!pVictim || !pVictim->isAlive()) - return false; - - // pVictim is caster of aura - if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID()) - return false; - - // energize amount - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; - pVictim->CastCustomSpell(pVictim,34919,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - return true; // no hidden cooldown - } - switch(dummySpell->Id) - { - // Vampiric Embrace - case 15286: - { - if(!pVictim || !pVictim->isAlive()) - return false; - - // pVictim is caster of aura - if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID()) - return false; - - // heal amount - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; - pVictim->CastCustomSpell(pVictim,15290,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - return true; // no hidden cooldown - } - // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen) - case 40438: - { - // Shadow Word: Pain - if( procSpell->SpellFamilyFlags & 0x0000000000008000LL ) - triggered_spell_id = 40441; - // Renew - else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL ) - triggered_spell_id = 40440; - else - return false; - - target = this; - break; - } - // Oracle Healing Bonus ("Garments of the Oracle" set) - case 26169: - { - // heal amount - basepoints0 = int32(damage * 10/100); - target = this; - triggered_spell_id = 26170; - break; - } - // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set - case 39372: - { - if(!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW))==0 ) - return false; + uint32 triggered_spell_id = 0; + Unit* target = pVictim; + int32 basepoints0 = 0; - // heal amount - basepoints0 = int32(damage * 2 / 100); - target = this; - triggered_spell_id = 39373; - break; - } - // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus) - case 28809: + switch(hasteSpell->SpellFamilyName) + { + case SPELLFAMILY_ROGUE: + { + switch(hasteSpell->Id) + { + // Blade Flurry + case 13877: + case 33735: { - triggered_spell_id = 28810; + target = SelectNearbyTarget(); + if(!target) + return false; + basepoints0 = damage; + triggered_spell_id = 22482; break; } } break; } - case SPELLFAMILY_DRUID: + } + + // processed charge only counting case + if(!triggered_spell_id) + return true; + + SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); + + if(!triggerEntry) + { + sLog.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell->Id,triggered_spell_id); + return false; + } + + // default case + if(!target || target!=this && !target->isAlive()) + return false; + + if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) + return false; + + if(basepoints0) + CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + else + CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); + + if( cooldown && GetTypeId()==TYPEID_PLAYER ) + ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); + + return true; +} + +bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown) +{ + SpellEntry const *dummySpell = triggeredByAura->GetSpellProto (); + uint32 effIndex = triggeredByAura->GetEffIndex (); + + Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER + ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; + + uint32 triggered_spell_id = 0; + Unit* target = pVictim; + int32 basepoints0 = 0; + + switch(dummySpell->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: { - switch(dummySpell->Id) + switch (dummySpell->Id) { - // Healing Touch (Dreamwalker Raiment set) - case 28719: - { - // mana back - basepoints0 = int32(procSpell->manaCost * 30 / 100); - target = this; - triggered_spell_id = 28742; - break; - } - // Healing Touch Refund (Idol of Longevity trinket) - case 28847: - { - target = this; - triggered_spell_id = 28848; - break; - } - // Mana Restore (Malorne Raiment set / Malorne Regalia set) - case 37288: - case 37295: + // Eye for an Eye + case 9799: + case 25988: { - target = this; - triggered_spell_id = 37238; + // prevent damage back from weapon special attacks + if (!procSpell || procSpell->DmgClass != SPELL_DAMAGE_CLASS_MAGIC ) + return false; + + // return damage % to attacker but < 50% own total health + basepoints0 = triggeredByAura->GetModifier()->m_amount*int32(damage)/100; + if(basepoints0 > GetMaxHealth()/2) + basepoints0 = GetMaxHealth()/2; + + triggered_spell_id = 25997; break; } - // Druid Tier 6 Trinket - case 40442: + // Sweeping Strikes + case 12328: + case 18765: + case 35429: { - float chance; - - // Starfire - if( procSpell->SpellFamilyFlags & 0x0000000000000004LL ) - { - triggered_spell_id = 40445; - chance = 25.f; - } - // Rejuvenation - else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL ) - { - triggered_spell_id = 40446; - chance = 25.f; - } - // Mangle (cat/bear) - else if( procSpell->SpellFamilyFlags & 0x0000044000000000LL ) - { - triggered_spell_id = 40452; - chance = 40.f; - } - else + // prevent chain of triggered spell from same triggered spell + if(procSpell && procSpell->Id==26654) return false; - if (!roll_chance_f(chance)) + target = SelectNearbyTarget(); + if(!target) return false; - target = this; + triggered_spell_id = 26654; break; } - // Maim Interrupt - case 44835: + // Unstable Power + case 24658: { - // Deadly Interrupt Effect - triggered_spell_id = 32747; - break; + if (!procSpell || procSpell->Id == 24659) + return false; + // Need remove one 24659 aura + RemoveSingleAuraFromStack(24659, 0); + RemoveSingleAuraFromStack(24659, 1); + return true; } - } - break; - } - case SPELLFAMILY_ROGUE: - { - switch(dummySpell->Id) - { - // Deadly Throw Interrupt - case 32748: + // Restless Strength + case 24661: { - // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw - if(this == pVictim) - return false; - - triggered_spell_id = 32747; - break; + // Need remove one 24662 aura + RemoveSingleAuraFromStack(24662, 0); + return true; } - } - // Quick Recovery - if( dummySpell->SpellIconID == 2116 ) - { - if(!procSpell) - return false; - - // only rogue's finishing moves (maybe need additional checks) - if( procSpell->SpellFamilyName!=SPELLFAMILY_ROGUE || - (procSpell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE) == 0) - return false; - - // energy cost save - basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100; - if(basepoints0 <= 0) - return false; - - target = this; - triggered_spell_id = 31663; - break; - } - break; - } - case SPELLFAMILY_HUNTER: - { - // Thrill of the Hunt - if ( dummySpell->SpellIconID == 2236 ) - { - if(!procSpell) - return false; + // Adaptive Warding (Frostfire Regalia set) + case 28764: + { + if(!procSpell) + return false; - // mana cost save - basepoints0 = procSpell->manaCost * 40/100; - if(basepoints0 <= 0) - return false; + // find Mage Armor + bool found = false; + AuraList const& mRegenInterupt = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT); + for(AuraList::const_iterator iter = mRegenInterupt.begin(); iter != mRegenInterupt.end(); ++iter) + { + if(SpellEntry const* iterSpellProto = (*iter)->GetSpellProto()) + { + if(iterSpellProto->SpellFamilyName==SPELLFAMILY_MAGE && (iterSpellProto->SpellFamilyFlags & 0x10000000)) + { + found=true; + break; + } + } + } + if(!found) + return false; - target = this; - triggered_spell_id = 34720; - break; - } - break; - } - case SPELLFAMILY_PALADIN: - { - // TODO: spell list, formula change in 3.0.3 - // Seal of Righteousness - melee proc dummy - if (dummySpell->SpellFamilyFlags&0x000000008000000LL && triggeredByAura->GetEffIndex()==0) - { - if(GetTypeId() != TYPEID_PLAYER) - return false; + switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) + { + case SPELL_SCHOOL_NORMAL: + case SPELL_SCHOOL_HOLY: + return false; // ignored + case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break; + case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break; + case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break; + case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break; + case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break; + default: + return false; + } - uint32 spellId; - switch (triggeredByAura->GetId()) + target = this; + break; + } + // Obsidian Armor (Justice Bearer`s Pauldrons shoulder) + case 27539: { - case 21084: spellId = 25742; break; // Rank 1 - case 20287: spellId = 25740; break; // Rank 2 - case 20288: spellId = 25739; break; // Rank 3 - case 20289: spellId = 25738; break; // Rank 4 - case 20290: spellId = 25737; break; // Rank 5 - case 20291: spellId = 25736; break; // Rank 6 - case 20292: spellId = 25735; break; // Rank 7 - case 20293: spellId = 25713; break; // Rank 8 - case 27155: spellId = 27156; break; // Rank 9 - default: - sLog.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura->GetId()); + if(!procSpell) return false; - } - Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - float speed = (item ? item->GetProto()->Delay : BASE_ATTACK_TIME)/1000.0f; - - float damageBasePoints; - if(item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON) - // two hand weapon - damageBasePoints=1.20f*triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f + 1; - else - // one hand weapon/no weapon - damageBasePoints=0.85f*ceil(triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f) - 1; - int32 damagePoint = int32(damageBasePoints + 0.03f * (GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE)+GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE))/2.0f) + 1; + switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) + { + case SPELL_SCHOOL_NORMAL: + return false; // ignore + case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break; + case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break; + case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break; + case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break; + case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break; + case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break; + default: + return false; + } - // apply damage bonuses manually - if(damagePoint >= 0) - damagePoint = SpellDamageBonus(pVictim, dummySpell, damagePoint, SPELL_DIRECT_DAMAGE); + target = this; + break; + } + // Mana Leech (Passive) (Priest Pet Aura) + case 28305: + { + // Cast on owner + target = GetOwner(); + if(!target) + return false; - CastCustomSpell(pVictim,spellId,&damagePoint,NULL,NULL,true,NULL, triggeredByAura); - return true; // no hidden cooldown - } - // Seal of Blood do damage trigger - if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL) - { - switch(triggeredByAura->GetEffIndex()) + basepoints0 = int32(damage * 2.5f); // manaregen + triggered_spell_id = 34650; + break; + } + // Mark of Malice + case 33493: { - case 0: - triggered_spell_id = 31893; - break; - case 1: - { - // damage - damage += CalculateDamage(BASE_ATTACK, false) * 35 / 100; // add spell damage from prev effect (35%) - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + // Cast finish spell at last charge + if (triggeredByAura->m_procCharges > 1) + return false; - target = this; - triggered_spell_id = 32221; - break; - } + target = this; + triggered_spell_id = 33494; + break; } - } + // Twisted Reflection (boss spell) + case 21063: + triggered_spell_id = 21064; + break; + // Vampiric Aura (boss spell) + case 38196: + { + basepoints0 = 3 * damage; // 300% + if (basepoints0 < 0) + return false; - switch(dummySpell->Id) - { - // Holy Power (Redemption Armor set) - case 28789: + triggered_spell_id = 31285; + target = this; + break; + } + // Aura of Madness (Darkmoon Card: Madness trinket) + //===================================================== + // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior) + // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid) + // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid) + // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin) + // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes) + // 41005 Manic: +35 haste (spell, melee and ranged) (All classes) + // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter) + // 41011 Martyr Complex: +35 stamina (All classes) + // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) + // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) + case 39446: { - if(!pVictim) + if(GetTypeId() != TYPEID_PLAYER) return false; - // Set class defined buff - switch (pVictim->getClass()) + // Select class defined buff + switch (getClass()) { - case CLASS_PALADIN: - case CLASS_PRIEST: - case CLASS_SHAMAN: - case CLASS_DRUID: - triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. + case CLASS_PALADIN: // 39511,40997,40998,40999,41002,41005,41009,41011,41409 + case CLASS_DRUID: // 39511,40997,40998,40999,41002,41005,41009,41011,41409 + { + uint32 RandomSpell[]={39511,40997,40998,40999,41002,41005,41009,41011,41409}; + triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; break; - case CLASS_MAGE: - case CLASS_WARLOCK: - triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d. + } + case CLASS_ROGUE: // 39511,40997,40998,41002,41005,41011 + case CLASS_WARRIOR: // 39511,40997,40998,41002,41005,41011 + { + uint32 RandomSpell[]={39511,40997,40998,41002,41005,41011}; + triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; break; - case CLASS_HUNTER: - case CLASS_ROGUE: - triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d. + } + case CLASS_PRIEST: // 40999,41002,41005,41009,41011,41406,41409 + case CLASS_SHAMAN: // 40999,41002,41005,41009,41011,41406,41409 + case CLASS_MAGE: // 40999,41002,41005,41009,41011,41406,41409 + case CLASS_WARLOCK: // 40999,41002,41005,41009,41011,41406,41409 + { + uint32 RandomSpell[]={40999,41002,41005,41009,41011,41406,41409}; + triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; break; - case CLASS_WARRIOR: - triggered_spell_id = 28790; // Increases the friendly target's armor + } + case CLASS_HUNTER: // 40997,40999,41002,41005,41009,41011,41406,41409 + { + uint32 RandomSpell[]={40997,40999,41002,41005,41009,41011,41406,41409}; + triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ]; break; + } default: return false; } + + target = this; + if (roll_chance_i(10)) + ((Player*)this)->Say("This is Madness!", LANG_UNIVERSAL); break; } - // TODO: fix basepoint calculation (changed in 3.0.3) - // Seal of Vengeance - case 31801: + /* + // TODO: need find item for aura and triggered spells + // Sunwell Exalted Caster Neck (??? neck) + // cast ??? Light's Wrath if Exalted by Aldor + // cast ??? Arcane Bolt if Exalted by Scryers*/ + case 46569: + return false; // disable for while + /* { - if(effIndex != 0) // effect 1,2 used by seal unleashing code + if(GetTypeId() != TYPEID_PLAYER) return false; - triggered_spell_id = 31803; - break; + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = ??? + break; + } + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = ??? + break; + } + return false; + }/**/ + // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck) + // cast 45479 Light's Wrath if Exalted by Aldor + // cast 45429 Arcane Bolt if Exalted by Scryers + case 45481: + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45479; + break; + } + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = 45429; + break; + } + return false; } - // Spiritual Attunement - case 31785: - case 33776: + // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck) + // cast 45480 Light's Strength if Exalted by Aldor + // cast 45428 Arcane Strike if Exalted by Scryers + case 45482: { - // if healed by another unit (pVictim) - if(this == pVictim) + if(GetTypeId() != TYPEID_PLAYER) return false; - // heal amount - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; - target = this; - triggered_spell_id = 31786; - break; + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45480; + break; + } + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = 45428; + break; + } + return false; } - // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal) - case 40470: + // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck) + // cast 45431 Arcane Insight if Exalted by Aldor + // cast 45432 Light's Ward if Exalted by Scryers + case 45483: { - if( !procSpell ) + if(GetTypeId() != TYPEID_PLAYER) return false; - float chance; - - // Flash of light/Holy light - if( procSpell->SpellFamilyFlags & 0x00000000C0000000LL) + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) { - triggered_spell_id = 40471; - chance = 15.f; + target = this; + triggered_spell_id = 45432; + break; } - // Judgement - else if( procSpell->SpellFamilyFlags & 0x0000000000800000LL ) + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) { - triggered_spell_id = 40472; - chance = 50.f; + target = this; + triggered_spell_id = 45431; + break; } - else - return false; - - if (!roll_chance_f(chance)) + return false; + } + // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck) + // cast 45478 Light's Salvation if Exalted by Aldor + // cast 45430 Arcane Surge if Exalted by Scryers + case 45484: + { + if(GetTypeId() != TYPEID_PLAYER) return false; - break; + // Get Aldor reputation rank + if (((Player *)this)->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45478; + break; + } + // Get Scryers reputation rank + if (((Player *)this)->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = 45430; + break; + } + return false; } } break; } - case SPELLFAMILY_SHAMAN: + case SPELLFAMILY_MAGE: { - switch(dummySpell->Id) + // Magic Absorption + if (dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura { - // Totemic Power (The Earthshatterer set) - case 28823: - { - if( !pVictim ) - return false; + if (getPowerType() != POWER_MANA) + return false; - // Set class defined buff - switch (pVictim->getClass()) - { - case CLASS_PALADIN: - case CLASS_PRIEST: - case CLASS_SHAMAN: - case CLASS_DRUID: - triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. - break; - case CLASS_MAGE: - case CLASS_WARLOCK: - triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d. - break; - case CLASS_HUNTER: - case CLASS_ROGUE: - triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d. - break; - case CLASS_WARRIOR: - triggered_spell_id = 28827; // Increases the friendly target's armor - break; - default: - return false; - } - break; - } - // Lesser Healing Wave (Totem of Flowing Water Relic) - case 28849: - { - target = this; - triggered_spell_id = 28850; - break; - } - // Windfury Weapon (Passive) 1-5 Ranks - case 33757: - { - if(GetTypeId()!=TYPEID_PLAYER) - return false; + // mana reward + basepoints0 = (triggeredByAura->GetModifier()->m_amount * GetMaxPower(POWER_MANA) / 100); + target = this; + triggered_spell_id = 29442; + break; + } + // Master of Elements + if (dummySpell->SpellIconID == 1920) + { + if(!procSpell) + return false; - if(!castItem || !castItem->IsEquipped()) - return false; + // mana cost save + basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100; + if( basepoints0 <=0 ) + return false; - // custom cooldown processing case - if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) - return false; + target = this; + triggered_spell_id = 29077; + break; + } + // Incanter's Regalia set (add trigger chance to Mana Shield) + if (dummySpell->SpellFamilyFlags & 0x0000000000008000LL) + { + if(GetTypeId() != TYPEID_PLAYER) + return false; - uint32 spellId; - switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT))) + target = this; + triggered_spell_id = 37436; + break; + } + switch(dummySpell->Id) + { + // Ignite + case 11119: + case 11120: + case 12846: + case 12847: + case 12848: + { + switch (dummySpell->Id) { - case 283: spellId = 33757; break; //1 Rank - case 284: spellId = 33756; break; //2 Rank - case 525: spellId = 33755; break; //3 Rank - case 1669:spellId = 33754; break; //4 Rank - case 2636:spellId = 33727; break; //5 Rank + case 11119: basepoints0 = int32(0.04f*damage); break; + case 11120: basepoints0 = int32(0.08f*damage); break; + case 12846: basepoints0 = int32(0.12f*damage); break; + case 12847: basepoints0 = int32(0.16f*damage); break; + case 12848: basepoints0 = int32(0.20f*damage); break; default: - { - sLog.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)", - castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)),dummySpell->Id); + sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell->Id); return false; - } } - SpellEntry const* windfurySpellEntry = sSpellStore.LookupEntry(spellId); - if(!windfurySpellEntry) - { - sLog.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId); - return false; - } - - int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry,0,windfurySpellEntry->EffectBasePoints[0],pVictim); - - // Off-Hand case - if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND ) - { - // Value gained from additional AP - basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2); - triggered_spell_id = 33750; - } - // Main-Hand case - else - { - // Value gained from additional AP - basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000); - triggered_spell_id = 25504; - } - - // apply cooldown before cast to prevent processing itself - if( cooldown ) - ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); - - // Attack Twice - for ( uint32 i = 0; i<2; ++i ) - CastCustomSpell(pVictim,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - - return true; + triggered_spell_id = 12654; + break; } - // Shaman Tier 6 Trinket - case 40463: + // Combustion + case 11129: { - if( !procSpell ) - return false; - - float chance; - if (procSpell->SpellFamilyFlags & 0x0000000000000001LL) - { - triggered_spell_id = 40465; // Lightning Bolt - chance = 15.f; - } - else if (procSpell->SpellFamilyFlags & 0x0000000000000080LL) - { - triggered_spell_id = 40465; // Lesser Healing Wave - chance = 10.f; - } - else if (procSpell->SpellFamilyFlags & 0x0000001000000000LL) + //last charge and crit + if (triggeredByAura->m_procCharges <= 1 && (procEx & PROC_EX_CRITICAL_HIT) ) { - triggered_spell_id = 40466; // Stormstrike - chance = 50.f; + RemoveAurasDueToSpell(28682); //-> remove Combustion auras + return true; // charge counting (will removed) } - else - return false; - if (!roll_chance_f(chance)) - return false; + CastSpell(this, 28682, true, castItem, triggeredByAura); + return (procEx & PROC_EX_CRITICAL_HIT);// charge update only at crit hits, no hidden cooldowns + } + } + break; + } + case SPELLFAMILY_WARRIOR: + { + // Retaliation + if(dummySpell->SpellFamilyFlags==0x0000000800000000LL) + { + // check attack comes not from behind + if (!HasInArc(M_PI, pVictim)) + return false; - target = this; - break; + triggered_spell_id = 22858; + break; + } + else if (dummySpell->SpellIconID == 1697) // Second Wind + { + // only for spells and hit/crit (trigger start always) and not start from self casted spells (5530 Mace Stun Effect for example) + if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == pVictim) + return false; + // Need stun or root mechanic + if (procSpell->Mechanic != MECHANIC_ROOT && procSpell->Mechanic != MECHANIC_STUN) + { + int32 i; + for (i=0; i<3; i++) + if (procSpell->EffectMechanic[i] == MECHANIC_ROOT || procSpell->EffectMechanic[i] == MECHANIC_STUN) + break; + if (i == 3) + return false; } - } - // Earth Shield - if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL) - { - if(GetTypeId() != TYPEID_PLAYER) + switch (dummySpell->Id) + { + case 29838: triggered_spell_id=29842; break; + case 29834: triggered_spell_id=29841; break; + default: + sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (SW)",dummySpell->Id); return false; + } - // heal - basepoints0 = triggeredByAura->GetModifier()->m_amount; target = this; - triggered_spell_id = 379; break; } - // Lightning Overload - if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura + break; + } + case SPELLFAMILY_WARLOCK: + { + // Seed of Corruption + if (dummySpell->SpellFamilyFlags & 0x0000001000000000LL) { - if(!procSpell || GetTypeId() != TYPEID_PLAYER || !pVictim ) - return false; - - // custom cooldown processing case - if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) - return false; - - uint32 spellId = 0; - // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost - switch (procSpell->Id) + Modifier* mod = triggeredByAura->GetModifier(); + // if damage is more than need or target die from damage deal finish spell + if( mod->m_amount <= damage || GetHealth() <= damage ) { - // Lightning Bolt - case 403: spellId = 45284; break; // Rank 1 - case 529: spellId = 45286; break; // Rank 2 - case 548: spellId = 45287; break; // Rank 3 - case 915: spellId = 45288; break; // Rank 4 - case 943: spellId = 45289; break; // Rank 5 - case 6041: spellId = 45290; break; // Rank 6 - case 10391: spellId = 45291; break; // Rank 7 - case 10392: spellId = 45292; break; // Rank 8 - case 15207: spellId = 45293; break; // Rank 9 - case 15208: spellId = 45294; break; // Rank 10 - case 25448: spellId = 45295; break; // Rank 11 - case 25449: spellId = 45296; break; // Rank 12 - case 49237: spellId = 49239; break; // Rank 13 - case 49238: spellId = 49240; break; // Rank 14 - // Chain Lightning - case 421: spellId = 45297; break; // Rank 1 - case 930: spellId = 45298; break; // Rank 2 - case 2860: spellId = 45299; break; // Rank 3 - case 10605: spellId = 45300; break; // Rank 4 - case 25439: spellId = 45301; break; // Rank 5 - case 25442: spellId = 45302; break; // Rank 6 - case 49268: spellId = 49270; break; // Rank 7 - case 49269: spellId = 49271; break; // Rank 8 - default: - sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id); - return false; - } - // No thread generated mod - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_THREAT; - mod->value = -100; - mod->type = SPELLMOD_PCT; - mod->spellId = dummySpell->Id; - mod->mask = 0x0000000000000003LL; - mod->mask2= 0LL; - ((Player*)this)->AddSpellMod(mod, true); + // remember guid before aura delete + uint64 casterGuid = triggeredByAura->GetCasterGUID(); - // Remove cooldown (Chain Lightning - have Category Recovery time) - if (procSpell->SpellFamilyFlags & 0x0000000000000002LL) - ((Player*)this)->RemoveSpellCooldown(spellId); + // Remove aura (before cast for prevent infinite loop handlers) + RemoveAurasDueToSpell(triggeredByAura->GetId()); - CastSpell(pVictim, spellId, true, castItem, triggeredByAura); + // Cast finish spell (triggeredByAura already not exist!) + if(Unit* caster = GetUnit(*this, casterGuid)) + caster->CastSpell(this, 27285, true, castItem); + return true; // no hidden cooldown + } - ((Player*)this)->AddSpellMod(mod, false); + // Damage counting + mod->m_amount-=damage; + return true; + } + // Seed of Corruption (Mobs cast) - no die req + if (dummySpell->SpellFamilyFlags == 0x00LL && dummySpell->SpellIconID == 1932) + { + Modifier* mod = triggeredByAura->GetModifier(); + // if damage is more than need deal finish spell + if( mod->m_amount <= damage ) + { + // remember guid before aura delete + uint64 casterGuid = triggeredByAura->GetCasterGUID(); - if( cooldown && GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); + // Remove aura (before cast for prevent infinite loop handlers) + RemoveAurasDueToSpell(triggeredByAura->GetId()); + // Cast finish spell (triggeredByAura already not exist!) + if(Unit* caster = GetUnit(*this, casterGuid)) + caster->CastSpell(this, 32865, true, castItem); + return true; // no hidden cooldown + } + // Damage counting + mod->m_amount-=damage; return true; } + switch(dummySpell->Id) + { + // Nightfall + case 18094: + case 18095: + { + target = this; + triggered_spell_id = 17941; + break; + } + //Soul Leech + case 30293: + case 30295: + case 30296: + { + // health + basepoints0 = int32(damage*triggeredByAura->GetModifier()->m_amount/100); + target = this; + triggered_spell_id = 30294; + break; + } + // Shadowflame (Voidheart Raiment set bonus) + case 37377: + { + triggered_spell_id = 37379; + break; + } + // Pet Healing (Corruptor Raiment or Rift Stalker Armor) + case 37381: + { + target = GetPet(); + if(!target) + return false; + + // heal amount + basepoints0 = damage * triggeredByAura->GetModifier()->m_amount/100; + triggered_spell_id = 37382; + break; + } + // Shadowflame Hellfire (Voidheart Raiment set bonus) + case 39437: + { + triggered_spell_id = 37378; + break; + } + } break; } - default: - break; - } - - // processed charge only counting case - if(!triggered_spell_id) - return true; - - SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); - - if(!triggerEntry) - { - sLog.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id); - return false; - } - - // default case - if(!target || target!=this && !target->isAlive()) - return false; - - if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; + case SPELLFAMILY_PRIEST: + { + // Vampiric Touch + if( dummySpell->SpellFamilyFlags & 0x0000040000000000LL ) + { + if(!pVictim || !pVictim->isAlive()) + return false; - if(basepoints0) - CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - else - CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); + // pVictim is caster of aura + if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID()) + return false; - if( cooldown && GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); + // energize amount + basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + pVictim->CastCustomSpell(pVictim,34919,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + return true; // no hidden cooldown + } + switch(dummySpell->Id) + { + // Vampiric Embrace + case 15286: + { + if(!pVictim || !pVictim->isAlive()) + return false; - return true; -} -/* -bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attackType, uint32 cooldown) -{ - SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto(); + // pVictim is caster of aura + if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID()) + return false; - Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER - ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; + // heal amount + basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + pVictim->CastCustomSpell(pVictim,15290,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + return true; // no hidden cooldown + } + // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen) + case 40438: + { + // Shadow Word: Pain + if( procSpell->SpellFamilyFlags & 0x0000000000008000LL ) + triggered_spell_id = 40441; + // Renew + else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL ) + triggered_spell_id = 40440; + else + return false; - uint32 triggered_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()]; - Unit* target = !(procFlags & PROC_FLAG_HEAL) && IsPositiveSpell(triggered_spell_id) ? this : pVictim; - int32 basepoints0 = 0; + target = this; + break; + } + // Oracle Healing Bonus ("Garments of the Oracle" set) + case 26169: + { + // heal amount + basepoints0 = int32(damage * 10/100); + target = this; + triggered_spell_id = 26170; + break; + } + // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set + case 39372: + { + if(!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW))==0 ) + return false; - switch(auraSpellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - switch(auraSpellInfo->Id) - { - // Aegis of Preservation - case 23780: - //Aegis Heal (instead non-existed triggered spell) - triggered_spell_id = 23781; + // heal amount + basepoints0 = int32(damage * 2 / 100); target = this; + triggered_spell_id = 39373; break; - // Elune's Touch (moonkin mana restore) - case 24905: + } + // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus) + case 28809: { - // Elune's Touch (instead non-existed triggered spell) - triggered_spell_id = 33926; - basepoints0 = int32(0.3f * GetTotalAttackPowerValue(BASE_ATTACK)); - target = this; + triggered_spell_id = 28810; break; } - // Enlightenment - case 29601: + } + break; + } + case SPELLFAMILY_DRUID: + { + switch(dummySpell->Id) + { + // Healing Touch (Dreamwalker Raiment set) + case 28719: { - // only for cast with mana price - if(!procSpell || procSpell->powerType!=POWER_MANA || procSpell->manaCost==0 && procSpell->ManaCostPercentage==0 && procSpell->manaCostPerlevel==0) - return false; - break; // fall through to normal cast + // mana back + basepoints0 = int32(procSpell->manaCost * 30 / 100); + target = this; + triggered_spell_id = 28742; + break; } - // Health Restore - case 33510: + // Healing Touch Refund (Idol of Longevity trinket) + case 28847: { - // at melee hit call std triggered spell - if(procFlags & PROC_FLAG_HIT_MELEE) - break; // fall through to normal cast - - // Mark of Conquest - else (at range hit) called custom case - triggered_spell_id = 39557; target = this; + triggered_spell_id = 28848; break; } - // Shaleskin - case 36576: - return true; // nothing to do - // Forgotten Knowledge (Blade of Wizardry) - case 38319: - // only for harmful enemy targeted spell - if(!pVictim || pVictim==this || !procSpell || IsPositiveSpell(procSpell->Id)) - return false; - break; // fall through to normal cast - // Aura of Wrath (Darkmoon Card: Wrath trinket bonus) - case 39442: + // Mana Restore (Malorne Raiment set / Malorne Regalia set) + case 37288: + case 37295: { - // proc only at non-crit hits - if(procFlags & (PROC_FLAG_CRIT_MELEE|PROC_FLAG_CRIT_RANGED|PROC_FLAG_CRIT_SPELL)) - return false; - break; // fall through to normal cast + target = this; + triggered_spell_id = 37238; + break; } - // Augment Pain (Timbal's Focusing Crystal trinket bonus) - case 45054: + // Druid Tier 6 Trinket + case 40442: { - if(!procSpell) - return false; + float chance; - //only periodic damage can trigger spell - bool found = false; - for(int j = 0; j < 3; ++j) + // Starfire + if( procSpell->SpellFamilyFlags & 0x0000000000000004LL ) { - if( procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE || - procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT || - procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_LEECH ) - { - found = true; - break; - } + triggered_spell_id = 40445; + chance = 25.f; } - if(!found) - return false; - - break; // fall through to normal cast - } - // Evasive Maneuvers (Commendation of Kael'thas) - case 45057: - { - // damage taken that reduces below 35% health - // does NOT mean you must have been >= 35% before - if (int32(GetHealth())-int32(damage) >= int32(GetMaxHealth()*0.35f)) + // Rejuvenation + else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL ) + { + triggered_spell_id = 40446; + chance = 25.f; + } + // Mangle (cat/bear) + else if( procSpell->SpellFamilyFlags & 0x0000044000000000LL ) + { + triggered_spell_id = 40452; + chance = 40.f; + } + else return false; - break; // fall through to normal cast - } - } - switch(triggered_spell_id) - { - // Setup - case 15250: - { - // applied only for main target - if(!pVictim || pVictim != getVictim()) + if (!roll_chance_f(chance)) return false; - // continue normal case + target = this; break; } - // Shamanistic Rage triggered spell - case 30824: - basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100); + // Maim Interrupt + case 44835: + { + // Deadly Interrupt Effect + triggered_spell_id = 32747; break; + } } break; } - case SPELLFAMILY_MAGE: + case SPELLFAMILY_ROGUE: { - switch(auraSpellInfo->SpellIconID) + switch(dummySpell->Id) { - // Blazing Speed - case 2127: - //Blazing Speed (instead non-existed triggered spell) - triggered_spell_id = 31643; - target = this; + // Deadly Throw Interrupt + case 32748: + { + // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw + if(this == pVictim) + return false; + + triggered_spell_id = 32747; break; + } } - switch(auraSpellInfo->Id) + // Quick Recovery + if( dummySpell->SpellIconID == 2116 ) { - // Persistent Shield (Scarab Brooch) - case 26467: - basepoints0 = int32(damage * 0.15f); - break; + if(!procSpell) + return false; + + // only rogue's finishing moves (maybe need additional checks) + if( procSpell->SpellFamilyName!=SPELLFAMILY_ROGUE || + (procSpell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE) == 0) + return false; + + // energy cost save + basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100; + if(basepoints0 <= 0) + return false; + + target = this; + triggered_spell_id = 31663; + break; } break; } - case SPELLFAMILY_WARRIOR: + case SPELLFAMILY_HUNTER: { - //Rampage - if((auraSpellInfo->SpellFamilyFlags & 0x100000) && auraSpellInfo->SpellIconID==2006) + // Thrill of the Hunt + if ( dummySpell->SpellIconID == 2236 ) { - //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed) - //and effect[1]==TriggerSpell - if(auraSpellInfo->Effect[1]!=SPELL_EFFECT_TRIGGER_SPELL) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura->GetSpellProto()->Id); + if(!procSpell) return false; - } - triggered_spell_id = auraSpellInfo->EffectTriggerSpell[1]; - break; // fall through to normal cast + + // mana cost save + basepoints0 = procSpell->manaCost * 40/100; + if(basepoints0 <= 0) + return false; + + target = this; + triggered_spell_id = 34720; + break; } break; } - case SPELLFAMILY_WARLOCK: + case SPELLFAMILY_PALADIN: { - // Pyroclasm - if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000 && auraSpellInfo->SpellIconID==1137) + // TODO: spell list, formula change in 3.0.3 + // Seal of Righteousness - melee proc dummy + if (dummySpell->SpellFamilyFlags&0x000000008000000LL && triggeredByAura->GetEffIndex()==0) { - // last case for Hellfire that damage caster also but don't must stun caster - if( pVictim == this ) + if(GetTypeId() != TYPEID_PLAYER) return false; - // custom chance - float chance = 0; + uint32 spellId; switch (triggeredByAura->GetId()) { - case 18096: chance = 13.0f; break; - case 18073: chance = 26.0f; break; + case 21084: spellId = 25742; break; // Rank 1 + case 20287: spellId = 25740; break; // Rank 2 + case 20288: spellId = 25739; break; // Rank 3 + case 20289: spellId = 25738; break; // Rank 4 + case 20290: spellId = 25737; break; // Rank 5 + case 20291: spellId = 25736; break; // Rank 6 + case 20292: spellId = 25735; break; // Rank 7 + case 20293: spellId = 25713; break; // Rank 8 + case 27155: spellId = 27156; break; // Rank 9 + default: + sLog.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura->GetId()); + return false; } - if (!roll_chance_f(chance)) - return false; + Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + float speed = (item ? item->GetProto()->Delay : BASE_ATTACK_TIME)/1000.0f; - // Pyroclasm (instead non-existed triggered spell) - triggered_spell_id = 18093; - target = pVictim; - break; + float damageBasePoints; + if(item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON) + // two hand weapon + damageBasePoints=1.20f*triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f + 1; + else + // one hand weapon/no weapon + damageBasePoints=0.85f*ceil(triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f) - 1; + + int32 damagePoint = int32(damageBasePoints + 0.03f * (GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE)+GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE))/2.0f) + 1; + + // apply damage bonuses manually + if(damagePoint >= 0) + damagePoint = SpellDamageBonus(pVictim, dummySpell, damagePoint, SPELL_DIRECT_DAMAGE); + + CastCustomSpell(pVictim,spellId,&damagePoint,NULL,NULL,true,NULL, triggeredByAura); + return true; // no hidden cooldown + } + // Seal of Blood do damage trigger + if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL) + { + switch(triggeredByAura->GetEffIndex()) + { + case 0: + triggered_spell_id = 31893; + break; + case 1: + { + // damage + damage += CalculateDamage(BASE_ATTACK, false) * 35 / 100; // add spell damage from prev effect (35%) + basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + + target = this; + triggered_spell_id = 32221; + break; + } + } } - // Drain Soul - if(auraSpellInfo->SpellFamilyFlags & 0x0000000000004000) + + switch(dummySpell->Id) { - bool found = false; - Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER); - for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i) + // Holy Power (Redemption Armor set) + case 28789: + { + if(!pVictim) + return false; + + // Set class defined buff + switch (pVictim->getClass()) + { + case CLASS_PALADIN: + case CLASS_PRIEST: + case CLASS_SHAMAN: + case CLASS_DRUID: + triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. + break; + case CLASS_MAGE: + case CLASS_WARLOCK: + triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d. + break; + case CLASS_HUNTER: + case CLASS_ROGUE: + triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d. + break; + case CLASS_WARRIOR: + triggered_spell_id = 28790; // Increases the friendly target's armor + break; + default: + return false; + } + break; + } + // TODO: fix basepoint calculation (changed in 3.0.3) + // Seal of Vengeance + case 31801: + { + if(effIndex != 0) // effect 1,2 used by seal unleashing code + return false; + + triggered_spell_id = 31803; + break; + } + // Spiritual Attunement + case 31785: + case 33776: + { + // if healed by another unit (pVictim) + if(this == pVictim) + return false; + + // heal amount + basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + target = this; + triggered_spell_id = 31786; + break; + } + // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal) + case 40470: { - //Improved Drain Soul - if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113) + if( !procSpell ) + return false; + + float chance; + + // Flash of light/Holy light + if( procSpell->SpellFamilyFlags & 0x00000000C0000000LL) + { + triggered_spell_id = 40471; + chance = 15.f; + } + // Judgement + else if( procSpell->SpellFamilyFlags & 0x0000000000800000LL ) { - int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this); - basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100; - // Drain Soul - CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - break; + triggered_spell_id = 40472; + chance = 50.f; } - } - // Not remove charge (aura removed on death in any cases) - // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura - return false; - } - break; - } - case SPELLFAMILY_PRIEST: - { - //Blessed Recovery - if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL && auraSpellInfo->SpellIconID==1875) - { - switch (triggeredByAura->GetSpellProto()->Id) - { - case 27811: triggered_spell_id = 27813; break; - case 27815: triggered_spell_id = 27817; break; - case 27816: triggered_spell_id = 27818; break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id); + else return false; - } - int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100; - basepoints0 = heal_amount/3; - target = this; - break; - } - // Shadowguard - if((auraSpellInfo->SpellFamilyFlags & 0x80000000LL) && auraSpellInfo->SpellVisual[0]==7958) - { - switch(triggeredByAura->GetSpellProto()->Id) - { - case 18137: - triggered_spell_id = 28377; break; // Rank 1 - case 19308: - triggered_spell_id = 28378; break; // Rank 2 - case 19309: - triggered_spell_id = 28379; break; // Rank 3 - case 19310: - triggered_spell_id = 28380; break; // Rank 4 - case 19311: - triggered_spell_id = 28381; break; // Rank 5 - case 19312: - triggered_spell_id = 28382; break; // Rank 6 - case 25477: - triggered_spell_id = 28385; break; // Rank 7 - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura->GetSpellProto()->Id); + if (!roll_chance_f(chance)) return false; + + break; } - target = pVictim; - break; } break; } - case SPELLFAMILY_DRUID: + case SPELLFAMILY_SHAMAN: { - switch(auraSpellInfo->Id) + switch(dummySpell->Id) { - // Leader of the Pack (triggering Improved Leader of the Pack heal) - case 24932: + // Totemic Power (The Earthshatterer set) + case 28823: { - if (triggeredByAura->GetModifier()->m_amount == 0) + if( !pVictim ) return false; - basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100; - triggered_spell_id = 34299; - break; - }; - // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form) - case 37336: - { - switch(m_form) + + // Set class defined buff + switch (pVictim->getClass()) { - case FORM_BEAR: - case FORM_DIREBEAR: - triggered_spell_id=37340; break;// Ursine Blessing - case FORM_CAT: - triggered_spell_id=37341; break;// Feline Blessing - case FORM_TREE: - triggered_spell_id=37342; break;// Slyvan Blessing - case FORM_MOONKIN: - triggered_spell_id=37343; break;// Lunar Blessing - case FORM_NONE: - triggered_spell_id=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN) + case CLASS_PALADIN: + case CLASS_PRIEST: + case CLASS_SHAMAN: + case CLASS_DRUID: + triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. + break; + case CLASS_MAGE: + case CLASS_WARLOCK: + triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d. + break; + case CLASS_HUNTER: + case CLASS_ROGUE: + triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d. + break; + case CLASS_WARRIOR: + triggered_spell_id = 28827; // Increases the friendly target's armor + break; default: return false; } - - target = this; break; } - } - break; - } - case SPELLFAMILY_ROGUE: - { - if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000LL) - { - switch(auraSpellInfo->SpellIconID) + // Lesser Healing Wave (Totem of Flowing Water Relic) + case 28849: { - // Combat Potency - case 2260: - { - // skip non offhand attacks - if(attackType!=OFF_ATTACK) - return false; - break; // fall through to normal cast - } + target = this; + triggered_spell_id = 28850; + break; } - } - break; - } - case SPELLFAMILY_PALADIN: - { - if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL) - { - switch(auraSpellInfo->Id) + // Windfury Weapon (Passive) 1-5 Ranks + case 33757: { - // Lightning Capacitor - case 37657: - { - // trinket ProcTriggerSpell but for safe checks for player - if(!castItem || !pVictim || !pVictim->isAlive() || GetTypeId()!=TYPEID_PLAYER) - return false; + if(GetTypeId()!=TYPEID_PLAYER) + return false; - if(((Player*)this)->HasSpellCooldown(37657)) - return false; + if(!castItem || !castItem->IsEquipped()) + return false; - // stacking - CastSpell(this, 37658, true, castItem, triggeredByAura); - // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown - ((Player*)this)->AddSpellCooldown(37657,0,time(NULL)+(roll_chance_i(50) ? 2 : 3)); + // custom cooldown processing case + if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) + return false; - // counting - Aura * dummy = GetDummyAura(37658); - if (!dummy) + uint32 spellId; + switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT))) + { + case 283: spellId = 33757; break; //1 Rank + case 284: spellId = 33756; break; //2 Rank + case 525: spellId = 33755; break; //3 Rank + case 1669:spellId = 33754; break; //4 Rank + case 2636:spellId = 33727; break; //5 Rank + default: + { + sLog.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)", + castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)),dummySpell->Id); return false; + } + } + + SpellEntry const* windfurySpellEntry = sSpellStore.LookupEntry(spellId); + if(!windfurySpellEntry) + { + sLog.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId); + return false; + } - // release at 3 aura in stack - if(dummy->GetStackAmount() <= 2) - return true; // main triggered spell casted anyway + int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry,0,windfurySpellEntry->EffectBasePoints[0],pVictim); - RemoveAurasDueToSpell(37658); - CastSpell(pVictim, 37661, true, castItem, triggeredByAura); - return true; + // Off-Hand case + if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND ) + { + // Value gained from additional AP + basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2); + triggered_spell_id = 33750; } - // Healing Discount - case 37705: - // Healing Trance (instead non-existed triggered spell) - triggered_spell_id = 37706; - target = this; - break; - // HoTs on Heals (Fel Reaver's Piston trinket) - case 38299: + // Main-Hand case + else { - // at direct heal effect - if(!procSpell || !IsSpellHaveEffect(procSpell,SPELL_EFFECT_HEAL)) - return false; + // Value gained from additional AP + basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000); + triggered_spell_id = 25504; + } + + // apply cooldown before cast to prevent processing itself + if( cooldown ) + ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); - // single proc at time - AuraList const& scAuras = GetSingleCastAuras(); - for(AuraList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr) - if((*itr)->GetId()==triggered_spell_id) - return false; + // Attack Twice + for ( uint32 i = 0; i<2; ++i ) + CastCustomSpell(pVictim,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - // positive cast at victim instead self - target = pVictim; - break; - } + return true; } - switch(auraSpellInfo->SpellIconID) + // Shaman Tier 6 Trinket + case 40463: { - case 241: + if( !procSpell ) + return false; + + float chance; + if (procSpell->SpellFamilyFlags & 0x0000000000000001LL) { - switch(auraSpellInfo->EffectTriggerSpell[0]) - { - //Illumination - case 18350: - { - if(!procSpell) - return false; - - // procspell is triggered spell but we need mana cost of original casted spell - uint32 originalSpellId = procSpell->Id; - - // Holy Shock - if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN) - { - if(procSpell->SpellFamilyFlags & 0x0001000000000000LL) - { - switch(procSpell->Id) - { - case 25914: originalSpellId = 20473; break; - case 25913: originalSpellId = 20929; break; - case 25903: originalSpellId = 20930; break; - case 27175: originalSpellId = 27174; break; - case 33074: originalSpellId = 33072; break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id); - return false; - } - } - } - - SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId); - if(!originalSpell) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId); - return false; - } - - // percent stored in effect 1 (class scripts) base points - int32 percent = auraSpellInfo->EffectBasePoints[1]+1; - - basepoints0 = originalSpell->manaCost*percent/100; - triggered_spell_id = 20272; - target = this; - break; - } - } - break; + triggered_spell_id = 40465; // Lightning Bolt + chance = 15.f; } - } - } - if(auraSpellInfo->SpellFamilyFlags & 0x00080000) - { - switch(auraSpellInfo->SpellIconID) - { - //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc - case 206: + else if (procSpell->SpellFamilyFlags & 0x0000000000000080LL) { - if(!pVictim || !pVictim->isAlive()) - return false; - - switch(triggeredByAura->GetSpellProto()->Id) - { - case 20186: - triggered_spell_id = 20268; // Rank 1 - break; - case 20354: - triggered_spell_id = 20352; // Rank 2 - break; - case 20355: - triggered_spell_id = 20353; // Rank 3 - break; - case 27164: - triggered_spell_id = 27165; // Rank 4 - break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura->GetSpellProto()->Id); - return false; - } - - pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID()); - return true; // no hidden cooldown + triggered_spell_id = 40465; // Lesser Healing Wave + chance = 10.f; } - //Judgement of Light - case 299: + else if (procSpell->SpellFamilyFlags & 0x0000001000000000LL) { - if(!pVictim || !pVictim->isAlive()) - return false; - - // overwrite non existing triggered spell call in spell.dbc - switch(triggeredByAura->GetSpellProto()->Id) - { - case 20185: - triggered_spell_id = 20267; // Rank 1 - break; - case 20344: - triggered_spell_id = 20341; // Rank 2 - break; - case 20345: - triggered_spell_id = 20342; // Rank 3 - break; - case 20346: - triggered_spell_id = 20343; // Rank 4 - break; - case 27162: - triggered_spell_id = 27163; // Rank 5 - break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura->GetSpellProto()->Id); - return false; - } - pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID()); - return true; // no hidden cooldown + triggered_spell_id = 40466; // Stormstrike + chance = 50.f; } - } - } - // custom check for proc spell - switch(auraSpellInfo->Id) - { - // Bonus Healing (item spell) - case 40971: - { - if(!pVictim || !pVictim->isAlive()) + else return false; - // bonus if health < 50% - if(pVictim->GetHealth() >= pVictim->GetMaxHealth()*triggeredByAura->GetModifier()->m_amount/100) + if (!roll_chance_f(chance)) return false; - // cast at target positive spell - target = pVictim; + target = this; break; } } - switch(triggered_spell_id) + + // Earth Shield + if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL) { - // Seal of Command - case 20424: - // prevent chain of triggered spell from same triggered spell - if(procSpell && procSpell->Id==20424) - return false; - break; + if(GetTypeId() != TYPEID_PLAYER) + return false; + + // heal + basepoints0 = triggeredByAura->GetModifier()->m_amount; + target = this; + triggered_spell_id = 379; + break; } - break; - } - case SPELLFAMILY_SHAMAN: - { - if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000) + // Lightning Overload + if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura { - switch(auraSpellInfo->SpellIconID) - { - case 19: - { - switch(auraSpellInfo->Id) - { - case 23551: // Lightning Shield - Tier2: 8 pieces proc shield - { - // Lightning Shield (overwrite non existing triggered spell call in spell.dbc) - triggered_spell_id = 23552; - target = pVictim; - break; - } - case 23552: // Lightning Shield - trigger shield damage - { - // Lightning Shield (overwrite non existing triggered spell call in spell.dbc) - triggered_spell_id = 27635; - target = pVictim; - break; - } - } - break; - } - // Mana Surge (Shaman T1 bonus) - case 87: - { - if(!procSpell) - return false; - - basepoints0 = procSpell->manaCost * 35/100; - triggered_spell_id = 23571; - target = this; - break; - } - //Nature's Guardian - case 2013: - { - if(GetTypeId()!=TYPEID_PLAYER) - return false; + if(!procSpell || GetTypeId() != TYPEID_PLAYER || !pVictim ) + return false; - // damage taken that reduces below 30% health - // does NOT mean you must have been >= 30% before - if (10*(int32(GetHealth())-int32(damage)) >= 3*GetMaxHealth()) - return false; + // custom cooldown processing case + if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) + return false; - triggered_spell_id = 31616; + uint32 spellId = 0; + // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost + switch (procSpell->Id) + { + // Lightning Bolt + case 403: spellId = 45284; break; // Rank 1 + case 529: spellId = 45286; break; // Rank 2 + case 548: spellId = 45287; break; // Rank 3 + case 915: spellId = 45288; break; // Rank 4 + case 943: spellId = 45289; break; // Rank 5 + case 6041: spellId = 45290; break; // Rank 6 + case 10391: spellId = 45291; break; // Rank 7 + case 10392: spellId = 45292; break; // Rank 8 + case 15207: spellId = 45293; break; // Rank 9 + case 15208: spellId = 45294; break; // Rank 10 + case 25448: spellId = 45295; break; // Rank 11 + case 25449: spellId = 45296; break; // Rank 12 + case 49237: spellId = 49239; break; // Rank 13 + case 49238: spellId = 49240; break; // Rank 14 + // Chain Lightning + case 421: spellId = 45297; break; // Rank 1 + case 930: spellId = 45298; break; // Rank 2 + case 2860: spellId = 45299; break; // Rank 3 + case 10605: spellId = 45300; break; // Rank 4 + case 25439: spellId = 45301; break; // Rank 5 + case 25442: spellId = 45302; break; // Rank 6 + case 49268: spellId = 49270; break; // Rank 7 + case 49269: spellId = 49271; break; // Rank 8 + default: + sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id); + return false; + } + // No thread generated mod + SpellModifier *mod = new SpellModifier; + mod->op = SPELLMOD_THREAT; + mod->value = -100; + mod->type = SPELLMOD_PCT; + mod->spellId = dummySpell->Id; + mod->mask = 0x0000000000000003LL; + mod->mask2= 0LL; + ((Player*)this)->AddSpellMod(mod, true); - // need check cooldown now - if( cooldown && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; + // Remove cooldown (Chain Lightning - have Category Recovery time) + if (procSpell->SpellFamilyFlags & 0x0000000000000002LL) + ((Player*)this)->RemoveSpellCooldown(spellId); - basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100; - target = this; - if(pVictim && pVictim->isAlive()) - pVictim->getThreatManager().modifyThreatPercent(this,-10); - break; - } - } - } + CastSpell(pVictim, spellId, true, castItem, triggeredByAura); - // Water Shield (we can't set cooldown for main spell - it's player casted spell - if((auraSpellInfo->SpellFamilyFlags & 0x0000002000000000LL) && auraSpellInfo->SpellVisual[0]==7358) - { - target = this; - break; - } + ((Player*)this)->AddSpellMod(mod, false); - // Lightning Shield - if((auraSpellInfo->SpellFamilyFlags & 0x00000400) && auraSpellInfo->SpellVisual[0]==37) - { - // overwrite non existing triggered spell call in spell.dbc - switch(triggeredByAura->GetSpellProto()->Id) - { - case 324: - triggered_spell_id = 26364; break; // Rank 1 - case 325: - triggered_spell_id = 26365; break; // Rank 2 - case 905: - triggered_spell_id = 26366; break; // Rank 3 - case 945: - triggered_spell_id = 26367; break; // Rank 4 - case 8134: - triggered_spell_id = 26369; break; // Rank 5 - case 10431: - triggered_spell_id = 26370; break; // Rank 6 - case 10432: - triggered_spell_id = 26363; break; // Rank 7 - case 25469: - triggered_spell_id = 26371; break; // Rank 8 - case 25472: - triggered_spell_id = 26372; break; // Rank 9 - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id); - return false; - } + if( cooldown && GetTypeId()==TYPEID_PLAYER ) + ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); - target = pVictim; - break; + return true; } break; } + default: + break; } - // standard non-dummy case + // processed charge only counting case if(!triggered_spell_id) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex()); - return false; - } + return true; SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); if(!triggerEntry) { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex(),triggered_spell_id); + sLog.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id); return false; } - // not allow proc extra attack spell at extra attack - if( m_extraAttacks && IsSpellHaveEffect(triggerEntry,SPELL_EFFECT_ADD_EXTRA_ATTACKS) ) + // default case + if(!target || target!=this && !target->isAlive()) return false; if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) return false; - // default case - if(!target || target!=this && !target->isAlive()) - return false; - if(basepoints0) CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); else @@ -7145,7 +5579,6 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB return true; } -*/ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown) { @@ -7173,14 +5606,30 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB // ..... //===================================================================== case SPELLFAMILY_GENERIC: +// if (auraSpellInfo->Id==59532) // Abandon Passengers on Poly +// if (auraSpellInfo->Id==54775) // Abandon Vehicle on Poly // if (auraSpellInfo->Id==34082) // Advantaged State (DND) -// trigger_spell_id = ???; if (auraSpellInfo->Id == 23780) // Aegis of Preservation (Aegis of Preservation trinket) - trigger_spell_id = 23781; + trigger_spell_id = 23781; // else if (auraSpellInfo->Id==43504) // Alterac Valley OnKill Proc Aura -// trigger_spell_id = ; +// else if (auraSpellInfo->Id == 48876) // Beast's Mark +// { +// trigger_spell_id = 48877; +// } +// else if (auraSpellInfo->Id == 59237) // Beast's Mark +// { +// trigger_spell_id = 59233; +// } +// else if (auraSpellInfo->Id==46939) // Black Bow of the Betrayer +// { +// trigger_spell_id = 29471; // gain mana +// 27526; // drain mana if possible +// } +// else if (auraSpellInfo->Id==50844) // Blood Mirror +// else if (auraSpellInfo->Id==54476) // Blood Presence +// else if (auraSpellInfo->Id==50689) // Blood Presence (Rank 1) // else if (auraSpellInfo->Id==37030) // Chaotic Temperament -// trigger_spell_id = ; +// else if (auraSpellInfo->Id==52856) // Charge else if (auraSpellInfo->Id==43820) // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket) { // Pct value stored in dummy @@ -7190,31 +5639,37 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB } // else if (auraSpellInfo->Id==41248) // Consuming Strikes // trigger_spell_id = 41249; +// else if (auraSpellInfo->Id==45205) // Copy Offhand Weapon +// else if (auraSpellInfo->Id==57594) // Copy Ranged Weapon // else if (auraSpellInfo->Id==41054) // Copy Weapon // trigger_spell_id = 41055; +// else if (auraSpellInfo->Id==45343) // Dark Flame Aura +// else if (auraSpellInfo->Id==47300) // Dark Flame Aura + else if (auraSpellInfo->Id==57345) // Darkmoon Card: Greatness + { + uint32 stat = 0; + // strength + if (GetStat(STAT_STRENGTH) > stat){trigger_spell_id = 60229;stat = GetStat(STAT_STRENGTH);} + // agility + if (GetStat(STAT_AGILITY) > stat){trigger_spell_id = 60233;stat = GetStat(STAT_AGILITY);} + // intellect + if (GetStat(STAT_INTELLECT) > stat){trigger_spell_id = 60234;stat = GetStat(STAT_INTELLECT);} + // spirit + if (GetStat(STAT_SPIRIT) > stat){trigger_spell_id = 60235;stat = GetStat(STAT_SPIRIT);} + } // else if (auraSpellInfo->Id==31255) // Deadly Swiftness (Rank 1) -// trigger_spell_id = ; // else if (auraSpellInfo->Id==5301) // Defensive State (DND) -// trigger_spell_id = ; // else if (auraSpellInfo->Id==13358) // Defensive State (DND) -// trigger_spell_id = ; // else if (auraSpellInfo->Id==16092) // Defensive State (DND) -// trigger_spell_id = ; // else if (auraSpellInfo->Id==24949) // Defensive State 2 (DND) -// trigger_spell_id = ; // else if (auraSpellInfo->Id==40329) // Demo Shout Sensor -// trigger_spell_id = ; // Desperate Defense (Stonescythe Whelp, Stonescythe Alpha, Stonescythe Ambusher) else if (auraSpellInfo->Id == 33896) trigger_spell_id = 33898; // else if (auraSpellInfo->Id==18943) // Double Attack -// trigger_spell_id = ; // else if (auraSpellInfo->Id==19194) // Double Attack -// trigger_spell_id = ; // else if (auraSpellInfo->Id==19817) // Double Attack -// trigger_spell_id = ; // else if (auraSpellInfo->Id==19818) // Double Attack -// trigger_spell_id = ; // else if (auraSpellInfo->Id==22835) // Drunken Rage // trigger_spell_id = 14822; /* @@ -7246,21 +5701,21 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB return false; } }*/ -// else if (auraSpellInfo->Id==6542) // Enraged Defense -// trigger_spell_id = ; // else if (auraSpellInfo->Id==40364) // Entangling Roots Sensor -// trigger_spell_id = ; // else if (auraSpellInfo->Id==33207) // Gossip NPC Periodic - Fidget -// trigger_spell_id = ; +// else if (auraSpellInfo->Id==50051) // Ethereal Pet Aura // else if (auraSpellInfo->Id==35321) // Gushing Wound -// trigger_spell_id = ; // else if (auraSpellInfo->Id==38363) // Gushing Wound -// trigger_spell_id = ; // else if (auraSpellInfo->Id==39215) // Gushing Wound -// trigger_spell_id = ; +// else if (auraSpellInfo->Id==44527) // Hate Monster (Spar Buddy) (30 sec) +// else if (auraSpellInfo->Id==44819) // Hate Monster (Spar Buddy) (>30% Health) +// else if (auraSpellInfo->Id==44526) // Hate Monster (Spar) (30 sec) +// else if (auraSpellInfo->Id==44820) // Hate Monster (Spar) (<30%) +// else if (auraSpellInfo->Id==49059) // Horde, Hate Monster (Spar Buddy) (>30% Health) // else if (auraSpellInfo->Id==40250) // Improved Duration -// trigger_spell_id = ; - else if (auraSpellInfo->Id==27522) // Mana Drain Trigger +// else if (auraSpellInfo->Id==59288) // Infra-Green Shield +// else if (auraSpellInfo->Id==54072) // Knockback Ball Passive + else if (auraSpellInfo->Id==27522 || auraSpellInfo->Id==40336) // Mana Drain Trigger { // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target. if (this && this->isAlive()) @@ -7269,27 +5724,21 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB CastSpell(pVictim, 27526, true, castItem, triggeredByAura); return true; } - else if (auraSpellInfo->Id==24905) // Moonkin Form (Passive) - { - // Elune's Touch (instead non-existed triggered spell) 30% from AP - trigger_spell_id = 33926; - basepoints0 = GetTotalAttackPowerValue(BASE_ATTACK) * 30 / 100; - target = this; - } +// else if (auraSpellInfo->Id==55580) // Mana Link +// else if (auraSpellInfo->Id==45903) // Offensive State +// else if (auraSpellInfo->Id==44326) // Pure Energy Passive // else if (auraSpellInfo->Id==43453) // Rune Ward -// trigger_spell_id = ; -// else if (auraSpellInfo->Id==7137) // Shadow Charge (Rank 1) -// trigger_spell_id = ; - // Shaleskin (Shaleskin Flayer, Shaleskin Ripper) 30023 trigger -// else if (auraSpellInfo->Id==36576) -// trigger_spell_id = ; +// else if (auraSpellInfo->Id== 7137) // Shadow Charge (Rank 1) +// else if (auraSpellInfo->Id==36576) // Shaleskin (Shaleskin Flayer, Shaleskin Ripper) 30023 trigger // else if (auraSpellInfo->Id==34783) // Spell Reflection -// trigger_spell_id = ; // else if (auraSpellInfo->Id==36096) // Spell Reflection -// trigger_spell_id = ; +// else if (auraSpellInfo->Id==57587) // Steal Ranged () // else if (auraSpellInfo->Id==36207) // Steal Weapon -// trigger_spell_id = ; +// else if (auraSpellInfo->Id== 7377) // Take Immune Periodic Damage // else if (auraSpellInfo->Id==35205) // Vanish +// else if (auraSpellInfo->Id==42730) // Woe Strike +// else if (auraSpellInfo->Id==59735) // Woe Strike +// else if (auraSpellInfo->Id==46146) // [PH] Ahune Spanky Hands break; //===================================================================== // Mage @@ -7315,27 +5764,20 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB //===================================================================== // Warrior //===================================================================== - // Rampage (Rank 1-3) trigger = 18350 + // Scent of Blood //===================================================================== case SPELLFAMILY_WARRIOR: - // Rampage - if (auraSpellInfo->SpellIconID == 2006 && auraSpellInfo->SpellFamilyFlags==0x100000) { - switch(auraSpellInfo->Id) - { - case 29801: trigger_spell_id = 30029; break; // Rank 1 - case 30030: trigger_spell_id = 30031; break; // Rank 2 - case 30033: trigger_spell_id = 30032; break; // Rank 3 - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in Rampage",auraSpellInfo->Id); - return false; - } + // Scent of Blood + if (auraSpellInfo->Id == 50421) + trigger_spell_id = 50422; } break; //===================================================================== // Warlock //===================================================================== // Pyroclasm trigger = 18350 + // Nether Protection trigger = 1206 // Drain Soul (Rank 1-5) trigger = 0 //===================================================================== case SPELLFAMILY_WARLOCK: @@ -7379,12 +5821,33 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113) { int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this); - basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100; + // Drain Soul + CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); + break; } } - if ( basepoints0 == 0 ) + // Not remove charge (aura removed on death in any cases) + // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura + return false; + } + // Nether Protection + else if (auraSpellInfo->SpellIconID == 1985) + { + if (!procSpell) return false; - trigger_spell_id = 18371; + switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) + { + case SPELL_SCHOOL_NORMAL: + case SPELL_SCHOOL_HOLY: + return false; // ignore + case SPELL_SCHOOL_FIRE: trigger_spell_id = 54371; break; + case SPELL_SCHOOL_NATURE: trigger_spell_id = 54375; break; + case SPELL_SCHOOL_FROST: trigger_spell_id = 54372; break; + case SPELL_SCHOOL_SHADOW: trigger_spell_id = 54374; break; + case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break; + default: + return false; + } } break; } @@ -7393,30 +5856,12 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB //===================================================================== // Greater Heal Refund trigger = 18350 // Blessed Recovery (Rank 1-3) trigger = 18350 - // Shadowguard (1-7) trigger = 28376 //===================================================================== case SPELLFAMILY_PRIEST: { // Greater Heal Refund if (auraSpellInfo->Id==37594) trigger_spell_id = 37595; - // Shadowguard - else if(auraSpellInfo->SpellFamilyFlags==0x100080000000LL && auraSpellInfo->SpellVisual[0]==7958) - { - switch(auraSpellInfo->Id) - { - case 18137: trigger_spell_id = 28377; break; // Rank 1 - case 19308: trigger_spell_id = 28378; break; // Rank 2 - case 19309: trigger_spell_id = 28379; break; // Rank 3 - case 19310: trigger_spell_id = 28380; break; // Rank 4 - case 19311: trigger_spell_id = 28381; break; // Rank 5 - case 19312: trigger_spell_id = 28382; break; // Rank 6 - case 25477: trigger_spell_id = 28385; break; // Rank 7 - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG", auraSpellInfo->Id); - return false; - } - } // Blessed Recovery else if (auraSpellInfo->SpellIconID == 1875) { @@ -7483,9 +5928,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB // Blessed Life trigger = 31934 // Healing Discount trigger = 18350 // Illumination (Rank 1-5) trigger = 18350 - // Judgement of Light (Rank 1-5) trigger = 5373 - // Judgement of Wisdom (Rank 1-4) trigger = 1826 // Lightning Capacitor trigger = 18350 + // Thunder Capacitor trigger = 18350 + // Soul Preserver trigger = 18350 //===================================================================== case SPELLFAMILY_PALADIN: { @@ -7509,28 +5954,11 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB trigger_spell_id = 37706; target = this; } - // Judgement of Light and Judgement of Wisdom - else if (auraSpellInfo->SpellFamilyFlags & 0x0000000000080000LL) + // Soul Preserver + if (auraSpellInfo->Id==60510) { - switch (auraSpellInfo->Id) - { - // Judgement of Light - case 20185: trigger_spell_id = 20267;break; // Rank 1 - case 20344: trigger_spell_id = 20341;break; // Rank 2 - case 20345: trigger_spell_id = 20342;break; // Rank 3 - case 20346: trigger_spell_id = 20343;break; // Rank 4 - case 27162: trigger_spell_id = 27163;break; // Rank 5 - // Judgement of Wisdom - case 20186: trigger_spell_id = 20268;break; // Rank 1 - case 20354: trigger_spell_id = 20352;break; // Rank 2 - case 20355: trigger_spell_id = 20353;break; // Rank 3 - case 27164: trigger_spell_id = 27165;break; // Rank 4 - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Judgement of Light/Wisdom", auraSpellInfo->Id); - return false; - } - pVictim->CastSpell(pVictim, trigger_spell_id, true, castItem, triggeredByAura); - return true; // no hidden cooldown + trigger_spell_id = 60515; + target = this; } // Illumination else if (auraSpellInfo->SpellIconID==241) @@ -7577,13 +6005,34 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB if (!dummy) return false; // release at 3 aura in stack (cont contain in basepoint of trigger aura) - if(dummy->GetStackAmount() <= 2) + if(dummy->GetStackAmount() < triggerAmount) return false; RemoveAurasDueToSpell(37658); trigger_spell_id = 37661; target = pVictim; } + // Thunder Capacitor + else if (auraSpellInfo->Id == 54841) + { + if(!pVictim || !pVictim->isAlive()) + return false; + // stacking + CastSpell(this, 54842, true, NULL, triggeredByAura); + // counting + uint32 count = 0; + AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr) + if((*itr)->GetId()==54842) + ++count; + // release at 3 aura in stack (cont contain in basepoint of trigger aura) + if(count < triggerAmount) + return false; + + RemoveAurasDueToSpell(54842); + trigger_spell_id = 54843; + target = pVictim; + } break; } //===================================================================== @@ -7595,8 +6044,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB //===================================================================== case SPELLFAMILY_SHAMAN: { - //Lightning Shield (overwrite non existing triggered spell call in spell.dbc - if(auraSpellInfo->SpellFamilyFlags==0x00000400 && auraSpellInfo->SpellVisual[0]==37) + // Lightning Shield (overwrite non existing triggered spell call in spell.dbc + if(auraSpellInfo->SpellFamilyFlags & 0x0000000000000400) { switch(auraSpellInfo->Id) { @@ -7609,6 +6058,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB case 10432: trigger_spell_id = 26363; break; // Rank 7 case 25469: trigger_spell_id = 26371; break; // Rank 8 case 25472: trigger_spell_id = 26372; break; // Rank 9 + case 49280: trigger_spell_id = 49278; break; // Rank 10 + case 49281: trigger_spell_id = 49279; break; // Rank 11 default: sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield", auraSpellInfo->Id); return false; @@ -7632,7 +6083,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB trigger_spell_id = 23571; target = this; } - else if (auraSpellInfo->SpellIconID == 2013) //Nature's Guardian + // Nature's Guardian + else if (auraSpellInfo->SpellIconID == 2013) { // Check health condition - should drop to less 30% (damage deal after this!) if (!(10*(int32(GetHealth() - damage)) < 3 * GetMaxHealth())) @@ -7647,6 +6099,45 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB } break; } + //===================================================================== + // Death Knight + //==================================================================== + // Acclimation trigger = 1206 + // Blood Presence trigger = 1206 + //===================================================================== + case SPELLFAMILY_DEATHKNIGHT: + { + // Acclimation + if (auraSpellInfo->SpellIconID == 1930) + { + if (!procSpell) + return false; + switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) + { + case SPELL_SCHOOL_NORMAL: + return false; // ignore + case SPELL_SCHOOL_HOLY: trigger_spell_id = 50490; break; + case SPELL_SCHOOL_FIRE: trigger_spell_id = 50362; break; + case SPELL_SCHOOL_NATURE: trigger_spell_id = 50488; break; + case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break; + case SPELL_SCHOOL_SHADOW: trigger_spell_id = 50489; break; + case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break; + default: + return false; + } + } + // Blood Presence + else if (auraSpellInfo->Id == 48266) + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + if (!((Player*)this)->RewardPlayerAndGroupAtKill(pVictim)) + return false; + trigger_spell_id = 50475; + basepoints0 = damage * triggerAmount / 100; + } + break; + } // default default: break; @@ -8000,7 +6491,7 @@ bool Unit::IsHostileTo(Unit const* unit) const return false; // Sanctuary - if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) + if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) return false; // PvP FFA state @@ -8109,7 +6600,7 @@ bool Unit::IsFriendlyTo(Unit const* unit) const return true; // Sanctuary - if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) + if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) return true; // PvP FFA state @@ -11394,181 +9885,6 @@ bool Unit::isFrozen() const return false; } -/* -struct ProcTriggeredData -{ - ProcTriggeredData(Aura* _triggeredByAura, uint32 _cooldown) - : 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 -}; - -typedef std::list< ProcTriggeredData > ProcTriggeredList; - -void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask ) -{ - for(AuraTypeSet::const_iterator aur = procAuraTypes.begin(); aur != procAuraTypes.end(); ++aur) - { - // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE) - ProcTriggeredList procTriggered; - - AuraList const& auras = GetAurasByType(*aur); - for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next) - { - next = i; ++next; - - Aura* i_aura = *i; - - uint32 cooldown; // returned at next line - if(!IsTriggeredAtSpellProcEvent(i_aura->GetSpellProto(), procSpell, procFlag,attType,isVictim,cooldown)) - continue; - - procTriggered.push_back( ProcTriggeredData(i_aura, cooldown) ); - } - - // Handle effects proceed this time - for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i) - { - // Some auras can be deleted in function called in this loop (except first, ofc) - // Until storing auras in std::multimap to hard check deleting by another way - if(i != procTriggered.begin()) - { - bool found = false; - AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair); - AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair); - for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr) - { - if(itr->second==i->triggeredByAura) - { - found = true; - break; - } - } - - if(!found) - { - sLog.outError("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler",*aur,i->triggeredByAura_SpellPair.first,i->triggeredByAura_SpellPair.second); - sLog.outError("It can be deleted one from early processed auras:"); - for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2) - sLog.outError(" Spell aura %u (id:%u effect:%u)",*aur,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second); - sLog.outError(" "); - continue; - } - } - - /// 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 - /// used in speedup code check before check aura existance. - bool triggeredByAuraWithCharges = triggeredByAura->m_procCharges > 0; - - /// success in event proccesing - /// used in speedup code check before check aura existance. - bool casted = false; - - /// process triggered code - 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"),triggeredByAura->GetId()); - casted = HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, 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); - 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); - 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()); - - casted = HandleMeandingAuraProc(triggeredByAura); - 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, 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; - break; - } - case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: - { - sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s class script aura of spell %u)", - (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); - casted = HandleOverrideClassScriptAuraProc(pTarget, triggeredByAura, procSpell,i->cooldown); - break; - } - default: - { - // nothing do, just charges counter - casted = true; - break; - } - } - - /// Update charge (aura can be removed by triggers) - if(casted && triggeredByAuraWithCharges) - { - /// need re-found aura (can be dropped by triggers) - AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair); - AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair); - for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr) - { - if(itr->second == triggeredByAura) // pointer still valid - { - if(triggeredByAura->m_procCharges > 0) - triggeredByAura->m_procCharges -= 1; - - triggeredByAura->UpdateAuraCharges(); - break; - } - } - } - } - - /// Safely remove auras with zero charges - for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next) - { - next = i; ++next; - if((*i)->m_procCharges == 0) - { - RemoveAurasDueToSpell((*i)->GetId()); - next = auras.begin(); - } - } - } -} -*/ struct ProcTriggeredData { ProcTriggeredData(SpellProcEventEntry const * _spellProcEvent, Aura* _triggeredByAura) @@ -11587,9 +9903,7 @@ typedef std::list< uint32> RemoveSpellList; // in most case need for drop charges // in some types of aura need do additional check // for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic -static bool isTriggerAura[TOTAL_AURAS]; -static bool isNonTriggerAura[TOTAL_AURAS]; -void InitTriggerAuraData() +bool InitTriggerAuraData() { for (int i=0;iGetTypeId() == TYPEID_PLAYER ? 5 : 7; + int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim); + if(leveldif < 3) + HitChance = 95 - leveldif; + else + HitChance = 93 - (leveldif - 2) * lchance;*/ + if (spellId || attType == RANGED_ATTACK || !haveOffhandWeapon()) + HitChance = 95.0f; + else + HitChance = 76.0f; + + // Hit chance depends from victim auras + if(attType == RANGED_ATTACK) + HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); + else + HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); + + // Spellmod from SPELLMOD_RESIST_MISS_CHANCE + if(spellId) + { + if(Player *modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, HitChance); + } + + // Miss = 100 - hit + float miss_chance= 100.0f - HitChance; + + // Bonuses from attacker aura and ratings + if (attType == RANGED_ATTACK) + miss_chance -= m_modRangedHitChance; + else + miss_chance -= m_modMeleeHitChance; + + // bonus from skills is 0.04% + //miss_chance -= skillDiff * 0.04f; + int32 diff = -skillDiff; + if(pVictim->GetTypeId()==TYPEID_PLAYER) + miss_chance += diff > 0 ? diff * 0.04 : diff * 0.02; + else + miss_chance += diff > 10 ? 2 + (diff - 10) * 0.4 : diff * 0.1; + + // Limit miss chance from 0 to 60% + if (miss_chance < 0.0f) + return 0.0f; + if (miss_chance > 60.0f) + return 60.0f; + return miss_chance; +} diff --git a/src/game/Unit.h b/src/game/Unit.h index 31787663968..01eba9d0184 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -778,7 +778,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject typedef std::multimap< spellEffectPair, Aura*> AuraMap; typedef std::list AuraList; typedef std::list Diminishing; - typedef std::set AuraTypeSet; typedef std::set ComboPointHolderSet; typedef std::map VisibleAuraMap; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 08976dc2423..5d8d14cb83b 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "6957" + #define REVISION_NR "6963" #endif // __REVISION_NR_H__ -- cgit v1.2.3