/src/server/game/Entities/Unit/Unit.cpp
C++ | 12650 lines | 9953 code | 1410 blank | 1287 comment | 3557 complexity | 7ec1cff59d0e2ad064991a504da14235 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
- *
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
- #include "Common.h"
- #include "CreatureAIImpl.h"
- #include "Log.h"
- #include "Opcodes.h"
- #include "WorldPacket.h"
- #include "WorldSession.h"
- #include "World.h"
- #include "ObjectMgr.h"
- #include "SpellMgr.h"
- #include "Unit.h"
- #include "QuestDef.h"
- #include "Player.h"
- #include "Creature.h"
- #include "Spell.h"
- #include "Group.h"
- #include "SpellAuras.h"
- #include "SpellAuraEffects.h"
- #include "MapManager.h"
- #include "ObjectAccessor.h"
- #include "CreatureAI.h"
- #include "Formulas.h"
- #include "Pet.h"
- #include "Util.h"
- #include "Totem.h"
- #include "Battleground.h"
- #include "OutdoorPvP.h"
- #include "InstanceSaveMgr.h"
- #include "GridNotifiersImpl.h"
- #include "CellImpl.h"
- #include "CreatureGroups.h"
- #include "PetAI.h"
- #include "PassiveAI.h"
- #include "TemporarySummon.h"
- #include "Vehicle.h"
- #include "Transport.h"
- #include "InstanceScript.h"
- #include "MoveSplineInit.h"
- #include "MoveSpline.h"
- #include "PathFinder.h"
- #include <math.h>
- float baseMoveSpeed[MAX_MOVE_TYPE] =
- {
- 2.5f, // MOVE_WALK
- 7.0f, // MOVE_RUN
- 4.5f, // MOVE_RUN_BACK
- 4.722222f, // MOVE_SWIM
- 2.5f, // MOVE_SWIM_BACK
- 3.141594f, // MOVE_TURN_RATE
- 7.0f, // MOVE_FLIGHT
- 4.5f, // MOVE_FLIGHT_BACK
- 3.14f // MOVE_PITCH_RATE
- };
- float playerBaseMoveSpeed[MAX_MOVE_TYPE] = {
- 2.5f, // MOVE_WALK
- 7.0f, // MOVE_RUN
- 4.5f, // MOVE_RUN_BACK
- 4.722222f, // MOVE_SWIM
- 2.5f, // MOVE_SWIM_BACK
- 3.141594f, // MOVE_TURN_RATE
- 7.0f, // MOVE_FLIGHT
- 4.5f, // MOVE_FLIGHT_BACK
- 3.14f // MOVE_PITCH_RATE
- };
- // Used for prepare can/can`t triggr aura
- static bool InitTriggerAuraData();
- // Define can trigger auras
- static bool isTriggerAura[TOTAL_AURAS];
- // Define can`t trigger auras (need for disable second trigger)
- static bool isNonTriggerAura[TOTAL_AURAS];
- // Triggered always, even from triggered spells
- static bool isAlwaysTriggeredAura[TOTAL_AURAS];
- // Prepare lists
- static bool procPrepared = InitTriggerAuraData();
- DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellEntry const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType)
- : m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask),
- m_damageType(_damageType), m_attackType(BASE_ATTACK)
- {
- m_absorb = 0;
- m_resist = 0;
- m_block = 0;
- }
- DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo)
- : m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(NULL), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)),
- m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType)
- {
- m_absorb = 0;
- m_resist = 0;
- m_block = 0;
- }
- void DamageInfo::ModifyDamage(int32 amount)
- {
- amount = std::min(amount, int32(GetDamage()));
- m_damage += amount;
- }
- void DamageInfo::AbsorbDamage(uint32 amount)
- {
- amount = std::min(amount, GetDamage());
- m_absorb += amount;
- m_damage -= amount;
- }
- void DamageInfo::ResistDamage(uint32 amount)
- {
- amount = std::min(amount, GetDamage());
- m_resist += amount;
- m_damage -= amount;
- }
- void DamageInfo::BlockDamage(uint32 amount)
- {
- amount = std::min(amount, GetDamage());
- m_block += amount;
- m_damage -= amount;
- }
- static uint32 SpellFamilyNameByClass[] = {4, 10, 9, 8, 6, 15, 11, 3, 5, 18, 7};
- ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
- :_actor(actor), _actionTarget(actionTarget), _procTarget(procTarget), _typeMask(typeMask), _spellTypeMask(spellTypeMask), _spellPhaseMask(spellPhaseMask),
- _hitMask(hitMask), _spell(spell), _damageInfo(damageInfo), _healInfo(healInfo) { }
- // we can disable this warning for this since it only
- // causes undefined behavior when passed to the base class constructor
- #ifdef _MSC_VER
- #pragma warning(disable:4355)
- #endif
- Unit::Unit(bool isWorldObject): WorldObject(isWorldObject),
- m_movedPlayer(NULL), m_lastSanctuaryTime(0), IsAIEnabled(false), NeedChangeAI(false),
- m_ControlledByPlayer(false), i_AI(NULL), i_disabledAI(NULL), m_procDeep(0),
- m_removedAurasCount(0), i_motionMaster(this), m_ThreatManager(this), m_vehicle(NULL),
- m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this), movespline(new Movement::MoveSpline())
- {
- #ifdef _MSC_VER
- #pragma warning(default:4355)
- #endif
- m_objectType |= TYPEMASK_UNIT;
- m_objectTypeId = TYPEID_UNIT;
- m_updateFlag = (UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION);
- m_attackTimer[BASE_ATTACK] = 0;
- m_attackTimer[OFF_ATTACK] = 0;
- m_attackTimer[RANGED_ATTACK] = 0;
- m_modAttackSpeedPct[BASE_ATTACK] = 1.0f;
- m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
- m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
- m_extraAttacks = 0;
- m_canDualWield = false;
- m_rootTimes = 0;
- m_state = 0;
- m_deathState = ALIVE;
- for(uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
- m_currentSpells[i] = NULL;
- m_addDmgOnce = 0;
- for(uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
- m_SummonSlot[i] = 0;
- m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
- m_auraUpdateIterator = m_ownedAuras.end();
- m_interruptMask = 0;
- m_transform = 0;
- m_canModifyStats = false;
- for(uint8 i = 0; i < MAX_SPELL_IMMUNITY; ++i)
- m_spellImmune[i].clear();
- for(uint8 i = 0; i < UNIT_MOD_END; ++i)
- {
- m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
- m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
- m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
- m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
- }
- // implement 50% base damage from offhand
- m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
- for(uint8 i = 0; i < MAX_ATTACK; ++i)
- {
- m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
- m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
- }
- for(uint8 i = 0; i < MAX_STATS; ++i)
- m_createStats[i] = 0.0f;
- m_attacking = NULL;
- m_modMeleeHitChance = 0.0f;
- m_modRangedHitChance = 0.0f;
- m_modSpellHitChance = 0.0f;
- m_baseSpellCritChance = 5;
- m_CombatTimer = 0;
- m_lastManaUse = 0;
- for(uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
- m_threatModifier[i] = 1.0f;
- m_isSorted = true;
- for(uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
- m_speed_rate[i] = 1.0f;
- m_charmInfo = NULL;
- m_reducedThreatPercent = 0;
- m_misdirectionTargetGUID = 0;
- // remove aurastates allowing special moves
- for(uint8 i = 0; i < MAX_REACTIVE; ++i)
- m_reactiveTimer[i] = 0;
- m_cleanupDone = false;
- m_duringRemoveFromWorld = false;
- m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
- _focusSpell = NULL;
- _targetLocked = false;
- m_lastLiquid = NULL;
- }
- bool GlobalCooldownMgr::HasGlobalCooldown(SpellEntry const* spellInfo) const
- {
- GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory);
- return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, getMSTime()) < itr->second.duration;
- }
- void GlobalCooldownMgr::AddGlobalCooldown(SpellEntry const* spellInfo, uint32 gcd)
- {
- m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, getMSTime());
- }
- void GlobalCooldownMgr::CancelGlobalCooldown(SpellEntry const* spellInfo)
- {
- m_GlobalCooldowns[spellInfo->StartRecoveryCategory].duration = 0;
- }
- Unit::~Unit()
- {
- // set current spells as deletable
- for(uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
- {
- if(m_currentSpells[i])
- {
- m_currentSpells[i]->SetReferencedFromCurrent(false);
- m_currentSpells[i] = NULL;
- }
- }
- _DeleteRemovedAuras();
- // remove veiw point for spectator
- if (!m_sharedVision.empty())
- {
- for (SharedVisionList::iterator itr = m_sharedVision.begin(); itr != m_sharedVision.end(); ++itr)
- if ((*itr)->isSpectator() && (*itr)->getSpectateFrom())
- {
- (*itr)->SetViewpoint((*itr)->getSpectateFrom(), false);
- if (m_sharedVision.empty())
- break;
- --itr;
- }
- }
- delete m_charmInfo;
- delete m_vehicleKit;
- delete movespline;
- ASSERT(!m_duringRemoveFromWorld);
- ASSERT(!m_attacking);
- ASSERT(m_attackers.empty());
- ASSERT(m_sharedVision.empty());
- ASSERT(m_Controlled.empty());
- ASSERT(m_appliedAuras.empty());
- ASSERT(m_ownedAuras.empty());
- ASSERT(m_removedAuras.empty());
- ASSERT(m_gameObj.empty());
- ASSERT(m_dynObj.empty());
- }
- void Unit::Update(uint32 p_time)
- {
- m_Events.Update(p_time);
- if(!IsInWorld())
- return;
- _UpdateSpells(p_time);
- // If this is set during update SetCantProc(false) call is missing somewhere in the code
- // Having this would prevent spells from being proced, so let's crash
- ASSERT(!m_procDeep);
- if(CanHaveThreatList() && getThreatManager().isNeedUpdateToClient(p_time))
- SendThreatListUpdate();
- // update combat timer only for players and pets (only pets with PetAI)
- if(isInCombat() && (GetTypeId() == TYPEID_PLAYER || (ToCreature()->isPet() && IsControlledByPlayer())))
- {
- // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
- // targets without stopping half way there and running off.
- // These flags are reset after target dies or another command is given.
- if(m_HostileRefManager.isEmpty())
- {
- // m_CombatTimer set at aura start and it will be freeze until aura removing
- if(m_CombatTimer <= p_time)
- ClearInCombat();
- else
- m_CombatTimer -= p_time;
- }
- }
- // not implemented before 3.0.2
- //if(!HasUnitState(UNIT_STAT_CASTING))
- {
- if(uint32 base_att = getAttackTimer(BASE_ATTACK))
- setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
- if(uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
- setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time));
- if(uint32 off_att = getAttackTimer(OFF_ATTACK))
- setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time));
- }
- // update abilities available only for fraction of time
- UpdateReactives(p_time);
- if(isAlive())
- {
- ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, HealthBelowPct(20));
- ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, HealthBelowPct(35));
- ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, HealthAbovePct(75));
- }
- UpdateSplineMovement(p_time);
- i_motionMaster.UpdateMotion(p_time);
- }
- bool Unit::haveOffhandWeapon() const
- {
- if(GetTypeId() == TYPEID_PLAYER)
- return ToPlayer()->GetWeaponForAttack(OFF_ATTACK, true);
- else
- return m_canDualWield;
- }
- void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
- {
- Movement::MoveSplineInit init(*this);
- init.MoveTo(x, y, z, generatePath, forceDestination);
- init.SetVelocity(speed);
- init.Launch();
- }
- void Unit::UpdateSplineMovement(uint32 t_diff)
- {
- if(movespline->Finalized())
- return;
- movespline->updateState(t_diff);
- bool arrived = movespline->Finalized();
- if(arrived)
- DisableSpline();
- m_movesplineTimer.Update(t_diff);
- if(m_movesplineTimer.Passed() || arrived)
- {
- m_movesplineTimer.Reset(400 /*POSITION_UPDATE_DELAY*/);
- Movement::Location loc = movespline->ComputePosition();
- if(GetTypeId() == TYPEID_PLAYER)
- ((Player*)this)->SetPosition(loc.x,loc.y,loc.z,loc.orientation);
- else
- GetMap()->CreatureRelocation((Creature*)this,loc.x,loc.y,loc.z,loc.orientation);
- }
- }
- void Unit::DisableSpline()
- {
- m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD));
- movespline->_Interrupt();
- }
- void Unit::SendMonsterMoveExitVehicle(Position const* newPos)
- {
- WorldPacket data(SMSG_MONSTER_MOVE, 1+12+4+1+4+4+4+12+GetPackGUID().size());
- data.append(GetPackGUID());
- data << uint8(GetTypeId() == TYPEID_PLAYER ? 1 : 0); // new in 3.1, bool
- data << GetPositionX() << GetPositionY() << GetPositionZ();
- data << getMSTime();
- data << uint8(SPLINETYPE_FACING_ANGLE);
- data << float(GetOrientation()); // guess
- data << uint32(SPLINEFLAG_EXIT_VEHICLE);
- data << uint32(0); // Time in between points
- data << uint32(1); // 1 single waypoint
- data << newPos->GetPositionX();
- data << newPos->GetPositionY();
- data << newPos->GetPositionZ();
- SendMessageToSet(&data, true);
- }
- void Unit::SendMonsterMoveTransport(Unit* vehicleOwner)
- {
- // TODO: Turn into BuildMonsterMoveTransport packet and allow certain variables (for npc movement aboard vehicles)
- WorldPacket data(SMSG_MONSTER_MOVE_TRANSPORT, GetPackGUID().size()+vehicleOwner->GetPackGUID().size() + 47);
- data.append(GetPackGUID());
- data.append(vehicleOwner->GetPackGUID());
- data << int8(GetTransSeat());
- data << uint8(GetTypeId() == TYPEID_PLAYER ? 1 : 0); // boolean
- data << GetPositionX() - vehicleOwner->GetPositionX();
- data << GetPositionY() - vehicleOwner->GetPositionY();
- data << GetPositionZ() - vehicleOwner->GetPositionZ();
- data << uint32(getMSTime()); // should be an increasing constant that indicates movement packet count
- data << uint8(SPLINETYPE_FACING_ANGLE);
- data << GetTransOffsetO(); // facing angle?
- data << uint32(SPLINEFLAG_TRANSPORT);
- data << uint32(GetTransTime()); // move time
- data << uint32(1); // amount of waypoints
- data << uint32(0); // waypoint X
- data << uint32(0); // waypoint Y
- data << uint32(0); // waypoint Z
- SendMessageToSet(&data, true);
- }
- void Unit::resetAttackTimer(WeaponAttackType type)
- {
- m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
- }
- bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const
- {
- if(!obj || !IsInMap(obj)) return false;
- float dx = GetPositionX() - obj->GetPositionX();
- float dy = GetPositionY() - obj->GetPositionY();
- float dz = GetPositionZ() - obj->GetPositionZ();
- float distsq = dx*dx + dy*dy + dz*dz;
- float sizefactor = GetCombatReach() + obj->GetCombatReach();
- float maxdist = dist2compare + sizefactor;
- return distsq < maxdist * maxdist;
- }
- bool Unit::IsWithinMeleeRange(const Unit* obj, float dist) const
- {
- if(!obj || !IsInMap(obj)) return false;
- float dx = GetPositionX() - obj->GetPositionX();
- float dy = GetPositionY() - obj->GetPositionY();
- float dz = GetPositionZ() - obj->GetPositionZ();
- float distsq = dx*dx + dy*dy + dz*dz;
- float sizefactor = GetMeleeReach() + obj->GetMeleeReach();
- float maxdist = dist + sizefactor;
- return distsq < maxdist * maxdist;
- }
- void Unit::GetRandomContactPoint(const Unit* obj, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const
- {
- float combat_reach = GetCombatReach();
- if(combat_reach < 0.1f) // sometimes bugged for players
- combat_reach = DEFAULT_COMBAT_REACH;
- uint32 attacker_number = getAttackers().size();
- if(attacker_number > 0)
- --attacker_number;
- GetNearPoint(obj, x, y, z, obj->GetCombatReach(), distance2dMin+(distance2dMax-distance2dMin) * (float)rand_norm()
- , GetAngle(obj) + (attacker_number ? (static_cast<float>(M_PI/2) - static_cast<float>(M_PI) * (float)rand_norm()) * float(attacker_number) / combat_reach * 0.3f : 0));
- }
- void Unit::SetVisibleAura(uint8 slot, AuraApplication * aur)
- {
- if (Aura* aura = aur->GetBase())
- if (Player *player = ToPlayer())
- if (player->HaveSpectators() && slot < MAX_AURAS)
- {
- SpectatorAddonMsg msg;
- uint64 casterID = 0;
- if (aura->GetCaster())
- casterID = (aura->GetCaster()->ToPlayer()) ? aura->GetCaster()->GetGUID() : 0;
- msg.SetPlayer(player->GetName());
- msg.CreateAura(casterID, aura->GetSpellProto()->Id,
- aur->IsPositive(), aura->GetSpellProto()->Dispel,
- aura->GetDuration(), aura->GetMaxDuration(),
- aura->GetStackAmount(), false);
- player->SendSpectatorAddonMsgToBG(msg);
- }
- m_visibleAuras[slot] = aur;
- UpdateAuraForGroup(slot);
- }
- void Unit::RemoveVisibleAura(uint8 slot)
- {
- AuraApplication *aurApp = GetVisibleAura(slot);
- if (aurApp && slot < MAX_AURAS)
- {
- if (Aura* aura = aurApp->GetBase())
- if (Player *player = ToPlayer())
- if (player->HaveSpectators())
- {
- SpectatorAddonMsg msg;
- uint64 casterID = 0;
- if (aura->GetCaster())
- casterID = (aura->GetCaster()->ToPlayer()) ? aura->GetCaster()->GetGUID() : 0;
- msg.SetPlayer(player->GetName());
- msg.CreateAura(casterID, aura->GetSpellProto()->Id,
- aurApp->IsPositive(), aura->GetSpellProto()->Dispel,
- aura->GetDuration(), aura->GetMaxDuration(),
- aura->GetStackAmount(), true);
- player->SendSpectatorAddonMsgToBG(msg);
- }
- }
- m_visibleAuras.erase(slot);
- UpdateAuraForGroup(slot);
- }
- void Unit::UpdateInterruptMask()
- {
- m_interruptMask = 0;
- for(AuraApplicationList::const_iterator i = m_interruptableAuras.begin(); i != m_interruptableAuras.end(); ++i)
- m_interruptMask |= (*i)->GetBase()->GetSpellProto()->AuraInterruptFlags;
- if(Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
- if(spell->getState() == SPELL_STATE_CASTING)
- m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
- }
- bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint32 familyFlags) const
- {
- if(!HasAuraType(auraType))
- return false;
- AuraEffectList const& auras = GetAuraEffectsByType(auraType);
- for(AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- if(SpellEntry const* iterSpellProto = (*itr)->GetSpellProto())
- if(iterSpellProto->SpellFamilyName == familyName && iterSpellProto->SpellFamilyFlags[0] & familyFlags)
- return true;
- return false;
- }
- void Unit::DealDamageMods(Unit* victim, uint32 &damage, uint32* absorb)
- {
- if(!victim || !victim->isAlive() || victim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
- {
- if(absorb)
- *absorb += damage;
- damage = 0;
- return;
- }
- uint32 originalDamage = damage;
- if(absorb && originalDamage > damage)
- *absorb += (originalDamage - damage);
- }
- uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* pCleanDMG, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const* pSpell, bool durabilityLoss)
- {
- if(!pVictim)
- return 0;
- if(pVictim->IsAIEnabled)
- pVictim->GetAI()->DamageTaken(this, damage);
- if(IsAIEnabled)
- GetAI()->DamageDealt(pVictim, damage, damagetype);
- if(damage >= pVictim->GetHealth() && this->GetTypeId() == TYPEID_PLAYER)
- ((Player*)this)->UpdateKillingTimedAchievementProgress(pVictim->GetEntry(),pVictim->GetTypeId());
- if(damagetype != NODAMAGE)
- {
- // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
- if(pSpell)
- {
- if(!(pSpell->AttributesEx4 & SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
- pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, pSpell->Id);
- } else pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, 0);
- // We're going to call functions which can modify content of the list during iteration over it's elements
- // Let's copy the list so we can prevent iterator invalidation
- AuraEffectList vCopyDamageCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_SHARE_DAMAGE_PCT));
- // copy damage to casters of this aura
- for(AuraEffectList::iterator i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
- {
- // Check if aura was removed during iteration - we don't need to work on such auras
- if(!((*i)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
- continue;
- // check damage school mask
- if(((*i)->GetMiscValue() & damageSchoolMask) == 0)
- continue;
- Unit* shareDamageTarget = (*i)->GetCaster();
- if(!shareDamageTarget)
- continue;
- SpellEntry const* spell = (*i)->GetSpellProto();
- uint32 share = CalculatePctN(damage, (*i)->GetAmount());
- // TODO: check packets if damage is done by pVictim, or by attacker of pVictim
- DealDamageMods(shareDamageTarget, share, NULL);
- DealDamage(shareDamageTarget, share, NULL, NODAMAGE, GetSpellSchoolMask(spell), spell, false);
- }
- }
- // Rage from Damage made (only from direct weapon damage)
- if(pCleanDMG && damagetype == DIRECT_DAMAGE && this != pVictim && getPowerType() == POWER_RAGE)
- {
- uint32 weaponSpeedHitFactor;
- uint32 rage_damage = damage + pCleanDMG->absorbed_damage;
- switch(pCleanDMG->attackType)
- {
- case BASE_ATTACK:
- {
- weaponSpeedHitFactor = uint32(GetAttackTime(pCleanDMG->attackType) / 1000.0f * 3.5f);
- if(pCleanDMG->hitOutCome == MELEE_HIT_CRIT)
- weaponSpeedHitFactor *= 2;
- RewardRage(rage_damage, weaponSpeedHitFactor, true);
- break;
- }
- case OFF_ATTACK:
- {
- weaponSpeedHitFactor = uint32(GetAttackTime(pCleanDMG->attackType) / 1000.0f * 1.75f);
- if(pCleanDMG->hitOutCome == MELEE_HIT_CRIT)
- weaponSpeedHitFactor *= 2;
- RewardRage(rage_damage, weaponSpeedHitFactor, true);
- break;
- }
- default:
- break;
- }
- }
- if(!damage)
- {
- // Rage from absorbed damage
- if(pCleanDMG && pCleanDMG->absorbed_damage && pVictim->getPowerType() == POWER_RAGE)
- pVictim->RewardRage(pCleanDMG->absorbed_damage, 0, false);
- return 0;
- }
- uint32 health = pVictim->GetHealth();
- // duel ends when player has 1 or less hp
- bool duel_hasEnded = false;
- bool duel_wasMounted = false;
- if(pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->ToPlayer()->duel && damage >= (health-1))
- {
- // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
- if(pVictim->ToPlayer()->duel->opponent == this || pVictim->ToPlayer()->duel->opponent->GetGUID() == GetOwnerGUID())
- damage = health - 1;
- duel_hasEnded = true;
- } else if(pVictim->IsVehicle() && damage >= (health-1) && pVictim->GetCharmer() && pVictim->GetCharmer()->GetTypeId() == TYPEID_PLAYER) {
- Player* pPlayer = pVictim->GetCharmer()->ToPlayer();
- if(pPlayer && pPlayer->duel && pPlayer->duel->isMounted)
- {
- // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
- if(pPlayer->duel->opponent == this || pPlayer->duel->opponent->GetGUID() == GetCharmerGUID())
- damage = health - 1;
- duel_wasMounted = true;
- duel_hasEnded = true;
- }
- }
- if(GetTypeId() == TYPEID_PLAYER && this != pVictim)
- {
- Player* pKiller = ToPlayer();
- // in bg, count dmg if pVictim is also a player
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- if(Battleground* pBG = pKiller->GetBattleground())
- pBG->UpdatePlayerScore(pKiller, SCORE_DAMAGE_DONE, damage);
- pKiller->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, pVictim);
- pKiller->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage);
- }
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- pVictim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED, damage);
- else if(!pVictim->IsControlledByPlayer() || pVictim->IsVehicle()) {
- if(!pVictim->ToCreature()->hasLootRecipient())
- pVictim->ToCreature()->SetLootRecipient(this);
- if(IsControlledByPlayer())
- pVictim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage);
- }
- if(health <= damage)
- {
- if(pVictim->GetTypeId() == TYPEID_PLAYER && pVictim != this)
- {
- pVictim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health);
- // call before auras are removed
- if(Player* pPlayer = GetCharmerOrOwnerPlayerOrPlayerItself())
- pPlayer->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, pVictim);
- }
- // Heirloom trinkets on "kill a target that yields experience or honor" effect
- if(this->ToPlayer() && this->isAlive()) {
- if(this->ToPlayer()->isHonorOrXPTarget(pVictim)) {
- AuraEffectList const& heirloom = GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for(AuraEffectList::const_iterator j = heirloom.begin(); j != heirloom.end(); ++j)
- {
- if((*j)->GetId() == 59915 && this->getPowerType() == POWER_MANA)
- this->CastSpell(this, 59914, true);
- if((*j)->GetId() == 59906)
- {
- int32 bonushealth = this->GetMaxHealth() * this->GetAura(59906)->GetEffect(0)->GetAmount() / 100;
- this->CastCustomSpell(this, 59913, &bonushealth, 0, 0, true);
- }
- }
- }
- }
- Kill(pVictim, durabilityLoss);
- } else {
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- pVictim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage);
- pVictim->ModifyHealth(- (int32)damage);
- if(damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
- pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, pSpell ? pSpell->Id : 0);
- if(pVictim->GetTypeId() != TYPEID_PLAYER)
- pVictim->AddThreat(this, (float)damage, damageSchoolMask, pSpell);
- else { // pVictim is a player
- // random durability for items (HIT TAKEN)
- if(roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE))) {
- EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1));
- pVictim->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
- }
- }
- // Rage from damage received
- if(this != pVictim && pVictim->getPowerType() == POWER_RAGE)
- {
- uint32 rage_damage = damage + (pCleanDMG ? pCleanDMG->absorbed_damage : 0);
- pVictim->RewardRage(rage_damage, 0, false);
- }
- if(GetTypeId() == TYPEID_PLAYER)
- {
- // random durability for items (HIT DONE)
- if(roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
- {
- EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1));
- ToPlayer()->DurabilityPointLossForEquipSlot(slot);
- }
- }
- if(damagetype != NODAMAGE && damage)
- {
- if(pVictim != this && pVictim->GetTypeId() == TYPEID_PLAYER) // does not support creature push_back
- {
- if(damagetype != DOT)
- {
- if(Spell* pSpell = pVictim->m_currentSpells[CURRENT_GENERIC_SPELL])
- {
- if(pSpell->getState() == SPELL_STATE_PREPARING)
- {
- uint32 interruptFlags = pSpell->m_spellInfo->InterruptFlags;
- if(interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG)
- pVictim->InterruptNonMeleeSpells(false);
- else if(interruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK)
- pSpell->Delayed();
- }
- }
- }
- if(Spell* pSpell = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL])
- {
- if(pSpell->getState() == SPELL_STATE_CASTING)
- {
- uint32 channelInterruptFlags = pSpell->m_spellInfo->ChannelInterruptFlags;
- if(((channelInterruptFlags & CHANNEL_FLAG_DELAY) != 0) && (damagetype != DOT))
- pSpell->DelayedChannel();
- }
- }
- }
- }
- // last damage from duel opponent
- if(duel_hasEnded)
- {
- Player* pPlayer;
- duel_wasMounted ? pPlayer = pVictim->GetCharmer()->ToPlayer() : pPlayer = pVictim->ToPlayer();
- if(!pPlayer->isAlive())
- pPlayer->ResurrectPlayer(1.0f);
- pPlayer->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
- pPlayer->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
- pPlayer->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
- pPlayer->SetHealth(1);
- pPlayer->duel->opponent->CombatStopWithPets(true);
- pPlayer->CombatStopWithPets(true);
- pPlayer->CastSpell(pPlayer, 7267, true);
- pPlayer->DuelComplete(DUEL_WON);
- }
- }
- return damage;
- }
- void Unit::CastStop(uint32 except_spellid)
- {
- for(uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
- if(m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
- InterruptSpell(CurrentSpellTypes(i), false);
- }
- void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
- if(!spellInfo)
- {
- sLog->outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- CastSpell(Victim, spellInfo, triggered, castItem, triggeredByAura, originalCaster);
- }
- void Unit::CastSpell(Unit* Victim, SpellEntry const* spellInfo, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- if(!spellInfo)
- {
- sLog->outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- if(!originalCaster && GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem() && IsControlledByPlayer())
- if(Unit* owner = GetOwner())
- originalCaster=owner->GetGUID();
- SpellCastTargets targets;
- targets.SetUnitTarget(Victim);
- if(castItem)
- sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", spellInfo->Id);
- if(!originalCaster && triggeredByAura)
- originalCaster = triggeredByAura->GetCasterGUID();
- Spell* pSpell = new Spell(this, spellInfo, triggered, originalCaster);
- pSpell->m_CastItem = castItem;
- pSpell->prepare(&targets, triggeredByAura);
- }
- void Unit::CastCustomSpell(Unit* target, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- CustomSpellValues values;
- if(bp0)
- values.AddSpellMod(SPELLVALUE_BASE_POINT0, *bp0);
- if(bp1)
- values.AddSpellMod(SPELLVALUE_BASE_POINT1, *bp1);
- if(bp2)
- values.AddSpellMod(SPELLVALUE_BASE_POINT2, *bp2);
- CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
- }
- void Unit::CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* target, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- CustomSpellValues values;
- values.AddSpellMod(mod, value);
- CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
- }
- void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const& value, Unit* Victim, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellId);
- if(!pSpellInfo)
- {
- sLog->outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- SpellCastTargets targets;
- targets.SetUnitTarget(Victim);
- if(!originalCaster && triggeredByAura)
- originalCaster = triggeredByAura->GetCasterGUID();
- Spell* pSpell = new Spell(this, pSpellInfo, triggered, originalCaster);
- if(castItem)
- {
- sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", pSpellInfo->Id);
- pSpell->m_CastItem = castItem;
- }
- for(CustomSpellValues::const_iterator itr = value.begin(); itr != value.end(); ++itr)
- pSpell->SetSpellValue(itr->first, itr->second);
- pSpell->prepare(&targets, triggeredByAura);
- }
- // used for scripting
- void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster, Unit* OriginalVictim)
- {
- SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellId);
- if(!pSpellInfo)
- {
- sLog->outError("CastSpell(x, y, z): unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- if(castItem)
- sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", pSpellInfo->Id);
- if(!originalCaster && triggeredByAura)
- originalCaster = triggeredByAura->GetCasterGUID();
- Spell* pSpell = new Spell(this, pSpellInfo, triggered, originalCaster);
- SpellCastTargets targets;
- targets.SetDst(x, y, z, GetOrientation());
- if(OriginalVictim)
- targets.SetUnitTarget(OriginalVictim);
- pSpell->m_CastItem = castItem;
- pSpell->prepare(&targets, triggeredByAura);
- }
- void Unit::CastSpell(GameObject* pGO, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
- {
- if(!pGO)
- return;
- SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellId);
- if(!pSpellInfo)
- {
- sLog->outError("CastSpell(x, y, z): unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- if(castItem)
- sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", pSpellInfo->Id);
- if(!originalCaster && triggeredByAura)
- originalCaster = triggeredByAura->GetCasterGUID();
- Spell* pSpell = new Spell(this, pSpellInfo, triggered, originalCaster);
- SpellCastTargets targets;
- targets.SetGOTarget(pGO);
- pSpell->m_CastItem = castItem;
- pSpell->prepare(&targets, triggeredByAura);
- }
- // Obsolete func need remove, here only for comotability vs another patches
- uint32 Unit::SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage)
- {
- SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellID);
- SpellNonMeleeDamage damageInfo(this, victim, pSpellInfo->Id, pSpellInfo->SchoolMask);
- damage = SpellDamageBonus(victim, pSpellInfo, damage, SPELL_DIRECT_DAMAGE);
- CalculateSpellDamageTaken(&damageInfo, damage, pSpellInfo);
- DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
- SendSpellNonMeleeDamageLog(&damageInfo);
- DealSpellDamage(&damageInfo, true);
- return damageInfo.damage;
- }
- void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const* spellInfo, WeaponAttackType attackType, bool crit)
- {
- if(damage < 0)
- return;
- Unit* victim = damageInfo->target;
- if(!victim || !victim->isAlive())
- return;
- SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
- uint32 crTypeMask = victim->GetCreatureTypeMask();
- if(IsDamageReducedByArmor(damageSchoolMask, spellInfo))
- damage = CalcArmorReducedDamage(victim, damage, spellInfo, attackType);
- bool blocked = false;
- // Per-school calc
- switch(spellInfo->DmgClass)
- {
- // Melee and Ranged Spells
- case SPELL_DAMAGE_CLASS_RANGED:
- case SPELL_DAMAGE_CLASS_MELEE:
- {
- // Physical Damage
- if(damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)
- {
- // Get blocked status
- blocked = isSpellBlocked(victim, spellInfo, attackType);
- }
- if(crit)
- {
- damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
- // Calculate crit bonus
- uint32 crit_bonus = damage;
- // Apply crit_damage bonus for melee spells
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
- damage += crit_bonus;
- // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
- float critPctDamageMod = 0.0f;
- if(attackType == RANGED_ATTACK)
- critPctDamageMod += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
- else
- critPctDamageMod += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
- // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
- critPctDamageMod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellInfo)) - 1.0f) * 100;
- // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
- critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
- if(critPctDamageMod != 0)
- AddPctF(damage, critPctDamageMod);
- }
- // Spell weapon based damage CAN BE crit & blocked at same time
- if(blocked)
- {
- damageInfo->blocked = victim->GetShieldBlockValue();
- // double blocked amount if block is critical
- if(victim->isBlockCritical())
- damageInfo->blocked += damageInfo->blocked;
- if(damage < int32(damageInfo->blocked))
- damageInfo->blocked = uint32(damage);
- damage -= damageInfo->blocked;
- }
- if(attackType != RANGED_ATTACK)
- ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_MELEE);
- else
- ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_RANGED);
- break;
- }
- // Magical Attacks
- case SPELL_DAMAGE_CLASS_NONE:
- case SPELL_DAMAGE_CLASS_MAGIC:
- {
- // If crit add critical bonus
- if(crit)
- {
- damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
- damage = SpellCriticalDamageBonus(spellInfo, damage, victim);
- }
- ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_SPELL);
- break;
- }
- default:
- break;
- }
- // Calculate absorb resist
- if(damage > 0)
- {
- CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo);
- damage -= damageInfo->absorb + damageInfo->resist;
- }
- else
- damage = 0;
- damageInfo->damage = damage;
- }
- void Unit::DealSpellDamage(SpellNonMeleeDamage* pDamageInfo, bool durabilityLoss)
- {
- if(pDamageInfo == 0)
- return;
- Unit* victim = pDamageInfo->target;
- if(!victim)
- return;
- if(!victim->isAlive() || victim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (victim->HasUnitState(UNIT_STAT_ONVEHICLE) && victim->GetVehicleBase() != this) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
- return;
- SpellEntry const* pSpellEntry = sSpellStore.LookupEntry(pDamageInfo->SpellID);
- if(pSpellEntry == NULL)
- {
- sLog->outDebug(LOG_FILTER_UNITS, "Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", pDamageInfo->SpellID);
- return;
- }
- // Call default DealDamage
- CleanDamage cleanDamage(pDamageInfo->cleanDamage, pDamageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(victim, pDamageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(pDamageInfo->schoolMask), pSpellEntry, durabilityLoss);
- }
- // TODO for melee need create structure as in
- void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* pDamageInfo, WeaponAttackType attackType)
- {
- pDamageInfo->attacker = this;
- pDamageInfo->target = pVictim;
- pDamageInfo->damageSchoolMask = GetMeleeDamageSchoolMask();
- pDamageInfo->attackType = attackType;
- pDamageInfo->damage = 0;
- pDamageInfo->cleanDamage = 0;
- pDamageInfo->absorb = 0;
- pDamageInfo->resist = 0;
- pDamageInfo->blocked_amount = 0;
- pDamageInfo->TargetState = 0;
- pDamageInfo->HitInfo = 0;
- pDamageInfo->procAttacker = PROC_FLAG_NONE;
- pDamageInfo->procVictim = PROC_FLAG_NONE;
- pDamageInfo->procEx = PROC_EX_NONE;
- pDamageInfo->hitOutCome = MELEE_HIT_EVADE;
- if(!pVictim)
- return;
- if(!isAlive() || !pVictim->isAlive())
- return;
- // Select HitInfo/procAttacker/procVictim flag based on attack type
- switch(attackType)
- {
- case BASE_ATTACK:
- {
- pDamageInfo->procAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_MAINHAND_ATTACK;
- pDamageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK;
- pDamageInfo->HitInfo = HITINFO_NORMALSWING2;
- break;
- }
- case OFF_ATTACK:
- {
- pDamageInfo->procAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK;
- pDamageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK;
- pDamageInfo->HitInfo = HITINFO_LEFTSWING;
- break;
- }
- default:
- return;
- }
- // Physical Immune check
- if(pDamageInfo->target->IsImmunedToDamage(SpellSchoolMask(pDamageInfo->damageSchoolMask)))
- {
- pDamageInfo->HitInfo |= HITINFO_NORMALSWING;
- pDamageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
- pDamageInfo->procEx |= PROC_EX_IMMUNE;
- pDamageInfo->damage = 0;
- pDamageInfo->cleanDamage = 0;
- return;
- }
- damage += CalculateDamage(pDamageInfo->attackType, false, true);
- // Add melee damage bonus
- MeleeDamageBonus(pDamageInfo->target, &damage, pDamageInfo->attackType);
- // Calculate armor reduction
- if(IsDamageReducedByArmor((SpellSchoolMask)(pDamageInfo->damageSchoolMask)))
- {
- pDamageInfo->damage = CalcArmorReducedDamage(pDamageInfo->target, damage, NULL, pDamageInfo->attackType);
- pDamageInfo->cleanDamage += damage - pDamageInfo->damage;
- } else pDamageInfo->damage = damage;
- pDamageInfo->hitOutCome = RollMeleeOutcomeAgainst(pDamageInfo->target, pDamageInfo->attackType);
- switch(pDamageInfo->hitOutCome)
- {
- case MELEE_HIT_EVADE:
- {
- pDamageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND;
- pDamageInfo->TargetState = VICTIMSTATE_EVADES;
- pDamageInfo->procEx|=PROC_EX_EVADE;
- pDamageInfo->damage = 0;
- pDamageInfo->cleanDamage = 0;
- return;
- }
- case MELEE_HIT_MISS:
- {
- pDamageInfo->HitInfo |= HITINFO_MISS;
- pDamageInfo->TargetState = VICTIMSTATE_INTACT;
- pDamageInfo->procEx |= PROC_EX_MISS;
- pDamageInfo->damage = 0;
- pDamageInfo->cleanDamage = 0;
- break;
- }
- case MELEE_HIT_NORMAL:
- {
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->procEx|=PROC_EX_NORMAL_HIT;
- break;
- }
- case MELEE_HIT_CRIT:
- {
- pDamageInfo->HitInfo |= HITINFO_CRITICALHIT;
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->procEx |= PROC_EX_CRITICAL_HIT;
- // Crit bonus calc
- pDamageInfo->damage += pDamageInfo->damage;
- float mod = 0.0f;
- // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
- if(pDamageInfo->attackType == RANGED_ATTACK)
- mod += pDamageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
- else
- mod += pDamageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
- // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
- mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, pDamageInfo->damageSchoolMask) - 1.0f) * 100;
- uint32 crTypeMask = pDamageInfo->target->GetCreatureTypeMask();
- // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
- mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
- if(mod != 0)
- AddPctF(pDamageInfo->damage, mod);
- break;
- }
- case MELEE_HIT_PARRY:
- {
- pDamageInfo->TargetState = VICTIMSTATE_PARRY;
- pDamageInfo->procEx |= PROC_EX_PARRY;
- pDamageInfo->cleanDamage += pDamageInfo->damage;
- pDamageInfo->damage = 0;
- break;
- }
- case MELEE_HIT_DODGE:
- {
- pDamageInfo->TargetState = VICTIMSTATE_DODGE;
- pDamageInfo->procEx |= PROC_EX_DODGE;
- pDamageInfo->cleanDamage += pDamageInfo->damage;
- pDamageInfo->damage = 0;
- break;
- }
- case MELEE_HIT_BLOCK:
- {
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->HitInfo |= HITINFO_BLOCK;
- pDamageInfo->procEx |= PROC_EX_BLOCK;
- pDamageInfo->blocked_amount = pDamageInfo->target->GetShieldBlockValue();
- if(pDamageInfo->target->isBlockCritical())
- pDamageInfo->blocked_amount+=pDamageInfo->blocked_amount;
- if(pDamageInfo->blocked_amount >= pDamageInfo->damage)
- {
- pDamageInfo->TargetState = VICTIMSTATE_BLOCKS;
- pDamageInfo->blocked_amount = pDamageInfo->damage;
- pDamageInfo->procEx |= PROC_EX_FULL_BLOCK;
- } else pDamageInfo->procEx |= PROC_EX_NORMAL_HIT;
- pDamageInfo->damage -= pDamageInfo->blocked_amount;
- pDamageInfo->cleanDamage += pDamageInfo->blocked_amount;
- break;
- }
- case MELEE_HIT_GLANCING:
- {
- pDamageInfo->HitInfo |= HITINFO_GLANCING;
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->procEx |= PROC_EX_NORMAL_HIT;
- int32 leveldif = int32(pVictim->getLevel()) - int32(getLevel());
- if(leveldif > 3)
- leveldif = 3;
- float reducePercent = 1 - leveldif * 0.1f;
- pDamageInfo->cleanDamage += pDamageInfo->damage-uint32(reducePercent * pDamageInfo->damage);
- pDamageInfo->damage = uint32(reducePercent * pDamageInfo->damage);
- break;
- }
- case MELEE_HIT_CRUSHING:
- {
- pDamageInfo->HitInfo |= HITINFO_CRUSHING;
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->procEx |= PROC_EX_NORMAL_HIT;
- // 150% normal damage
- pDamageInfo->damage += (pDamag…
Large files files are truncated, but you can click here to view the full file