mirror of
https://github.com/mangosfour/server.git
synced 2025-12-15 19:37:02 +00:00
Cmangos commits applied
Cmangos commits applied
This commit is contained in:
parent
df3ab5df8e
commit
068c67b932
12 changed files with 261 additions and 138 deletions
|
|
@ -987,7 +987,7 @@ bool ChatHandler::HandleModifyTalentCommand(char* args)
|
||||||
else if (((Creature*)target)->IsPet())
|
else if (((Creature*)target)->IsPet())
|
||||||
{
|
{
|
||||||
Unit* owner = target->GetOwner();
|
Unit* owner = target->GetOwner();
|
||||||
if (owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet*)target)->IsPermanentPetFor((Player*)owner))
|
if (owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet*)target)->isControlled())
|
||||||
{
|
{
|
||||||
// check online security
|
// check online security
|
||||||
if (HasLowerSecurity((Player*)owner))
|
if (HasLowerSecurity((Player*)owner))
|
||||||
|
|
|
||||||
|
|
@ -5281,7 +5281,7 @@ bool ChatHandler::HandleResetTalentsCommand(char* args)
|
||||||
if (!*args && creature && creature->IsPet())
|
if (!*args && creature && creature->IsPet())
|
||||||
{
|
{
|
||||||
Unit* owner = creature->GetOwner();
|
Unit* owner = creature->GetOwner();
|
||||||
if (owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet*)creature)->IsPermanentPetFor((Player*)owner))
|
if (owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet*)creature)->isControlled())
|
||||||
{
|
{
|
||||||
((Pet*)creature)->resetTalents(true);
|
((Pet*)creature)->resetTalents(true);
|
||||||
((Player*)owner)->SendTalentsInfoData(true);
|
((Player*)owner)->SendTalentsInfoData(true);
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_charmInfo->SetPetNumber(pet_number, IsPermanentPetFor(owner));
|
m_charmInfo->SetPetNumber(pet_number, isControlled());
|
||||||
|
|
||||||
SetOwnerGuid(owner->GetObjectGuid());
|
SetOwnerGuid(owner->GetObjectGuid());
|
||||||
SetDisplayId(fields[3].GetUInt32());
|
SetDisplayId(fields[3].GetUInt32());
|
||||||
|
|
@ -722,6 +722,8 @@ void Pet::GivePetXP(uint32 xp)
|
||||||
if (level >= maxlevel)
|
if (level >= maxlevel)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
xp *= sWorld.getConfig(CONFIG_FLOAT_RATE_PET_XP_KILL);
|
||||||
|
|
||||||
uint32 nextLvlXP = GetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP);
|
uint32 nextLvlXP = GetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP);
|
||||||
uint32 curXP = GetUInt32Value(UNIT_FIELD_PETEXPERIENCE);
|
uint32 curXP = GetUInt32Value(UNIT_FIELD_PETEXPERIENCE);
|
||||||
uint32 newXP = curXP + xp;
|
uint32 newXP = curXP + xp;
|
||||||
|
|
@ -1914,29 +1916,6 @@ void Pet::ToggleAutocast(uint32 spellid, bool apply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pet::IsPermanentPetFor(Player* owner)
|
|
||||||
{
|
|
||||||
switch (getPetType())
|
|
||||||
{
|
|
||||||
case SUMMON_PET:
|
|
||||||
switch (owner->getClass())
|
|
||||||
{
|
|
||||||
// oddly enough, Mage's Water Elemental is still treated as temporary pet with Glyph of Eternal Water
|
|
||||||
// i.e. does not unsummon at mounting, gets dismissed at teleport etc.
|
|
||||||
case CLASS_WARLOCK:
|
|
||||||
return GetCreatureInfo()->CreatureType == CREATURE_TYPE_DEMON;
|
|
||||||
case CLASS_DEATH_KNIGHT:
|
|
||||||
return GetCreatureInfo()->CreatureType == CREATURE_TYPE_UNDEAD;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case HUNTER_PET:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Pet::Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, uint32 pet_number)
|
bool Pet::Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, uint32 pet_number)
|
||||||
{
|
{
|
||||||
SetMap(cPos.GetMap());
|
SetMap(cPos.GetMap());
|
||||||
|
|
@ -1989,10 +1968,11 @@ void Pet::LearnPetPassives()
|
||||||
|
|
||||||
void Pet::CastPetAuras(bool current)
|
void Pet::CastPetAuras(bool current)
|
||||||
{
|
{
|
||||||
Unit* owner = GetOwner();
|
if (!isControlled())
|
||||||
if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Unit* owner = GetOwner();
|
||||||
|
|
||||||
for (PetAuraSet::const_iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
|
for (PetAuraSet::const_iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
|
||||||
{
|
{
|
||||||
PetAura const* pa = *itr;
|
PetAura const* pa = *itr;
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,17 @@ enum PetSaveMode
|
||||||
// There might be a lot more
|
// There might be a lot more
|
||||||
enum PetModeFlags
|
enum PetModeFlags
|
||||||
{
|
{
|
||||||
PET_MODE_UNKNOWN_0 = 0x0000001,
|
PET_MODE_STAY = 0x0000000,
|
||||||
PET_MODE_UNKNOWN_2 = 0x0000100,
|
PET_MODE_FOLLOW = 0x0000001,
|
||||||
|
PET_MODE_ATTACK = 0x0000002,
|
||||||
|
PET_MODE_PASSIVE = 0x0000000,
|
||||||
|
PET_MODE_DEFENSIVE = 0x0000100,
|
||||||
|
PET_MODE_AGGRESSIVE = 0x0000200,
|
||||||
|
|
||||||
PET_MODE_DISABLE_ACTIONS = 0x8000000,
|
PET_MODE_DISABLE_ACTIONS = 0x8000000,
|
||||||
|
|
||||||
// autoset in client at summon
|
// autoset in client at summon
|
||||||
PET_MODE_DEFAULT = PET_MODE_UNKNOWN_0 | PET_MODE_UNKNOWN_2,
|
PET_MODE_DEFAULT = PET_MODE_FOLLOW | PET_MODE_DEFENSIVE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PetSpellState
|
enum PetSpellState
|
||||||
|
|
@ -147,8 +152,6 @@ class Pet : public Creature
|
||||||
bool isControlled() const { return getPetType() == SUMMON_PET || getPetType() == HUNTER_PET; }
|
bool isControlled() const { return getPetType() == SUMMON_PET || getPetType() == HUNTER_PET; }
|
||||||
bool isTemporarySummoned() const { return m_duration > 0; }
|
bool isTemporarySummoned() const { return m_duration > 0; }
|
||||||
|
|
||||||
bool IsPermanentPetFor(Player* owner); // pet have tab in character windows and set UNIT_FIELD_PETNUMBER
|
|
||||||
|
|
||||||
bool Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, uint32 pet_number);
|
bool Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, uint32 pet_number);
|
||||||
bool CreateBaseAtCreature(Creature* creature);
|
bool CreateBaseAtCreature(Creature* creature);
|
||||||
bool LoadPetFromDB(Player* owner, uint32 petentry = 0, uint32 petnumber = 0, bool current = false);
|
bool LoadPetFromDB(Player* owner, uint32 petentry = 0, uint32 petnumber = 0, bool current = false);
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,15 @@ void PetAI::UpdateAI(const uint32 diff)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Unit* owner = m_creature->GetCharmerOrOwner();
|
Unit* owner = m_creature->GetCharmerOrOwner();
|
||||||
|
Unit* victim = nullptr;
|
||||||
|
|
||||||
|
if (!((Pet*)m_creature)->isControlled())
|
||||||
|
m_creature->SelectHostileTarget();
|
||||||
|
|
||||||
|
// Creature pets and guardians will always look in threat list for victim
|
||||||
|
if (!(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)
|
||||||
|
|| (m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)))
|
||||||
|
victim = m_creature->getVictim();
|
||||||
|
|
||||||
if (m_updateAlliesTimer <= diff)
|
if (m_updateAlliesTimer <= diff)
|
||||||
// UpdateAllies self set update timer
|
// UpdateAllies self set update timer
|
||||||
|
|
@ -135,62 +144,68 @@ void PetAI::UpdateAI(const uint32 diff)
|
||||||
else
|
else
|
||||||
m_updateAlliesTimer -= diff;
|
m_updateAlliesTimer -= diff;
|
||||||
|
|
||||||
if (inCombat && (!m_creature->getVictim() || (m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)))
|
if (inCombat && !victim)
|
||||||
_stopAttack();
|
|
||||||
|
|
||||||
// i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc.
|
|
||||||
if (m_creature->getVictim())
|
|
||||||
{
|
{
|
||||||
if (_needToStop())
|
m_creature->AttackStop(true);
|
||||||
{
|
inCombat = false;
|
||||||
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow());
|
|
||||||
_stopAttack();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool meleeReach = m_creature->CanReachWithMeleeAttack(m_creature->getVictim());
|
if (((Pet*)m_creature)->GetIsRetreating())
|
||||||
|
{
|
||||||
|
if (!owner->IsWithinDistInMap(m_creature, (PET_FOLLOW_DIST * 2)))
|
||||||
|
{
|
||||||
|
if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW))
|
||||||
|
m_creature->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||||
|
|
||||||
if (m_creature->IsStopped() || meleeReach)
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
((Pet*)m_creature)->SetIsRetreating();
|
||||||
|
}
|
||||||
|
else if (((Pet*)m_creature)->GetSpellOpener() != 0) // have opener stored
|
||||||
{
|
{
|
||||||
// required to be stopped cases
|
uint32 minRange = ((Pet*)m_creature)->GetSpellOpenerMinRange();
|
||||||
if (m_creature->IsStopped() && m_creature->IsNonMeleeSpellCasted(false))
|
|
||||||
|
if (!(victim = m_creature->getVictim())
|
||||||
|
|| (minRange != 0 && m_creature->IsWithinDistInMap(victim, minRange)))
|
||||||
|
((Pet*)m_creature)->SetSpellOpener();
|
||||||
|
else if (m_creature->IsWithinDistInMap(victim, ((Pet*)m_creature)->GetSpellOpenerMaxRange())
|
||||||
|
&& m_creature->IsWithinLOSInMap(victim))
|
||||||
{
|
{
|
||||||
if (m_creature->hasUnitState(UNIT_STAT_FOLLOW_MOVE))
|
// stop moving
|
||||||
m_creature->InterruptNonMeleeSpells(false);
|
m_creature->clearUnitState(UNIT_STAT_MOVING);
|
||||||
|
|
||||||
|
// auto turn to target
|
||||||
|
m_creature->SetInFront(victim);
|
||||||
|
|
||||||
|
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
m_creature->SendCreateUpdateToPlayer((Player*)victim);
|
||||||
|
|
||||||
|
if (owner->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
m_creature->SendCreateUpdateToPlayer((Player*)owner);
|
||||||
|
|
||||||
|
uint32 spell_id = ((Pet*)m_creature)->GetSpellOpener();
|
||||||
|
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||||
|
|
||||||
|
Spell* spell = new Spell(m_creature, spellInfo, false);
|
||||||
|
|
||||||
|
SpellCastResult result = spell->CheckPetCast(victim);
|
||||||
|
|
||||||
|
if (result == SPELL_CAST_OK)
|
||||||
|
{
|
||||||
|
m_creature->AddCreatureSpellCooldown(spell_id);
|
||||||
|
spell->SpellStart(&(spell->m_targets));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
delete spell;
|
||||||
|
|
||||||
|
((Pet*)m_creature)->SetSpellOpener();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// not required to be stopped case
|
|
||||||
else if (DoMeleeAttackIfReady())
|
|
||||||
{
|
|
||||||
if (!m_creature->getVictim())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if pet misses its target, it will also be the first in threat list
|
|
||||||
m_creature->getVictim()->AddThreat(m_creature);
|
|
||||||
|
|
||||||
if (_needToStop())
|
|
||||||
_stopAttack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (owner && m_creature->GetCharmInfo())
|
|
||||||
{
|
|
||||||
if (owner->IsInCombat() && !(m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) || m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY)))
|
|
||||||
{
|
|
||||||
AttackStart(owner->getAttackerForHelper());
|
|
||||||
}
|
|
||||||
else if (m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
|
|
||||||
{
|
|
||||||
if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW))
|
|
||||||
{
|
|
||||||
m_creature->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Autocast (casted only in combat or persistent spells in any state)
|
// Autocast (casted only in combat or persistent spells in any state)
|
||||||
if (!m_creature->IsNonMeleeSpellCasted(false))
|
else if (!m_creature->IsNonMeleeSpellCasted(false))
|
||||||
{
|
{
|
||||||
typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
|
typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
|
||||||
TargetSpellList targetSpellStore;
|
TargetSpellList targetSpellStore;
|
||||||
|
|
@ -220,7 +235,6 @@ void PetAI::UpdateAI(const uint32 diff)
|
||||||
// Consume Shadows, Lesser Invisibility, so ignore checks for its
|
// Consume Shadows, Lesser Invisibility, so ignore checks for its
|
||||||
if (!IsNonCombatSpell(spellInfo))
|
if (!IsNonCombatSpell(spellInfo))
|
||||||
{
|
{
|
||||||
// allow only spell without spell cost or with spell cost but not duration limit
|
|
||||||
int32 duration = GetSpellDuration(spellInfo);
|
int32 duration = GetSpellDuration(spellInfo);
|
||||||
SpellPowerEntry const* spellPower = spellInfo->GetSpellPower();
|
SpellPowerEntry const* spellPower = spellInfo->GetSpellPower();
|
||||||
if (spellPower && (spellPower->manaCost || spellPower->ManaCostPercentage || spellPower->manaPerSecond) && duration > 0)
|
if (spellPower && (spellPower->manaCost || spellPower->ManaCostPercentage || spellPower->manaPerSecond) && duration > 0)
|
||||||
|
|
@ -228,22 +242,21 @@ void PetAI::UpdateAI(const uint32 diff)
|
||||||
|
|
||||||
// allow only spell without cooldown > duration
|
// allow only spell without cooldown > duration
|
||||||
int32 cooldown = GetSpellRecoveryTime(spellInfo);
|
int32 cooldown = GetSpellRecoveryTime(spellInfo);
|
||||||
if (cooldown >= 0 && duration >= 0 && cooldown > duration)
|
|
||||||
|
// allow only spell not on cooldown
|
||||||
|
if (cooldown != 0 && duration < cooldown)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// just ignore non-combat spells
|
// just ignore non-combat spells
|
||||||
if (IsNonCombatSpell(spellInfo))
|
else if (IsNonCombatSpell(spellInfo))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
Spell* spell = new Spell(m_creature, spellInfo, false);
|
Spell* spell = new Spell(m_creature, spellInfo, false);
|
||||||
|
|
||||||
if (inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(m_creature->getVictim()))
|
if (inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(victim))
|
||||||
{
|
{
|
||||||
targetSpellStore.push_back(TargetSpellList::value_type(m_creature->getVictim(), spell));
|
targetSpellStore.push_back(TargetSpellList::value_type(victim, spell));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -301,6 +314,105 @@ void PetAI::UpdateAI(const uint32 diff)
|
||||||
for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr)
|
for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr)
|
||||||
delete itr->second;
|
delete itr->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Guardians will always look in threat list for victim
|
||||||
|
if (!((Pet*)m_creature)->isControlled())
|
||||||
|
m_creature->SelectHostileTarget();
|
||||||
|
|
||||||
|
if (!(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)
|
||||||
|
|| (m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)))
|
||||||
|
victim = m_creature->getVictim();
|
||||||
|
|
||||||
|
// Stop here if casting spell (No melee and no movement)
|
||||||
|
if (m_creature->IsNonMeleeSpellCasted(false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (victim)
|
||||||
|
{
|
||||||
|
// i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc.
|
||||||
|
// This is needed for charmed creatures, as once their target was reset other effects can trigger threat
|
||||||
|
if ((m_creature->IsCharmed() && victim == m_creature->GetCharmer()) || !victim->IsTargetableForAttack())
|
||||||
|
{
|
||||||
|
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow());
|
||||||
|
m_creature->CombatStop();
|
||||||
|
inCombat = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if pet misses its target, it will also be the first in threat list
|
||||||
|
if (!(m_creature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_MELEE)
|
||||||
|
&& m_creature->CanReachWithMeleeAttack(victim))
|
||||||
|
{
|
||||||
|
if (!m_creature->HasInArc(2 * M_PI_F / 3, victim))
|
||||||
|
{
|
||||||
|
m_creature->SetInFront(victim);
|
||||||
|
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
m_creature->SendCreateUpdateToPlayer((Player*)victim);
|
||||||
|
|
||||||
|
if (owner && owner->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
m_creature->SendCreateUpdateToPlayer((Player*)owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DoMeleeAttackIfReady())
|
||||||
|
victim->AddThreat(m_creature);
|
||||||
|
}
|
||||||
|
else if (!(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)
|
||||||
|
|| m_creature->hasUnitState(UNIT_STAT_MOVING)))
|
||||||
|
AttackStart(victim);
|
||||||
|
}
|
||||||
|
else if (owner)
|
||||||
|
{
|
||||||
|
CharmInfo* charmInfo = m_creature->GetCharmInfo();
|
||||||
|
|
||||||
|
if (owner->IsInCombat() && !(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)
|
||||||
|
|| (charmInfo && charmInfo->HasReactState(REACT_PASSIVE))))
|
||||||
|
AttackStart(owner->getAttackerForHelper());
|
||||||
|
else if (!m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
|
||||||
|
{
|
||||||
|
if (charmInfo && charmInfo->HasCommandState(COMMAND_STAY))
|
||||||
|
{
|
||||||
|
if (Pet* pet = (Pet*)m_creature)
|
||||||
|
{
|
||||||
|
//if stay command is set but we dont have stay pos set then we need to establish current pos as stay position
|
||||||
|
if (!pet->IsStayPosSet())
|
||||||
|
pet->SetStayPosition(true);
|
||||||
|
|
||||||
|
float stayPosX = pet->GetStayPosX();
|
||||||
|
float stayPosY = pet->GetStayPosY();
|
||||||
|
float stayPosZ = pet->GetStayPosZ();
|
||||||
|
|
||||||
|
if (m_creature->GetPositionX() == stayPosX
|
||||||
|
&& m_creature->GetPositionY() == stayPosY
|
||||||
|
&& m_creature->GetPositionZ() == stayPosZ)
|
||||||
|
{
|
||||||
|
float StayPosO = pet->GetStayPosO();
|
||||||
|
|
||||||
|
if (m_creature->hasUnitState(UNIT_STAT_MOVING))
|
||||||
|
{
|
||||||
|
m_creature->GetMotionMaster()->Clear(false);
|
||||||
|
m_creature->GetMotionMaster()->MoveIdle();
|
||||||
|
}
|
||||||
|
else if (m_creature->GetOrientation() != StayPosO)
|
||||||
|
m_creature->SetOrientation(StayPosO);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pet->GetMotionMaster()->MovePoint(0, stayPosX, stayPosY, stayPosZ, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_creature->hasUnitState(UNIT_STAT_FOLLOW))
|
||||||
|
{
|
||||||
|
if (owner->IsWithinDistInMap(m_creature, PET_FOLLOW_DIST))
|
||||||
|
{
|
||||||
|
m_creature->GetMotionMaster()->Clear(false);
|
||||||
|
m_creature->GetMotionMaster()->MoveIdle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (charmInfo && charmInfo->HasCommandState(COMMAND_FOLLOW)
|
||||||
|
&& !owner->IsWithinDistInMap(m_creature, (PET_FOLLOW_DIST * 2)))
|
||||||
|
m_creature->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PetAI::_isVisible(Unit* u) const
|
bool PetAI::_isVisible(Unit* u) const
|
||||||
|
|
@ -350,8 +462,9 @@ void PetAI::UpdateAllies()
|
||||||
|
|
||||||
void PetAI::AttackedBy(Unit* attacker)
|
void PetAI::AttackedBy(Unit* attacker)
|
||||||
{
|
{
|
||||||
// when attacked, fight back in case 1)no victim already AND 2)not set to passive AND 3)not set to stay, unless can it can reach attacker with melee attack anyway
|
// when attacked, fight back if no victim unless we have a charm state set to passive
|
||||||
if (!m_creature->getVictim() && m_creature->GetCharmInfo() && !m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) &&
|
if (!(m_creature->getVictim() || ((Pet*)m_creature)->GetIsRetreating() == true)
|
||||||
(!m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY) || m_creature->CanReachWithMeleeAttack(attacker)))
|
&& !(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)
|
||||||
|
|| (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE))))
|
||||||
AttackStart(attacker);
|
AttackStart(attacker);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18416,7 +18416,7 @@ void Player::PetSpellInitialize()
|
||||||
uint8 addlist = 0;
|
uint8 addlist = 0;
|
||||||
data << uint8(addlist); // placeholder
|
data << uint8(addlist); // placeholder
|
||||||
|
|
||||||
if (pet->IsPermanentPetFor(this))
|
if (pet->isControlled())
|
||||||
{
|
{
|
||||||
// spells loop
|
// spells loop
|
||||||
for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
|
for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
|
||||||
|
|
@ -21328,7 +21328,7 @@ struct UpdateZoneDependentPetsHelper
|
||||||
explicit UpdateZoneDependentPetsHelper(Player* _owner, uint32 zone, uint32 area) : owner(_owner), zone_id(zone), area_id(area) {}
|
explicit UpdateZoneDependentPetsHelper(Player* _owner, uint32 zone, uint32 area) : owner(_owner), zone_id(zone), area_id(area) {}
|
||||||
void operator()(Unit* unit) const
|
void operator()(Unit* unit) const
|
||||||
{
|
{
|
||||||
if (unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->IsPet() && !((Pet*)unit)->IsPermanentPetFor(owner))
|
if (unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->IsPet() && !((Pet*)unit)->isControlled())
|
||||||
if (uint32 spell_id = unit->GetUInt32Value(UNIT_CREATED_BY_SPELL))
|
if (uint32 spell_id = unit->GetUInt32Value(UNIT_CREATED_BY_SPELL))
|
||||||
if (SpellEntry const* spellEntry = sSpellStore.LookupEntry(spell_id))
|
if (SpellEntry const* spellEntry = sSpellStore.LookupEntry(spell_id))
|
||||||
if (sSpellMgr.GetSpellAllowedInLocationError(spellEntry, owner->GetMapId(), zone_id, area_id, owner) != SPELL_CAST_OK)
|
if (sSpellMgr.GetSpellAllowedInLocationError(spellEntry, owner->GetMapId(), zone_id, area_id, owner) != SPELL_CAST_OK)
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,10 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recv_data)
|
||||||
if (!s_show)
|
if (!s_show)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// 49 is maximum player count sent to client
|
||||||
|
if (++matchcount > 49)
|
||||||
|
continue;
|
||||||
|
|
||||||
++displaycount;
|
++displaycount;
|
||||||
|
|
||||||
data << pname; // player name
|
data << pname; // player name
|
||||||
|
|
|
||||||
|
|
@ -95,17 +95,27 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
switch (spellid)
|
switch (spellid)
|
||||||
{
|
{
|
||||||
case COMMAND_STAY: // flat=1792 // STAY
|
case COMMAND_STAY: // flat=1792 // STAY
|
||||||
pet->clearUnitState(UNIT_STAT_MOVING);
|
{
|
||||||
pet->StopMoving();
|
pet->StopMoving();
|
||||||
pet->GetMotionMaster()->Clear(false);
|
pet->AttackStop(true);
|
||||||
pet->GetMotionMaster()->MoveIdle();
|
pet->GetMotionMaster()->Clear();
|
||||||
|
((Pet*)pet)->SetStayPosition(true);
|
||||||
|
((Pet*)pet)->SetIsRetreating();
|
||||||
|
((Pet*)pet)->SetSpellOpener();
|
||||||
charmInfo->SetCommandState(COMMAND_STAY);
|
charmInfo->SetCommandState(COMMAND_STAY);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case COMMAND_FOLLOW: // spellid=1792 // FOLLOW
|
case COMMAND_FOLLOW: // spellid=1792 // FOLLOW
|
||||||
pet->AttackStop();
|
{
|
||||||
pet->GetMotionMaster()->MoveFollow(_player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
pet->StopMoving();
|
||||||
|
pet->AttackStop(true);
|
||||||
|
pet->GetMotionMaster()->Clear();
|
||||||
|
((Pet*)pet)->SetStayPosition();
|
||||||
|
((Pet*)pet)->SetIsRetreating(true);
|
||||||
|
((Pet*)pet)->SetSpellOpener();
|
||||||
charmInfo->SetCommandState(COMMAND_FOLLOW);
|
charmInfo->SetCommandState(COMMAND_FOLLOW);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case COMMAND_ATTACK: // spellid=1792 // ATTACK
|
case COMMAND_ATTACK: // spellid=1792 // ATTACK
|
||||||
{
|
{
|
||||||
Unit* TargetUnit = _player->GetMap()->GetUnit(targetGuid);
|
Unit* TargetUnit = _player->GetMap()->GetUnit(targetGuid);
|
||||||
|
|
@ -182,11 +192,17 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
switch (spellid)
|
switch (spellid)
|
||||||
{
|
{
|
||||||
case REACT_PASSIVE: // passive
|
case REACT_PASSIVE: // passive
|
||||||
|
{
|
||||||
|
pet->AttackStop(true);
|
||||||
|
((Pet*)pet)->SetSpellOpener();
|
||||||
|
}
|
||||||
case REACT_DEFENSIVE: // recovery
|
case REACT_DEFENSIVE: // recovery
|
||||||
case REACT_AGGRESSIVE: // activete
|
case REACT_AGGRESSIVE: // activete
|
||||||
|
{
|
||||||
charmInfo->SetReactState(ReactStates(spellid));
|
charmInfo->SetReactState(ReactStates(spellid));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ACT_DISABLED: // 0x81 spell (disabled), ignore
|
case ACT_DISABLED: // 0x81 spell (disabled), ignore
|
||||||
case ACT_PASSIVE: // 0x01
|
case ACT_PASSIVE: // 0x01
|
||||||
|
|
@ -226,6 +242,28 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
|
|
||||||
SpellCastResult result = spell->CheckPetCast(unit_target);
|
SpellCastResult result = spell->CheckPetCast(unit_target);
|
||||||
|
|
||||||
|
const SpellRangeEntry* sRange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
|
||||||
|
|
||||||
|
if (unit_target && !(pet->IsWithinDistInMap(unit_target, sRange->maxRange) && pet->IsWithinLOSInMap(unit_target))
|
||||||
|
&& !(GetPlayer()->IsFriendlyTo(unit_target) || pet->HasAuraType(SPELL_AURA_MOD_POSSESS)))
|
||||||
|
{
|
||||||
|
((Pet*)pet)->SetSpellOpener(spellid, sRange->minRange, sRange->maxRange);
|
||||||
|
spell->finish(false);
|
||||||
|
delete spell;
|
||||||
|
|
||||||
|
pet->AttackStop();
|
||||||
|
pet->GetMotionMaster()->Clear();
|
||||||
|
|
||||||
|
((Creature*)pet)->AI()->AttackStart(unit_target);
|
||||||
|
// 10% chance to play special warlock pet attack talk, else growl
|
||||||
|
if (((Creature*)pet)->IsPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != unit_target && roll_chance_i(10))
|
||||||
|
pet->SendPetTalk((uint32)PET_TALK_ATTACK);
|
||||||
|
|
||||||
|
pet->SendPetAIReaction();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// auto turn to target unless possessed
|
// auto turn to target unless possessed
|
||||||
if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
|
if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
|
||||||
{
|
{
|
||||||
|
|
@ -253,28 +291,7 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
|
|
||||||
unit_target = spell->m_targets.getUnitTarget();
|
unit_target = spell->m_targets.getUnitTarget();
|
||||||
|
|
||||||
// 10% chance to play special pet attack talk, else growl
|
((Pet*)pet)->SetSpellOpener();
|
||||||
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
|
||||||
if (((Creature*)pet)->IsPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10))
|
|
||||||
pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pet->SendPetAIReaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
|
|
||||||
{
|
|
||||||
// This is true if pet has no target or has target but targets differs.
|
|
||||||
if (pet->getVictim() != unit_target)
|
|
||||||
{
|
|
||||||
if (pet->getVictim())
|
|
||||||
pet->AttackStop();
|
|
||||||
pet->GetMotionMaster()->Clear();
|
|
||||||
if (((Creature*)pet)->AI())
|
|
||||||
((Creature*)pet)->AI()->AttackStart(unit_target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spell->SpellStart(&(spell->m_targets));
|
spell->SpellStart(&(spell->m_targets));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -291,6 +308,7 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
if (!((Creature*)pet)->HasSpellCooldown(spellid))
|
if (!((Creature*)pet)->HasSpellCooldown(spellid))
|
||||||
GetPlayer()->SendClearCooldown(spellid, pet);
|
GetPlayer()->SendClearCooldown(spellid, pet);
|
||||||
|
|
||||||
|
((Pet*)pet)->SetSpellOpener();
|
||||||
spell->finish(false);
|
spell->finish(false);
|
||||||
delete spell;
|
delete spell;
|
||||||
}
|
}
|
||||||
|
|
@ -702,20 +720,10 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
|
||||||
spell->m_cast_count = cast_count; // probably pending spell cast
|
spell->m_cast_count = cast_count; // probably pending spell cast
|
||||||
spell->m_targets = targets;
|
spell->m_targets = targets;
|
||||||
|
|
||||||
SpellCastResult result = triggeredByAura ? SPELL_CAST_OK : spell->CheckPetCast(NULL);
|
SpellCastResult result = triggeredByAura ? SPELL_CAST_OK : spell->CheckPetCast(nullptr);
|
||||||
if (result == SPELL_CAST_OK)
|
if (result == SPELL_CAST_OK)
|
||||||
{
|
{
|
||||||
pet->AddCreatureSpellCooldown(spellid);
|
pet->AddCreatureSpellCooldown(spellid);
|
||||||
if (pet->IsPet())
|
|
||||||
{
|
|
||||||
// 10% chance to play special pet attack talk, else growl
|
|
||||||
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
|
||||||
if (((Pet*)pet)->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
|
|
||||||
pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
|
|
||||||
else
|
|
||||||
pet->SendPetAIReaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
spell->SpellStart(&(spell->m_targets), triggeredByAura);
|
spell->SpellStart(&(spell->m_targets), triggeredByAura);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -7497,6 +7497,11 @@ void Spell::UpdatePointers()
|
||||||
UpdateOriginalCasterPointer();
|
UpdateOriginalCasterPointer();
|
||||||
|
|
||||||
m_targets.Update(m_caster);
|
m_targets.Update(m_caster);
|
||||||
|
|
||||||
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
m_CastItem = ((Player *)m_caster)->GetItemByGuid(m_CastItemGuid);
|
||||||
|
else
|
||||||
|
m_CastItem = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Spell::CheckTargetCreatureType(Unit* target) const
|
bool Spell::CheckTargetCreatureType(Unit* target) const
|
||||||
|
|
@ -8063,6 +8068,7 @@ void Spell::ClearCastItem()
|
||||||
m_targets.setItemTarget(NULL);
|
m_targets.setItemTarget(NULL);
|
||||||
|
|
||||||
m_CastItem = NULL;
|
m_CastItem = NULL;
|
||||||
|
m_CastItemGuid.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Spell::HasGlobalCooldown()
|
bool Spell::HasGlobalCooldown()
|
||||||
|
|
|
||||||
|
|
@ -470,6 +470,7 @@ void World::LoadConfigSettings(bool reload)
|
||||||
setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY, "Rate.Drop.Money", 1.0f);
|
setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY, "Rate.Drop.Money", 1.0f);
|
||||||
setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY, "Rate.Drop.Currency", 1.0f);
|
setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY, "Rate.Drop.Currency", 1.0f);
|
||||||
setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT, "Rate.Drop.Currency.Amount", 1.0f);
|
setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT, "Rate.Drop.Currency.Amount", 1.0f);
|
||||||
|
setConfig(CONFIG_FLOAT_RATE_PET_XP_KILL, "Rate.Pet.XP.Kill", 1.0f);
|
||||||
setConfig(CONFIG_FLOAT_RATE_XP_KILL, "Rate.XP.Kill", 1.0f);
|
setConfig(CONFIG_FLOAT_RATE_XP_KILL, "Rate.XP.Kill", 1.0f);
|
||||||
setConfig(CONFIG_FLOAT_RATE_XP_QUEST, "Rate.XP.Quest", 1.0f);
|
setConfig(CONFIG_FLOAT_RATE_XP_QUEST, "Rate.XP.Quest", 1.0f);
|
||||||
setConfig(CONFIG_FLOAT_RATE_XP_EXPLORE, "Rate.XP.Explore", 1.0f);
|
setConfig(CONFIG_FLOAT_RATE_XP_EXPLORE, "Rate.XP.Explore", 1.0f);
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,7 @@ enum eConfigFloatValues
|
||||||
CONFIG_FLOAT_RATE_DROP_MONEY,
|
CONFIG_FLOAT_RATE_DROP_MONEY,
|
||||||
CONFIG_FLOAT_RATE_DROP_CURRENCY,
|
CONFIG_FLOAT_RATE_DROP_CURRENCY,
|
||||||
CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT,
|
CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT,
|
||||||
|
CONFIG_FLOAT_RATE_PET_XP_KILL,
|
||||||
CONFIG_FLOAT_RATE_XP_KILL,
|
CONFIG_FLOAT_RATE_XP_KILL,
|
||||||
CONFIG_FLOAT_RATE_XP_QUEST,
|
CONFIG_FLOAT_RATE_XP_QUEST,
|
||||||
CONFIG_FLOAT_RATE_XP_EXPLORE,
|
CONFIG_FLOAT_RATE_XP_EXPLORE,
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,10 @@ BindIP = "0.0.0.0"
|
||||||
# Default: 1 (Enable)
|
# Default: 1 (Enable)
|
||||||
# 0 (Disabled)
|
# 0 (Disabled)
|
||||||
#
|
#
|
||||||
|
# MaxWhoListReturns
|
||||||
|
# Set the max number of players returned in the /who list and interface (0 means unlimited)
|
||||||
|
# Default: 49 - (stable)
|
||||||
|
#
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
UseProcessors = 0
|
UseProcessors = 0
|
||||||
|
|
@ -231,6 +235,7 @@ UpdateUptimeInterval = 10
|
||||||
MaxCoreStuckTime = 0
|
MaxCoreStuckTime = 0
|
||||||
AddonChannel = 1
|
AddonChannel = 1
|
||||||
CleanCharacterDB = 1
|
CleanCharacterDB = 1
|
||||||
|
MaxWhoListReturns = 49
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# SERVER LOGGING
|
# SERVER LOGGING
|
||||||
|
|
@ -1282,6 +1287,7 @@ Visibility.AIRelocationNotifyDelay = 1000
|
||||||
# Drop rate for currency amount
|
# Drop rate for currency amount
|
||||||
# Default: 1
|
# Default: 1
|
||||||
#
|
#
|
||||||
|
# Rate.Pet.XP.Kill
|
||||||
# Rate.XP.Kill
|
# Rate.XP.Kill
|
||||||
# Rate.XP.Quest
|
# Rate.XP.Quest
|
||||||
# Rate.XP.Explore
|
# Rate.XP.Explore
|
||||||
|
|
@ -1428,6 +1434,7 @@ Rate.Drop.Item.Quest = 1
|
||||||
Rate.Drop.Money = 1
|
Rate.Drop.Money = 1
|
||||||
Rate.Drop.Currency = 1
|
Rate.Drop.Currency = 1
|
||||||
Rate.Drop.Currency.Amount = 1
|
Rate.Drop.Currency.Amount = 1
|
||||||
|
Rate.Pet.XP.Kill = 1
|
||||||
Rate.XP.Kill = 1
|
Rate.XP.Kill = 1
|
||||||
Rate.XP.Quest = 1
|
Rate.XP.Quest = 1
|
||||||
Rate.XP.Explore = 1
|
Rate.XP.Explore = 1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue