aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game/Creature.h2
-rw-r--r--src/game/ObjectMgr.cpp8
-rw-r--r--src/game/PetAI.cpp181
-rw-r--r--src/game/PetAI.h11
-rw-r--r--src/game/PetHandler.cpp6
5 files changed, 108 insertions, 100 deletions
diff --git a/src/game/Creature.h b/src/game/Creature.h
index f8e51a58328..dcbe6a47b29 100644
--- a/src/game/Creature.h
+++ b/src/game/Creature.h
@@ -571,6 +571,8 @@ class TRINITY_DLL_SPEC Creature : public Unit
void SetCombatStartPosition(float x, float y, float z) { CombatStartX = x; CombatStartY = y; CombatStartZ = z; }
void GetCombatStartPosition(float &x, float &y, float &z) { x = CombatStartX; y = CombatStartY; z = CombatStartZ; }
+ uint32 GetGlobalCooldown() const { return m_GlobalCooldown; }
+
protected:
bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL);
bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 38926c8cef0..8a49d4dac0c 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -6784,11 +6784,17 @@ GameTele const* ObjectMgr::GetGameTele(std::string name) const
// converting string that we try to find to lower case
wstrToLower( wname );
+ // Alternative first GameTele what contains wnameLow as substring in case no GameTele location found
+ const GameTele* alt = NULL;
for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
+ {
if(itr->second.wnameLow == wname)
return &itr->second;
+ else if (alt == NULL && itr->second.wnameLow.find(wname) != std::wstring::npos)
+ alt = &itr->second;
+ }
- return NULL;
+ return alt;
}
bool ObjectMgr::AddGameTele(GameTele& tele)
diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp
index d14c8882df5..91d42af2340 100644
--- a/src/game/PetAI.cpp
+++ b/src/game/PetAI.cpp
@@ -38,7 +38,7 @@ int PetAI::Permissible(const Creature *creature)
return PERMIT_BASE_NO;
}
-PetAI::PetAI(Creature &c) : i_pet(c), i_victimGuid(0), i_tracker(TIME_INTERVAL_LOOK)
+PetAI::PetAI(Creature &c) : i_pet(c), i_tracker(TIME_INTERVAL_LOOK), inCombat(false)
{
m_AllySet.clear();
UpdateAllies();
@@ -65,7 +65,7 @@ void PetAI::MoveInLineOfSight(Unit *u)
void PetAI::AttackStart(Unit *u)
{
- if( i_pet.getVictim() || !u || i_pet.isPet() && ((Pet&)i_pet).getPetType()==MINI_PET )
+ if( inCombat || !u || (i_pet.isPet() && ((Pet&)i_pet).getPetType() == MINI_PET) )
return;
if(i_pet.Attack(u,true))
@@ -75,8 +75,8 @@ void PetAI::AttackStart(Unit *u)
// thus with the following clear the original TMG gets invalidated and crash, doh
// hope it doesn't start to leak memory without this :-/
//i_pet->Clear();
- i_victimGuid = u->GetGUID();
i_pet.GetMotionMaster()->MoveChase(u);
+ inCombat = true;
}
}
@@ -91,9 +91,6 @@ bool PetAI::IsVisible(Unit *pl) const
bool PetAI::_needToStop() const
{
- if(!i_pet.getVictim() || !i_pet.isAlive())
- return true;
-
// This is needed for charmed creatures, as once their target was reset other effects can trigger threat
if(i_pet.isCharmed() && i_pet.getVictim() == i_pet.GetCharmer())
return true;
@@ -103,48 +100,18 @@ bool PetAI::_needToStop() const
void PetAI::_stopAttack()
{
- if( !i_victimGuid )
- return;
-
- Unit* victim = ObjectAccessor::GetUnit(i_pet, i_victimGuid );
-
- if ( !victim )
- return;
-
- assert(!i_pet.getVictim() || i_pet.getVictim() == victim);
-
+ inCombat = false;
if( !i_pet.isAlive() )
{
DEBUG_LOG("Creature stoped attacking cuz his dead [guid=%u]", i_pet.GetGUIDLow());
i_pet.StopMoving();
i_pet.GetMotionMaster()->Clear();
i_pet.GetMotionMaster()->MoveIdle();
- i_victimGuid = 0;
i_pet.CombatStop();
i_pet.getHostilRefManager().deleteReferences();
return;
}
- else if( !victim )
- {
- DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_pet.GetGUIDLow());
- }
- else if( !victim->isAlive() )
- {
- DEBUG_LOG("Creature stopped attacking cuz his victim is dead [guid=%u]", i_pet.GetGUIDLow());
- }
- else if( victim->HasStealthAura() )
- {
- DEBUG_LOG("Creature stopped attacking cuz his victim is stealth [guid=%u]", i_pet.GetGUIDLow());
- }
- else if( victim->isInFlight() )
- {
- DEBUG_LOG("Creature stopped attacking cuz his victim is fly away [guid=%u]", i_pet.GetGUIDLow());
- }
- else
- {
- DEBUG_LOG("Creature stopped attacking due to target out run him [guid=%u]", i_pet.GetGUIDLow());
- }
Unit* owner = i_pet.GetCharmerOrOwner();
@@ -158,15 +125,13 @@ void PetAI::_stopAttack()
i_pet.GetMotionMaster()->Clear();
i_pet.GetMotionMaster()->MoveIdle();
}
- i_victimGuid = 0;
i_pet.AttackStop();
}
void PetAI::UpdateAI(const uint32 diff)
{
- // update i_victimGuid if i_pet.getVictim() !=0 and changed
- if(i_pet.getVictim())
- i_victimGuid = i_pet.getVictim()->GetGUID();
+ if (!i_pet.isAlive())
+ return;
Unit* owner = i_pet.GetCharmerOrOwner();
@@ -176,13 +141,16 @@ void PetAI::UpdateAI(const uint32 diff)
else
m_updateAlliesTimer -= diff;
+ if (inCombat && i_pet.getVictim() == NULL)
+ _stopAttack();
+
// i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc.
- if( i_victimGuid )
+ if( i_pet.getVictim() != NULL )
{
if( _needToStop() )
{
DEBUG_LOG("Pet AI stoped attacking [guid=%u]", i_pet.GetGUIDLow());
- _stopAttack(); // i_victimGuid == 0 && i_pet.getVictim() == NULL now
+ _stopAttack();
return;
}
else if( i_pet.IsStopped() || i_pet.IsWithinDistInMap(i_pet.getVictim(), ATTACK_DISTANCE))
@@ -228,75 +196,96 @@ void PetAI::UpdateAI(const uint32 diff)
}
}
- //Autocast
- HM_NAMESPACE::hash_map<uint32, Unit*> targetMap;
- targetMap.clear();
- SpellCastTargets NULLtargets;
-
- for (uint8 i = 0; i < i_pet.GetPetAutoSpellSize(); i++)
+ if (i_pet.GetGlobalCooldown() == 0 && !i_pet.IsNonMeleeSpellCasted(false))
{
- uint32 spellID = i_pet.GetPetAutoSpellOnPos(i);
- if (!spellID)
- continue;
-
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
- if (!spellInfo)
- continue;
+ //Autocast
+ for (uint8 i = 0; i < i_pet.GetPetAutoSpellSize(); i++)
+ {
+ uint32 spellID = i_pet.GetPetAutoSpellOnPos(i);
+ if (!spellID)
+ continue;
- Spell *spell = new Spell(&i_pet, spellInfo, false, 0);
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
+ if (!spellInfo)
+ continue;
- if(!IsPositiveSpell(spellInfo->Id) && i_pet.getVictim() && !_needToStop() && !i_pet.hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(i_pet.getVictim()))
- targetMap[spellID] = i_pet.getVictim();
- else
- {
- spell->m_targets = NULLtargets;
- for(std::set<uint64>::iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar)
+ // ignore some combinations of combat state and combat/noncombat spells
+ if (!inCombat)
{
- Unit* Target = ObjectAccessor::GetUnit(i_pet,*tar);
-
- //only buff targets that are in combat, unless the spell can only be cast while out of combat
- if(!Target || (!Target->isInCombat() && !IsNonCombatSpell(spellInfo)))
+ if (!IsPositiveSpell(spellInfo->Id))
+ continue;
+ }
+ else
+ {
+ if (IsNonCombatSpell(spellInfo))
continue;
- if(spell->CanAutoCast(Target))
- targetMap[spellID] = Target;
}
- }
- delete spell;
- }
+ Spell *spell = new Spell(&i_pet, spellInfo, false, 0);
- //found units to cast on to
- if(!targetMap.empty())
- {
- uint32 index = urand(1, targetMap.size());
- HM_NAMESPACE::hash_map<uint32, Unit*>::iterator itr;
- uint32 i;
- for(itr = targetMap.begin(), i = 1; i < index; ++itr, ++i);
+ if(inCombat && !i_pet.hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(i_pet.getVictim()))
+ {
+ m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(i_pet.getVictim(), spell));
+ continue;
+ }
+ else
+ {
+ bool spellUsed = false;
+ for(std::set<uint64>::iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar)
+ {
+ Unit* Target = ObjectAccessor::GetUnit(i_pet,*tar);
+
+ //only buff targets that are in combat, unless the spell can only be cast while out of combat
+ if(!Target)
+ continue;
+
+ if(spell->CanAutoCast(Target))
+ {
+ m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(Target, spell));
+ spellUsed = true;
+ break;
+ }
+ }
+ if (!spellUsed)
+ delete spell;
+ }
+ }
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
+ //found units to cast on to
+ if(!m_targetSpellStore.empty())
+ {
+ uint32 index = urand(0, m_targetSpellStore.size() - 1);
- Spell *spell = new Spell(&i_pet, spellInfo, false);
+ Spell* spell = m_targetSpellStore[index].second;
+ Unit* target = m_targetSpellStore[index].first;
- SpellCastTargets targets;
- targets.setUnitTarget( itr->second );
+ m_targetSpellStore.erase(m_targetSpellStore.begin() + index);
- if(!i_pet.HasInArc(M_PI, itr->second))
- {
- i_pet.SetInFront(itr->second);
- if( itr->second->GetTypeId() == TYPEID_PLAYER )
- i_pet.SendUpdateToPlayer( (Player*)itr->second );
+ SpellCastTargets targets;
+ targets.setUnitTarget( target );
- if(owner && owner->GetTypeId() == TYPEID_PLAYER)
- i_pet.SendUpdateToPlayer( (Player*)owner );
- }
+ if( !i_pet.HasInArc(M_PI, target) )
+ {
+ i_pet.SetInFront(target);
+ if( target->GetTypeId() == TYPEID_PLAYER )
+ i_pet.SendUpdateToPlayer( (Player*)target );
+
+ if(owner && owner->GetTypeId() == TYPEID_PLAYER)
+ i_pet.SendUpdateToPlayer( (Player*)owner );
+ }
- i_pet.AddCreatureSpellCooldown(itr->first);
- if(i_pet.isPet())
- ((Pet*)&i_pet)->CheckLearning(itr->first);
+ i_pet.AddCreatureSpellCooldown(spell->m_spellInfo->Id);
+ if(i_pet.isPet())
+ ((Pet*)&i_pet)->CheckLearning(spell->m_spellInfo->Id);
- spell->prepare(&targets);
+ spell->prepare(&targets);
+ }
+ while (!m_targetSpellStore.empty())
+ {
+ delete m_targetSpellStore.begin()->second;
+ m_targetSpellStore.erase(m_targetSpellStore.begin());
+ }
}
- targetMap.clear();
}
bool PetAI::_isVisible(Unit *u) const
diff --git a/src/game/PetAI.h b/src/game/PetAI.h
index e95eb16426e..33118dabdcb 100644
--- a/src/game/PetAI.h
+++ b/src/game/PetAI.h
@@ -25,6 +25,7 @@
#include "Timer.h"
class Creature;
+class Spell;
class TRINITY_DLL_DECL PetAI : public CreatureAI
{
@@ -38,9 +39,9 @@ class TRINITY_DLL_DECL PetAI : public CreatureAI
void DamageTaken(Unit *done_by, uint32& /*damage*/) { AttackedBy(done_by); }
void AttackedBy(Unit*);
bool IsVisible(Unit *) const;
+ void JustDied(Unit* who) { _stopAttack(); }
void UpdateAI(const uint32);
- void UpdateAllies();
static int Permissible(const Creature *);
private:
@@ -48,11 +49,15 @@ class TRINITY_DLL_DECL PetAI : public CreatureAI
bool _needToStop(void) const;
void _stopAttack(void);
+ void UpdateAllies();
+
Creature &i_pet;
- uint64 i_victimGuid;
+ bool inCombat;
TimeTracker i_tracker;
- //uint32 i_RepeatAction;
std::set<uint64> m_AllySet;
uint32 m_updateAlliesTimer;
+
+ typedef std::pair<Unit*, Spell*> TargetSpellPair;
+ std::vector<TargetSpellPair> m_targetSpellStore;
};
#endif
diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp
index b8e96cf3a75..e9f860c7207 100644
--- a/src/game/PetHandler.cpp
+++ b/src/game/PetHandler.cpp
@@ -166,6 +166,9 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
else
unit_target = NULL;
+ if (((Creature*)pet)->GetGlobalCooldown() > 0)
+ return;
+
// do not cast unknown spells
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid );
if(!spellInfo)
@@ -601,6 +604,9 @@ void WorldSession::HandleAddDynamicTargetObsoleteOpcode( WorldPacket& recvPacket
return;
}
+ if (pet->GetGlobalCooldown() > 0)
+ return;
+
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
if(!spellInfo)
{