Merge remote branch 'origin/master' into 330

This commit is contained in:
tomrus88 2009-12-30 01:16:15 +03:00
commit 33cd1a0aca
32 changed files with 659 additions and 293 deletions

View file

@ -18,6 +18,7 @@
#include "CreatureAI.h"
#include "Creature.h"
#include "DBCStores.h"
CreatureAI::~CreatureAI()
{
@ -28,3 +29,90 @@ void CreatureAI::AttackedBy( Unit* attacker )
if(!m_creature->getVictim())
AttackStart(attacker);
}
CanCastResult CreatureAI::CanCastSpell(Unit* pTarget, const SpellEntry *pSpell, bool isTriggered)
{
// If not triggered, we check
if (!isTriggered)
{
// State does not allow
if (m_creature->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DIED))
return CAST_FAIL_STATE;
if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
return CAST_FAIL_STATE;
if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
return CAST_FAIL_STATE;
// Check for power (also done by Spell::CheckCast())
if (m_creature->GetPower((Powers)pSpell->powerType) < pSpell->manaCost)
return CAST_FAIL_POWER;
}
if (const SpellRangeEntry *pSpellRange = sSpellRangeStore.LookupEntry(pSpell->rangeIndex))
{
if (pTarget != m_creature)
{
// pTarget is out of range of this spell (also done by Spell::CheckCast())
float fDistance = m_creature->GetCombatDistance(pTarget);
if (fDistance > (m_creature->IsHostileTo(pTarget) ? pSpellRange->maxRange : pSpellRange->maxRangeFriendly))
return CAST_FAIL_TOO_FAR;
float fMinRange = m_creature->IsHostileTo(pTarget) ? pSpellRange->minRange : pSpellRange->minRangeFriendly;
if (fMinRange && fDistance < fMinRange)
return CAST_FAIL_TOO_CLOSE;
}
return CAST_OK;
}
else
return CAST_FAIL_OTHER;
}
CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags, uint64 uiOriginalCasterGUID)
{
Unit* pCaster = m_creature;
if (uiCastFlags & CAST_FORCE_TARGET_SELF)
pCaster = pTarget;
// Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered
if (!pCaster->IsNonMeleeSpellCasted(false) || (uiCastFlags & (CAST_TRIGGERED | CAST_INTURRUPT_PREVIOUS)))
{
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(uiSpell))
{
// If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them
if (uiCastFlags & CAST_AURA_NOT_PRESENT)
{
if (pTarget->HasAura(uiSpell))
return CAST_FAIL_TARGET_AURA;
}
// Check if cannot cast spell
if (!(uiCastFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST)))
{
CanCastResult castResult = CanCastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED);
if (castResult != CAST_OK)
return castResult;
}
// Interrupt any previous spell
if (uiCastFlags & CAST_INTURRUPT_PREVIOUS && pCaster->IsNonMeleeSpellCasted(false))
pCaster->InterruptNonMeleeSpells(false);
pCaster->CastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED, NULL, NULL, uiOriginalCasterGUID);
return CAST_OK;
}
else
{
sLog.outErrorDb("DoCastSpellIfCan by creature entry %u attempt to cast spell %u but spell does not exist.", m_creature->GetEntry(), uiSpell);
return CAST_FAIL_OTHER;
}
}
else
return CAST_FAIL_IS_CASTING;
}

View file

@ -34,6 +34,18 @@ struct SpellEntry;
#define TIME_INTERVAL_LOOK 5000
#define VISIBILITY_RANGE 10000
enum CanCastResult
{
CAST_OK = 0,
CAST_FAIL_IS_CASTING = 1,
CAST_FAIL_OTHER = 2,
CAST_FAIL_TOO_FAR = 3,
CAST_FAIL_TOO_CLOSE = 4,
CAST_FAIL_POWER = 5,
CAST_FAIL_STATE = 6,
CAST_FAIL_TARGET_AURA = 7
};
enum CastFlags
{
CAST_INTURRUPT_PREVIOUS = 0x01, //Interrupt any spell casting
@ -68,6 +80,10 @@ class MANGOS_DLL_SPEC CreatureAI
// Called at any heal cast/item used (call non implemented)
virtual void HealBy(Unit * /*healer*/, uint32 /*amount_healed*/) {}
// Helper functions for cast spell
CanCastResult DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags = 0, uint64 uiOriginalCasterGUID = 0);
virtual CanCastResult CanCastSpell(Unit* pTarget, const SpellEntry *pSpell, bool isTriggered);
// Called at any Damage to any victim (before damage apply)
virtual void DamageDeal(Unit * /*done_to*/, uint32 & /*damage*/) {}

View file

@ -1752,6 +1752,13 @@ uint16 Map::GetAreaFlag(float x, float y, float z) const
case 856: // The Noxious Glade (Eastern Plaguelands)
case 2456: // Death's Breach (Eastern Plaguelands)
if(z > 350.0f) areaflag = 1950; break;
// Winterfin Caverns
case 1652: // Coldarra
case 1653: // The Westrift
case 1661: // Winterfin Village
if (x > 3823.0f && x < 4141.5f && y > 6247.0f && y < 64890.0f && z < 42.5f)
areaflag = 1723;
break;
// Dalaran
case 2492: // Forlorn Woods (Crystalsong Forest)
case 2371: // Valley of Echoes (Icecrown Glacier)

View file

@ -463,3 +463,12 @@ bool MotionMaster::GetDestination(float &x, float &y, float &z)
return top()->GetDestination(x,y,z);
}
void MotionMaster::UpdateFinalDistanceToTarget(float fDistance)
{
if (!empty())
{
if (top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE)
top()->UpdateFinalDistance(fDistance);
}
}

View file

@ -121,6 +121,9 @@ class MANGOS_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *>
void propagateSpeedChange();
// will only work in MMgens where we have a target (TARGETED_MOTION_TYPE)
void UpdateFinalDistanceToTarget(float fDistance);
bool GetDestination(float &x, float &y, float &z);
private:
void Mutate(MovementGenerator *m); // use Move* functions instead

View file

@ -44,6 +44,8 @@ class MANGOS_DLL_SPEC MovementGenerator
virtual void unitSpeedChanged() { }
virtual void UpdateFinalDistance(float fDistance) { }
virtual bool GetDestination(float& /*x*/, float& /*y*/, float& /*z*/) const { return false; }
};

View file

@ -40,7 +40,7 @@ char const* petTypeSuffix[MAX_PET_TYPE] =
Pet::Pet(PetType type) :
Creature(), m_removed(false), m_petType(type), m_happinessTimer(7500), m_duration(0), m_resetTalentsCost(0),
m_bonusdamage(0), m_resetTalentsTime(0), m_usedTalentCount(0), m_auraUpdateMask(0), m_loading(false),
m_declinedname(NULL)
m_declinedname(NULL), m_petModeFlags(PET_MODE_DEFAULT)
{
m_isPet = true;
m_name = "Pet";
@ -1948,3 +1948,20 @@ void Pet::SynchronizeLevelWithOwner()
break;
}
}
void Pet::ApplyModeFlags(PetModeFlags mode, bool apply)
{
if (apply)
m_petModeFlags = PetModeFlags(m_petModeFlags | mode);
else
m_petModeFlags = PetModeFlags(m_petModeFlags & ~mode);
Unit* owner = GetOwner();
if(!owner || owner->GetTypeId()!=TYPEID_PLAYER)
return;
WorldPacket data(SMSG_PET_MODE, 12);
data << uint64(GetGUID());
data << uint32(m_petModeFlags);
((Player*)owner)->GetSession()->SendPacket(&data);
}

View file

