/*
* Copyright (C) 2008-2019 TrinityCore
*
* 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 .
*/
#include "CommonHelpers.h"
#include "Common.h"
#include "Item.h"
#include "ItemTemplate.h"
#include "Player.h"
#include "SharedDefines.h"
enum PlayerSpecializationIconicSpellIds
{
/* Warrior - Arms */
SPELL_SWEEPING_STRIKES = 12328,
SPELL_MORTAL_STRIKE = 12294,
SPELL_BLADESTORM = 46924,
/* Warrior - Fury */
SPELL_DEATH_WISH = 12292,
SPELL_BLOODTHIRST = 23881,
PASSIVE_TITANS_GRIP = 46917,
/* Warrior - Protection */
SPELL_VIGILANCE = 50720,
SPELL_DEVASTATE = 20243,
SPELL_SHOCKWAVE = 46968,
/* Paladin - Holy*/
PASSIVE_ILLUMINATION = 20215,
SPELL_HOLY_SHOCK = 20473,
SPELL_BEACON_OF_LIGHT = 53563,
/* Paladin - Protection */
SPELL_BLESS_OF_SANC = 20911,
SPELL_HOLY_SHIELD = 20925,
SPELL_HAMMER_OF_RIGHTEOUS = 53595,
/* Paladin - Retribution */
SPELL_SEAL_OF_COMMAND = 20375,
SPELL_CRUSADER_STRIKE = 35395,
SPELL_DIVINE_STORM = 53385,
/* Hunter - Beast Mastery */
SPELL_BESTIAL_WRATH = 19574,
PASSIVE_BEAST_WITHIN = 34692,
PASSIVE_BEAST_MASTERY = 53270,
/* Hunter - Marksmanship */
SPELL_AIMED_SHOT = 19434,
PASSIVE_TRUESHOT_AURA = 19506,
SPELL_CHIMERA_SHOT = 53209,
/* Hunter - Survival */
PASSIVE_LOCK_AND_LOAD = 56344,
SPELL_WYVERN_STING = 19386,
SPELL_EXPLOSIVE_SHOT = 53301,
/* Rogue - Assassination */
SPELL_COLD_BLOOD = 14177,
SPELL_MUTILATE = 1329,
SPELL_HUNGER_FOR_BLOOD = 51662,
/* Rogue - Combat */
SPELL_BLADE_FLURRY = 13877,
SPELL_ADRENALINE_RUSH = 13750,
SPELL_KILLING_SPREE = 51690,
/* Rogue - Sublety */
SPELL_HEMORRHAGE = 16511,
SPELL_PREMEDITATION = 14183,
SPELL_SHADOW_DANCE = 51713,
/* Priest - Discipline */
PASSIVE_SOUL_WARDING = 63574,
SPELL_POWER_INFUSION = 10060,
SPELL_PENANCE = 47540,
/* Priest - Holy */
PASSIVE_SPIRIT_REDEMPTION = 20711,
SPELL_DESPERATE_PRAYER = 19236,
SPELL_GUARDIAN_SPIRIT = 47788,
/* Priest - Shadow */
SPELL_VAMPIRIC_EMBRACE = 15286,
SPELL_SHADOWFORM = 15473,
SPELL_VAMPIRIC_TOUCH = 34914,
/* Death Knight - Blood */
SPELL_RUNE_TAP = 48982,
SPELL_HYSTERIA = 49016,
SPELL_HEART_STRIKE = 55050,
/* Death Knight - Frost */
PASSIVE_ICY_TALONS = 50887,
SPELL_FROST_STRIKE = 49143,
SPELL_HOWLING_BLAST = 49184,
/* Death Knight - Unholy */
PASSIVE_UNHOLY_BLIGHT = 49194,
PASSIVE_MASTER_OF_GHOUL = 52143,
SPELL_SCOURGE_STRIKE = 55090,
/* Shaman - Elemental*/
PASSIVE_ELEMENTAL_FOCUS = 16164,
SPELL_TOTEM_OF_WRATH = 30706,
SPELL_THUNDERSTORM = 51490,
/* Shaman - Enhancement */
PASSIVE_SPIRIT_WEAPONS = 16268,
SPELL_LAVA_LASH = 60103,
SPELL_FERAL_SPIRIT = 51533,
/* Shaman - Restoration*/
SPELL_SHA_NATURE_SWIFT = 591,
SPELL_MANA_TIDE_TOTEM = 590,
SPELL_RIPTIDE = 61295,
/* Mage - Arcane */
SPELL_FOCUS_MAGIC = 54646,
SPELL_ARCANE_POWER = 12042,
SPELL_ARCANE_BARRAGE = 44425,
/* Mage - Fire */
SPELL_PYROBLAST = 11366,
SPELL_COMBUSTION = 11129,
SPELL_LIVING_BOMB = 44457,
/* Mage - Frost */
SPELL_ICY_VEINS = 12472,
SPELL_ICE_BARRIER = 11426,
SPELL_DEEP_FREEZE = 44572,
/* Warlock - Affliction */
PASSIVE_SIPHON_LIFE = 63108,
SPELL_UNSTABLE_AFFLICTION = 30108,
SPELL_HAUNT = 48181,
/* Warlock - Demonology */
SPELL_SOUL_LINK = 19028,
SPELL_DEMONIC_EMPOWERMENT = 47193,
SPELL_METAMORPHOSIS = 59672,
/* Warlock - Destruction */
SPELL_SHADOWBURN = 17877,
SPELL_CONFLAGRATE = 17962,
SPELL_CHAOS_BOLT = 50796,
/* Druid - Balance */
SPELL_INSECT_SWARM = 5570,
SPELL_MOONKIN_FORM = 24858,
SPELL_STARFALL = 48505,
/* Druid - Feral */
SPELL_SURVIVAL_INSTINCTS = 61336,
SPELL_MANGLE = 33917,
SPELL_BERSERK = 50334,
/* Druid - Restoration */
SPELL_SWIFTMEND = 18562,
SPELL_TREE_OF_LIFE = 33891,
SPELL_WILD_GROWTH = 48438
};
static const uint8 MaximumSpecializationIconicSpells = 3u;
// As it turns out, finding out "how many points does the player have in spec X" is actually really expensive to do frequently
// So instead, we just check for a handful of spells that, realistically, no spec is gonna go without (and "has spell" is cheap!)
// Can players deliberately trick this check? Yes.
// Is it worth doing? No.
// Close enough.
static const uint32 PlayerSpecializationIconicSpells[MAX_CLASSES][MAX_TALENT_TREES][MaximumSpecializationIconicSpells] = {
{ // CLASS_NONE
{0,0,0},
{0,0,0},
{0,0,0}
},
{ // CLASS_WARRIOR
{SPELL_BLADESTORM, SPELL_MORTAL_STRIKE, SPELL_SWEEPING_STRIKES}, // Arms
{PASSIVE_TITANS_GRIP, SPELL_BLOODTHIRST, SPELL_DEATH_WISH}, // Fury
{SPELL_SHOCKWAVE, SPELL_DEVASTATE, SPELL_VIGILANCE} // Protection
},
{ // CLASS_PALADIN
{SPELL_BEACON_OF_LIGHT, SPELL_HOLY_SHOCK, PASSIVE_ILLUMINATION}, // Holy
{SPELL_HAMMER_OF_RIGHTEOUS, SPELL_HOLY_SHIELD, SPELL_BLESS_OF_SANC}, // Protection
{SPELL_DIVINE_STORM, SPELL_CRUSADER_STRIKE, SPELL_SEAL_OF_COMMAND} // Retribution
},
{ // CLASS_HUNTER
{PASSIVE_BEAST_MASTERY, PASSIVE_BEAST_WITHIN, SPELL_BESTIAL_WRATH}, // Beast Mastery
{SPELL_CHIMERA_SHOT, PASSIVE_TRUESHOT_AURA, SPELL_AIMED_SHOT}, // Marksmanship
{SPELL_EXPLOSIVE_SHOT, SPELL_WYVERN_STING, PASSIVE_LOCK_AND_LOAD} // Survival
},
{ // CLASS_ROGUE
{SPELL_HUNGER_FOR_BLOOD, SPELL_MUTILATE, SPELL_COLD_BLOOD}, // Assassination
{SPELL_KILLING_SPREE, SPELL_ADRENALINE_RUSH, SPELL_BLADE_FLURRY}, // Combat
{SPELL_SHADOW_DANCE, SPELL_PREMEDITATION, SPELL_HEMORRHAGE} // Sublety
},
{ // CLASS_PRIEST
{SPELL_PENANCE, SPELL_POWER_INFUSION, PASSIVE_SOUL_WARDING}, // Discipline
{SPELL_GUARDIAN_SPIRIT, PASSIVE_SPIRIT_REDEMPTION, SPELL_DESPERATE_PRAYER}, // Holy
{SPELL_VAMPIRIC_TOUCH, SPELL_SHADOWFORM, SPELL_VAMPIRIC_EMBRACE} // Shadow
},
{ // CLASS_DEATH_KNIGHT
{SPELL_HEART_STRIKE, SPELL_HYSTERIA, SPELL_RUNE_TAP}, // Blood
{SPELL_HOWLING_BLAST, SPELL_FROST_STRIKE, PASSIVE_ICY_TALONS}, // Frost
{SPELL_SCOURGE_STRIKE, PASSIVE_MASTER_OF_GHOUL, PASSIVE_UNHOLY_BLIGHT} // Unholy
},
{ // CLASS_SHAMAN
{SPELL_THUNDERSTORM, SPELL_TOTEM_OF_WRATH, PASSIVE_ELEMENTAL_FOCUS}, // Elemental
{SPELL_FERAL_SPIRIT, SPELL_LAVA_LASH, PASSIVE_SPIRIT_WEAPONS}, // Enhancement
{SPELL_RIPTIDE, SPELL_MANA_TIDE_TOTEM, SPELL_SHA_NATURE_SWIFT} // Restoration
},
{ // CLASS_MAGE
{SPELL_ARCANE_BARRAGE, SPELL_ARCANE_POWER, SPELL_FOCUS_MAGIC}, // Arcane
{SPELL_LIVING_BOMB, SPELL_COMBUSTION, SPELL_PYROBLAST}, // Fire
{SPELL_DEEP_FREEZE, SPELL_ICE_BARRIER, SPELL_ICY_VEINS} // Frost
},
{ // CLASS_WARLOCK
{SPELL_HAUNT, SPELL_UNSTABLE_AFFLICTION, PASSIVE_SIPHON_LIFE}, // Affliction
{SPELL_METAMORPHOSIS, SPELL_DEMONIC_EMPOWERMENT, SPELL_SOUL_LINK}, // Demonology
{SPELL_CHAOS_BOLT, SPELL_CONFLAGRATE, SPELL_SHADOWBURN} // Destruction
},
{ // CLASS_UNK
{0,0,0},
{0,0,0},
{0,0,0}
},
{ // CLASS_DRUID
{SPELL_STARFALL, SPELL_MOONKIN_FORM, SPELL_INSECT_SWARM}, // Balance
{SPELL_BERSERK, SPELL_MANGLE, SPELL_SURVIVAL_INSTINCTS}, // Feral
{SPELL_WILD_GROWTH, SPELL_TREE_OF_LIFE, SPELL_SWIFTMEND} // Restoration
}
};
uint8 Trinity::Helpers::Entity::GetPlayerSpecialization(Player const* who)
{
if (!who)
return 0;
uint8 playerClass = who->GetClass();
for (uint8 tier = 0; tier < MaximumSpecializationIconicSpells; ++tier)
{
for (uint8 tree = 0; tree < MAX_TALENT_TREES; ++tree)
if (PlayerSpecializationIconicSpells[playerClass][tree][tier] && who->HasSpell(PlayerSpecializationIconicSpells[playerClass][tree][tier]))
return tree;
}
return 0;
}
bool Trinity::Helpers::Entity::IsPlayerHealer(Player const* who)
{
if (!who)
return false;
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 (Trinity::Helpers::Entity::GetPlayerSpecialization(who) == SPEC_PALADIN_HOLY);
case CLASS_PRIEST:
return (Trinity::Helpers::Entity::GetPlayerSpecialization(who) != SPEC_PRIEST_SHADOW);
case CLASS_SHAMAN:
return (Trinity::Helpers::Entity::GetPlayerSpecialization(who) == SPEC_SHAMAN_RESTORATION);
case CLASS_DRUID:
return (Trinity::Helpers::Entity::GetPlayerSpecialization(who) == SPEC_DRUID_RESTORATION);
}
}
bool Trinity::Helpers::Entity::IsPlayerRangedAttacker(Player const* who)
{
if (!who)
return false;
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->SubClass) & ITEM_SUBCLASS_MASK_WEAPON_RANGED)
return true;
}
return false;
}
case CLASS_PRIEST:
return (Trinity::Helpers::Entity::GetPlayerSpecialization(who) == SPEC_PRIEST_SHADOW);
case CLASS_SHAMAN:
return (Trinity::Helpers::Entity::GetPlayerSpecialization(who) == SPEC_SHAMAN_ELEMENTAL);
case CLASS_DRUID:
return (Trinity::Helpers::Entity::GetPlayerSpecialization(who) == SPEC_DRUID_BALANCE);
}
}