mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 13:37:05 +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())
|
||||
{
|
||||
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
|
||||
if (HasLowerSecurity((Player*)owner))
|
||||
|
|
|
|||
|
|
@ -5281,7 +5281,7 @@ bool ChatHandler::HandleResetTalentsCommand(char* args)
|
|||
if (!*args && creature && creature->IsPet())
|
||||
{
|
||||
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);
|
||||
((Player*)owner)->SendTalentsInfoData(true);
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
|
|||
return true;
|
||||
}
|
||||
|
||||
m_charmInfo->SetPetNumber(pet_number, IsPermanentPetFor(owner));
|
||||
m_charmInfo->SetPetNumber(pet_number, isControlled());
|
||||
|
||||
SetOwnerGuid(owner->GetObjectGuid());
|
||||
SetDisplayId(fields[3].GetUInt32());
|
||||
|
|
@ -722,6 +722,8 @@ void Pet::GivePetXP(uint32 xp)
|
|||
if (level >= maxlevel)
|
||||
return;
|
||||
|
||||
xp *= sWorld.getConfig(CONFIG_FLOAT_RATE_PET_XP_KILL);
|
||||
|
||||
uint32 nextLvlXP = GetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP);
|
||||
uint32 curXP = GetUInt32Value(UNIT_FIELD_PETEXPERIENCE);
|
||||
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)
|
||||
{
|
||||
SetMap(cPos.GetMap());
|
||||
|
|
@ -1989,10 +1968,11 @@ void Pet::LearnPetPassives()
|
|||
|
||||
void Pet::CastPetAuras(bool current)
|
||||
{
|
||||
Unit* owner = GetOwner();
|
||||
if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
|
||||
if (!isControlled())
|
||||
return;
|
||||
|
||||
Unit* owner = GetOwner();
|
||||
|
||||
for (PetAuraSet::const_iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
|
||||
{
|
||||
PetAura const* pa = *itr;
|
||||
|
|
|
|||
|
|
@ -56,12 +56,17 @@ enum PetSaveMode
|
|||
// There might be a lot more
|
||||
enum PetModeFlags
|
||||
{
|
||||
PET_MODE_UNKNOWN_0 = 0x0000001,
|
||||
PET_MODE_UNKNOWN_2 = 0x0000100,
|
||||
PET_MODE_STAY = 0x0000000,
|
||||
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,
|
||||
|
||||
// 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
|
||||
|
|
@ -146,9 +151,7 @@ class Pet : public Creature
|
|||
void setPetType(PetType type) { m_petType = type; }
|
||||
bool isControlled() const { return getPetType() == SUMMON_PET || getPetType() == HUNTER_PET; }
|
||||
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 CreateBaseAtCreature(Creature* creature);
|
||||
bool LoadPetFromDB(Player* owner, uint32 petentry = 0, uint32 petnumber = 0, bool current = false);
|
||||
|
|
|
|||
|
|
@ -128,6 +128,15 @@ void PetAI::UpdateAI(const uint32 diff)
|
|||
return;
|
||||
|
||||
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)
|
||||
// UpdateAllies self set update timer
|
||||
|
|
@ -135,62 +144,68 @@ void PetAI::UpdateAI(const uint32 diff)
|
|||
else
|
||||
m_updateAlliesTimer -= diff;
|
||||
|
||||
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.
|
||||
if (m_creature->getVictim())
|
||||
if (inCombat && !victim)
|
||||
{
|
||||
if (_needToStop())
|
||||
{
|
||||
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 (m_creature->IsStopped() || meleeReach)
|
||||
{
|
||||
// required to be stopped cases
|
||||
if (m_creature->IsStopped() && m_creature->IsNonMeleeSpellCasted(false))
|
||||
{
|
||||
if (m_creature->hasUnitState(UNIT_STAT_FOLLOW_MOVE))
|
||||
m_creature->InterruptNonMeleeSpells(false);
|
||||
else
|
||||
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();
|
||||
}
|
||||
}
|
||||
m_creature->AttackStop(true);
|
||||
inCombat = false;
|
||||
}
|
||||
else if (owner && m_creature->GetCharmInfo())
|
||||
|
||||
if (((Pet*)m_creature)->GetIsRetreating())
|
||||
{
|
||||
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 (!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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
((Pet*)m_creature)->SetIsRetreating();
|
||||
}
|
||||
else if (((Pet*)m_creature)->GetSpellOpener() != 0) // have opener stored
|
||||
{
|
||||
uint32 minRange = ((Pet*)m_creature)->GetSpellOpenerMinRange();
|
||||
|
||||
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))
|
||||
{
|
||||
// stop moving
|
||||
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
|
||||
return;
|
||||
}
|
||||
// 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;
|
||||
TargetSpellList targetSpellStore;
|
||||
|
|
@ -220,7 +235,6 @@ void PetAI::UpdateAI(const uint32 diff)
|
|||
// Consume Shadows, Lesser Invisibility, so ignore checks for its
|
||||
if (!IsNonCombatSpell(spellInfo))
|
||||
{
|
||||
// allow only spell without spell cost or with spell cost but not duration limit
|
||||
int32 duration = GetSpellDuration(spellInfo);
|
||||
SpellPowerEntry const* spellPower = spellInfo->GetSpellPower();
|
||||
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
|
||||
int32 cooldown = GetSpellRecoveryTime(spellInfo);
|
||||
if (cooldown >= 0 && duration >= 0 && cooldown > duration)
|
||||
|
||||
// allow only spell not on cooldown
|
||||
if (cooldown != 0 && duration < cooldown)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// just ignore non-combat spells
|
||||
if (IsNonCombatSpell(spellInfo))
|
||||
continue;
|
||||
}
|
||||
// just ignore non-combat spells
|
||||
else if (IsNonCombatSpell(spellInfo))
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
|
@ -301,6 +314,105 @@ void PetAI::UpdateAI(const uint32 diff)
|
|||
for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr)
|
||||
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
|
||||
|
|
@ -350,8 +462,9 @@ void PetAI::UpdateAllies()
|
|||
|
||||
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
|
||||
if (!m_creature->getVictim() && m_creature->GetCharmInfo() && !m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) &&
|
||||
(!m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY) || m_creature->CanReachWithMeleeAttack(attacker)))
|
||||
// when attacked, fight back if no victim unless we have a charm state set to passive
|
||||
if (!(m_creature->getVictim() || ((Pet*)m_creature)->GetIsRetreating() == true)
|
||||
&& !(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)
|
||||
|| (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE))))
|
||||
AttackStart(attacker);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18416,7 +18416,7 @@ void Player::PetSpellInitialize()
|
|||
uint8 addlist = 0;
|
||||
data << uint8(addlist); // placeholder
|
||||
|
||||
if (pet->IsPermanentPetFor(this))
|
||||
if (pet->isControlled())
|
||||
{
|
||||
// spells loop
|
||||
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) {}
|
||||
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 (SpellEntry const* spellEntry = sSpellStore.LookupEntry(spell_id))
|
||||
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)
|
||||
continue;
|
||||
|
||||
// 49 is maximum player count sent to client
|
||||
if (++matchcount > 49)
|
||||
continue;
|
||||
|
||||
++displaycount;
|
||||
|
||||
data << pname; // player name
|
||||
|
|
|
|||
|
|
@ -95,17 +95,27 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
|||
switch (spellid)
|
||||
{
|
||||
case COMMAND_STAY: // flat=1792 // STAY
|
||||
pet->clearUnitState(UNIT_STAT_MOVING);
|
||||
{
|
||||
pet->StopMoving();
|
||||
pet->GetMotionMaster()->Clear(false);
|
||||
pet->GetMotionMaster()->MoveIdle();
|
||||
pet->AttackStop(true);
|
||||
pet->GetMotionMaster()->Clear();
|
||||
((Pet*)pet)->SetStayPosition(true);
|
||||
((Pet*)pet)->SetIsRetreating();
|
||||
((Pet*)pet)->SetSpellOpener();
|
||||
charmInfo->SetCommandState(COMMAND_STAY);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
break;
|
||||
}
|
||||
case COMMAND_ATTACK: // spellid=1792 // ATTACK
|
||||
{
|
||||
Unit* TargetUnit = _player->GetMap()->GetUnit(targetGuid);
|
||||
|
|
@ -182,10 +192,16 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
|||
switch (spellid)
|
||||
{
|
||||
case REACT_PASSIVE: // passive
|
||||
{
|
||||
pet->AttackStop(true);
|
||||
((Pet*)pet)->SetSpellOpener();
|
||||
}
|
||||
case REACT_DEFENSIVE: // recovery
|
||||
case REACT_AGGRESSIVE: // activete
|
||||
{
|
||||
charmInfo->SetReactState(ReactStates(spellid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACT_DISABLED: // 0x81 spell (disabled), ignore
|
||||
|
|
@ -226,6 +242,28 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
|||
|
||||
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
|
||||
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();
|
||||
|
||||
// 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 (((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);
|
||||
}
|
||||
}
|
||||
|
||||
((Pet*)pet)->SetSpellOpener();
|
||||
spell->SpellStart(&(spell->m_targets));
|
||||
}
|
||||
else
|
||||
|
|
@ -291,6 +308,7 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
|||
if (!((Creature*)pet)->HasSpellCooldown(spellid))
|
||||
GetPlayer()->SendClearCooldown(spellid, pet);
|
||||
|
||||
((Pet*)pet)->SetSpellOpener();
|
||||
spell->finish(false);
|
||||
delete spell;
|
||||
}
|
||||
|
|
@ -702,20 +720,10 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
|
|||
spell->m_cast_count = cast_count; // probably pending spell cast
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -7497,6 +7497,11 @@ void Spell::UpdatePointers()
|
|||
UpdateOriginalCasterPointer();
|
||||
|
||||
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
|
||||
|
|
@ -8063,6 +8068,7 @@ void Spell::ClearCastItem()
|
|||
m_targets.setItemTarget(NULL);
|
||||
|
||||
m_CastItem = NULL;
|
||||
m_CastItemGuid.Clear();
|
||||
}
|
||||
|
||||
bool Spell::HasGlobalCooldown()
|
||||
|
|
|
|||
|
|
@ -470,9 +470,10 @@ void World::LoadConfigSettings(bool reload)
|
|||
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_AMOUNT, "Rate.Drop.Currency.Amount", 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_EXPLORE, "Rate.XP.Explore", 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_QUEST, "Rate.XP.Quest", 1.0f);
|
||||
setConfig(CONFIG_FLOAT_RATE_XP_EXPLORE, "Rate.XP.Explore", 1.0f);
|
||||
setConfig(CONFIG_FLOAT_RATE_REPUTATION_GAIN, "Rate.Reputation.Gain", 1.0f);
|
||||
setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_KILL, "Rate.Reputation.LowLevel.Kill", 1.0f);
|
||||
setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_QUEST, "Rate.Reputation.LowLevel.Quest", 1.0f);
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ enum eConfigFloatValues
|
|||
CONFIG_FLOAT_RATE_DROP_MONEY,
|
||||
CONFIG_FLOAT_RATE_DROP_CURRENCY,
|
||||
CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT,
|
||||
CONFIG_FLOAT_RATE_PET_XP_KILL,
|
||||
CONFIG_FLOAT_RATE_XP_KILL,
|
||||
CONFIG_FLOAT_RATE_XP_QUEST,
|
||||
CONFIG_FLOAT_RATE_XP_EXPLORE,
|
||||
|
|
|
|||
|
|
@ -203,6 +203,10 @@ BindIP = "0.0.0.0"
|
|||
# Default: 1 (Enable)
|
||||
# 0 (Disabled)
|
||||
#
|
||||
# MaxWhoListReturns
|
||||
# Set the max number of players returned in the /who list and interface (0 means unlimited)
|
||||
# Default: 49 - (stable)
|
||||
#
|
||||
################################################################################
|
||||
|
||||
UseProcessors = 0
|
||||
|
|
@ -231,6 +235,7 @@ UpdateUptimeInterval = 10
|
|||
MaxCoreStuckTime = 0
|
||||
AddonChannel = 1
|
||||
CleanCharacterDB = 1
|
||||
MaxWhoListReturns = 49
|
||||
|
||||
################################################################################
|
||||
# SERVER LOGGING
|
||||
|
|
@ -1282,6 +1287,7 @@ Visibility.AIRelocationNotifyDelay = 1000
|
|||
# Drop rate for currency amount
|
||||
# Default: 1
|
||||
#
|
||||
# Rate.Pet.XP.Kill
|
||||
# Rate.XP.Kill
|
||||
# Rate.XP.Quest
|
||||
# Rate.XP.Explore
|
||||
|
|
@ -1428,6 +1434,7 @@ Rate.Drop.Item.Quest = 1
|
|||
Rate.Drop.Money = 1
|
||||
Rate.Drop.Currency = 1
|
||||
Rate.Drop.Currency.Amount = 1
|
||||
Rate.Pet.XP.Kill = 1
|
||||
Rate.XP.Kill = 1
|
||||
Rate.XP.Quest = 1
|
||||
Rate.XP.Explore = 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue