Files
TCPlayerbotCore/src/server/game/AI/PlayerAI/PlayerAI.cpp
T
treeston f5a1b75fbd Core/PlayerAI: More follow-up. Helper functions and some internal cleanup.
(cherry picked from commit 5a3a21c2d02a2e3527ef61641c62d6ad6a44926b)
2016-04-08 20:17:40 +02:00

210 lines
6.1 KiB
C++

/*
* Copyright (C) 2016-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PlayerAI.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
enum Spells
{
/* Generic */
SPELL_AUTO_SHOT = 75,
SPELL_SHOOT = 3018,
SPELL_THROW = 2764,
SPELL_SHOOT_WAND = 5019,
/* Paladin */
PASSIVE_ILLUMINATION = 20215,
/* Priest */
SPELL_SOUL_WARDING = 63574,
SPELL_SPIRIT_REDEMPTION = 20711,
SPELL_SHADOWFORM = 15473,
/* Shaman */
SPELL_TIDAL_FORCE = 582,
SPELL_MANA_TIDE_TOTEM = 590,
SPELL_SHA_NATURE_SWIFT = 591,
SPELL_STORMSTRIKE = 17364,
/* Druid */
SPELL_MOONKIN_FORM = 24858,
SPELL_SWIFTMEND = 18562,
SPELL_DRU_NATURE_SWIFT = 17116,
SPELL_TREE_OF_LIFE = 33891
};
bool PlayerAI::IsPlayerHealer(Player const* who)
{
switch (who->getClass())
{
case CLASS_WARRIOR:
case CLASS_HUNTER:
case CLASS_ROGUE:
case CLASS_DEATH_KNIGHT:
case CLASS_MAGE:
case CLASS_WARLOCK:
default:
return false;
case CLASS_PALADIN:
return who->HasSpell(PASSIVE_ILLUMINATION);
case CLASS_PRIEST:
return who->HasSpell(SPELL_SOUL_WARDING) || who->HasSpell(SPELL_SPIRIT_REDEMPTION);
case CLASS_SHAMAN:
return who->HasSpell(SPELL_MANA_TIDE_TOTEM) || who->HasSpell(SPELL_SHA_NATURE_SWIFT) || who->HasSpell(SPELL_TIDAL_FORCE);
case CLASS_DRUID:
return who->HasSpell(SPELL_SWIFTMEND) || who->HasSpell(SPELL_DRU_NATURE_SWIFT) || who->HasSpell(SPELL_TREE_OF_LIFE);
}
}
bool PlayerAI::IsPlayerRangedAttacker(Player const* who)
{
switch (who->getClass())
{
case CLASS_WARRIOR:
case CLASS_PALADIN:
case CLASS_ROGUE:
case CLASS_DEATH_KNIGHT:
default:
return false;
case CLASS_MAGE:
case CLASS_WARLOCK:
return true;
case CLASS_HUNTER:
{
// check if we have a ranged weapon equipped
Item const* rangedSlot = who->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
if (ItemTemplate const* rangedTemplate = rangedSlot ? rangedSlot->GetTemplate() : nullptr)
if ((1 << rangedTemplate->GetSubClass()) & ITEM_SUBCLASS_MASK_WEAPON_RANGED)
return true;
return false;
}
case CLASS_PRIEST:
return who->HasSpell(SPELL_SHADOWFORM);
case CLASS_SHAMAN:
return !who->HasSpell(SPELL_STORMSTRIKE);
case CLASS_DRUID:
return who->HasSpell(SPELL_MOONKIN_FORM);
}
}
void PlayerAI::DoRangedAttackIfReady()
{
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (!me->isAttackReady(RANGED_ATTACK))
return;
Unit* victim = me->GetVictim();
if (!victim)
return;
uint32 rangedAttackSpell = 0;
Item const* rangedItem = me->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
if (ItemTemplate const* rangedTemplate = rangedItem ? rangedItem->GetTemplate() : nullptr)
{
switch (rangedTemplate->GetSubClass())
{
case ITEM_SUBCLASS_WEAPON_BOW:
case ITEM_SUBCLASS_WEAPON_GUN:
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
rangedAttackSpell = SPELL_SHOOT;
break;
case ITEM_SUBCLASS_WEAPON_THROWN:
rangedAttackSpell = SPELL_THROW;
break;
case ITEM_SUBCLASS_WEAPON_WAND:
rangedAttackSpell = SPELL_SHOOT_WAND;
break;
}
}
if (!rangedAttackSpell)
return;
me->CastSpell(victim, rangedAttackSpell, TRIGGERED_CAST_DIRECTLY);
me->resetAttackTimer(RANGED_ATTACK);
}
void PlayerAI::DoAutoAttackIfReady()
{
if (IsRangedAttacker())
DoRangedAttackIfReady();
else
DoMeleeAttackIfReady();
}
void SimpleCharmedPlayerAI::UpdateAI(const uint32 /*diff*/)
{
Creature* charmer = me->GetCharmer()->ToCreature();
//kill self if charm aura has infinite duration
if (charmer->IsInEvadeMode())
{
Player::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM);
for (Player::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent())
{
me->Kill(me);
return;
}
}
if (charmer->IsInCombat())
{
Unit* target = me->GetVictim();
if (!target || !charmer->IsValidAttackTarget(target))
{
target = charmer->SelectNearestTarget();
if (!target)
return;
if (IsRangedAttacker())
AttackStartCaster(target, 28.0f);
else
AttackStart(target);
}
}
else
{
me->AttackStop();
me->CastStop();
me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
}
DoAutoAttackIfReady();
}
void SimpleCharmedPlayerAI::OnCharmed(bool apply)
{
if (apply)
{
me->CastStop();
me->AttackStop();
}
else
{
me->CastStop();
me->AttackStop();
// @todo only voluntary movement (don't cancel stuff like death grip or charge mid-animation)
me->GetMotionMaster()->Clear();
me->StopMoving();
}
}