@ -46,6 +46,17 @@ enum PetSaveMode
PET_SAVE_NOT_IN_SLOT = 100 // for avoid conflict with stable size grow will use 100
};
// There might be a lot more
enum PetModeFlags
{
PET_MODE_UNKNOWN_0 = 0x0000001,
PET_MODE_UNKNOWN_2 = 0x0000100,
PET_MODE_DISABLE_ACTIONS = 0x8000000,
// autoset in client at summon
PET_MODE_DEFAULT = PET_MODE_UNKNOWN_0 | PET_MODE_UNKNOWN_2,
};
enum HappinessState
{
UNHAPPY = 1,
@ -182,6 +193,9 @@ class Pet : public Creature
bool CanTakeMoreActiveSpells(uint32 SpellIconID);
void ToggleAutocast(uint32 spellid, bool apply);
void ApplyModeFlags(PetModeFlags mode, bool apply);
PetModeFlags GetModeFlags() const { return m_petModeFlags; }
bool HasSpell(uint32 spell) const;
void LearnPetPassives();
@ -242,6 +256,8 @@ class Pet : public Creature
DeclinedName *m_declinedname;
private:
PetModeFlags m_petModeFlags;
void SaveToDB(uint32, uint8) // overwrited of Creature::SaveToDB - don't must be called
{
assert(false);

View file

@ -44,9 +44,16 @@ PetAI::PetAI(Creature *c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK), inComb
void PetAI::MoveInLineOfSight(Unit *u)
{
if( !m_creature->getVictim() && m_creature->GetCharmInfo() &&
m_creature->GetCharmInfo()->HasReactState(REACT_AGGRESSIVE) &&
u->isTargetableForAttack() && m_creature->IsHostileTo( u ) &&
if (m_creature->getVictim())
return;
if (m_creature->isPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)
return;
if (!m_creature->GetCharmInfo() || !m_creature->GetCharmInfo()->HasReactState(REACT_AGGRESSIVE))
return;
if (u->isTargetableForAttack() && m_creature->IsHostileTo( u ) &&
u->isInAccessablePlaceFor(m_creature))
{
float attackRadius = m_creature->GetAttackDistance(u);
@ -139,7 +146,7 @@ void PetAI::UpdateAI(const uint32 diff)
else
m_updateAlliesTimer -= diff;
if (inCombat && !m_creature->getVictim())
if (inCombat && (!m_creature->getVictim() || m_creature->isPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS))
_stopAttack();
// i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc.

View file

@ -44,23 +44,33 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
// used also for charmed creature
Unit* pet= ObjectAccessor::GetUnit(*_player, guid1);
sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2)) );
if(!pet)
if (!pet)
{
sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid1)) );
return;
}
if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
if (pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
{
sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName() );
return;
}
if(!pet->isAlive())
if (!pet->isAlive())
return;
if(pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK))
return;
if (pet->GetTypeId() == TYPEID_PLAYER)
{
// controller player can only do melee attack
if (!(flag == ACT_COMMAND && spellid == COMMAND_ATTACK))
return;
}
else if (((Creature*)pet)->isPet())
{
// pet can have action bar disabled
if(((Pet*)pet)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)
return;
}
CharmInfo *charmInfo = pet->GetCharmInfo();
if(!charmInfo)
@ -316,6 +326,10 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
return;
}
// pet can have action bar disabled
if(pet->isPet() && ((Pet*)pet)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)
return;
CharmInfo *charmInfo = pet->GetCharmInfo();
if(!charmInfo)
{

View file

@ -17095,6 +17095,18 @@ void Player::PetSpellInitialize()
GetSession()->SendPacket(&data);
}
void Player::SendPetGUIDs()
{
if(!GetPetGUID())
return;
// Later this function might get modified for multiple guids
WorldPacket data(SMSG_PET_GUIDS, 12);
data << uint32(1); // count
data << uint64(GetPetGUID());
GetSession()->SendPacket(&data);
}
void Player::PossessSpellInitialize()
{
Unit* charm = GetCharm();

View file

@ -1565,6 +1565,7 @@ class MANGOS_DLL_SPEC Player : public Unit
}
void PetSpellInitialize();
void SendPetGUIDs();
void CharmSpellInitialize();
void PossessSpellInitialize();
void RemovePetActionBar();

View file

@ -358,7 +358,7 @@ const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = {
#define SPELL_ATTR_EX4_UNK5 0x00000020 // 5
#define SPELL_ATTR_EX4_NOT_STEALABLE 0x00000040 // 6 although such auras might be dispellable, they cannot be stolen
#define SPELL_ATTR_EX4_UNK7 0x00000080 // 7
#define SPELL_ATTR_EX4_UNK8 0x00000100 // 8
#define SPELL_ATTR_EX4_STACK_DOT_MODIFIER 0x00000100 // 8 no effect on non DoTs?
#define SPELL_ATTR_EX4_UNK9 0x00000200 // 9
#define SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST 0x00000400 // 10 Rogue Shiv have this flag
#define SPELL_ATTR_EX4_UNK11 0x00000800 // 11
@ -445,7 +445,7 @@ const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = {
#define SPELL_ATTR_EX6_UNK26 0x04000000 // 26 not set in 3.0.3
#define SPELL_ATTR_EX6_UNK27 0x08000000 // 27 not set in 3.0.3
#define SPELL_ATTR_EX6_UNK28 0x10000000 // 28 not set in 3.0.3
#define SPELL_ATTR_EX6_UNK29 0x20000000 // 29 not set in 3.0.3
#define SPELL_ATTR_EX6_NO_DMG_PERCENT_MODS 0x20000000 // 29 do not apply damage percent mods (usually in cases where it has already been applied)
#define SPELL_ATTR_EX6_UNK30 0x40000000 // 30 not set in 3.0.3
#define SPELL_ATTR_EX6_UNK31 0x80000000 // 31 not set in 3.0.3

File diff suppressed because it is too large Load diff

View file

@ -372,12 +372,12 @@ class Spell
typedef std::list<Unit*> UnitList;
void FillTargetMap();
void SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap);
void SetTargetMap(uint32 effIndex, uint32 targetMode, UnitList &targetUnitMap);
void FillAreaTargets( UnitList& TagUnitMap, float x, float y, float radius, SpellNotifyPushType pushType, SpellTargets spellTargets );
void FillRaidOrPartyTargets( UnitList &TagUnitMap, Unit* member, Unit* center, float radius, bool raid, bool withPets, bool withcaster );
void FillRaidOrPartyManaPriorityTargets( UnitList &TagUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withcaster );
void FillRaidOrPartyHealthPriorityTargets( UnitList &TagUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withcaster );
void FillAreaTargets(UnitList &targetUnitMap, float x, float y, float radius, SpellNotifyPushType pushType, SpellTargets spellTargets);
void FillRaidOrPartyTargets(UnitList &targetUnitMap, Unit* member, Unit* center, float radius, bool raid, bool withPets, bool withcaster);
void FillRaidOrPartyManaPriorityTargets(UnitList &targetUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withcaster);
void FillRaidOrPartyHealthPriorityTargets(UnitList &targetUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withcaster);
template<typename T> WorldObject* FindCorpseUsing();

View file

@ -205,7 +205,7 @@ enum AuraType
SPELL_AURA_MOD_AOE_AVOIDANCE = 160,
SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT = 161,
SPELL_AURA_POWER_BURN_MANA = 162,
SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE = 163,
SPELL_AURA_MOD_CRIT_DAMAGE_BONUS = 163,
SPELL_AURA_164 = 164,
SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS = 165,
SPELL_AURA_MOD_ATTACK_POWER_PCT = 166,

View file

@ -213,7 +213,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //160 SPELL_AURA_MOD_AOE_AVOIDANCE implemented in Unit::MagicSpellHitResult
&Aura::HandleNoImmediateEffect, //161 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT implemented in Player::RegenerateAll and Player::RegenerateHealth
&Aura::HandleAuraPowerBurn, //162 SPELL_AURA_POWER_BURN_MANA
&Aura::HandleNoImmediateEffect, //163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE implememnted in Unit::CalculateMeleeDamage and Unit::SpellCriticalDamageBonus
&Aura::HandleNoImmediateEffect, //163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS implemented in Unit::CalculateMeleeDamage and Unit::SpellCriticalDamageBonus
&Aura::HandleUnused, //164 unused (3.0.8a-3.2.2a), only one test spell 10654
&Aura::HandleNoImmediateEffect, //165 SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus
&Aura::HandleAuraModAttackPowerPercent, //166 SPELL_AURA_MOD_ATTACK_POWER_PCT
@ -2241,6 +2241,12 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
if (Unit* caster = GetCaster())
m_target->AddThreat(caster, 10.0f, false, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
return;
case 7057: // Haunting Spirits
// expected to tick with 30 sec period (tick part see in Aura::PeriodicTick)
m_isPeriodic = true;
m_modifier.periodictime = 30*IN_MILISECONDS;
m_periodicTimer = m_modifier.periodictime;
return;
case 13139: // net-o-matic
// root to self part of (root_target->charge->root_self sequence
if (Unit* caster = GetCaster())
@ -2389,6 +2395,14 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
switch(GetId())
{
case 28169: // Mutating Injection
{
// Mutagen Explosion
m_target->CastSpell(m_target, 28206, true, NULL, this);
// Poison Cloud
m_target->CastSpell(m_target, 28240, true, NULL, this);
return;
}
case 36730: // Flame Strike
{
m_target->CastSpell(m_target, 36731, true, NULL, this);
@ -2813,7 +2827,7 @@ void Aura::HandleAuraMounted(bool apply, bool Real)
if (minfo)
display_id = minfo->modelid;
m_target->Mount(display_id);
m_target->Mount(display_id, m_spellProto->Id);
}
else
{
@ -7014,6 +7028,7 @@ void Aura::PeriodicTick()
break;
}
// Here tick dummy auras
case SPELL_AURA_DUMMY: // some spells have dummy aura
case SPELL_AURA_PERIODIC_DUMMY:
{
PeriodicDummyTick();
@ -7099,6 +7114,10 @@ void Aura::PeriodicDummyTick()
// 7053 Forsaken Skill: Shadow
return;
}
case 7057: // Haunting Spirits
if (roll_chance_i(33))
m_target->CastSpell(m_target,m_modifier.m_amount,true,NULL,this);
return;
// // Panda
// case 19230: break;
// // Gossip NPC Periodic - Talk
@ -7253,6 +7272,21 @@ void Aura::PeriodicDummyTick()
// case 50493: break;
// // Love Rocket Barrage
// case 50530: break;
case 50789: // Summon iron dwarf (left or right)
case 59860:
m_target->CastSpell(m_target, roll_chance_i(50) ? 50790 : 50791, true, NULL, this);
return;
case 50792: // Summon iron trogg (left or right)
case 59859:
m_target->CastSpell(m_target, roll_chance_i(50) ? 50793 : 50794, true, NULL, this);
return;
case 50801: // Summon malformed ooze (left or right)
case 59858:
m_target->CastSpell(m_target, roll_chance_i(50) ? 50802 : 50803, true, NULL, this);
return;
case 50824: // Summon earthen dwarf
m_target->CastSpell(m_target, roll_chance_i(50) ? 50825 : 50826, true, NULL, this);
return;
// Exist more after, need add later
default:
break;

View file

@ -749,44 +749,6 @@ void Spell::EffectDummy(uint32 i)
((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
return;
}
case 12162: // Deep wounds
case 12850: // (now good common check for this spells)
case 12868:
{
if (!unitTarget)
return;
float damage;
// DW should benefit of attack power, damage percent mods etc.
// TODO: check if using offhand damage is correct and if it should be divided by 2
if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
else
damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
switch (m_spellInfo->Id)
{
case 12162: damage *= 0.16f; break; // Rank 1
case 12850: damage *= 0.32f; break; // Rank 2
case 12868: damage *= 0.48f; break; // Rank 3
default:
sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
return;
};
// get remaining damage of old Deep Wound aura
Aura* deepWound = unitTarget->GetAura(12721, 0);
if (deepWound)
{
int32 remainingTicks = deepWound->GetAuraDuration() / deepWound->GetModifier()->periodictime;
damage += remainingTicks * deepWound->GetModifier()->m_amount;
}
// 1 tick/sec * 6 sec = 6 ticks
int32 deepWoundsDotBasePoints0 = int32(damage / 6);
m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
return;
}
case 13120: // net-o-matic
{
if (!unitTarget)
@ -6477,7 +6439,11 @@ void Spell::EffectPlayerPull(uint32 i)
if(!unitTarget)
return;
unitTarget->KnockBackFrom(m_caster,float(damage ? damage : unitTarget->GetDistance2d(m_caster)),float(m_spellInfo->EffectMiscValue[i])/10);
float dist = unitTarget->GetDistance2d(m_caster);
if (damage && dist > damage)
dist = damage;
unitTarget->KnockBackFrom(m_caster,-dist,float(m_spellInfo->EffectMiscValue[i])/10);
}
void Spell::EffectDispelMechanic(uint32 i)

View file

@ -1568,6 +1568,11 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
(spellId_2 == 33891 && spellId_1 == 34123))
return false;
// Lifebloom and Wild Growth
if (spellInfo_1->SpellIconID == 2101 && spellInfo_2->SpellIconID == 2864 ||
spellInfo_2->SpellIconID == 2101 && spellInfo_1->SpellIconID == 2864 )
return false;
// Innervate and Glyph of Innervate and some other spells
if (spellInfo_1->SpellIconID == 62 && spellInfo_2->SpellIconID == 62)
return false;

View file

@ -102,6 +102,19 @@ void TargetedMovementGenerator<Creature>::Initialize(Creature &owner)
_setTargetLocation(owner);
}
template<>
void TargetedMovementGenerator<Player>::UpdateFinalDistance(float fDistance)
{
// nothing to do for Player
}
template<>
void TargetedMovementGenerator<Creature>::UpdateFinalDistance(float fDistance)
{
i_offset = fDistance;
i_recalculateTravel = true;
}
template<>
void TargetedMovementGenerator<Player>::Initialize(Player &owner)
{

View file

@ -61,6 +61,8 @@ class MANGOS_DLL_SPEC TargetedMovementGenerator
}
void unitSpeedChanged() { i_recalculateTravel=true; }
void UpdateFinalDistance(float fDistance);
private:
void _setTargetLocation(T &);

View file

@ -216,17 +216,17 @@ void Unit::Update( uint32 p_time )
// 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() )
if (m_HostileRefManager.isEmpty())
{
// m_CombatTimer set at aura start and it will be freeze until aura removing
if ( m_CombatTimer <= p_time )
ClearInCombat();
if (m_CombatTimer <= p_time)
CombatStop();
else
m_CombatTimer -= p_time;
}
}
if(uint32 base_att = getAttackTimer(BASE_ATTACK))
if (uint32 base_att = getAttackTimer(BASE_ATTACK))
{
setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) );
}
@ -1292,10 +1292,9 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da
if(damageInfo->attackType == RANGED_ATTACK)
mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
else
{
mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
}
mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, SPELL_SCHOOL_MASK_NORMAL);
uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask();
@ -3608,16 +3607,26 @@ bool Unit::AddAura(Aura *Aur)
{
for(AuraMap::iterator i2 = m_Auras.lower_bound(spair); i2 != m_Auras.upper_bound(spair); ++i2)
{
if(i2->second->GetCasterGUID()==Aur->GetCasterGUID())
Aura* aur2 = i2->second;
if(aur2->GetCasterGUID()==Aur->GetCasterGUID())
{
// Aura can stack on self -> Stack it;
if(aurSpellInfo->StackAmount)
{
// can be created with >1 stack by some spell mods
i2->second->modStackAmount(Aur->GetStackAmount());
aur2->modStackAmount(Aur->GetStackAmount());
delete Aur;
return false;
}
// Carry over removed Aura's remaining damage if Aura still has ticks remaining
else if (aur2->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_STACK_DOT_MODIFIER && aurName == SPELL_AURA_PERIODIC_DAMAGE && aur2->GetAuraDuration() > 0)
{
int32 remainingTicks = 1 + (aur2->GetAuraDuration() / aur2->GetModifier()->periodictime);
int32 remainingDamage = aur2->GetModifier()->m_amount * remainingTicks;
int32 maxTicks = Aur->GetAuraMaxDuration() / Aur->GetModifier()->periodictime;
Aur->GetModifier()->m_amount += int32(remainingDamage / maxTicks);
}
// can be only single (this check done at _each_ aura add
RemoveAura(i2,AURA_REMOVE_BY_STACK);
break;
@ -5833,6 +5842,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
// Wrath crit
if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000001))
{
if (HasAura(48517))
return false;
if (!roll_chance_i(60))
return false;
triggered_spell_id = 48518;
@ -5842,6 +5853,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
// Starfire crit
if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000004))
{
if (HasAura(48518))
return false;
triggered_spell_id = 48517;
target = this;
break;
@ -7007,6 +7020,34 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
}
break;
case SPELLFAMILY_WARRIOR:
// Deep Wounds (replace triggered spells to directly apply DoT), dot spell have finilyflags
if (auraSpellInfo->SpellFamilyFlags == UI64LIT(0x0) && auraSpellInfo->SpellIconID == 243)
{
float weaponDamage;
// DW should benefit of attack power, damage percent mods etc.
// TODO: check if using offhand damage is correct and if it should be divided by 2
if (haveOffhandWeapon() && getAttackTimer(BASE_ATTACK) > getAttackTimer(OFF_ATTACK))
weaponDamage = (GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
else
weaponDamage = (GetFloatValue(UNIT_FIELD_MINDAMAGE) + GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
switch (auraSpellInfo->Id)
{
case 12834: basepoints[0] = int32(weaponDamage * 16 / 100); break;
case 12849: basepoints[0] = int32(weaponDamage * 32 / 100); break;
case 12867: basepoints[0] = int32(weaponDamage * 48 / 100); break;
// Impossible case
default:
sLog.outError("Unit::HandleProcTriggerSpell: DW unknown spell rank %u",auraSpellInfo->Id);
return false;
}
// 1 tick/sec * 6 sec = 6 ticks
basepoints[0] /= 6;
trigger_spell_id = 12721;
break;
}
if (auraSpellInfo->Id == 50421) // Scent of Blood
trigger_spell_id = 50422;
break;
@ -8346,6 +8387,9 @@ void Unit::SetPet(Pet* pet)
{
SetPetGUID(pet ? pet->GetGUID() : 0);
if(pet && GetTypeId() == TYPEID_PLAYER)
((Player*)this)->SendPetGUIDs();
// FIXME: hack, speed must be set only at follow
if(pet && GetTypeId()==TYPEID_PLAYER)
for(int i = 0; i < MAX_MOVE_TYPE; ++i)
@ -8520,16 +8564,19 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
if( GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() )
DoneTotalMod *= ((Creature*)this)->GetSpellDamageMod(((Creature*)this)->GetCreatureInfo()->rank);
AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
if (!(spellProto->AttributesEx6 & SPELL_ATTR_EX6_NO_DMG_PERCENT_MODS))
{
if (((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) &&
(*i)->GetSpellProto()->EquippedItemClass == -1 &&
// -1 == any item class (not wand then)
(*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0)
// 0 == any inventory type (not wand then)
AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
{
DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f;
if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) &&
(*i)->GetSpellProto()->EquippedItemClass == -1 &&
// -1 == any item class (not wand then)
(*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
// 0 == any inventory type (not wand then)
{
DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
}
}
}
@ -9034,17 +9081,6 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
break;
}
case SPELL_DAMAGE_CLASS_MELEE:
{
// Judgement of Command proc always crits on stunned target
if(spellProto->SpellFamilyName == SPELLFAMILY_PALADIN)
{
if(spellProto->SpellFamilyFlags & 0x0000000000800000LL && spellProto->SpellIconID == 561)
{
if(pVictim->hasUnitState(UNIT_STAT_STUNNED))
return true;
}
}
}
case SPELL_DAMAGE_CLASS_RANGED:
{
if (pVictim)
@ -9095,14 +9131,13 @@ uint32 Unit::SpellCriticalDamageBonus(SpellEntry const *spellProto, uint32 damag
if(GetWeaponAttackType(spellProto) == RANGED_ATTACK)
critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
else
{
critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
critPctDamageMod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
}
}
else
critPctDamageMod += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_DAMAGE,GetSpellSchoolMask(spellProto));
critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellProto));
uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
critPctDamageMod += GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask);
@ -9839,9 +9874,9 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const
return WeaponSpeed * PPM / 600.0f; // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
}
void Unit::Mount(uint32 mount)
void Unit::Mount(uint32 mount, uint32 spellId)
{
if(!mount)
if (!mount)
return;
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING);
@ -9850,9 +9885,27 @@ void Unit::Mount(uint32 mount)
SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT );
// unsummon pet
if(GetTypeId() == TYPEID_PLAYER)
((Player*)this)->UnsummonPetTemporaryIfAny();
if (GetTypeId() == TYPEID_PLAYER)
{
// Called by Taxi system / GM command
if (!spellId)
((Player*)this)->UnsummonPetTemporaryIfAny();
// Called by mount aura
else if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId))
{
// Flying case (Unsummon any pet)
if (IsSpellHaveAura(spellInfo, SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED))
((Player*)this)->UnsummonPetTemporaryIfAny();
// Normal case (Unsummon only permanent pet)
else if (Pet* pet = GetPet())
{
if (pet->IsPermanentPetFor((Player*)this))
((Player*)this)->UnsummonPetTemporaryIfAny();
else
pet->ApplyModeFlags(PET_MODE_DISABLE_ACTIONS,true);
}
}
}
}
void Unit::Unmount()
@ -9869,7 +9922,12 @@ void Unit::Unmount()
// this prevents adding a pet to a not created map which would otherwise cause a crash
// (it could probably happen when logging in after a previous crash)
if(GetTypeId() == TYPEID_PLAYER)
((Player*)this)->ResummonPetTemporaryUnSummonedIfAny();
{
if(Pet* pet = GetPet())
pet->ApplyModeFlags(PET_MODE_DISABLE_ACTIONS,false);
else
((Player*)this)->ResummonPetTemporaryUnSummonedIfAny();
}
}
void Unit::SetInCombatWith(Unit* enemy)

View file

@ -1026,7 +1026,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
bool IsMounted() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); }
uint32 GetMountID() const { return GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID); }
void Mount(uint32 mount);
void Mount(uint32 mount, uint32 spellId = 0);
void Unmount();
uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }