Cmangos commits applied

Cmangos commits applied
This commit is contained in:
Charles A Edwards 2016-09-14 13:21:23 +01:00 committed by Antz
parent df3ab5df8e
commit 068c67b932
12 changed files with 261 additions and 138 deletions

View file

@ -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))

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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);
} }

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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);

View file

@ -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,

View file

@ -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