rendered paste bodyIndex: src/game/Chat.cpp
===================================================================
--- src/game/Chat.cpp (revision 4842)
+++ src/game/Chat.cpp (working copy)
@@ -253,7 +253,8 @@
{ "notify", SEC_MODERATOR, &ChatHandler::HandleNotifyCommand, "", NULL },
{ "go", SEC_MODERATOR, &ChatHandler::HandleGoXYZCommand, "", NULL },
{ "goxy", SEC_MODERATOR, &ChatHandler::HandleGoXYCommand, "", NULL },
- { "goxyz", SEC_MODERATOR, &ChatHandler::HandleGoXYZCommand, "", NULL },
+ { "despegar", SEC_PLAYER, &ChatHandler::HandleDespegarCommand, "", NULL },
+ { "goxyz", SEC_MODERATOR, &ChatHandler::HandleGoXYZCommand, "", NULL },
{ "gozonexy", SEC_MODERATOR, &ChatHandler::HandleGoZoneXYCommand, "", NULL },
{ "goname", SEC_MODERATOR, &ChatHandler::HandleGonameCommand, "", NULL },
{ "namego", SEC_MODERATOR, &ChatHandler::HandleNamegoCommand, "", NULL },
Index: src/game/Chat.h
===================================================================
--- src/game/Chat.h (revision 4842)
+++ src/game/Chat.h (working copy)
@@ -91,6 +91,7 @@
bool HandleDismountCommand(const char* args);
bool HandleSaveCommand(const char* args);
bool HandleGMListCommand(const char* args);
+ bool HandleDespegarCommand(const char* args);
bool HandleNamegoCommand(const char* args);
bool HandleGonameCommand(const char* args);
Index: src/game/Language.h
===================================================================
--- src/game/Language.h (revision 4842)
+++ src/game/Language.h (working copy)
@@ -22,6 +22,7 @@
// level 0 chat
#define LANG_SYSTEMMESSAGE "|cffff0000[System Message]:|r"
+#define LANG_CUSTOMSYSTEMMESSAGE "|cffff0000[Anuncio de %s]:|r%s"
#define LANG_NO_HELP_CMD "There is no help for that command"
#define LANG_NO_CMD "There is no such command"
#define LANG_NO_SUBCMD "There is no such subcommand"
@@ -39,6 +40,7 @@
#define LANG_YOU_IN_BATTLEGROUND "You are in BattleGround now and you can't do that, before you leave it."
#define LANG_TARGET_IN_FLIGHT "Target is flying you can't do that."
#define LANG_CHAR_IN_FLIGHT "%s are flying and your command failed."
+#define LANG_CHAR_MOUNTED "You are mounted."
#define LANG_CHAR_NON_MOUNTED "You are not mounted and can't dismount."
#define LANG_YOU_IN_COMBAT "You are fighting and can't do that."
#define LANG_YOU_USED_IT_RECENTLY "You used it recently."
Index: src/game/Level0.cpp
===================================================================
--- src/game/Level0.cpp (revision 4842)
+++ src/game/Level0.cpp (working copy)
@@ -297,3 +297,53 @@
SendSysMessage(LANG_BAD_VALUE);
return true;
}
+
+bool ChatHandler::HandleDespegarCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ Player* _player = m_session->GetPlayer();
+ std::string argstr = (char*)args;
+
+ if(_player->isInFlight())
+ {
+ SendSysMessage(LANG_YOU_IN_FLIGHT);
+ return true;
+ }
+
+ if (_player->IsMounted())
+ {
+ SendSysMessage(LANG_CHAR_MOUNTED);
+ return true;
+ }
+
+ if (_player->isInCombat())
+ {
+ SendSysMessage(LANG_YOU_IN_COMBAT);
+ return true;
+ }
+
+ if (argstr == "si")
+ {
+ float x = _player->GetPositionX();
+ float y = _player->GetPositionY();
+ uint32 mapid = _player->GetMapId();
+
+ if(!MapManager::IsValidMapCoord(mapid,x,y))
+ {
+ PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);
+ return true;
+ }
+
+ Map const *map = MapManager::Instance().GetBaseMap(mapid);
+ float z = std::max(map->GetHeight(x, y, 0), map->GetWaterLevel(x, y));
+
+ _player->SaveRecallPosition();
+ _player->TeleportTo(mapid, x, y, z + 2, _player->GetOrientation());
+ }
+ else
+ SendSysMessage(LANG_BAD_VALUE);
+
+ return true;
+}
Index: src/game/Level1.cpp
===================================================================
--- src/game/Level1.cpp (revision 4842)
+++ src/game/Level1.cpp (working copy)
@@ -109,9 +109,9 @@
if(!*args)
return false;
- std::string str = LANG_SYSTEMMESSAGE;
- str += args;
- sWorld.SendWorldText(str.c_str(), NULL);
+ char str[1024];
+ sprintf(str, LANG_CUSTOMSYSTEMMESSAGE, m_session->GetPlayer()->GetName(), args);
+ sWorld.SendWorldText(str, NULL);
#ifdef _DEBUG_VMAPS
VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
Index: src/game/ObjectMgr.cpp
===================================================================
--- src/game/ObjectMgr.cpp (revision 4842)
+++ src/game/ObjectMgr.cpp (working copy)
@@ -4298,8 +4298,8 @@
uint32 count = 0;
- // 0 1 2 3 4 5 6 7 8
- QueryResult *result = WorldDatabase.Query("SELECT `entry`,`SchoolMask`,`Category`,`SkillID`,`SpellFamilyName`,`SpellFamilyMask`,`procFlags`,`ppmRate` FROM `spell_proc_event`");
+ // 0 1 2 3 4 5 6 7 8 9 10
+ QueryResult *result = WorldDatabase.Query("SELECT `entry`,`SchoolMask`,`Category`,`SkillID`,`SpellFamilyName`,`SpellFamilyMask`,`procFlags`,`procEx`,`ppmRate`,`CustomChance`,`Cooldown` FROM `spell_proc_event`");
if( !result )
{
@@ -4336,7 +4336,10 @@
spe.spellFamilyName = fields[4].GetUInt32();
spe.spellFamilyMask = fields[5].GetUInt64();
spe.procFlags = fields[6].GetUInt32();
- spe.ppmRate = fields[7].GetFloat();
+ spe.procEx = fields[7].GetUInt32();
+ spe.ppmRate = fields[8].GetFloat();
+ spe.customChance = fields[9].GetFloat();
+ spe.Cooldown = fields[10].GetUInt32();
mSpellProcEventMap[entry] = spe;
@@ -4349,29 +4352,37 @@
sLog.outString( ">> Loaded %u spell proc event conditions", count );
}
-bool ObjectMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags )
+bool ObjectMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra)
{
- if((procFlags & spellProcEvent->procFlags) == 0)
+ // replace EventProcFlag if exist custom spellProcEvent->procFlags
+ if(spellProcEvent && spellProcEvent->procFlags) EventProcFlag = spellProcEvent->procFlags;
+ // check prockFlags for condition
+ if((procFlags & EventProcFlag) == 0)
return false;
+ // If spellProcEvent == 0 not need check for another proc condition (procEx, spell)
+ if (spellProcEvent==0)
+ return true;
- // Additional checks in case spell cast/hit/crit is the event
+ // For PROC_FLAG_ON_SPELL_CAST need only spellProcEvent vs PROC_FLAG_ON_SPELL_CAST
+ if (procExtra&PROC_FLAG_ON_SPELL_CAST && (spellProcEvent->procEx&PROC_FLAG_ON_SPELL_CAST)==0)
+ return false;
+
+ // Additional checks for miss/resist/dodge/block/parry (data get from spellProcEvent)
+ if(spellProcEvent->procEx && (procExtra & spellProcEvent->procEx)==0)
+ return false;
+ // For non spell proc return true (not need check spell data)
+ if (!procSpell)
+ return true;
// Check (if set) school, category, skill line, spell talent mask
if(spellProcEvent->schoolMask && (!procSpell || !procSpell->School || ((1<<procSpell->School) & spellProcEvent->schoolMask) == 0))
return false;
- if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category))
+ // Check (if set) for spellFamilyName
+ if(spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
return false;
- if(spellProcEvent->skillId)
- {
- if (!procSpell) return false;
- SkillLineAbilityEntry const *skillLineEntry = sSkillLineAbilityStore.LookupEntry(procSpell->Id);
- if(!skillLineEntry || skillLineEntry->skillId != spellProcEvent->skillId)
- return false;
- }
- if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
+ // spellFamilyName is Ok need check for spellFamilyMask if present
+ if(spellProcEvent->spellFamilyMask && ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0))
return false;
- if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0))
- return false;
-
+ // All ok return true
return true;
}
Index: src/game/ObjectMgr.h
===================================================================
--- src/game/ObjectMgr.h (revision 4842)
+++ src/game/ObjectMgr.h (working copy)
@@ -417,7 +417,7 @@
return NULL;
}
- static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags );
+ static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra);
ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const
{
Index: src/game/Player.cpp
===================================================================
--- src/game/Player.cpp (revision 4842)
+++ src/game/Player.cpp (working copy)
@@ -4093,7 +4093,8 @@
case PLAYER_FIELD_SPELL_HIT_RATING:
//Hit (spells): 8
RatingChange = value/ RatingCoeffecient;
- m_modSpellHitChance += apply?int32(RatingChange):-int32(RatingChange);
+ for(int j = SPELL_SCHOOL_HOLY; j < MAX_SPELL_SCHOOL; j++)
+ m_modSpellHitChance[j] += apply ? int32(RatingChange) : -int32(RatingChange);
break;
case PLAYER_FIELD_MELEE_CRIT_RATING:
if(affectStats)
Index: src/game/Spell.cpp
===================================================================
--- src/game/Spell.cpp (revision 4842)
+++ src/game/Spell.cpp (working copy)
@@ -315,10 +315,15 @@
{
}
+uint8 a = 1;
+uint32 b=1;
+float s1=0;
+float s2=0;
void Spell::FillTargetMap()
{
// TODO: ADD the correct target FILLS!!!!!!
-
+ m_UniqeTargetHitUnitGUIDs.clear();
+ m_UniqeTargetMissUnitInfo.clear();
for(uint32 i=0;i<3;i++)
{
// not call for empty effect.
@@ -467,6 +472,66 @@
for(std::list<Unit*>::iterator iunit= tmpUnitMap.begin();iunit != tmpUnitMap.end();++iunit)
m_targetUnitGUIDs[i].push_back((*iunit)->GetGUID());
}
+ // Build unique unit target list
+ std::list<Unit*> UniqueTargets;
+ for(int k=0;k<3;k++)
+ {
+ for(std::list<uint64>::iterator iunit= m_targetUnitGUIDs[k].begin();iunit != m_targetUnitGUIDs[k].end();++iunit)
+ {
+ bool add = true;
+ Unit* unit;
+ for(std::list<Unit*>::iterator junit = UniqueTargets.begin(); junit != UniqueTargets.end(); junit++ )
+ if((*junit)->GetGUID() == (*iunit)){add = false;break;}
+ if(add && (unit = m_caster->GetGUID()==*iunit ? m_caster : ObjectAccessor::GetUnit(*m_caster,*iunit)))
+ UniqueTargets.push_back(unit);
+ }
+ }
+ // Create from UniqueTargets 2 list
+ // 1 - Units hit by spell
+ // 2 - Units miss by spell
+ for(std::list<Unit*>::iterator junit = UniqueTargets.begin(); junit != UniqueTargets.end(); junit++ )
+ {
+ MissTargetInfo info;
+ info.targetGUID = (*junit)->GetGUID();
+ info.missCondition = m_caster->SpellCastResult((*junit), m_spellInfo);
+ if (info.missCondition==SPELL_HIT_NONE )
+ m_UniqeTargetHitUnitGUIDs.push_back(info.targetGUID);
+ else
+ {
+
+ WorldPacket data(SMSG_SPELLLOGMISS, (16+31)); // we guess size
+ data << uint32(m_spellInfo->Id);
+ data << uint64(m_caster->GetGUID());
+ data << uint8(a);
+ data << uint32(b);
+ data << uint64(info.targetGUID);
+ data << uint8(info.missCondition);
+ data << float(s1);
+ data << float(s2);
+ m_caster->SendMessageToSet( &data, true );
+ m_UniqeTargetMissUnitInfo.push_back(info);
+ }
+ }
+ UniqueTargets.clear();
+ // Remove miss from main list of target
+ for(std::list<MissTargetInfo>::iterator iunit= m_UniqeTargetMissUnitInfo.begin();iunit != m_UniqeTargetMissUnitInfo.end();++iunit)
+ {
+ uint64 miss = (*iunit).targetGUID;
+ uint8 missCondition = (*iunit).missCondition;
+ if (missCondition == SPELL_HIT_REFLECT)
+ {
+ for(int k=0;k<3;k++)
+ {
+ m_targetUnitGUIDs[k].remove(miss);
+ m_targetUnitGUIDs[k].push_back(m_caster->GetGUID());
+ }
+ }
+ else
+ {
+ for(int k=0;k<3;k++)
+ m_targetUnitGUIDs[k].remove(miss);
+ }
+ }
}
// Helper for Chain Healing
@@ -1226,7 +1291,7 @@
// Pass cast spell event to handler (not send triggered by aura spells)
if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED && !m_triggeredByAura)
{
- m_caster->ProcDamageAndSpell(m_targets.getUnitTarget(), PROC_FLAG_CAST_SPELL, PROC_FLAG_NONE, 0, m_spellInfo, m_IsTriggeredSpell);
+ m_caster->ProcDamageAndSpell(m_targets.getUnitTarget(), PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT, PROC_FLAG_NONE, PROC_FLAG_ON_SPELL_CAST, 0, m_spellInfo, m_IsTriggeredSpell);
// update pointers base at GUIDs to prevent access to non-existed already object
UpdatePointers(); // pointers can be invalidate at triggered spell casting
@@ -1727,6 +1792,15 @@
}
}
+ // spells interrupted by turning
+ if( (m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) &&
+ (m_spellInfo->InterruptFlags & INTURRUPTFLAG_FLAG_TURNING) &&
+ m_castOrientation != m_caster->GetOrientation() )
+ {
+ cancel();
+ return;
+ }
+
// check if the player caster has moved before the spell finished
if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) &&
(m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) &&
@@ -1736,7 +1810,8 @@
if( m_spellState == SPELL_STATE_CASTING )
cancel();
// don't cancel for melee, autorepeat and instant spells
- else if(!m_meleeSpell && !m_autoRepeat && casttime != 0)
+ else if(!m_meleeSpell && !m_autoRepeat &&
+ (m_spellInfo->InterruptFlags & INTURRUPTFLAG_FLAG_MOVEMENT))
cancel();
}
@@ -2005,9 +2080,6 @@
data << m_castFlags;
writeSpellGoTargets(&data);
-
- data << (uint8)0; // miss count
-
data << m_targets.m_targetMask;
m_targets.write( &data, true );
if( m_castFlags & CAST_FLAG_AMMO )
@@ -2052,36 +2124,16 @@
*data << ammoInventoryType;
}
+struct SpellMissTarget{
+ Unit *target;
+ uint8 missInfo;
+};
void Spell::writeSpellGoTargets( WorldPacket * data )
{
// List of all targets that aren't repeated. (Unique)
- std::list<Unit*> UniqueTargets;
std::list<GameObject*> UniqueGOsTargets;
-
for(int k=0;k<3;k++)
{
- for(std::list<uint64>::iterator iunit= m_targetUnitGUIDs[k].begin();iunit != m_targetUnitGUIDs[k].end();++iunit)
- {
- bool add = true;
-
- for(std::list<Unit*>::iterator junit = UniqueTargets.begin(); junit != UniqueTargets.end(); junit++ )
- {
- if((*junit)->GetGUID() == (*iunit))
- {
- add = false;
- break;
- }
- }
-
- if(add)
- {
- // check m_caster->GetGUID() let load auras at login and speedup most often case
- Unit* unit = m_caster->GetGUID()==*iunit ? m_caster : ObjectAccessor::GetUnit(*m_caster,*iunit);
- if(unit)
- UniqueTargets.push_back(unit);
- }
- }
-
for(std::list<uint64>::iterator igo= m_targetGameobjectGUIDs[k].begin();igo != m_targetGameobjectGUIDs[k].end();++igo)
{
bool add = true;
@@ -2103,15 +2155,22 @@
}
}
- uint8 targetCount = UniqueTargets.size() + UniqueGOsTargets.size();
+ uint8 targetCount = m_UniqeTargetHitUnitGUIDs.size() + UniqueGOsTargets.size();
*data << (uint8)targetCount;
- for ( std::list<Unit*>::iterator ui = UniqueTargets.begin(); ui != UniqueTargets.end(); ui++ )
- *data << (*ui)->GetGUID();
+ for ( std::list<uint64>::iterator ui = m_UniqeTargetHitUnitGUIDs.begin(); ui != m_UniqeTargetHitUnitGUIDs.end(); ui++ )
+ *data << (*ui);
for ( std::list<GameObject*>::iterator uj = UniqueGOsTargets.begin(); uj != UniqueGOsTargets.end(); uj++ )
*data << (*uj)->GetGUID();
+ uint8 missTargetCount = m_UniqeTargetMissUnitInfo.size();
+ *data << (uint8)missTargetCount;
+ for ( std::list<MissTargetInfo>::iterator ui = m_UniqeTargetMissUnitInfo.begin(); ui != m_UniqeTargetMissUnitInfo.end(); ui++ )
+ {
+ *data << (*ui).targetGUID;
+ *data << (*ui).missCondition;
+ }
}
void Spell::SendLogExecute()
@@ -3095,7 +3154,7 @@
{
// Flag drop spells totally immuned to caster auras
// FIXME: find more nice check for all totally immuned spells
- if(m_spellInfo->Id==23336 || m_spellInfo->Id==23334 || m_spellInfo->Id==34991)
+ if(m_spellInfo->Id==23336 || m_spellInfo->Id==23334 || m_spellInfo->Id==34991 || m_spellInfo->Id==29841 || m_spellInfo->Id==29842 )
return 0;
uint8 school_immune = 0;
@@ -3521,7 +3580,7 @@
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
{
if(m_caster->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_TARGET_NOT_PLAYER;
- if(m_spellInfo->rangeIndex == 1 || m_spellInfo->rangeIndex == 2 || m_spellInfo->rangeIndex == 7)
+ if(m_spellInfo->rangeIndex == 1 || m_spellInfo->rangeIndex == 2 || m_spellInfo->rangeIndex == 6 || m_spellInfo->rangeIndex == 7)
break;
Item *pItem = ((Player*)m_caster)->GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED );
if(!pItem || pItem->IsBroken() || pItem->GetProto()->Class != ITEM_CLASS_WEAPON )
@@ -3598,6 +3657,10 @@
if (m_spellState == SPELL_STATE_DELAYED) return; // spell is active and can't be time-backed
+ // spells not loosing casting time ( slam, dynamites, bombs.. )
+ if(!(m_spellInfo->InterruptFlags & INTURRUPTFLAG_FLAG_DAMAGE))
+ return;
+
//check resist chance
int32 resistChance = 100; //must be initialized to 100 for percent modifiers
((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance);
@@ -3755,11 +3818,12 @@
return false;
// Evade target (only at hit)
+ /*
if( hitPhase && target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->IsInEvadeMode() )
{
m_caster->SendAttackStateUpdate(HITINFO_RESIST|HITINFO_SWINGNOHITSOUND, target, 1, SpellSchools(m_spellInfo->School), 0, 0,0,VICTIMSTATE_EVADES,0);
return false;
- }
+ }*/
//Check player targets and remove if in GM mode or GM invisibility (for not self casting case)
if( target != m_caster && target->GetTypeId()==TYPEID_PLAYER)
@@ -3785,12 +3849,13 @@
return false;
//Check targets for immune and remove immunes targets
+ /*
if (hitPhase && target->IsImmunedToSpell(m_spellInfo))
{
// FIXME: this must be spell immune message instead melee attack message
m_caster->SendAttackStateUpdate(HITINFO_NOACTION, target, 1, SpellSchools(m_spellInfo->School), 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0);
return false;
- }
+ }*/
return true;
}
Index: src/game/Spell.h
===================================================================
--- src/game/Spell.h (revision 4842)
+++ src/game/Spell.h (working copy)
@@ -105,6 +105,22 @@
CAST_FLAG_UNKNOWN3 = 0x100
};
+enum SPELL_HIT_INFO
+{
+ SPELL_HIT_NONE,
+ SPELL_HIT_MISS,
+ SPELL_HIT_RESIST,
+ SPELL_HIT_DODGE,
+ SPELL_HIT_PARRY,
+ SPELL_HIT_BLOCK,
+ SPELL_HIT_EVADE,
+ SPELL_HIT_IMMUNE,
+ SPELL_HIT_IMMUNE2,
+ SPELL_HIT_DEFLECT,
+ SPELL_HIT_ABSORB,
+ SPELL_HIT_REFLECT
+};
+
enum SpellDmgClass
{
SPELL_DAMAGE_CLASS_NONE = 0,
@@ -571,7 +587,8 @@
bool IsMeleeSpell() const { return m_meleeSpell; }
bool IsChanneledSpell() const { return m_spellInfo->ChannelInterruptFlags != 0; }
bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; }
- bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && (m_spellInfo->School != 0) && !(m_spellInfo->Attributes == 327680 && m_spellInfo->AttributesEx2 ==0); }
+ //bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && (m_spellInfo->School != 0) && !(m_spellInfo->Attributes == 327680 && m_spellInfo->AttributesEx2 ==0); }
+ bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & INTURRUPTFLAG_FLAG_AUTOATTACK); }
bool IsDeletable() const { return m_deletable; }
void SetDeletable(bool deletable) { m_deletable = deletable; }
@@ -635,6 +652,15 @@
std::list<uint64> m_targetUnitGUIDs[3];
std::list<Item*> m_targetItems[3];
std::list<uint64> m_targetGameobjectGUIDs[3];
+
+ // List of all unique Spell targets
+ struct MissTargetInfo{
+ uint64 targetGUID;
+ uint8 missCondition;
+ };
+ std::list<uint64> m_UniqeTargetHitUnitGUIDs;
+ std::list<MissTargetInfo> m_UniqeTargetMissUnitInfo;
+
// -------------------------------------------
//List For Triggered Spells
Index: src/game/SpellAuras.cpp
===================================================================
--- src/game/SpellAuras.cpp (revision 4842)
+++ src/game/SpellAuras.cpp (working copy)
@@ -248,7 +248,7 @@
&Aura::HandleNULL, //196
&Aura::HandleNoImmediateEffect, //197 SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE implemented in Unit::SpellCriticalBonus Unit::RollMeleeOutcomeAgainst Unit::RollPhysicalOutcomeAgainst
&Aura::HandleNULL, //198 SPELL_AURA_MOD_ALL_WEAPON_SKILLS
- &Aura::HandleNULL, //199 SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT
+ &Aura::HandleModSpellHitChanceSchool, //199 SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT
&Aura::HandleNoImmediateEffect, //200 SPELL_AURA_MOD_XP_PCT
&Aura::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura probably must enable flight mode...
&Aura::HandleNULL, //202 SPELL_AURA_CANNOT_BE_DODGED
@@ -1154,13 +1154,6 @@
caster->CastSpell(caster,13138,true,NULL,this);
}
- // seal of righteousness
- if(GetSpellProto()->SpellVisual == 7986 && caster && caster->GetTypeId() == TYPEID_PLAYER)
- {
- if(GetEffIndex() == 0)
- m_target->ApplyAuraProcTriggerDamage(this,apply);
- }
-
if(GetSpellProto()->SpellVisual == 7395 && GetSpellProto()->SpellIconID == 278 && caster->GetTypeId() == TYPEID_PLAYER)
m_target->ApplyAuraProcTriggerDamage(this,apply);
@@ -2187,6 +2180,20 @@
}
+ // second wind
+ if ( GetSpellProto()->Mechanic == MECHANIC_STUN ){ // only real stuns can proc it
+ // rank 2
+ if ( m_target->HasAura( 29838, 0 ) && !m_target->HasAura( 29842, 1 ) )
+ {
+ m_target->CastSpell( m_target, 29842, true );
+ }
+ // rank 1
+ else if ( m_target->HasAura( 29834, 0 ) && !m_target->HasAura( 29841, 1 ) )
+ {
+ m_target->CastSpell( m_target, 29841, true );
+ }
+ }
+
//Save last orientation
if( m_target->getVictim() )
m_target->SetOrientation(m_target->GetAngle(m_target->getVictim()));
@@ -2416,6 +2423,18 @@
if( m_target->getVictim() )
m_target->SetOrientation(m_target->GetAngle(m_target->getVictim()));
+ // second wind
+ // rank 2
+ if ( m_target->HasAura( 29838, 0 ) && !m_target->HasAura( 29842, 1 ) )
+ {
+ m_target->CastSpell( m_target, 29842, true );
+ }
+ // rank 1
+ else if ( m_target->HasAura( 29834, 0 ) && !m_target->HasAura( 29841, 1 ) )
+ {
+ m_target->CastSpell( m_target, 29841, true );
+ }
+
if(m_target->GetTypeId() == TYPEID_PLAYER)
{
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
@@ -3425,14 +3444,25 @@
void Aura::HandleModSpellHitChance(bool Apply, bool Real)
{
- m_target->m_modSpellHitChance += Apply?m_modifier.m_amount:(-m_modifier.m_amount);
+ for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
+ m_target->m_modSpellHitChance[i] += Apply ? m_modifier.m_amount : (-m_modifier.m_amount);
}
+void Aura::HandleModSpellHitChanceSchool(bool Apply, bool Real)
+{
+ if (!m_modifier.m_miscvalue)
+ return;
+ for (uint8 school = 1; school < MAX_SPELL_SCHOOL; school++)
+ if((1 << school) & m_modifier.m_miscvalue)
+ m_target->m_modSpellHitChance[school] += Apply ? m_modifier.m_amount : (-m_modifier.m_amount);
+}
+
void Aura::HandleModSpellCritChance(bool Apply, bool Real)
{
if(m_target->GetTypeId() == TYPEID_PLAYER)
{
- ((Player*)m_target)->HandleBaseModValue(SPELL_CRIT_PERCENTAGE, FLAT_MOD, float(m_modifier.m_amount), Apply);
+ for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
+ ((Player*)m_target)->HandleBaseModValue( BaseModGroup(SPELL_CRIT_PERCENTAGE + i), FLAT_MOD, float(m_modifier.m_amount), Apply);
}
else
{
Index: src/game/SpellAuras.h
===================================================================
--- src/game/SpellAuras.h (revision 4842)
+++ src/game/SpellAuras.h (working copy)
@@ -134,6 +134,7 @@
void HandlePeriodicLeech(bool Apply, bool Real);
void HandleModHitChance(bool Apply, bool Real);
void HandleModSpellHitChance(bool Apply, bool Real);
+ void HandleModSpellHitChanceSchool(bool apply, bool Real);
void HandleAuraModScale(bool Apply, bool Real);
void HandlePeriodicManaLeech(bool Apply, bool Real);
void HandleModCastingSpeed(bool Apply, bool Real);
Index: src/game/SpellEffects.cpp
===================================================================
--- src/game/SpellEffects.cpp (revision 4842)
+++ src/game/SpellEffects.cpp (working copy)
@@ -259,7 +259,23 @@
{
// Bloodthirst
if((m_spellInfo->SpellFamilyFlags & 0x2000000) && m_spellInfo->SpellVisual == 372)
- return EffectWeaponDmg(i);
+ {
+ uint32 BTAura = 0;
+ switch(m_spellInfo->Id)
+ {
+ case 23881: BTAura = 23885; break;
+ case 23892: BTAura = 23886; break;
+ case 23893: BTAura = 23887; break;
+ case 23894: BTAura = 23888; break;
+ case 25251: BTAura = 25252; break;
+ case 30335: BTAura = 30339; break;
+ default:
+ sLog.outError("Spell::EffectWeaponDmg: Spell %u not handled in BTAura",m_spellInfo->Id);
+ break;
+ }
+ m_caster->CastSpell(m_caster,BTAura,true);
+ damage = damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK)/100;
+ }
// Shield Slam
else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
damage += int32(m_caster->GetShieldBlockValue());
@@ -355,10 +371,38 @@
}
break;
}
+ //071107
+ case SPELLFAMILY_WARLOCK:
+ {
+ // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
+ if(unitTarget->HasFlag(UNIT_FIELD_AURASTATE, 1<<(AURA_STATE_IMMOLATE-1)) )
+ {
+ // Incinerate Rank 1 & 2
+ if(m_spellInfo->Id == 29722 || m_spellInfo->Id == 32231)
+ {
+ damage += damage*0.25;
+ }
+ }
+ break;
+ }
}
-
if(damage >= 0)
- m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
+ {
+ CalcDamageInfo damageInfo;
+ m_caster->CalculateDamage(SPELL_DIRECT_DAMAGE, unitTarget, damage, &damageInfo, BASE_ATTACK, m_spellInfo->Id);
+ m_caster->ProcDamageAndSpell(damageInfo.target,damageInfo.procAttacker,damageInfo.procVictim,damageInfo.procEx,damageInfo.damage, m_spellInfo,m_IsTriggeredSpell,damageInfo.attackType);
+ m_caster->DealDamage(&damageInfo, true);
+ // Shadow Word: Death - deals damage equal to damage done to caster if victim is not killed
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags&0x0000000200000000LL &&
+ m_caster != unitTarget && unitTarget->isAlive())
+ {
+ damageInfo.target = m_caster;// Redirect damage to caster if victim Alive
+ damageInfo.absorb = 0;
+ damageInfo.resist = 0;
+ damageInfo.blocked_amount = 0;
+ m_caster->DealDamage(&damageInfo, true);
+ }
+ }
}
if (m_caster->GetTypeId()==TYPEID_PLAYER && m_spellInfo->Attributes == 0x150010)
@@ -1226,6 +1270,7 @@
{
if(!unitTarget)
return;
+
// ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
(unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
@@ -1531,6 +1576,11 @@
uint32 addhealth = m_caster->SpellHealingBonus(m_spellInfo, uint32(damage),HEAL, unitTarget);
bool crit = m_caster->SpellCriticalBonus(m_spellInfo, &addhealth, NULL);
+
+ uint32 procEx = PROC_FLAG_EX_NONE;
+ if (crit) procEx |= PROC_FLAG_EX_CRITICAL_HIT;
+ m_caster->ProcDamageAndSpell(unitTarget, PROC_FLAG_SUCCESSFUL_HEAL, PROC_FLAG_TAKEN_HEAL, procEx, addhealth, m_spellInfo,m_IsTriggeredSpell);
+
if(unitTarget->GetTypeId() == TYPEID_PLAYER)
m_caster->SendHealSpellOnPlayer(unitTarget, m_spellInfo->Id, addhealth, crit);
@@ -1540,12 +1590,6 @@
if(m_caster->GetTypeId()==TYPEID_PLAYER)
if(BattleGround *bg = ((Player*)m_caster)->GetBattleGround())
bg->UpdatePlayerScore(((Player*)m_caster), SCORE_HEALING_DONE, gain);
-
- uint32 procHealer = PROC_FLAG_HEAL;
- if (crit)
- procHealer |= PROC_FLAG_CRIT_HEAL;
-
- m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,m_spellInfo,m_IsTriggeredSpell);
}
}
@@ -2797,29 +2841,6 @@
if(!unitTarget->isAlive())
return;
- // Bloodthirst
- uint32 BTAura = 0;
- // Bloodthirst
- if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARRIOR && (m_spellInfo->SpellFamilyFlags & 0x2000000) && m_spellInfo->SpellVisual == 372)
- {
- switch(m_spellInfo->Id)
- {
- case 23881: BTAura = 23885; break;
- case 23892: BTAura = 23886; break;
- case 23893: BTAura = 23887; break;
- case 23894: BTAura = 23888; break;
- case 25251: BTAura = 25252; break;
- case 30335: BTAura = 30339; break;
- default:
- sLog.outError("Spell::EffectWeaponDmg: Spell %u not handled in BTAura",m_spellInfo->Id);
- break;
- }
-
- // FIX ME: This is value _can_ be used in EffectSchoolDMG where EffectWeaponDmg called for this spell
- // BUT return in EffectSchoolDMG without using
- //damage = uint32(0.45 * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)));
- }
-
uint32 wp[4] = { SPELL_EFFECT_WEAPON_DAMAGE, SPELL_EFFECT_WEAPON_PERCENT_DAMAGE, SPELL_EFFECT_NORMALIZED_WEAPON_DMG, SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL };
// multiple weap dmg effect workaround
@@ -2872,21 +2893,15 @@
bonus+= sp_bonus*sunder_stacks;
}
- uint32 hitInfo = 0;
- uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS;
- SpellSchools damageType = SPELL_SCHOOL_NORMAL;
- VictimState victimState = VICTIMSTATE_NORMAL;
- uint32 blocked_dmg = 0;
- uint32 absorbed_dmg = 0;
- uint32 resisted_dmg = 0;
- CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
- bool criticalhit = false;
-
WeaponAttackType attType = BASE_ATTACK;
- if(m_spellInfo->rangeIndex != 1 && m_spellInfo->rangeIndex != 2 && m_spellInfo->rangeIndex != 7)
- {
+ if(m_spellInfo->rangeIndex != 1 && m_spellInfo->rangeIndex != 2 && m_spellInfo->rangeIndex != 6 && m_spellInfo->rangeIndex != 7)
attType = RANGED_ATTACK;
-
+ uint32 eff_damage = bonus;
+ // Calculate weapon damage
+ CalcDamageInfo damageInfo;
+ SpellSchools damageSchool = SpellSchools(m_spellInfo->School);
+ if (attType == RANGED_ATTACK)
+ {
// wand case
if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0)
{
@@ -2896,59 +2911,23 @@
Item* pItem = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
if (!pItem)
return;
-
- if( unitTarget->IsImmunedToSpellDamage(m_spellInfo) )
- return;
-
- damageType = SpellSchools(pItem->GetProto()->Damage->DamageType);
+ SpellSchools damageSchool = SpellSchools(pItem->GetProto()->Damage->DamageType);
+ // Damage of Wand calculated as spell damage
}
}
+ eff_damage += m_caster->CalculateDamage (attType);
+ for (j = 0; j < 3; j++) // Add
+ if (m_spellInfo->Effect[j] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE)
+ eff_damage = uint32(eff_damage * (m_spellInfo->EffectBasePoints[j]+1) / 100);
- if(damageType==SPELL_SCHOOL_NORMAL && unitTarget->IsImmunedToPhysicalDamage() )
- {
- m_caster->SendAttackStateUpdate (HITINFO_MISS, unitTarget, 1, SPELL_SCHOOL_NORMAL, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0);
- return;
- }
+ m_caster->CalculateDamage(SPELL_DIRECT_DAMAGE, unitTarget, eff_damage, &damageInfo, attType, m_spellInfo->Id, damageSchool);
- //set base eff_damage, total normal hit damage after DoAttackDamage call will be bonus + weapon
- //if miss/parry, no eff=0 automatically by func DoAttackDamage
- //if crit eff = (bonus + weapon) * 2
- //In a word, bonus + weapon will be calculated together in cases of miss, armor reduce, crit, etc.
- uint32 eff_damage = bonus;
- m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, damageType, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType, m_spellInfo, m_IsTriggeredSpell);
-
- for (j = 0; j < 3; j++)
- if (m_spellInfo->Effect[j] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE)
- eff_damage = uint32(eff_damage * (m_currentBasePoints[j]+1) / 100);
-
- if ((hitInfo & nohitMask) && attType != RANGED_ATTACK) // not send ranged miss/etc
- m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, SpellSchools(m_spellInfo->School), eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg);
-
- if(hitInfo & HITINFO_CRITICALHIT)
- criticalhit = true;
-
- m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, (damageType==SPELL_SCHOOL_NORMAL ? SpellSchools(m_spellInfo->School) : damageType), absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit);
-
- // Bloodthirst
- if (BTAura)
- m_caster->CastSpell(m_caster,BTAura,true);
-
- if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
- {
- eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
- }
- else
- {
- cleanDamage.damage += eff_damage;
- eff_damage = 0;
- }
-
- m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, true);
-
+ m_caster->ProcDamageAndSpell(damageInfo.target,damageInfo.procAttacker,damageInfo.procVictim,damageInfo.procEx,damageInfo.damage,m_spellInfo,m_IsTriggeredSpell,damageInfo.attackType);
+ m_caster->DealDamage(&damageInfo, true);
// take ammo
if(m_caster->GetTypeId() == TYPEID_PLAYER)
{
- if(m_spellInfo->rangeIndex != 1 && m_spellInfo->rangeIndex != 2 && m_spellInfo->rangeIndex != 7)
+ if(m_spellInfo->rangeIndex != 1 && m_spellInfo->rangeIndex != 2 && m_spellInfo->rangeIndex != 6 && m_spellInfo->rangeIndex != 7)
{
Item *pItem = ((Player*)m_caster)->GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED );
if(!pItem || pItem->IsBroken())
@@ -3006,6 +2985,8 @@
if(m_spellInfo->SpellVisual == 132) // drain all caster's mana
m_caster->SetPower(POWER_MANA, 0);
+ m_caster->ProcDamageAndSpell(unitTarget, PROC_FLAG_SUCCESSFUL_HEAL, PROC_FLAG_TAKEN_HEAL, PROC_FLAG_EX_NONE, heal, m_spellInfo,m_IsTriggeredSpell);
+
int32 gain = unitTarget->ModifyHealth(heal);
unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
@@ -3026,8 +3007,11 @@
{
if (unitTarget->m_currentSpells[i])
{
- unitTarget->ProhibitSpellScholl(SpellSchools(unitTarget->m_currentSpells[i]->m_spellInfo->School), GetDuration(m_spellInfo));
- unitTarget->InterruptSpell(i);
+ // check if we can interrupt spell
+ if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & INTURRUPTFLAG_FLAG_INTURRUPT ){
+ unitTarget->ProhibitSpellScholl(SpellSchools(unitTarget->m_currentSpells[i]->m_spellInfo->School), GetDuration(m_spellInfo));
+ unitTarget->InterruptSpell(i);
+ }
}
}
}
Index: src/game/TargetedMovementGenerator.cpp
===================================================================
--- src/game/TargetedMovementGenerator.cpp (revision 4842)
+++ src/game/TargetedMovementGenerator.cpp (working copy)
@@ -109,6 +109,13 @@
return true;
}
+ // prevent movement while casting spells with cast time or channel time
+ if ( owner.IsNonMeleeSpellCasted(false, false, true))
+ {
+ owner.StopMoving();
+ return true;
+ }
+
// prevent crash after creature killed pet
if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
return true;
Index: src/game/Unit.cpp
===================================================================
--- src/game/Unit.cpp (revision 4842)
+++ src/game/Unit.cpp (working copy)
@@ -175,7 +175,8 @@
m_attacking = NULL;
m_modHitChance = 0;
- m_modSpellHitChance = 0;
+ for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
+ m_modSpellHitChance[i] = 0;
m_baseSpellCritChance = 5;
m_modResilience = 0.0f;
m_CombatTimer = 0;
@@ -384,13 +385,13 @@
}
/* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
-void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage)
+void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage, uint32 casterLevel)
{
if(!HasAuraType(auraType))
return;
// The chance to dispell an aura depends on the damage taken with respect to the casters level.
- uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
+ uint32 max_dmg = casterLevel > 8 ? 10 * getLevel() - 30 : 50;
float chance = float(damage) / max_dmg * 100.0f;
if (roll_chance_f(chance))
RemoveSpellsCausingAura(auraType);
@@ -440,10 +441,10 @@
return;
}
- pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage);
+ pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage, getLevel());
// root type spells do not dispell the root effect
if(!spellProto || spellProto->Mechanic != MECHANIC_ROOT)
- pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage);
+ pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage, getLevel());
if(pVictim->GetTypeId() != TYPEID_PLAYER)
{
@@ -782,9 +783,11 @@
player->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
}
}
-
+ // For honor kill procAttacker = PROC_FLAG_KILL_AND_GET_XP
if(xp || honored_kill)
- player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_XP_GIVER,PROC_FLAG_NONE);
+ player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_AND_GET_XP, PROC_FLAG_KILLED,PROC_FLAG_EX_NONE);
+ else
+ player->ProcDamageAndSpell(pVictim,PROC_FLAG_NONE, PROC_FLAG_KILLED,PROC_FLAG_EX_NONE);
}
}
else // if (player)
@@ -822,18 +825,6 @@
pVictim->ModifyHealth(- (int32)damage);
- // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
- if(pVictim->GetHealth()*5 < pVictim->GetMaxHealth())
- {
- uint32 procVictim = PROC_FLAG_NONE;
-
- // if just dropped below 20% (for CheatDeath)
- if((pVictim->GetHealth()+damage)*5 > pVictim->GetMaxHealth())
- procVictim = PROC_FLAG_LOW_HEALTH;
-
- ProcDamageAndSpell(pVictim,PROC_FLAG_TARGET_LOW_HEALTH,procVictim);
- }
-
if(damagetype != DOT)
{
//start melee attacks only after melee hit
@@ -1011,7 +1002,7 @@
spell->m_CastItem = castItem;
spell->prepare(&targets);
}
-
+/*
void Unit::DealDamageBySchool(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell)
{
@@ -1318,10 +1309,22 @@
((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false);
}
}
+*/
+void Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
+{
+ SpellEntry const *procSpell = sSpellStore.LookupEntry(spellID);
+ CalcDamageInfo damageInfo;
+ CalculateDamage(SPELL_DIRECT_DAMAGE, pVictim, damage, &damageInfo, BASE_ATTACK, spellID);
+ ProcDamageAndSpell(damageInfo.target,damageInfo.procAttacker,damageInfo.procVictim,damageInfo.procEx,damageInfo.damage, procSpell, isTriggeredSpell, damageInfo.attackType);
+ DealDamage(&damageInfo, true);
+}
+
void Unit::PeriodicAuraLog(Unit *pVictim, SpellEntry const *spellProto, Modifier *mod, uint8 effect_idx)
{
- uint32 procFlag = 0;
+ uint32 procAttacker = PROC_FLAG_NONE;
+ uint32 procVictim = PROC_FLAG_NONE;
+ uint32 procEx = PROC_FLAG_EX_NONE;
if(!this || !pVictim || !isAlive() || !pVictim->isAlive())
{
return;
@@ -1332,48 +1335,10 @@
case SPELL_AURA_PERIODIC_DAMAGE:
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
{
- uint32 absorb=0;
- uint32 resist=0;
- CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
-
- uint32 pdamage;
-
- if(mod->m_auraname == SPELL_AURA_PERIODIC_DAMAGE)
- {
- pdamage = mod->m_amount;
-
- //Calculate armor mitigation if it is a physical spell
- if (spellProto->School == SPELL_SCHOOL_NORMAL)
- {
- uint32 pdamageReductedArmor = CalcArmorReducedDamage(pVictim, pdamage);
- cleanDamage.damage += pdamage - pdamageReductedArmor;
- pdamage = pdamageReductedArmor;
- }
-
- CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), DOT, pdamage, &absorb, &resist);
-
- pdamage = SpellDamageBonus(pVictim,spellProto,pdamage,DOT);
- }
- else
- pdamage = uint32(pVictim->GetMaxHealth()*mod->m_amount/100);
-
- sLog.outDetail("PeriodicAuraLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
- GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), pdamage, spellProto->Id,absorb);
-
- WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
- data.append(pVictim->GetPackGUID());
- data.append(GetPackGUID());
- data << uint32(spellProto->Id);
- data << uint32(1);
- data << uint32(mod->m_auraname);
- data << (uint32)pdamage;
- data << (uint32)spellProto->School;
- data << (uint32)absorb;
- data << (uint32)resist;
- SendMessageToSet(&data,true);
-
- DealDamage(pVictim, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, SpellSchools(spellProto->School), spellProto, procFlag, true);
- ProcDamageAndSpell(pVictim, PROC_FLAG_HIT_SPELL, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), spellProto);
+ CalcDamageInfo damageInfo;
+ CalculateDamage(DOT, pVictim, mod->m_amount, &damageInfo, BASE_ATTACK, spellProto->Id, SpellSchools(spellProto->School), mod->m_auraname);
+ ProcDamageAndSpell(damageInfo.target,damageInfo.procAttacker,damageInfo.procVictim,damageInfo.procEx,damageInfo.damage, spellProto, false, damageInfo.attackType);
+ DealDamage(&damageInfo, true);
break;
}
case SPELL_AURA_PERIODIC_LEECH:
@@ -1401,10 +1366,17 @@
sLog.outDetail("PeriodicAuraLog: %u (TypeId: %u) health leech of %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), pdamage, spellProto->Id,absorb);
+// Possibly SPELL_AURA_PERIODIC_LEECH not trigger on tick
+ procAttacker |= PROC_FLAG_SUCCESSFUL_PERIODIC_DAMAGE;
+ procVictim |= PROC_FLAG_TAKEN_PERIODIC_DAMAGE;
+ if (absorb)procEx |= PROC_FLAG_EX_ABSORB;
+ if (resist>=pdamage) procEx|= PROC_FLAG_EX_FULL_RESISTS;
+ if (pdamage <= absorb+resist) pdamage = 0;
+ else pdamage-=absorb+resist;
+ ProcDamageAndSpell(pVictim, procAttacker, procVictim, procEx, pdamage, spellProto);
SendSpellNonMeleeDamageLog(pVictim, spellProto->Id, pdamage, SpellSchools(spellProto->School), absorb, resist, false, 0);
- DealDamage(pVictim, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, SpellSchools(spellProto->School), spellProto, procFlag, false);
- ProcDamageAndSpell(pVictim, PROC_FLAG_HIT_SPELL, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), spellProto);
+ DealDamage(pVictim, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, SpellSchools(spellProto->School), spellProto, PROC_FLAG_NONE, false);
if (!pVictim->isAlive() && IsNonMeleeSpellCasted(false))
{
for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
@@ -1481,12 +1453,12 @@
SendSpellNonMeleeDamageLog(this, spellProto->Id, gain, SpellSchools(spellProto->School), 0, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
- DealDamage(this, gain, &cleanDamage, NODAMAGE, SpellSchools(spellProto->School), spellProto, PROC_FLAG_HEAL, true);
+ DealDamage(this, gain, &cleanDamage, NODAMAGE, SpellSchools(spellProto->School), spellProto, PROC_FLAG_SUCCESSFUL_HEAL, true);
}
}
- if(procSpell)
- ProcDamageAndSpell(pVictim, PROC_FLAG_HEAL, PROC_FLAG_HEALED, pdamage, spellProto);
+// if(procSpell)
+// ProcDamageAndSpell(pVictim, PROC_FLAG_HEAL, PROC_FLAG_HEALED, pdamage, spellProto);
break;
}
case SPELL_AURA_PERIODIC_MANA_LEECH:
@@ -1591,6 +1563,746 @@
}
}
+
+void Unit::CalculateDamage(DamageEffectType type, Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType, uint32 spellID, SpellSchools damageSchool, uint32 auraname)
+{
+ damageInfo->attackType = attackType;
+ damageInfo->hitOutCome = MELEE_HIT_EVADE;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ damageInfo->absorb = 0;
+ damageInfo->resist = 0;
+ damageInfo->blocked_amount = 0;
+ damageInfo->procAttacker = PROC_FLAG_NONE;
+ damageInfo->procVictim = PROC_FLAG_NONE;
+ damageInfo->procEx = PROC_FLAG_EX_NONE;
+ damageInfo->damagetype = type;
+ damageInfo->target = pVictim;
+ damageInfo->TargetState = 0;
+
+ if (damageInfo->attackType == BASE_ATTACK) damageInfo->HitInfo = HITINFO_NORMALSWING2;
+ else if (damageInfo->attackType == OFF_ATTACK ) damageInfo->HitInfo = HITINFO_LEFTSWING;
+ else if (damageInfo->attackType == RANGED_ATTACK ) damageInfo->HitInfo = 0x08;// test
+
+ damageInfo->SpellID = spellID;
+ damageInfo->damageSchool = damageSchool;
+ damageInfo->auraname = auraname;
+
+ if(!this || !pVictim)
+ return;
+ if(!this->isAlive() || !pVictim->isAlive())
+ return;
+
+
+ switch (type)
+ {
+ case DIRECT_DAMAGE: CalculateMeleeDamage(damage, damageInfo); break;
+ case SPELL_DIRECT_DAMAGE:CalculateSpellDamage(damage, damageInfo); break;
+ case DOT: CalculateDotDamage(damage, damageInfo); break;
+ // TODO add special func for this
+ case DAMAGE_SHIELD:
+ damageInfo->damage=damage;
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(damageInfo->SpellID);
+ if(!spellInfo)
+ break;
+ damageInfo->damageSchool = SpellSchools(spellInfo->School);
+ break;
+ }
+ // Calculate absorb resist
+ if(damageInfo->damage > 0)
+ {
+ // Immune check
+ if(pVictim->IsImmunedToSchoolDamage(damageInfo->damageSchool) )
+ {
+ damageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND;
+ damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ damageInfo->absorb = 0;
+ damageInfo->resist = 0;
+ damageInfo->blocked_amount = 0;
+ return;
+ }
+ // Calculate absorb & resists
+ if (damageInfo->damage)
+ CalcAbsorbResist(pVictim, damageInfo->damageSchool, damageInfo->damagetype, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist);
+ // Only send absorbed message if we actually absorbed some damage
+ if (damageInfo->absorb)
+ {
+ damageInfo->HitInfo|= HITINFO_ABSORB;
+ damageInfo->procEx |= PROC_FLAG_EX_ABSORB;
+ if (damageInfo->damage< damageInfo->absorb)damageInfo->absorb = damageInfo->damage;
+ damageInfo->damage-=damageInfo->absorb;
+ }
+ if (damageInfo->resist && damageInfo->damage)
+ {
+ damageInfo->HitInfo|= HITINFO_RESIST;
+ if (damageInfo->damage< damageInfo->resist)
+ {
+ damageInfo->resist = damageInfo->damage;
+ damageInfo->procEx |= PROC_FLAG_EX_FULL_RESISTS;
+ }
+ damageInfo->damage-=damageInfo->resist;
+ }
+ }
+
+ if (damageInfo->damage==0)
+ damageInfo->HitInfo|=HITINFO_SWINGNOHITSOUND;
+}
+void Unit::CalculateDotDamage(uint32 damage, CalcDamageInfo *damageInfo)
+{
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(damageInfo->SpellID);
+ if(!spellInfo)
+ return;
+
+ if (damageInfo->damageSchool==SPELL_SCHOOL_NORMAL)
+ damageInfo->damageSchool = SpellSchools(spellInfo->School);
+ switch(damageInfo->auraname)
+ {
+ case SPELL_AURA_PERIODIC_DAMAGE: break;//damage = damage;
+ case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: damage = uint32(damageInfo->target->GetMaxHealth()*damage/100);break;
+
+ }
+ //Calculate armor mitigation if it is a physical spell
+ if (damageInfo->damageSchool == SPELL_SCHOOL_NORMAL)
+ {
+ //Calculate armor mitigation
+ damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage);
+ damageInfo->cleanDamage += damageInfo->damage - damage;
+ }
+ else
+ damageInfo->damage = SpellDamageBonus(damageInfo->target, spellInfo, damage, DOT);
+ damageInfo->procAttacker |= PROC_FLAG_SUCCESSFUL_PERIODIC_DAMAGE;
+ damageInfo->procVictim |= PROC_FLAG_TAKEN_PERIODIC_DAMAGE;
+ if (damageInfo->damage) damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;
+}
+void Unit::CalculateSpellDamage(uint32 damage, CalcDamageInfo *damageInfo)
+{
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(damageInfo->SpellID);
+ if(!spellInfo)
+ return;
+ if (damageInfo->damageSchool==SPELL_SCHOOL_NORMAL)
+ damageInfo->damageSchool = SpellSchools(spellInfo->School);
+ // Per-school calc
+ switch (damageInfo->damageSchool)
+ {
+ // Physical damage school
+ case SPELL_SCHOOL_NORMAL:
+ {
+ // Add melee damage bonuses
+ MeleeDamageBonus(damageInfo->target, &damage, damageInfo->attackType);
+
+ //Calculate armor mitigation
+ damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage);
+ damageInfo->cleanDamage += damageInfo->damage - damage;
+
+ // Calculate physical outcome
+ damageInfo->hitOutCome = RollPhysicalOutcomeAgainst(damageInfo->target, damageInfo->attackType, spellInfo);
+ // Disable parry for ranged attack
+ if(damageInfo->attackType == RANGED_ATTACK && (damageInfo->hitOutCome == MELEE_HIT_PARRY))
+ damageInfo->hitOutCome = MELEE_HIT_NORMAL;
+
+ switch(damageInfo->hitOutCome)
+ {
+ case MELEE_HIT_EVADE:
+ {
+ damageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND;
+ damageInfo->TargetState = VICTIMSTATE_EVADES;
+ damageInfo->procEx|=PROC_FLAG_EX_HIT_EVADE_TARGET;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ return;
+ }
+ case MELEE_HIT_MISS:
+ {
+ damageInfo->HitInfo |= HITINFO_MISS;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_FLAG_EX_MISS;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ break;
+ }
+ case MELEE_HIT_CRIT:
+ {
+ damageInfo->HitInfo |= HITINFO_CRITICALHIT;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_FLAG_EX_CRITICAL_HIT;
+ uint32 crit_bonus = damageInfo->damage;
+ // Apply crit_damage bonus for melee spells
+ if(Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
+ damageInfo->damage += crit_bonus;
+ if(damageInfo->attackType == RANGED_ATTACK)
+ {
+ int32 mod = damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
+ damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod)/100.0f));
+ }
+ else
+ {
+ int32 mod = damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
+ damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod)/100.0f));
+ }
+
+ // Resilience - reduce crit damage by 2x%
+ uint32 resilienceReduction = uint32(damageInfo->target->m_modResilience * 2/100 * (damageInfo->damage));
+ damageInfo->cleanDamage += resilienceReduction;
+ damageInfo->damage -= resilienceReduction;
+ break;
+ }
+ case MELEE_HIT_PARRY:
+ {
+ damageInfo->HitInfo |= HITINFO_NORMALSWING;
+ damageInfo->TargetState = VICTIMSTATE_PARRY;
+ damageInfo->procEx|=PROC_FLAG_EX_PARRY;
+ damageInfo->cleanDamage += damageInfo->damage; // To Help Calculate Rage
+ damageInfo->damage = 0;
+ break;
+ }
+ case MELEE_HIT_DODGE:
+ {
+ damageInfo->HitInfo |= HITINFO_NORMALSWING;
+ damageInfo->TargetState = VICTIMSTATE_DODGE;
+ damageInfo->procEx|=PROC_FLAG_EX_DODGE;
+ damageInfo->cleanDamage += damageInfo->damage; // To Help Calculate Rage
+ damageInfo->damage = 0;
+ break;
+ }
+ case MELEE_HIT_BLOCK:
+ {
+ damageInfo->HitInfo |= HITINFO_NORMALSWING;
+ damageInfo->TargetState = VICTIMSTATE_BLOCKS;
+ damageInfo->procEx|=PROC_FLAG_EX_BLOCK;
+ damageInfo->blocked_amount = uint32(damageInfo->target->GetShieldBlockValue());
+ if (damageInfo->blocked_amount > damageInfo->damage)
+ damageInfo->blocked_amount = damageInfo->damage;
+
+ damageInfo->cleanDamage += damageInfo->blocked_amount; // To Help Calculate Rage
+ damageInfo->damage -= damageInfo->blocked_amount;
+ break;
+ }
+ case MELEE_HIT_GLANCING:
+ case MELEE_HIT_CRUSHING:
+ case MELEE_HIT_NORMAL:
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ break;
+ }
+ break;
+ }
+
+ // Other schools
+ case SPELL_SCHOOL_HOLY:
+ case SPELL_SCHOOL_FIRE:
+ case SPELL_SCHOOL_NATURE:
+ case SPELL_SCHOOL_FROST:
+ case SPELL_SCHOOL_SHADOW:
+ case SPELL_SCHOOL_ARCANE:
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+/* if( SpellMissChanceCalc(damageInfo->target, damageInfo->damageSchool) > urand(0,10000) )
+ {
+ damageInfo->HitInfo|= HITINFO_RESIST;
+
+ damageInfo->procEx|=PROC_FLAG_EX_MISS;
+ damageInfo->damage = 0;
+ break;
+ }*/
+
+ // Calculate damage bonus
+ damageInfo->damage = SpellDamageBonus(damageInfo->target, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ bool crit=false;
+ // Calculate critical bonus
+ if(spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE)
+ {
+ // Calculate physical outcome
+ if(RollPhysicalOutcomeAgainst(damageInfo->target, BASE_ATTACK, spellInfo) == MELEE_HIT_CRIT)
+ {
+ crit = true;
+ damageInfo->damage *= 2;
+ // Resilience - reduce crit damage by 2x%
+ uint32 resilienceReduction = uint32(damageInfo->target->m_modResilience * 2/100 * (damageInfo->damage));
+ damageInfo->cleanDamage += resilienceReduction;
+ damageInfo->damage -= resilienceReduction;
+ }
+ }
+ else
+ crit = SpellCriticalBonus(spellInfo, &damageInfo->damage, damageInfo->target);
+ if (crit)
+ {
+ damageInfo->HitInfo|= HITINFO_CRITICALHIT;
+ damageInfo->procEx|=PROC_FLAG_EX_CRITICAL_HIT;
+ }
+ break;
+ }
+ if(spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE)
+ {
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT;
+ damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_SPELL_HIT;
+ }
+ else if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
+ {
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
+ damageInfo->procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
+ }
+ else
+ {
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
+ damageInfo->procVictim = PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
+ }
+ if (damageInfo->damage) damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;
+}
+
+void Unit::CalculateMeleeDamage(uint32 damage, CalcDamageInfo *damageInfo)
+{
+ damage += CalculateDamage (damageInfo->attackType);
+ // Add melee damage bonus
+ MeleeDamageBonus(damageInfo->target, &damage, damageInfo->attackType);
+ // Calculate armor reduction
+ damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage);
+ damageInfo->cleanDamage += damage - damageInfo->damage;
+
+ damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType);
+
+ // Disable parry for ranged attack
+ if(damageInfo->attackType == RANGED_ATTACK && (damageInfo->hitOutCome == MELEE_HIT_PARRY))
+ damageInfo->hitOutCome = MELEE_HIT_NORMAL;
+
+ switch(damageInfo->hitOutCome)
+ {
+ case MELEE_HIT_EVADE:
+ {
+ damageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND;
+ damageInfo->TargetState = VICTIMSTATE_EVADES;
+
+ damageInfo->procEx|=PROC_FLAG_EX_HIT_EVADE_TARGET;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ return;
+ }
+ case MELEE_HIT_MISS:
+ {
+ damageInfo->HitInfo |= HITINFO_MISS;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+
+ damageInfo->procEx|=PROC_FLAG_EX_MISS;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ break;
+ }
+ case MELEE_HIT_NORMAL:
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ break;
+ case MELEE_HIT_CRIT:
+ {
+ damageInfo->HitInfo |= 0x8|HITINFO_CRITICALHIT;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+
+ damageInfo->procEx|=PROC_FLAG_EX_CRITICAL_HIT;
+ // Crit bonus calc
+ damageInfo->damage += damageInfo->damage;
+ if(damageInfo->attackType == RANGED_ATTACK)
+ damageInfo->damage *= (damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE)+100)/100;
+ else
+ damageInfo->damage *= (damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE)+100)/100;
+
+ // Resilience - reduce crit damage by 2x%
+ uint32 resilienceReduction;
+ resilienceReduction = uint32(damageInfo->target->m_modResilience * 2/100 * (damageInfo->damage));
+
+ damageInfo->damage -= resilienceReduction;
+ damageInfo->cleanDamage += resilienceReduction;
+ }
+ break;
+
+ case MELEE_HIT_PARRY:
+ damageInfo->TargetState = VICTIMSTATE_PARRY;
+ damageInfo->procEx|=PROC_FLAG_EX_PARRY;
+ damageInfo->cleanDamage += damageInfo->damage;
+ damageInfo->damage = 0;
+ break;
+
+ case MELEE_HIT_DODGE:
+ damageInfo->TargetState = VICTIMSTATE_DODGE;
+ damageInfo->procEx|=PROC_FLAG_EX_DODGE;
+ damageInfo->cleanDamage += damageInfo->damage;
+ damageInfo->damage = 0;
+ break;
+
+ case MELEE_HIT_BLOCK:
+ {
+ damageInfo->TargetState = VICTIMSTATE_BLOCKS;
+ damageInfo->procEx|=PROC_FLAG_EX_BLOCK;
+ damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue();
+ if (damageInfo->blocked_amount >= damageInfo->damage)
+ 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;
+ 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
+ {
+ case CLASS_WARRIOR:
+ case CLASS_ROGUE:
+ maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91
+ }
+
+ // calculate values
+ int32 diff = damageInfo->target->GetDefenseSkillValue() - GetWeaponSkillValue(damageInfo->attackType);
+ 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 );
+
+ 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;
+ // 150% normal damage
+ damageInfo->damage += (damageInfo->damage / 2);
+ // cleanDamage->damage = *damage;
+ break;
+ }
+ default:
+
+ break;
+ }
+
+ if (damageInfo->attackType == BASE_ATTACK)
+ {
+ damageInfo->procAttacker |= PROC_FLAG_SUCCESSFUL_MILEE_HIT;
+ damageInfo->procVictim |= PROC_FLAG_TAKEN_MELEE_HIT;
+ }
+ else if (damageInfo->attackType == 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
+ }
+ else if (damageInfo->attackType == RANGED_ATTACK)
+ {
+ damageInfo->procAttacker |= PROC_FLAG_SUCCESSFUL_RANGED_HIT;
+ damageInfo->procVictim |= PROC_FLAG_TAKEN_RANGED_HIT;
+ }
+ if (damageInfo->damage) damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;
+}
+
+void Unit::SendAttackStateUpdate(CalcDamageInfo *damageInfo)
+{
+ sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
+ 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 << (uint8)1; // Sub damage count
+ //=== Sub damage description
+ data << (uint32)damageInfo->damageSchool; // 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;
+// if(damageInfo->absorb == 0 ) //also 0x3E8 = 0x3E8, check when that happens
+ data << (uint32)0;
+// else
+// data << (uint32)-1;
+ data << (uint32)0;
+ data << (uint32)damageInfo->blocked_amount;
+ SendMessageToSet( &data, true );
+}
+void Unit::SendSpellNonMeleeDamageLog(CalcDamageInfo *damageInfo)
+{
+ uint8 CriticalHit = damageInfo->HitInfo&HITINFO_CRITICALHIT ? 2 : 0;
+ WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+31)); // we guess size
+ data.append(damageInfo->target->GetPackGUID());
+ data.append(GetPackGUID());
+ data << uint32(damageInfo->SpellID);
+ data << uint32(damageInfo->damage);
+ data << uint8(damageInfo->damageSchool); //damagetype
+ data << uint32(damageInfo->absorb); //AbsorbedDamage
+ data << uint32(damageInfo->resist); //resist
+ data << uint8(0);//PhysicalDamage);
+ data << uint8(0);
+ data << uint32(damageInfo->blocked_amount); //blocked
+ data << uint8(CriticalHit); //seen 0x05 also...
+ data << uint32(0);
+ SendMessageToSet( &data, true );/**/
+}
+
+void Unit::SendSpellDotDamageLog(CalcDamageInfo *damageInfo)
+{
+ WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
+ data.append(damageInfo->target->GetPackGUID());
+ data.append(GetPackGUID());
+ data << uint32(damageInfo->SpellID);
+ data << uint32(1);
+ data << uint32(damageInfo->auraname);
+ switch(damageInfo->auraname)
+ {
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
+ data << uint32(damageInfo->damage);
+ data << uint32(damageInfo->damageSchool);
+ data << uint32(damageInfo->absorb);
+ data << uint32(damageInfo->resist);
+ break;
+ case SPELL_AURA_PERIODIC_HEAL:
+ case SPELL_AURA_OBS_MOD_HEALTH:
+ data << uint32(damageInfo->damage);
+ break;
+ default:
+ return;
+ }
+ SendMessageToSet(&data,true);
+}
+
+void Unit::DealDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
+{
+ if (damageInfo==0) return;
+ Unit *pVictim = damageInfo->target;
+ if(!this || !pVictim)
+ return;
+ if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
+ return;
+ SpellEntry const *spellProto=NULL;
+ if (damageInfo->SpellID)
+ {
+ spellProto = sSpellStore.LookupEntry(damageInfo->SpellID);
+ if (spellProto == NULL)
+ {
+ sLog.outDebug("Unit::DealDamage have wrong damageInfo->SpellID: %u", damageInfo->SpellID);
+ 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)
+ {
+ const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
+ if(area && area->flags & 0x800) //sanctuary
+ return;
+ }
+ // Send log damage message to client
+ switch (damageInfo->damagetype)
+ {
+ case DIRECT_DAMAGE:
+ SendAttackStateUpdate(damageInfo);
+ break;
+ case DAMAGE_SHIELD:
+ {
+ WorldPacket data(SMSG_SPELLDAMAGESHIELD,(16+31));
+ data << uint64(GetGUID());
+ data << uint64(damageInfo->target->GetGUID());
+ data << uint32(damageInfo->damage);
+ data << uint32(damageInfo->damageSchool);
+ damageInfo->target->SendMessageToSet( &data, true );
+ }
+ break;
+ case SPELL_DIRECT_DAMAGE:
+ if (damageInfo->damage==0)
+ SendAttackStateUpdate(damageInfo);
+ else
+ SendSpellNonMeleeDamageLog(damageInfo);
+ break;
+ case DOT:
+ SendSpellDotDamageLog(damageInfo);
+ break;
+ default:
+ SendSpellNonMeleeDamageLog(damageInfo);
+ break;
+ }
+ // Enable AURA_STATE_CRIT on crit
+ if (damageInfo->HitInfo&HITINFO_CRITICALHIT)
+ {
+ ModifyAuraState(AURA_STATE_CRIT, true);
+ if(getClass()==CLASS_HUNTER)
+ ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true);
+
+ pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
+ }
+ // For melee attack UpdateCombatSkills
+ if (damageInfo->hitOutCome)
+ {
+ // Clear aura states for meele
+ pVictim->ModifyAuraState(AURA_STATE_DEFENSE, false);
+ if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) // Clear OVERPOWER
+ ((Player*)this)->ClearComboPoints();
+ ModifyAuraState(AURA_STATE_CRIT, false);
+
+ if(getClass()==CLASS_HUNTER)
+ ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false);
+ if(pVictim->getClass()==CLASS_HUNTER)
+ pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
+
+ if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
+ ((Player*)this)->UpdateCombatSkills(pVictim, damageInfo->attackType, damageInfo->hitOutCome, false);
+
+ if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)pVictim)->UpdateCombatSkills(this, damageInfo->attackType, damageInfo->hitOutCome, true);
+ }
+ // Modify victim state depends on damageInfo->TargetState
+ switch(damageInfo->TargetState)
+ {
+ case 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));
+ }
+ }
+ // Update victim defense ?
+ if(pVictim->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)pVictim)->UpdateDefense();
+
+ // Set parry flags
+ pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
+
+ if (pVictim->getClass() == CLASS_HUNTER) // Mongoose Bite
+ pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY, true);
+ else
+ pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
+ }
+ break;
+ case VICTIMSTATE_BLOCKS:
+ {
+ if (pVictim->GetUnitBlockChance())
+ pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
+ else
+ pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
+ if(pVictim->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)pVictim)->UpdateDefense();
+ pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true);
+ }
+ break;
+ case 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);
+ // Overpower
+ if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
+ ((Player*)this)->AddComboPoints(pVictim, 1);
+ }
+ break;
+ default:
+ break;
+ }
+ /// 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() || (spellProto && spellProto->Id == 35395) ))
+ {
+ (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
+ (*itr).second->UpdateAuraDuration();
+ }
+ }
+ }
+ // Call default DealDamage
+ CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->attackType,damageInfo->hitOutCome);
+ DealDamage(pVictim, damageInfo->damage, &cleanDamage, damageInfo->damagetype, damageInfo->damageSchool, spellProto, 0, durabilityLoss);
+}
+
+
void Unit::HandleEmoteCommand(uint32 anim_id)
{
WorldPacket data( SMSG_EMOTE, 12 );
@@ -1729,7 +2441,7 @@
*absorb = damage - RemainingDamage - *resist;
}
-
+/*
void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchools damageType, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell)
{
pVictim->ModifyAuraState(AURA_STATE_DEFENSE, false);
@@ -2141,7 +2853,7 @@
}
}
}
-
+*/
void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool isTriggered)
{
if(hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNDED | UNIT_STAT_FLEEING) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) )
@@ -2162,61 +2874,85 @@
return;
}
}
-
- uint32 hitInfo;
- if (attType == BASE_ATTACK)
- hitInfo = HITINFO_NORMALSWING2;
- else if (attType == OFF_ATTACK)
- hitInfo = HITINFO_LEFTSWING;
- else
- return;
-
- VictimState victimState = VICTIMSTATE_NORMAL;
-
- uint32 damage = 0;
- CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
- uint32 blocked_dmg = 0;
- uint32 absorbed_dmg = 0;
- uint32 resisted_dmg = 0;
-
- SpellSchools meleeSchool = GetMeleeDamageSchool();
-
- if( meleeSchool == SPELL_SCHOOL_NORMAL && pVictim->IsImmunedToPhysicalDamage() )
+ CalcDamageInfo damageInfo;
+ CalculateDamage(DIRECT_DAMAGE, pVictim, 0, &damageInfo, attType);
+ ProcDamageAndSpell(damageInfo.target,damageInfo.procAttacker,damageInfo.procVictim,damageInfo.procEx,damageInfo.damage, 0, false, damageInfo.attackType);
+ DealDamage(&damageInfo,true);
+ pVictim = damageInfo.target;
+ if (pVictim && !(damageInfo.HitInfo & HITINFO_MISS))
{
- SendAttackStateUpdate (HITINFO_MISS, pVictim, 1, meleeSchool, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0);
- return;
- }
-
- DoAttackDamage (pVictim, &damage, &cleanDamage, &blocked_dmg, meleeSchool, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType);
-
- if (hitInfo & HITINFO_MISS)
- //send miss
- SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchool, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
- else
- {
- //do animation
- SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchool, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
-
- if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
- damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
- else
- damage = 0;
-
- DealDamage (pVictim, damage, &cleanDamage, DIRECT_DAMAGE, meleeSchool, NULL, 0, true);
-
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,attType);
}
+ // victim's damage shield
+ // yet another hack to fix crashes related to the aura getting removed during iteration
+ std::set<Aura*> 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);
+ CalcDamageInfo damageInfo;
+ pVictim->CalculateDamage(DAMAGE_SHIELD, this, (*i)->GetModifier()->m_amount, &damageInfo, BASE_ATTACK, (*i)->GetId());
+ pVictim->DealDamage(&damageInfo, true);
+ if (pVictim->m_removedAuras > removedAuras)
+ {
+ removedAuras = pVictim->m_removedAuras;
+ next = vDamageShields.begin();
+ }
+ }
+ }
+ if (pVictim->GetTypeId() == TYPEID_PLAYER && damageInfo.damage)
+ {
+ for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
+ {
+ // skip channeled spell (processed differently below)
+ if (i == CURRENT_CHANNELED_SPELL)
+ continue;
+ if(pVictim->m_currentSpells[i])
+ {
+ sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * pVictim->m_currentSpells[i]->casttime));
+ pVictim->m_currentSpells[i]->Delayed((int32)(0.25f * pVictim->m_currentSpells[i]->casttime));
+ }
+ }
+ // process channeled spell separately
+ if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL])
+ {
+ if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_CASTING)
+ {
+ uint32 channelInterruptFlags = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->ChannelInterruptFlags;
+ if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
+ {
+ sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
+ pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->DelayedChannel((int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
+ return;
+ }
+ else if( !(channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
+ return;
+ sLog.outDetail("Spell Canceled!");
+ pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
+ }
+ else if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_DELAYED)
+ {
+ // break channeled spell in delayed state on damage
+ sLog.outDetail("Spell Canceled!");
+ pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
+ }
+ }
+ }
}
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(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
+ 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(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
+ GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
}
MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo)
@@ -2471,7 +3207,7 @@
((Creature*)victim)->AI().EnterEvadeMode(this);*/
}
-uint32 Unit::SpellMissChanceCalc(Unit *pVictim) const
+uint32 Unit::SpellMissChanceCalc(Unit *pVictim, SpellSchools school) const
{
if(!pVictim)
return 0;
@@ -2483,7 +3219,7 @@
if(leveldif < 0)
leveldif = 0;
- int32 misschance = 400 - m_modSpellHitChance*100;
+ int32 misschance = 400 - m_modSpellHitChance[school]*100;
if(leveldif < 3)
misschance += leveldif * 100;
else
@@ -2495,6 +3231,50 @@
return misschance < 100 ? 100 : misschance;
}
+uint32 Unit::SpellResistChanceCalc(Unit *pVictim, SpellSchools school) const
+{
+
+ return 0;
+}
+
+//static uint8 temp = 0;
+uint8 Unit::SpellCastResult(Unit *pVictim, SpellEntry const *spell) const
+{
+// return temp;
+ // Return evade for units in evade mode
+ if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
+ return SPELL_HIT_EVADE;
+ // All positive spells cant 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)) return SPELL_HIT_NONE;
+
+ // Immune check
+ // Possibly need use SPELL_HIT_IMMUNE for damage immune
+ // SPELL_HIT_IMMUNE2 for immune from school
+ if(pVictim->IsImmunedToSpellDamage(spell))
+ return SPELL_HIT_IMMUNE;
+
+ switch (spell->School)
+ {
+ // TODO remove hack for normal school
+ case SPELL_SCHOOL_NORMAL:
+ return SPELL_HIT_NONE;
+
+ case SPELL_SCHOOL_HOLY:
+ case SPELL_SCHOOL_FIRE:
+ case SPELL_SCHOOL_NATURE:
+ case SPELL_SCHOOL_FROST:
+ case SPELL_SCHOOL_SHADOW:
+ case SPELL_SCHOOL_ARCANE:
+ {
+ uint32 missChance = SpellMissChanceCalc(pVictim, SpellSchools(spell->School));
+ if (missChance>urand(0,10000)) return SPELL_HIT_RESIST;
+ }
+ }
+ return SPELL_HIT_NONE;
+}
+
+
int32 Unit::MeleeMissChanceCalc(const Unit *pVictim) const
{
if(!pVictim)
@@ -3375,6 +4155,8 @@
AuraMap::iterator iter;
while((iter = m_Auras.find(spellEffectPair(spellId, effindex))) != m_Auras.end())
RemoveAura(iter);
+
+
}
void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex)
@@ -3679,7 +4461,7 @@
data.append(target->GetPackGUID());
data.append(GetPackGUID());
data << uint32(SpellID);
- data << uint32(Damage-AbsorbedDamage-Resist-Blocked);
+ data << uint32(Damage);
data << uint8(DamageType); //damagetype
data << uint32(AbsorbedDamage); //AbsorbedDamage
data << uint32(Resist); //resist
@@ -3690,7 +4472,7 @@
data << uint32(0);
SendMessageToSet( &data, true );
}
-
+/*
void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchools DamageType, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
{
sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
@@ -3722,52 +4504,38 @@
SendMessageToSet( &data, true );
}
-
-void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType)
+*/
+void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 damage, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType)
{
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)":""));
-
- // 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 unexpacted 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)
{
- if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE)
+ switch (procSpell->SpellFamilyName)
{
- 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
+ case SPELLFAMILY_WARLOCK: // For Hellfire Effect and Rain of Fire triggers need do it
+ if (procSpell->SpellFamilyFlags & 0x0000000000000060LL) isTriggeredSpell = false;
+ break;
+ case SPELLFAMILY_PALADIN:// For Holy Shock triggers need do it
+ if (procSpell->SpellFamilyFlags & 0x0000000000200000LL) isTriggeredSpell = false;
+ break;
}
- 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);
-
- // Not much to do if no flags are set.
+ // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect
+ // That is the question though if it's fully correct
+ if (isTriggeredSpell)
+ return;
+ // Not much to do if no flags are set.
if (procAttacker)
- {
- ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcAuraTypes,attType, procSpell, damage);
- }
-
+ ProcDamageAndSpellFor(false,pVictim,procAttacker, procExtra,attType, procSpell, damage);
// 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)
- {
- pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcAuraTypes,attType,procSpell, damage);
- }
+ pVictim->ProcDamageAndSpellFor(true,this,procVictim, procExtra,attType,procSpell, damage);
}
+/*
void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell)
{
if(!pVictim)
@@ -3847,8 +4615,8 @@
if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE)
ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, spellCasted, isTriggeredSpell, attType);
}
-
-void Unit::HandleDummyAuraProc(Unit *pVictim, SpellEntry const *dummySpell, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag)
+*/
+void Unit::HandleDummyAuraProc(Unit *pVictim, SpellEntry const *dummySpell, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx)
{
switch(dummySpell->Id )
{
@@ -3882,10 +4650,11 @@
// Combustion
case 11129:
{
- CastSpell(this, 28682, true, NULL, triggredByAura);
- if (!(procFlag & PROC_FLAG_CRIT_SPELL)) //no crit
+ if (triggredByAura->m_procCharges == triggredByAura->GetSpellProto()->procCharges) // For 1 cast
+ CastSpell(this, 28682, true, NULL, triggredByAura);
+ if (!(procEx & PROC_FLAG_EX_CRITICAL_HIT)) //no crit
triggredByAura->m_procCharges += 1; //-> reincrease procCharge count since it was decreased before
- else if (triggredByAura->m_procCharges == 0) //no more charges left and crit
+ else if (triggredByAura->m_procCharges == 1) // last charges left and crit
RemoveAurasDueToSpell(28682); //-> remove Combustion auras
return;
}
@@ -4020,6 +4789,41 @@
return;
}
+ // Windfury weapon
+ case 33757:
+ case 33756:
+ case 33755:
+ case 33754:
+ case 33727:
+ {
+ // never proc from another windfury attack or the AP bonus will stack and we will get really huge criticals
+ if ( !procSpell || ( procSpell->Id != 25504 && procSpell->Id != 33750 ) ){
+ // give us temporary AP bonus
+
+ if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(25504) )
+ return;
+
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(dummySpell->EffectBasePoints[0]+1), true);
+
+ int32 EffectBasePoints0 = CalculateDamage(BASE_ATTACK);
+
+ CastCustomSpell(pVictim,25504,&EffectBasePoints0,NULL,NULL,true,NULL,triggredByAura);
+ // cooldown
+ ((Player*)this)->AddSpellCooldown(25504,0,time(NULL) + 3);
+
+ if (haveOffhandWeapon())
+ {
+ int32 EffectBasePoints0 = CalculateDamage(OFF_ATTACK);
+ CastCustomSpell(pVictim,33750,&EffectBasePoints0,NULL,NULL,true,NULL,triggredByAura);
+ // cooldown
+ ((Player*)this)->AddSpellCooldown(33750,0,time(NULL) + 3);
+ }
+
+ // remove it
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(dummySpell->EffectBasePoints[0]+1), false);
+ }
+ }
+
default: break;
}
@@ -4033,6 +4837,30 @@
return;
}
break;
+ case SPELLFAMILY_PALADIN:
+ // Seal of Righteousness - melee proc dummy
+ if (dummySpell->SpellFamilyFlags&0x000000008000000LL && triggredByAura->GetEffIndex()==0)
+ {
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ int32 damageBasePoints;
+ float speed = 2.0f;
+ Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
+ if(item) speed = item->GetProto()->Delay/1000.0f;
+ if(item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON)
+ damageBasePoints=1.20f*(triggredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f) + 1;// two hand weapon
+ else
+ damageBasePoints=0.85f*(triggredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f) - 1;// one hand weapon/no weapon
+ damageBasePoints +=0.03f * (m_weaponDamage[0][0]+m_weaponDamage[0][1])/2;
+ // TODO remove hack by using normal bonus calc
+ CalcDamageInfo damageInfo;
+ CalculateDamage(DAMAGE_SHIELD, pVictim, damageBasePoints, &damageInfo, BASE_ATTACK, dummySpell->Id);
+ DealDamage(&damageInfo, true);
+// CastCustomSpell(pVictim,25742,&damag,NULL,NULL,true,NULL, triggredByAura);
+ }
+ return;
+ }
+ break;
default:
break;
}
@@ -4111,7 +4939,7 @@
}
}
}
-
+/*
void Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags)
{
SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
@@ -4348,7 +5176,7 @@
((Player*)this)->AddSpellCooldown(31616,0,time(NULL) + 5);
((Player*)this)->AddSpellCooldown(39301,0,time(NULL) + 5);
}
- }*/
+ }
return;
}
case 2127:
@@ -4460,7 +5288,515 @@
else if(pVictim && pVictim->isAlive())
CastSpell(pVictim,trigger_spell_id,true,NULL,triggeredByAura);
}
+*/
+void Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags, uint32 procEx)
+{
+ // Get triggered aura spell info
+ SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
+ // Get trigger spell id
+ uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
+
+ // Try handle uncnown trigger spells
+ if (sSpellStore.LookupEntry(trigger_spell_id)==NULL)
+ switch (auraSpellInfo->SpellFamilyName)
+ {
+
+ //=====================================================================
+ // Generic class
+ // ====================================================================
+ // .....
+ // .....
+ //=====================================================================
+ case SPELLFAMILY_GENERIC:
+// if (auraSpellInfo->Id==34082) // Advantaged State (DND)
+// trigger_spell_id = ???;
+ if (auraSpellInfo->Id==23780) // Aegis of Preservation
+ trigger_spell_id = 23781;
+// else if (auraSpellInfo->Id==43504) // Alterac Valley OnKill Proc Aura
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==37030) // Chaotic Temperament ()
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==43820) // Charm of the Witch Doctor
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==41248) // Consuming Strikes
+// trigger_spell_id = 41249;
+// else if (auraSpellInfo->Id==41054) // Copy Weapon
+// trigger_spell_id = 41055;
+// 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 = ;
+// else if (auraSpellInfo->Id==33896) // Desperate Defense
+// trigger_spell_id = 33898; // ?? possibly this
+// 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;
+ /*
+ else if (auraSpellInfo->SpellIconID==191) // Elemental Response
+ {
+ switch (triggeredByAura->GetSpellProto()->Id && triggeredByAura->GetSpellProto()->AttributesEx==0)
+ {
+ case 34191:
+ case 34329:
+ case 34524:
+ case 34582:
+ case 36733:break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Elemental Response",triggeredByAura->GetSpellProto()->Id);
+ return;
+ }
+ //This generic aura self-triggers a different spell for each school of magic that lands on the wearer:
+ switch (procSpell->School)
+ {
+ case SPELL_SCHOOL_FIRE: trigger_spell_id = 34192;break;//Fire: 34192
+ case SPELL_SCHOOL_FROST: trigger_spell_id = 34193;break;//Frost: 34193
+ case SPELL_SCHOOL_ARCANE: trigger_spell_id = 34194;break;//Arcane: 34194
+ case SPELL_SCHOOL_NATURE: trigger_spell_id = 34195;break;//Nature: 34195
+ case SPELL_SCHOOL_SHADOW: trigger_spell_id = 34196;break;//Shadow: 34196
+ case SPELL_SCHOOL_HOLY: trigger_spell_id = 34197;break;//Holy: 34197
+ case SPELL_SCHOOL_NORMAL: trigger_spell_id = 34198;break;//Physical: 34198
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u Elemental Response wrong school",triggeredByAura->GetSpellProto()->Id);
+ return;
+ }
+ }*/
+// 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==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==40250) // Improved Duration
+// trigger_spell_id = ;
+ else if (auraSpellInfo->Id==27522)// 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())
+ CastSpell(this,29471,true,NULL,triggeredByAura);
+ if (pVictim && pVictim->isAlive())
+ CastSpell(pVictim,27526,true,NULL,triggeredByAura);
+ return;
+ }
+// else if (auraSpellInfo->Id==24905)// Moonkin Form (Passive)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==43453) // Rune Ward
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==7137) // Shadow Charge (Rank 1)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==36576) // Shaleskin
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==34783) // Spell Reflection
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==36096) // Spell Reflection
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==36207) // Steal Weapon
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==35205) // Vanish
+ break;
+
+ //=====================================================================
+ // Mage
+ // ====================================================================
+ // Blazing Speed (Rank 1,2) trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_MAGE:
+ if (auraSpellInfo->SpellIconID == 2127) // Blazing Speed
+ {
+ switch (triggeredByAura->GetSpellProto()->Id)
+ {
+ case 31641:// Blazing Speed (Rank 1)
+ case 31642:// Blazing Speed (Rank 2)
+ trigger_spell_id = 31643; //CastSpell(this,31643,true,NULL,triggeredByAura);
+ break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blazing Speed",auraSpellInfo->Id);
+ return;
+ }
+ }
+ break;
+
+ //=====================================================================
+ // Warrior
+ // ====================================================================
+ // 29801 Rampage (Rank 1-3) trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_WARRIOR:
+ if (auraSpellInfo->SpellIconID == 2006 && auraSpellInfo->SpellFamilyFlags==0x100000) //Rampage
+ {
+ 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;
+ }
+ }
+ break;
+ //=====================================================================
+ // Warlock
+ // ====================================================================
+ // Pet Mana Regen trigger = 18350
+ // Pet Resistance trigger = 18350
+ // Pyroclasm trigger = 18350 (possible 1 effect need to add not standart proc in add aura)
+ // Drain Soul (Rank 1-5) trigger = 0 ?? (chance = 0? but = 100 then Improved Drain Soul enabled)
+ //=====================================================================
+ case SPELLFAMILY_WARLOCK:
+// if (triggeredByAura->GetSpellProto()->SpellIconID == 37375) // Pet Mana Regen
+// trigger_spell_id = ????;break;
+// if (triggeredByAura->GetSpellProto()->SpellIconID == 37386) // Pet Resistance
+// trigger_spell_id = ????;
+ if (auraSpellInfo->SpellIconID == 1137) // Pyroclasm
+ {
+ if(!pVictim || !pVictim->isAlive() || pVictim == this || procSpell == NULL)
+ return;
+ // Calculate spell tick count for spells
+ uint32 tick = 1; // Default tick = 1
+ if (procSpell->SpellFamilyFlags&0x0000000000000040LL) tick = 15; // Hellfire have 15 tick
+ if (procSpell->SpellFamilyFlags&0x0000000000000020LL) tick = 4; // Rain of Fire have 4 tick
+ // Calculate chance = baseChance/tick
+ float chance = 0;
+ switch (auraSpellInfo->Id)
+ {
+ case 18096:chance = 13.0f/tick;break;
+ case 18073:chance = 26.0f/tick;break;
+ }
+ // Roll chance
+ if (roll_chance_f(chance))
+ CastSpell(pVictim, 18093, true, NULL, triggeredByAura);
+ return;
+ }
+ else if (auraSpellInfo->SpellFamilyFlags&0x0000000000004000LL) // Drain Soul
+ {
+ Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
+ for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
+ {
+ if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
+ {
+ int32 impDrainSoulBasePoints0 = (*i)->GetSpellProto()->EffectBasePoints[2] * GetMaxPower(POWER_MANA) / 100;
+ CastCustomSpell(this, 18371, &impDrainSoulBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
+ }
+ }
+ return;
+ }
+ break;
+
+ //=====================================================================
+ // Priest
+ // ====================================================================
+ // Greater Heal Refund trigger = 18350
+ // Improved Shadowfiend trigger = 18350
+ // Blessed Recovery (Rank 1-3) trigger = 18350
+ // Shadowguard (1-7) trigger = 28376
+ //=====================================================================
+ case SPELLFAMILY_PRIEST:
+ if (auraSpellInfo->Id==37594) //Greater Heal Refund
+ trigger_spell_id = 37595;
+// else if (triggeredByAura->GetSpellProto()->Id==37570)//Improved Shadowfiend
+// trigger_spell_id = ???;
+ else if(auraSpellInfo->SpellFamilyFlags==0x100080000000LL && auraSpellInfo->SpellVisual==7958) // Shadowguard
+ {
+ switch(triggeredByAura->GetSpellProto()->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",triggeredByAura->GetSpellProto()->Id);
+ return;
+ }
+ }
+ else if (auraSpellInfo->SpellIconID == 1875) //Blessed Recovery
+ {
+ uint32 EffectId = 0;
+ switch (triggeredByAura->GetSpellProto()->Id)
+ {
+ case 27811: EffectId = 27813; break;
+ case 27815: EffectId = 27817; break;
+ case 27816: EffectId = 27818; break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id);
+ return;
+ }
+ int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100;
+ int32 BRHealBasePoints0 = heal_amount/3-1;
+ CastCustomSpell(this, EffectId, &BRHealBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
+ return;
+ }
+ break;
+
+ //=====================================================================
+ // Druid
+ // ====================================================================
+ // Druid Forms Trinket trigger = 18350
+ // Entangling Roots trigger = 30023
+ // Leader of the Pack trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_DRUID:
+ if (auraSpellInfo->Id==37336)// Druid Forms Trinket
+ {
+ switch(m_form)
+ {
+ case 0: trigger_spell_id = 37344;break;
+ case FORM_CAT: trigger_spell_id = 37341;break;
+ case FORM_BEAR:
+ case FORM_DIREBEAR: trigger_spell_id = 37340;break;
+ case FORM_TREE: trigger_spell_id = 37342;break;
+ case FORM_MOONKIN: trigger_spell_id = 37343;break;
+ default:
+ return;
+ }
+ }
+// else if (auraSpellInfo->Id==40363)// Entangling Roots ()
+// trigger_spell_id = ????;
+ else if (triggeredByAura->GetSpellProto()->Id==24932)// Leader of the Pack ()
+ trigger_spell_id = 17007;
+ break;
+
+ //=====================================================================
+ // Hunter
+ // ====================================================================
+ // Increased Pet Attack Power trigger = 18350
+ // Pet Healing trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_HUNTER:
+// if (auraSpellInfo->Id==38297) // Increased Pet Attack Power
+// trigger_spell_id = ????;break;
+ if (auraSpellInfo->Id==37496) // Pet Healing
+ trigger_spell_id = 37501;
+ break;
+
+ //=====================================================================
+ // Paladin
+ // ====================================================================
+ // Blessed Life trigger = 31934
+ // Healing Discount trigger = 18350
+ // Illumination (Rank 1-5) trigger = 18350 (for HolyShock possibly use SPELL_AURA_OVERRIDE_CLASS_SCRIPTS)
+ // Judgement of Light (Rank 1-5) trigger = 5373
+ // Judgement of Wisdom (Rank 1-4) trigger = 1826
+ // Lightning Capacitor trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_PALADIN:
+// if (auraSpellInfo->SpellIconID == 2137) // Blessed Life
+// {
+// switch (triggeredByAura->GetSpellProto()->Id)
+// {
+// case 31828:// Blessed Life (Rank 1)
+// case 31829:// Blessed Life (Rank 2)
+// case 31830:// Blessed Life (Rank 3)
+// need change damage
+// break;
+// default:
+// sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blessed Life",triggeredByAura->GetSpellProto()->Id);
+// return;
+// }
+// }
+ if (auraSpellInfo->Id==37705) // Healing Discount
+ {
+ CastSpell(this,37706,true,NULL,triggeredByAura);
+ return;
+ }
+/* else if ((auraSpellInfo->SpellFamilyFlags&0x0000000000080000) &&
+ auraSpellInfo->SpellIconID==299)// Judgement of Light
+ {
+ switch (triggeredByAura->GetSpellProto()->Id)
+ {
+ case 20185:trigger_spell_id = 20267;break;// Judgement of Light (Rank 1)
+ case 20344:trigger_spell_id = 20341;break;// Judgement of Light (Rank 2)
+ case 20345:trigger_spell_id = 20342;break;// Judgement of Light (Rank 3)
+ case 20346:trigger_spell_id = 20343;break;// Judgement of Light (Rank 4)
+ case 27162:trigger_spell_id = 27163;break;// Judgement of Light (Rank 5)
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Judgement of Light",triggeredByAura->GetSpellProto()->Id);
+ return;
+ }
+ pVictim->CastSpell(pVictim,trigger_spell_id,true,NULL,triggeredByAura);
+ return;
+ }
+ else if ((auraSpellInfo->SpellFamilyFlags&0x0000000000080000) &&
+ auraSpellInfo->SpellIconID==206) // Judgement of Wisdom
+ {
+ switch (triggeredByAura->GetSpellProto()->Id)
+ {
+ case 20186:trigger_spell_id = 20268;break;// Judgement of Wisdom (Rank 1)
+ case 20354:trigger_spell_id = 20352;break;// Judgement of Wisdom (Rank 2)
+ case 20355:trigger_spell_id = 20353;break;// Judgement of Wisdom (Rank 3)
+ case 27164:trigger_spell_id = 27165;break;// Judgement of Wisdom (Rank 4)
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Judgement of Wisdom",triggeredByAura->GetSpellProto()->Id);
+ return;
+ }
+ pVictim->CastSpell(pVictim,trigger_spell_id,true,NULL,triggeredByAura);
+ return;
+ }*/
+ if (auraSpellInfo->SpellIconID==241 && trigger_spell_id==18350) //Illumination
+ {
+ if(!procSpell)
+ return;
+
+ SpellEntry const *originalSpell = procSpell;
+ // in case HShock procspell is triggered spell but we need mana cost of original casted spell
+ if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN && procSpell->SpellFamilyFlags == 0x00200000)
+ {
+ uint32 originalSpellId = 0;
+ 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;
+ }
+ SpellEntry const *HSSpell= sSpellStore.LookupEntry(originalSpellId);
+ if(!HSSpell)
+ {
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but used in HShock",originalSpellId);
+ return;
+ }
+ originalSpell = HSSpell;
+ }
+ // percent stored in effect 1 (class scripts) base points
+ int32 percent = auraSpellInfo->EffectBasePoints[1]+1;
+ // BasePoints = val -1 not required (EffectBaseDice==0)
+ int32 ILManaSpellBasePoints0 = originalSpell->manaCost*percent/100;
+ CastCustomSpell(this, 20272, &ILManaSpellBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
+ return;
+ }
+ else if (auraSpellInfo->Id==37657) // Lightning Capacitor
+ {
+ if(!pVictim || !pVictim->isAlive())
+ return;
+ // stacking
+ CastSpell(this, 37658, 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()==37658)
+ ++count;
+ // release at 3 aura in stack
+ if(count >2)
+ {
+ RemoveAurasDueToSpell(37658);
+ CastSpell(pVictim, 37661, true, NULL, triggeredByAura);
+ }
+ return;
+ }
+ break;
+ //=====================================================================
+ // Shaman
+ //====================================================================
+ // Lightning Shield trigger = 18350
+ // Mana Surge trigger = 18350
+ // Nature's Guardian (Rank 1-5) trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_SHAMAN:
+ //Lightning Shield (overwrite non existing triggered spell call in spell.dbc
+ if(auraSpellInfo->SpellFamilyFlags==0x00000400 && auraSpellInfo->SpellVisual==37)
+ {
+ switch(triggeredByAura->GetSpellProto()->Id)
+ {
+ case 324: trigger_spell_id = 26364; break; // Rank 1
+ case 325: trigger_spell_id = 26365; break; // Rank 2
+ case 905: trigger_spell_id = 26366; break; // Rank 3
+ case 945: trigger_spell_id = 26367; break; // Rank 4
+ case 8134: trigger_spell_id = 26369; break; // Rank 5
+ case 10431: trigger_spell_id = 26370; break; // Rank 6
+ 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
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id);
+ return;
+ }
+ }
+ else if (auraSpellInfo->Id == 23572) // Mana Surge (Shaman T1 bonus)
+ {
+ if(!procSpell)
+ return;
+ int32 manaSurgeSpellBasePoints0 = procSpell->manaCost * 35/100;
+ CastCustomSpell(this, 23571, &manaSurgeSpellBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
+ return;
+ }
+ else if (auraSpellInfo->SpellIconID == 2013) //Nature's Guardian
+ {
+ int32 heal = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100 - 1;
+ CastCustomSpell(this, 31616, &heal, 0, 0, true, NULL, triggeredByAura);
+ // if (pVictim && pVictim->isAlive())
+ // CastSpell(pVictim, 39301, true, NULL, triggredByAura);
+ return;
+ }
+ break;
+
+ // default
+ default:
+ break;
+ }
+
+ // All ok. Check current trigger spell
+ if (sSpellStore.LookupEntry(trigger_spell_id)==NULL)
+ {
+ // Not cast unknown spell
+ // sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex());
+ return;
+ }
+
+ // Costum basepoints/target for exist spell
+ // dummy basepoints or other customs
+ switch(trigger_spell_id)
+ {
+ case 30824: // Shamanistic Rage triggered spell
+ {
+ int32 SRBasePoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100) -1;
+ CastCustomSpell(this, 30824, &SRBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
+ return;
+ }
+ case 20233: // Improved Lay on Hands (cast on target)
+ {
+ if(pVictim && pVictim->isAlive())
+ CastSpell(pVictim,trigger_spell_id,true,NULL,triggeredByAura);
+ return;
+ }
+ }
+
+ // TODO need add more effective target/caster select
+ // default case
+ if(IsPositiveSpell(trigger_spell_id) && !(procFlags & PROC_FLAG_SUCCESSFUL_HEAL))
+ CastSpell(this,trigger_spell_id,true,NULL,triggeredByAura);
+ else if(pVictim && pVictim->isAlive())
+ CastSpell(pVictim,trigger_spell_id,true,NULL,triggeredByAura);
+}
+
void Unit::setPowerType(Powers new_powertype)
{
uint32 tem_bytes_0 = GetUInt32Value(UNIT_FIELD_BYTES_0);
@@ -5013,9 +6349,6 @@
if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
return pdamage;
- if(pVictim->IsImmunedToSpellDamage(spellProto))
- return 0;
-
uint32 creatureTypeMask = GetCreatureTypeMask();
// Damage Done
@@ -5395,6 +6728,23 @@
return false;
}
+bool Unit::IsImmunedToSchoolDamage(SpellSchools School) const
+{
+ //If m_immuneToDamage type contain magic, IMMUNE damage.
+ SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
+ for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
+ if(itr->type & uint32(1<<School))
+ return true;
+
+ //If m_immuneToSchool type contain this school type, IMMUNE damage.
+ SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ if(itr->type & uint32(1<<School))
+ return true;
+
+ return false;
+}
+
bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo) const
{
if (!spellInfo)
@@ -7171,15 +8521,27 @@
};
typedef std::list< ProcTriggeredData > ProcTriggeredList;
-
-void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage )
+typedef std::list< uint32> RemoveSpellList;
+// Trigger auras is SPELL_AURA_DUMMY, SPELL_AURA_PROC_TRIGGER_SPELL, SPELL_AURA_PROC_TRIGGER_DAMAGE
+// and procFlags!=0
+static inline bool isTriggerAura(uint8 aur)
{
- for(AuraTypeSet::const_iterator aur = procAuraTypes.begin(); aur != procAuraTypes.end(); ++aur)
+ if (aur == SPELL_AURA_DUMMY ||
+ aur == SPELL_AURA_PROC_TRIGGER_SPELL ||
+ aur == SPELL_AURA_PROC_TRIGGER_DAMAGE ||
+ aur == SPELL_AURA_MOD_STUN||
+ aur == SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)
+ return true;
+ return false;
+}
+void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage )
+{
+ for (uint8 aur = 1; aur<TOTAL_AURAS;aur++)
{
// List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
ProcTriggeredList procTriggered;
-
- AuraList const& auras = GetAurasByType(*aur);
+ RemoveSpellList removedSpells;
+ AuraList const& auras = GetAurasByType(AuraType(aur));
for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next)
{
next = i; next++;
@@ -7187,25 +8549,14 @@
SpellEntry const *spellProto = (*i)->GetSpellProto();
if(!spellProto)
continue;
-
SpellProcEventEntry const *spellProcEvent = objmgr.GetSpellProcEvent(spellProto->Id);
- if(!spellProcEvent)
- {
- // used to prevent spam in log about same non-handled spells
- static std::set<uint32> nonHandledSpellProcSet;
-
- if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
- {
- sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's"));
- nonHandledSpellProcSet.insert(spellProto->Id);
- }
-
- // spell.dbc use totally different flags, that only can create problems if used.
+ if (spellProto->procFlags==0 && spellProcEvent && spellProcEvent->procFlags==0)
continue;
- }
-
+ // If not trigger and spellProcEvent==NULL - skip
+ if (!isTriggerAura(aur) && spellProcEvent==NULL)
+ continue;
// Check spellProcEvent data requirements
- if(!ObjectMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag))
+ if(!ObjectMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, spellProto->procFlags, procSpell,procFlag,procExtra))
continue;
// Check if current equipment allows aura to proc
@@ -7232,27 +8583,26 @@
continue;
}
}
-
+ // Get chance from spell
float chance = (float)spellProto->procChance;
-
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
-
- if(!isVictim && spellProcEvent->ppmRate != 0)
+ // If in spellProcEvent exist custom chance, chance = spellProcEvent->customChance;
+ if(spellProcEvent && spellProcEvent->customChance)
+ chance = spellProcEvent->customChance;
+ // If PPM exist calculate chance from PPM
+ if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
{
uint32 WeaponSpeed = GetAttackTime(attType);
chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
}
-
+ // Apply chance modifer aura
+ if(Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
+
if(roll_chance_f(chance))
{
- if((*i)->m_procCharges > 0)
- (*i)->m_procCharges -= 1;
-
uint32 i_spell_eff = (*i)->GetEffIndex();
-
int32 i_spell_param;
- switch(*aur)
+ switch(aur)
{
case SPELL_AURA_PROC_TRIGGER_SPELL: i_spell_param = procFlag; break;
case SPELL_AURA_DUMMY: i_spell_param = i_spell_eff; break;
@@ -7284,57 +8634,104 @@
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("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 proccesed 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(" Spell aura %u (id:%u effect:%u)",aur,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second);
sLog.outError(" <end of list>");
continue;
}
}
+ SpellProcEventEntry const *spellProcEvent = objmgr.GetSpellProcEvent(i->spellInfo->Id);
+ if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->Cooldown && ((Player *)this)->HasSpellCooldown(i->spellInfo->Id))
+ continue;
- switch(*aur)
+ switch(aur)
{
case SPELL_AURA_PROC_TRIGGER_SPELL:
{
+ // TODO: adaptate more for costum requirements (not listed in procEx) and fix
+ // Warning! damage dealing after call ProcDamageAndSpellFor
+ switch (i->spellInfo->Id)
+ {
+ case 28845:// Cheat Death - When your health drops below 20% ....
+ if (!(GetHealth()-damage<GetMaxHealth()/5 && GetHealth()>GetMaxHealth()/5))
+ continue;
+ break;
+ case 31255:// Deadly Swiftness (Rank 1) - ... whenever you deal damage to a target who is below 20% health.
+ if (pTarget->GetHealth()>pTarget->GetMaxHealth()/5)
+ continue;
+ break;
+ case 40971:// Bonus Healing - If your target is below $s1% health
+ if (pTarget->GetHealth()>pTarget->GetMaxHealth()*i->triggeredByAura->GetModifier()->m_amount/100)
+ continue;
+ break;
+ case 37594:// Greater Heal Refund - If your Greater Heal brings the target to full health, you gain $37595s1 mana.
+ if (pTarget->GetHealth()+damage<pTarget->GetMaxHealth())
+ continue;
+ break;
+ case 30881:// Nature's Guardian (Rank 1-5) Whenever a damaging attack is taken that reduces you below 30% health...
+ case 30883:
+ case 30884:
+ case 30885:
+ case 30886:
+ if (!(GetHealth()-damage<GetMaxHealth()*0.3 && GetHealth()>GetMaxHealth()*0.3))
+ continue;
+ break;
+ }
+
sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
- HandleProcTriggerSpell(pTarget, damage, i->triggeredByAura, procSpell,i->spellParam);
+ HandleProcTriggerSpell(pTarget, damage, i->triggeredByAura, procSpell, i->spellParam, procExtra);
break;
}
case SPELL_AURA_PROC_TRIGGER_DAMAGE:
{
sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i->spellParam, i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
uint32 damage = i->spellParam;
- // TODO: remove hack for Seal of Righteousness. That should not be there
- if(!isVictim && i->spellInfo->SpellVisual == 7986)
- damage = (damage * GetAttackTime(BASE_ATTACK))/60/1000;
SpellNonMeleeDamageLog(pTarget, i->spellInfo->Id, damage, true, true);
break;
}
case SPELL_AURA_DUMMY:
{
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
- HandleDummyAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag);
+ HandleDummyAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag, procExtra);
break;
}
+ case SPELL_AURA_MOD_STUN:
+ removedSpells.push_back(i->triggeredByAura->GetId());
+ break;
+ break;
+ case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS:
+ // Hunter's Mark (1-4 Rangs)
+ // For - increasing the ranged attack power of all attackers against by an additional ${$m2/10} each time they are struck by a ranged attack, up to a maximum of ${$m2*4}
+ if (i->spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (i->spellInfo->SpellFamilyFlags&0x0000000000000400LL))
+ {
+ uint32 basevalue = i->triggeredByAura->GetBasePoints()+1;
+ i->triggeredByAura->GetModifier()->m_amount+=basevalue/10;
+ if (i->triggeredByAura->GetModifier()->m_amount>basevalue*4)
+ i->triggeredByAura->GetModifier()->m_amount = basevalue*4;
+ }
default:
{
// nothing do, just charges counter
break;
}
}
- }
+ if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->Cooldown)
+ ((Player *)this)->AddSpellCooldown(i->spellInfo->Id, 0, time(NULL)+spellProcEvent->Cooldown);
- // 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)
+ // Remove charge
+ if(i->triggeredByAura && i->triggeredByAura->m_procCharges > 0)
{
- RemoveAurasDueToSpell((*i)->GetId());
- next = auras.begin();
+ i->triggeredByAura->m_procCharges -=1;
+ if (i->triggeredByAura->m_procCharges==0)
+ removedSpells.push_back(i->triggeredByAura->GetId());
}
}
+
+ // Remove auras from removedAuras
+ for(RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end();i++)
+ RemoveAurasDueToSpell(*i);
}
}
Index: src/game/Unit.h
===================================================================
--- src/game/Unit.h (revision 4842)
+++ src/game/Unit.h (working copy)
@@ -56,6 +56,15 @@
// Horde Racial Passives
#define SPELL_HORDE_PASSIVE_NATURE_RESISTANCE 20551*/
+enum SpellInturruptFlags
+{
+ INTURRUPTFLAG_FLAG_MOVEMENT = 0x01,
+ INTURRUPTFLAG_FLAG_DAMAGE = 0x02,
+ INTURRUPTFLAG_FLAG_INTURRUPT = 0x04,
+ INTURRUPTFLAG_FLAG_AUTOATTACK = 0x08,
+ INTURRUPTFLAG_FLAG_TURNING = 0x10
+};
+
enum SpellChannelInterruptFlags
{
CHANNEL_FLAG_DAMAGE = 0x0002,
@@ -355,7 +364,8 @@
DOT = 2,
HEAL = 3,
NODAMAGE = 4, // used also in case when damage applied to health but not applied to spell channelInterruptFlags/etc
- SELF_DAMAGE = 5
+ SELF_DAMAGE = 5,
+ DAMAGE_SHIELD = 6
};
enum UnitVisibility
@@ -405,41 +415,59 @@
enum ProcFlags
{
- PROC_FLAG_NONE = 0x00000000, // None
- PROC_FLAG_HIT_MELEE = 0x00000001, // On melee hit
- PROC_FLAG_STRUCK_MELEE = 0x00000002, // On being struck melee
- PROC_FLAG_KILL_XP_GIVER = 0x00000004, // On kill target giving XP or honor
- PROC_FLAG_SPECIAL_DROP = 0x00000008, //
- PROC_FLAG_DODGE = 0x00000010, // On dodge melee attack
- PROC_FLAG_PARRY = 0x00000020, // On parry melee attack
- PROC_FLAG_BLOCK = 0x00000040, // On block attack
- PROC_FLAG_TOUCH = 0x00000080, // On being touched (for bombs, probably?)
- PROC_FLAG_TARGET_LOW_HEALTH = 0x00000100, // On deal damage to enemy with 20% or less health
- PROC_FLAG_LOW_HEALTH = 0x00000200, // On health dropped below 20%
- PROC_FLAG_STRUCK_RANGED = 0x00000400, // On being struck ranged
- PROC_FLAG_HIT_SPECIAL = 0x00000800, // (!)Removed, may be reassigned in future
- PROC_FLAG_CRIT_MELEE = 0x00001000, // On crit melee
- PROC_FLAG_STRUCK_CRIT_MELEE = 0x00002000, // On being critically struck in melee
- PROC_FLAG_CAST_SPELL = 0x00004000, // On cast spell (and broken Aspect of Hawk)
- PROC_FLAG_TAKE_DAMAGE = 0x00008000, // On take damage
- PROC_FLAG_CRIT_SPELL = 0x00010000, // On crit spell
- PROC_FLAG_HIT_SPELL = 0x00020000, // On hit spell
- PROC_FLAG_STRUCK_CRIT_SPELL = 0x00040000, // On being critically struck by a spell
- PROC_FLAG_HIT_RANGED = 0x00080000, // On getting ranged hit
- PROC_FLAG_STRUCK_SPELL = 0x00100000, // On being struck by a spell
- PROC_FLAG_TRAP = 0x00200000, // On trap activation (?)
- PROC_FLAG_CRIT_RANGED = 0x00400000, // On getting ranged crit
- PROC_FLAG_STRUCK_CRIT_RANGED = 0x00800000, // On being critically struck by a ranged attack
- PROC_FLAG_RESIST_SPELL = 0x01000000, // On resist enemy spell
- PROC_FLAG_TARGET_RESISTS = 0x02000000, // On enemy resisted spell
- PROC_FLAG_TARGET_DODGE_OR_PARRY= 0x04000000, // On enemy dodges/parries
- PROC_FLAG_HEAL = 0x08000000, // On heal
- PROC_FLAG_CRIT_HEAL = 0x10000000, // On critical healing effect
- PROC_FLAG_HEALED = 0x20000000, // On healing
- PROC_FLAG_TARGET_BLOCK = 0x40000000, // On enemy blocks
- PROC_FLAG_MISS = 0x80000000 // On miss melee attack
+ PROC_FLAG_NONE = 0x00000000,
+
+ 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_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
+ PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged 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
+
+ PROC_FLAG_SUCCESSFUL_10 = 0x00000400, // 10 Special flag
+ PROC_FLAG_TAKEN_11 = 0x00000800, // 11 Special flag
+
+ PROC_FLAG_SUCCESSFUL_12 = 0x00001000, // 12 Successful damage spell hit (spell type???)
+ PROC_FLAG_TAKEN_13 = 0x00002000, // 13 Taken damage spell hit (spell type???)
+
+ PROC_FLAG_SUCCESSFUL_HEAL = 0x00004000, // 14 Successful cast healing spell
+ PROC_FLAG_TAKEN_HEAL = 0x00008000, // 15 Taken healing spell hit
+
+ PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT = 0x00010000, // 16 Successful damage from harmful spell cast
+ PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT = 0x00020000, // 17 Taken spell damage
+
+ PROC_FLAG_SUCCESSFUL_PERIODIC_DAMAGE = 0x00040000, // 18 Successful deal spell periodic damage
+ PROC_FLAG_TAKEN_PERIODIC_DAMAGE = 0x00080000, // 19 Taken spell periodic damage
+
+ PROC_FLAG_TAKEN_ANY_DAMAGE = 0x00100000, // 20 Taken any damage
+ PROC_FLAG_ON_TRAP_ACTIVATION = 0x00200000, // 21 On trap activation
+
+ PROC_FLAG_TAKEN_OFFHAND_HIT = 0x00400000, // 22 Taken off-hand melee attacks(not used)
+ PROC_FLAG_SUCCESSFUL_OFFHAND_HIT = 0x00800000 // 23 Successful off-hand melee attacks
};
+enum ProcFlagsEx
+{
+ PROC_FLAG_EX_NONE = 0x00000000,
+ PROC_FLAG_EX_CRITICAL_HIT = 0x00000001,
+ PROC_FLAG_ON_SPELL_CAST = 0x00000002,
+ PROC_FLAG_EX_DODGE = 0x00000004,
+ PROC_FLAG_EX_PARRY = 0x00000008,
+ PROC_FLAG_EX_BLOCK = 0x00000010,
+ PROC_FLAG_EX_MISS = 0x00000020,
+ PROC_FLAG_EX_FULL_RESISTS = 0x00000080,
+ PROC_FLAG_EX_ABSORB = 0x00000100,
+ PROC_FLAG_EX_HIT_EVADE_TARGET = 0x00000200
+};
+
enum AuraState
{ // (C) used in caster aurastate (T) used in target aura state
AURA_STATE_DEFENSE = 1, // C
@@ -600,7 +628,30 @@
WeaponAttackType attackType;
MeleeHitOutcome hitOutCome;
};
+// Test struct for use in Unit::CalculateSpellDamage, Unit::CalculateMeleeDamage
+struct CalcDamageInfo
+{
+ DamageEffectType damagetype;
+ uint32 damage;
+ uint32 cleanDamage;
+ uint32 absorb;
+ uint32 resist;
+ uint32 blocked_amount;
+ uint32 procAttacker;
+ uint32 procVictim;
+ uint32 procEx;
+
+ Unit *target; // Target for damage
+ uint32 HitInfo;
+ uint32 TargetState;
+ WeaponAttackType attackType; //
+ MeleeHitOutcome hitOutCome; // TODO: remove this field
+ SpellSchools damageSchool;
+ uint32 SpellID;
+ uint32 auraname;
+
+};
struct UnitActionBarEntry
{
uint32 Type;
@@ -826,15 +877,24 @@
void Unmount();
uint16 GetMaxSkillValueForLevel() const { return getLevel()*5; }
+ void DealDamage(CalcDamageInfo *damageInfo, bool durabilityLoss);
void DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchools damageSchool, SpellEntry const *spellProto, uint32 procFlag, bool durabilityLoss);
- void DealDamageBySchool(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit = false, bool isTriggeredSpell = false);
- void DoAttackDamage(Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchools damageType, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false);
+// void DealDamageBySchool(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit = false, bool isTriggeredSpell = false);
- void CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false);
- void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage = 0, SpellEntry const *procSpell = NULL, bool isTriggeredSpell = false, WeaponAttackType attType = BASE_ATTACK);
+// void DoAttackDamage(Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchools damageType, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false);
+ void CalculateDamage(DamageEffectType type, Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType = BASE_ATTACK, uint32 spellID = 0, SpellSchools damageSchool = SPELL_SCHOOL_NORMAL, uint32 auraname = 0);
+ void CalculateMeleeDamage(uint32 damage, CalcDamageInfo *damageInfo);
+ void CalculateSpellDamage(uint32 damage, CalcDamageInfo *damageInfo);
+ void CalculateDotDamage(uint32 damage, CalcDamageInfo *damageInfo);
+// void CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false);
+ void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 damage = 0, SpellEntry const *procSpell = NULL, bool isTriggeredSpell = false, WeaponAttackType attType = BASE_ATTACK);
void HandleEmoteCommand(uint32 anim_id);
void AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType = BASE_ATTACK, bool isTriggered = false);
- uint32 SpellMissChanceCalc(Unit *pVictim) const;
+ uint32 SpellMissChanceCalc(Unit *pVictim, SpellSchools school) const;
+ uint32 SpellResistChanceCalc(Unit *pVictim, SpellSchools school) const;
+
+ uint8 SpellCastResult(Unit *pVictim, SpellEntry const *spell) const;
+
int32 MeleeMissChanceCalc(const Unit *pVictim) const;
float GetUnitDodgeChance() const;
@@ -917,7 +977,7 @@
bool isFrozen() const;
- void RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage);
+ void RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage, uint32 casterLevel);
bool isTargetableForAttack() const;
virtual bool IsInWater() const;
@@ -928,6 +988,9 @@
void SendHealSpellOnPlayerPet(Unit *pVictim, uint32 SpellID, uint32 Damage,Powers powertype, bool critical = false);
void PeriodicAuraLog(Unit *pVictim, SpellEntry const *spellProto, Modifier *mod, uint8 effect_idx);
void SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell = false, bool useSpellDamage = true);
+ void SendSpellNonMeleeDamageLog(CalcDamageInfo *damageInfo);
+ void SendSpellDotDamageLog(CalcDamageInfo *damageInfo);
+
void CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem = NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0);
void CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem= NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0);
void CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, Aura* triggredByAura = NULL, uint64 originalCaster = 0);
@@ -937,6 +1000,8 @@
void DeMorph();
void SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchools DamageType, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount);
+ void SendAttackStateUpdate(CalcDamageInfo *damageInfo);
+
void SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchools DamageType,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false);
void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, bool Run, uint32 Time);
@@ -1034,7 +1099,7 @@
uint32 m_ShapeShiftForm;
uint32 m_form;
int32 m_modHitChance;
- int32 m_modSpellHitChance;
+ int32 m_modSpellHitChance[MAX_SPELL_SCHOOL];
int32 m_baseSpellCritChance;
float m_modResilience;
float m_threatModifier[MAX_SPELL_SCHOOL];
@@ -1128,6 +1193,7 @@
virtual bool IsImmunedToSpell(SpellEntry const* spellInfo) const;
// redefined in Creature
bool IsImmunedToPhysicalDamage() const;
+ bool IsImmunedToSchoolDamage(SpellSchools School) const;
bool IsImmunedToSpellDamage(SpellEntry const* spellInfo) const;
bool IsImmunedToSpellEffect(uint32 effect) const;
@@ -1222,9 +1288,9 @@
void SendAttackStop(Unit* victim); // only from AttackStop(Unit*)
void SendAttackStart(Unit* pVictim); // only from Unit::AttackStart(Unit*)
- void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage );
- void HandleDummyAuraProc(Unit *pVictim, SpellEntry const *spellProto, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag);
- void HandleProcTriggerSpell(Unit *pVictim,uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlags);
+ void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage );
+ void HandleDummyAuraProc(Unit *pVictim, SpellEntry const *spellProto, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx);
+ void HandleProcTriggerSpell(Unit *pVictim,uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlags, uint32 procEx);
uint32 m_state; // Even derived shouldn't modify
uint32 m_CombatTimer;
Index: src/shared/Database/DBCStructure.h
===================================================================
--- src/shared/Database/DBCStructure.h (revision 4842)
+++ src/shared/Database/DBCStructure.h (working copy)
@@ -527,7 +527,10 @@
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value
uint64 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do)
uint32 procFlags; // bitmask for matching proc event
+ uint32 procEx;
float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc
+ float customChance;
+ uint32 Cooldown;
};
struct SpellThreatEntry