diff options
-rw-r--r-- | src/server/game/AI/PlayerAI/PlayerAI.cpp | 191 | ||||
-rw-r--r-- | src/server/game/AI/PlayerAI/PlayerAI.h | 14 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/CommonHelpers.cpp | 307 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/CommonHelpers.h | 39 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/SharedDefines.h | 36 |
5 files changed, 398 insertions, 189 deletions
diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp index e0c5ef51125..383c320bf8d 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.cpp +++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp @@ -16,6 +16,7 @@ */ #include "PlayerAI.h" +#include "CommonHelpers.h" #include "Creature.h" #include "Item.h" #include "MotionMaster.h" @@ -27,51 +28,6 @@ #include "SpellHistory.h" #include "SpellMgr.h" -static const uint8 NUM_TALENT_TREES = 3; -static const uint8 NUM_SPEC_ICONICS = 3; - -enum Specs -{ - SPEC_WARRIOR_ARMS = 0, - SPEC_WARRIOR_FURY = 1, - SPEC_WARRIOR_PROTECTION = 2, - - SPEC_PALADIN_HOLY = 0, - SPEC_PALADIN_PROTECTION = 1, - SPEC_PALADIN_RETRIBUTION = 2, - - SPEC_HUNTER_BEAST_MASTERY = 0, - SPEC_HUNTER_MARKSMANSHIP = 1, - SPEC_HUNTER_SURVIVAL = 2, - - SPEC_ROGUE_ASSASSINATION = 0, - SPEC_ROGUE_COMBAT = 1, - SPEC_ROGUE_SUBLETY = 2, - - SPEC_PRIEST_DISCIPLINE = 0, - SPEC_PRIEST_HOLY = 1, - SPEC_PRIEST_SHADOW = 2, - - SPEC_DEATH_KNIGHT_BLOOD = 0, - SPEC_DEATH_KNIGHT_FROST = 1, - SPEC_DEATH_KNIGHT_UNHOLY = 2, - - SPEC_SHAMAN_ELEMENTAL = 0, - SPEC_SHAMAN_ENHANCEMENT = 1, - SPEC_SHAMAN_RESTORATION = 2, - - SPEC_MAGE_ARCANE = 0, - SPEC_MAGE_FIRE = 1, - SPEC_MAGE_FROST = 2, - - SPEC_WARLOCK_AFFLICTION = 0, - SPEC_WARLOCK_DEMONOLOGY = 1, - SPEC_WARLOCK_DESTRUCTION = 2, - - SPEC_DRUID_BALANCE = 0, - SPEC_DRUID_FERAL = 1, - SPEC_DRUID_RESTORATION = 2 -}; enum Spells { /* Generic */ @@ -436,78 +392,10 @@ enum Spells SPELL_LIFEBLOOM = 48451 }; -// 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 SPEC_ICONICS[MAX_CLASSES][NUM_TALENT_TREES][NUM_SPEC_ICONICS] = { - { // 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 - } -}; - PlayerAI::PlayerAI(Player* player) : UnitAI(player), me(player), - _selfSpec(PlayerAI::GetPlayerSpec(player)), - _isSelfHealer(PlayerAI::IsPlayerHealer(player)), - _isSelfRangedAttacker(PlayerAI::IsPlayerRangedAttacker(player)) + _selfSpec(Trinity::Helpers::Entity::GetPlayerSpecialization(player)), + _isSelfHealer(Trinity::Helpers::Entity::IsPlayerHealer(player)), + _isSelfRangedAttacker(Trinity::Helpers::Entity::IsPlayerRangedAttacker(player)) { } @@ -518,78 +406,19 @@ Creature* PlayerAI::GetCharmer() const return nullptr; } -uint8 PlayerAI::GetPlayerSpec(Player const* who) +uint8 PlayerAI::GetSpec(Player const * who) const { - if (!who) - return 0; - - uint8 wClass = who->getClass(); - for (uint8 tier = 0; tier < NUM_SPEC_ICONICS; ++tier) - for (uint8 tree = 0; tree < NUM_TALENT_TREES; ++tree) - if (SPEC_ICONICS[wClass][tree][tier] && who->HasSpell(SPEC_ICONICS[wClass][tree][tier])) - return tree; - - return 0; + return (!who || who == me) ? _selfSpec : Trinity::Helpers::Entity::GetPlayerSpecialization(who); } -bool PlayerAI::IsPlayerHealer(Player const* who) +bool PlayerAI::IsHealer(Player const * who) const { - 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 (PlayerAI::GetPlayerSpec(who) == SPEC_PALADIN_HOLY); - case CLASS_PRIEST: - return (PlayerAI::GetPlayerSpec(who) != SPEC_PRIEST_SHADOW); - case CLASS_SHAMAN: - return (PlayerAI::GetPlayerSpec(who) == SPEC_SHAMAN_RESTORATION); - case CLASS_DRUID: - return (PlayerAI::GetPlayerSpec(who) == SPEC_DRUID_RESTORATION); - } + return (!who || who == me) ? _isSelfHealer : Trinity::Helpers::Entity::IsPlayerHealer(who); } -bool PlayerAI::IsPlayerRangedAttacker(Player const* who) +bool PlayerAI::IsRangedAttacker(Player const * who) const { - 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 (PlayerAI::GetPlayerSpec(who) == SPEC_PRIEST_SHADOW); - case CLASS_SHAMAN: - return (PlayerAI::GetPlayerSpec(who) == SPEC_SHAMAN_ELEMENTAL); - case CLASS_DRUID: - return (PlayerAI::GetPlayerSpec(who) == SPEC_DRUID_BALANCE); - } + return (!who || who == me) ? _isSelfRangedAttacker : Trinity::Helpers::Entity::IsPlayerRangedAttacker(who); } PlayerAI::TargetedSpell PlayerAI::VerifySpellCast(uint32 spellId, Unit* target) diff --git a/src/server/game/AI/PlayerAI/PlayerAI.h b/src/server/game/AI/PlayerAI/PlayerAI.h index ed77e46c1eb..f170865efd8 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.h +++ b/src/server/game/AI/PlayerAI/PlayerAI.h @@ -18,11 +18,13 @@ #ifndef TRINITY_PLAYERAI_H #define TRINITY_PLAYERAI_H +#include "Common.h" #include "UnitAI.h" class Creature; -class Unit; +class Player; class Spell; +class Unit; class TC_GAME_API PlayerAI : public UnitAI { @@ -33,13 +35,9 @@ class TC_GAME_API PlayerAI : public UnitAI // helper functions to determine player info // Return values range from 0 (left-most spec) to 2 (right-most spec). If two specs have the same number of talent points, the left-most of those specs is returned. - static uint8 GetPlayerSpec(Player const* who); - // Return values range from 0 (left-most spec) to 2 (right-most spec). If two specs have the same number of talent points, the left-most of those specs is returned. - uint8 GetSpec(Player const* who = nullptr) const { return (!who || who == me) ? _selfSpec : GetPlayerSpec(who); } - static bool IsPlayerHealer(Player const* who); - bool IsHealer(Player const* who = nullptr) const { return (!who || who == me) ? _isSelfHealer : IsPlayerHealer(who); } - static bool IsPlayerRangedAttacker(Player const* who); - bool IsRangedAttacker(Player const* who = nullptr) const { return (!who || who == me) ? _isSelfRangedAttacker : IsPlayerRangedAttacker(who); } + uint8 GetSpec(Player const* who = nullptr) const; + bool IsHealer(Player const* who = nullptr) const; + bool IsRangedAttacker(Player const* who = nullptr) const; protected: struct TargetedSpell : public std::pair<Spell*, Unit*> diff --git a/src/server/game/Miscellaneous/CommonHelpers.cpp b/src/server/game/Miscellaneous/CommonHelpers.cpp new file mode 100644 index 00000000000..1b4af78cdbc --- /dev/null +++ b/src/server/game/Miscellaneous/CommonHelpers.cpp @@ -0,0 +1,307 @@ +#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); + } +} diff --git a/src/server/game/Miscellaneous/CommonHelpers.h b/src/server/game/Miscellaneous/CommonHelpers.h new file mode 100644 index 00000000000..56483dbdbf0 --- /dev/null +++ b/src/server/game/Miscellaneous/CommonHelpers.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008-2018 TrinityCore <https://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/>. + */ + +#ifndef TRINITY_COMMONHELPERS_H +#define TRINITY_COMMONHELPERS_H + +#include "Define.h" + +class Player; + +namespace Trinity +{ + namespace Helpers + { + namespace Entity + { + // Return values range from 0 (left-most spec) to 2 (right-most spec). If two specs have the same number of talent points, the left-most of those specs is returned. + uint8 GetPlayerSpecialization(Player const* who); + bool IsPlayerHealer(Player const* who); + bool IsPlayerRangedAttacker(Player const* who); + } + } +} + +#endif //TRINITY_COMMONHELPERS_H diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 932becdffc6..4a610af171d 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -129,6 +129,42 @@ enum Classes (1<<(CLASS_MAGE-1)) |(1<<(CLASS_WARLOCK-1))|(1<<(CLASS_DRUID-1)) | \ (1<<(CLASS_DEATH_KNIGHT-1))) +#define MAX_TALENT_TREES 3 + +enum PlayerSpecializations +{ + SPEC_WARRIOR_ARMS = 0, + SPEC_WARRIOR_FURY = 1, + SPEC_WARRIOR_PROTECTION = 2, + SPEC_PALADIN_HOLY = 0, + SPEC_PALADIN_PROTECTION = 1, + SPEC_PALADIN_RETRIBUTION = 2, + SPEC_HUNTER_BEAST_MASTERY = 0, + SPEC_HUNTER_MARKSMANSHIP = 1, + SPEC_HUNTER_SURVIVAL = 2, + SPEC_ROGUE_ASSASSINATION = 0, + SPEC_ROGUE_COMBAT = 1, + SPEC_ROGUE_SUBLETY = 2, + SPEC_PRIEST_DISCIPLINE = 0, + SPEC_PRIEST_HOLY = 1, + SPEC_PRIEST_SHADOW = 2, + SPEC_DEATH_KNIGHT_BLOOD = 0, + SPEC_DEATH_KNIGHT_FROST = 1, + SPEC_DEATH_KNIGHT_UNHOLY = 2, + SPEC_SHAMAN_ELEMENTAL = 0, + SPEC_SHAMAN_ENHANCEMENT = 1, + SPEC_SHAMAN_RESTORATION = 2, + SPEC_MAGE_ARCANE = 0, + SPEC_MAGE_FIRE = 1, + SPEC_MAGE_FROST = 2, + SPEC_WARLOCK_AFFLICTION = 0, + SPEC_WARLOCK_DEMONOLOGY = 1, + SPEC_WARLOCK_DESTRUCTION = 2, + SPEC_DRUID_BALANCE = 0, + SPEC_DRUID_FERAL = 1, + SPEC_DRUID_RESTORATION = 2 +}; + // valid classes for creature_template.unit_class enum UnitClass { |