feat(Core/Unit): New helper IsClass and script hook OnPlayerIsClass (#18243)

* Class Comparison Logic Encapsulation - Parity

* Add Context to IsClass

* Add Unit IsClass script hook

* Replace additional getClass with IsClass

* Update CanUseItem to replace getClass with IsClass

* Add separate context for pet vs ability

* Change Create to Init since not all referenced contexts are creation

* Align spacing in ClassContext

* Drop context on LFGManager max power

* Update IsClass context that wraps around Missle Barrage

* Rename context for swapping weapons

* Be more specific than CLASS_CONTEXT_TALENT

* Remove duplicate context

* Moved IsClass Hook to Player

* Removed unused parameter in virtual base function

* Added maybe_unused to IsClass virtual in order to compile

To match the override signature, the virtual base needs to include the parameter in question, so using [maybe_unused] to signal to the compiler to allow it

* Remove extra blank line

* Add ABILITY_REACTIVE context

* Add context for PET_CHARM

* Remove explicit nullopt check per review

* Code Readability - Change if to if else in pet

Due to the return pattern, this doesn't change functionality in any way

* Add OnPlayer to disambiguate

---------

Co-authored-by: NathanHandley <nathanhandley@protonmail.com>
This commit is contained in:
Nathan Handley 2024-02-10 09:25:00 -06:00 committed by GitHub
parent c47c945aa4
commit df33a57b78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 344 additions and 280 deletions

View file

@ -42,7 +42,7 @@ bool ArenaSpectator::HandleSpectatorSpectateCommand(ChatHandler* handler, std::s
return true;
}
if (player->getClass() == CLASS_DEATH_KNIGHT && player->GetMapId() == 609)
if (player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TELEPORT) && player->GetMapId() == 609)
{
handler->PSendSysMessage("Death Knights can't spectate before finishing questline.");
return true;

View file

@ -1055,7 +1055,7 @@ namespace lfg
baseAP = p->GetTotalAttackPowerValue(BASE_ATTACK);
rangedAP = p->GetTotalAttackPowerValue(RANGED_ATTACK);
maxPower = 0;
if (p->getClass() == CLASS_DRUID)
if (p->IsClass(CLASS_DRUID))
maxPower = p->GetMaxPower(POWER_MANA);
else
maxPower = (p->getPowerType() == POWER_RAGE || p->getPowerType() == POWER_RUNIC_POWER) ? p->GetMaxPower(p->getPowerType()) / 10 : p->GetMaxPower(p->getPowerType());

View file

@ -1196,8 +1196,8 @@ bool Creature::isCanInteractWithBattleMaster(Player* player, bool msg) const
bool Creature::isCanTrainingAndResetTalentsOf(Player* player) const
{
return player->GetLevel() >= 10
&& GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS
&& player->getClass() == GetCreatureTemplate()->trainer_class;
&& GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS
&& player->IsClass((Classes)GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER);
}
bool Creature::IsValidTrainerForPlayer(Player* player, uint32* npcFlags /*= nullptr*/) const
@ -1211,7 +1211,7 @@ bool Creature::IsValidTrainerForPlayer(Player* player, uint32* npcFlags /*= null
{
case TRAINER_TYPE_CLASS:
case TRAINER_TYPE_PETS:
if (m_creatureInfo->trainer_class && m_creatureInfo->trainer_class != player->getClass())
if (m_creatureInfo->trainer_class && !player->IsClass((Classes)m_creatureInfo->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
{
if (npcFlags)
*npcFlags &= ~UNIT_NPC_FLAG_TRAINER_CLASS;

View file

@ -107,7 +107,7 @@ void Pet::AddToWorld()
{
if (Player* owner = GetOwner())
{
if (getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)
if (getPetType() == SUMMON_PET && owner->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET))
{
owner->SetLastPetSpell(GetUInt32Value(UNIT_CREATED_BY_SPELL));
}
@ -238,7 +238,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
bool forceLoadFromDB = false;
sScriptMgr->OnBeforeLoadPetFromDB(owner, petEntry, petnumber, current, forceLoadFromDB);
if (!forceLoadFromDB && (owner->getClass() == CLASS_DEATH_KNIGHT && !owner->CanSeeDKPet())) // DK Pet exception
if (!forceLoadFromDB && (owner->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_PET) && !owner->CanSeeDKPet())) // DK Pet exception
return false;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(petInfo->CreatedBySpellId);
@ -1043,12 +1043,12 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
if (petType == MAX_PET_TYPE)
{
// The petType was not overwritten by the hook, continue with default initialization
if (owner->getClass() == CLASS_WARLOCK ||
owner->getClass() == CLASS_SHAMAN || // Fire Elemental
owner->getClass() == CLASS_DEATH_KNIGHT || // Risen Ghoul
owner->getClass() == CLASS_MAGE) // Water Elemental with glyph
if (owner->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET) ||
owner->IsClass(CLASS_SHAMAN, CLASS_CONTEXT_PET) || // Fire Elemental
owner->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_PET) || // Risen Ghoul
owner->IsClass(CLASS_MAGE, CLASS_CONTEXT_PET)) // Water Elemental with glyph
petType = SUMMON_PET;
else if (owner->getClass() == CLASS_HUNTER)
else if (owner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
{
petType = HUNTER_PET;
}
@ -1080,7 +1080,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
uint32 attackTime = BASE_ATTACK_TIME;
if (owner->getClass() != CLASS_HUNTER && cinfo->BaseAttackTime >= 1000)
if (!owner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET) && cinfo->BaseAttackTime >= 1000)
attackTime = cinfo->BaseAttackTime;
SetAttackTime(BASE_ATTACK, attackTime);
@ -2299,17 +2299,14 @@ bool Pet::IsPermanentPetFor(Player* owner) const
switch (getPetType())
{
case SUMMON_PET:
switch (owner->getClass())
{
case CLASS_WARLOCK:
return GetCreatureTemplate()->type == CREATURE_TYPE_DEMON;
case CLASS_DEATH_KNIGHT:
return GetCreatureTemplate()->type == CREATURE_TYPE_UNDEAD;
case CLASS_MAGE:
return GetEntry() == 37994;
default:
return false;
}
if (owner->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET))
return GetCreatureTemplate()->type == CREATURE_TYPE_DEMON;
else if (owner->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_PET))
return GetCreatureTemplate()->type == CREATURE_TYPE_UNDEAD;
else if (owner->IsClass(CLASS_MAGE, CLASS_CONTEXT_PET))
return GetEntry() == 37994;
else
return false;
case HUNTER_PET:
return true;
default:

View file

@ -553,7 +553,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
// set starting level
uint32 start_level = getClass() != CLASS_DEATH_KNIGHT
uint32 start_level = !IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT)
? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)
: sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
@ -568,7 +568,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
InitRunes();
SetUInt32Value(PLAYER_FIELD_COINAGE, getClass() != CLASS_DEATH_KNIGHT
SetUInt32Value(PLAYER_FIELD_COINAGE, !IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT)
? sWorld->getIntConfig(CONFIG_START_PLAYER_MONEY)
: sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_MONEY));
SetHonorPoints(sWorld->getIntConfig(CONFIG_START_HONOR_POINTS));
@ -633,7 +633,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
switch (iProto->Spells[0].SpellCategory)
{
case SPELL_CATEGORY_FOOD: // food
count = getClass() == CLASS_DEATH_KNIGHT ? 10 : 4;
count = IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT) ? 10 : 4;
break;
case SPELL_CATEGORY_DRINK: // drink
count = 2;
@ -1269,6 +1269,15 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
return true;
}
bool Player::IsClass(Classes unitClass, ClassContext context) const
{
Optional<bool> scriptResult = sScriptMgr->OnPlayerIsClass(this, unitClass, context);
if (scriptResult != std::nullopt)
return *scriptResult;
else
return (getClass() == unitClass);
}
void Player::ToggleAFK()
{
ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK);
@ -1460,7 +1469,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
}
else
{
if (getClass() == CLASS_DEATH_KNIGHT && GetMapId() == 609 && !IsGameMaster() && !HasSpell(50977))
if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TELEPORT) && GetMapId() == 609 && !IsGameMaster() && !HasSpell(50977))
{
SendTransferAborted(mapid, TRANSFER_ABORT_UNIQUE_MESSAGE, 1);
return false;
@ -1745,7 +1754,7 @@ void Player::RegenerateAll()
Regenerate(POWER_MANA);
// Runes act as cooldowns, and they don't need to send any data
if (getClass() == CLASS_DEATH_KNIGHT)
if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
for (uint8 i = 0; i < MAX_RUNES; ++i)
{
// xinef: implement grace
@ -1775,7 +1784,7 @@ void Player::RegenerateAll()
}
Regenerate(POWER_RAGE);
if (getClass() == CLASS_DEATH_KNIGHT)
if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
Regenerate(POWER_RUNIC_POWER);
m_regenTimerCount -= 2000;
@ -2106,7 +2115,7 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask)
// pussywizard: many npcs have missing conditions for class training and rogue trainer can for eg. train dual wield to a shaman :/ too many to change in sql and watch in the future
// pussywizard: this function is not used when talking, but when already taking action (buy spell, reset talents, show spell list)
if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS && getClass() != creature->GetCreatureTemplate()->trainer_class)
if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS && !IsClass((Classes)creature->GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
return nullptr;
return creature;
@ -6393,7 +6402,7 @@ void Player::DuelComplete(DuelCompleteType type)
opponent->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
// Credit for quest Death's Challenge
if (getClass() == CLASS_DEATH_KNIGHT && opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE)
if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_QUEST) && opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE)
{
opponent->CastSpell(opponent, 52994, true);
}
@ -6789,7 +6798,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
}
// Druids get feral AP bonus from weapon dps (also use DPS from ScalingStatValue)
if (getClass() == CLASS_DRUID)
if (IsClass(CLASS_DRUID, CLASS_CONTEXT_STATS))
{
int32 dpsMod = 0;
int32 feral_bonus = 0;
@ -9846,7 +9855,7 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
if (apply)
{
m_spellMods[mod->op].push_back(mod);
if (getClass() == CLASS_MAGE)
if (IsClass(CLASS_MAGE, CLASS_CONTEXT_ABILITY))
m_spellMods[mod->op].sort(MageSpellModPred());
else
m_spellMods[mod->op].sort(SpellModPred());
@ -10280,7 +10289,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
// only one mount ID for both sides. Probably not good to use 315 in case DBC nodes
// change but I couldn't find a suitable alternative. OK to use class because only DK
// can use this taxi.
uint32 mount_display_id = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetTeamId(true), npc == nullptr || (sourcenode == 315 && getClass() == CLASS_DEATH_KNIGHT));
uint32 mount_display_id = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetTeamId(true), npc == nullptr || (sourcenode == 315 && IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TAXI)));
// in spell case allow 0 model
if ((mount_display_id == 0 && spellid == 0) || sourcepath == 0)
@ -11329,7 +11338,7 @@ WorldLocation Player::GetStartPosition() const
{
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(true), getClass());
uint32 mapId = info->mapId;
if (getClass() == CLASS_DEATH_KNIGHT && HasSpell(50977))
if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT) && HasSpell(50977))
return WorldLocation(0, 2352.0f, -5709.0f, 154.5f, 0.0f);
return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0);
}
@ -11823,7 +11832,7 @@ void Player::LearnDefaultSkill(uint32 skillId, uint16 rank)
{
skillValue = maxValue;
}
else if (getClass() == CLASS_DEATH_KNIGHT)
else if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_SKILL))
{
skillValue = std::min(std::max<uint16>({ 1, uint16((GetLevel() - 1) * 5) }), maxValue);
}
@ -11856,7 +11865,7 @@ void Player::LearnDefaultSkill(uint32 skillId, uint16 rank)
{
skillValue = maxValue;
}
else if (getClass() == CLASS_DEATH_KNIGHT)
else if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_SKILL))
{
skillValue = std::min(std::max<uint16>({ uint16(1), uint16((GetLevel() - 1) * 5) }), maxValue);
}
@ -13381,7 +13390,7 @@ static RuneType runeSlotTypes[MAX_RUNES] =
void Player::InitRunes()
{
if (getClass() != CLASS_DEATH_KNIGHT)
if (!IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return;
m_runes = new Runes;
@ -13547,7 +13556,7 @@ uint32 Player::CalculateTalentsPoints() const
uint32 base_talent = GetLevel() < 10 ? 0 : GetLevel() - 9;
uint32 talentPointsForLevel = 0;
if (getClass() != CLASS_DEATH_KNIGHT || GetMapId() != 609)
if (!IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TALENT_POINT_CALC) || GetMapId() != 609)
{
talentPointsForLevel = base_talent;
}
@ -14179,19 +14188,21 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
bool Player::CanResummonPet(uint32 spellid)
{
if (getClass() == CLASS_DEATH_KNIGHT)
if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_PET))
{
if (CanSeeDKPet())
return true;
else if (spellid == 52150) // Raise Dead
return false;
}
else if (getClass() == CLASS_MAGE)
if (IsClass(CLASS_MAGE, CLASS_CONTEXT_PET))
{
if (HasSpell(31687) && HasAura(70937)) //Has [Summon Water Elemental] spell and [Glyph of Eternal Water].
return true;
}
else if (getClass() == CLASS_HUNTER)
if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
{
return true;
}
@ -15176,7 +15187,7 @@ void Player::ActivateSpec(uint8 spec)
AutoUnequipOffhandIfNeed();
// Xinef: Patch 3.2.0: Switching spec removes paladins spell Righteous Fury (25780)
if (getClass() == CLASS_PALADIN)
if (IsClass(CLASS_PALADIN, CLASS_CONTEXT_ABILITY))
RemoveAurasDueToSpell(25780);
// Xinef: Remove talented single target auras at other targets

View file

@ -1112,6 +1112,8 @@ public:
static bool BuildEnumData(PreparedQueryResult result, WorldPacket* data);
[[nodiscard]] bool IsClass(Classes playerClass, ClassContext context = CLASS_CONTEXT_NONE) const override;
void SetInWater(bool apply);
[[nodiscard]] bool IsInWater() const override { return m_isInWater; }

View file

@ -109,7 +109,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
canTalk = false;
break;
case GOSSIP_OPTION_STABLEPET:
if (getClass() != CLASS_HUNTER)
if (!IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
canTalk = false;
break;
case GOSSIP_OPTION_QUESTGIVER:

View file

@ -133,8 +133,6 @@ void Player::SetSheath(SheathState sheathed)
uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const
{
uint8 playerClass = getClass();
uint8 slots[4];
slots[0] = NULL_SLOT;
slots[1] = NULL_SLOT;
@ -246,23 +244,23 @@ uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) c
switch (proto->SubClass)
{
case ITEM_SUBCLASS_ARMOR_LIBRAM:
if (playerClass == CLASS_PALADIN)
if (IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED;
break;
case ITEM_SUBCLASS_ARMOR_IDOL:
if (playerClass == CLASS_DRUID)
if (IsClass(CLASS_DRUID, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED;
break;
case ITEM_SUBCLASS_ARMOR_TOTEM:
if (playerClass == CLASS_SHAMAN)
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED;
break;
case ITEM_SUBCLASS_ARMOR_MISC:
if (playerClass == CLASS_WARLOCK)
if (IsClass(CLASS_WARLOCK, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED;
break;
case ITEM_SUBCLASS_ARMOR_SIGIL:
if (playerClass == CLASS_DEATH_KNIGHT)
if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_EQUIP_RELIC))
slots[0] = EQUIPMENT_SLOT_RANGED;
break;
}
@ -2270,16 +2268,13 @@ InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const
// In fact it's a visual bug, everything works properly... I need sniffs of operations with
// binded to account items from off server.
switch (getClass())
if (IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_ARMOR_CLASS) || IsClass(CLASS_WARRIOR, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
{
case CLASS_HUNTER:
case CLASS_SHAMAN:
allowEquip = (itemSkill == SKILL_MAIL);
break;
case CLASS_PALADIN:
case CLASS_WARRIOR:
allowEquip = (itemSkill == SKILL_PLATE_MAIL);
break;
allowEquip = (itemSkill == SKILL_PLATE_MAIL);
}
else if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_EQUIP_ARMOR_CLASS) || IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
{
allowEquip = (itemSkill == SKILL_MAIL);
}
}
if (!allowEquip && GetSkillValue(itemSkill) == 0)
@ -2394,39 +2389,40 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje
return EQUIP_ERR_CANT_EQUIP_SKILL;
}
uint8 _class = getClass();
if (proto->Class == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->SubClass]) == 0)
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
if (proto->Class == ITEM_CLASS_ARMOR)
{
// Check for shields
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_SHIELD && !(_class == CLASS_PALADIN || _class == CLASS_WARRIOR || _class == CLASS_SHAMAN))
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_SHIELD && !(
IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_SHIELDS)
|| IsClass(CLASS_WARRIOR, CLASS_CONTEXT_EQUIP_SHIELDS)
|| IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_SHIELDS)))
{
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
}
// Check for librams.
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_LIBRAM && _class != CLASS_PALADIN)
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_LIBRAM && !IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_RELIC))
{
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
}
// CHeck for idols.
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_IDOL && _class != CLASS_DRUID)
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_IDOL && !IsClass(CLASS_DRUID, CLASS_CONTEXT_EQUIP_RELIC))
{
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
}
// Check for totems.
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_TOTEM && _class != CLASS_SHAMAN)
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_TOTEM && !IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_RELIC))
{
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
}
// Check for sigils.
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_SIGIL && _class != CLASS_DEATH_KNIGHT)
if (proto->SubClass == ITEM_SUBCLASS_ARMOR_SIGIL && !IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_EQUIP_RELIC))
{
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
}
@ -2436,33 +2432,33 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje
proto->InventoryType != INVTYPE_CLOAK)
{
uint32 subclassToCompare = ITEM_SUBCLASS_ARMOR_CLOTH;
switch (_class)
if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_EQUIP_ARMOR_CLASS) || IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
{
case CLASS_WARRIOR:
if (proto->HasStat(ITEM_MOD_SPELL_POWER) || proto->HasSpellPowerStat())
{
return EQUIP_ERR_CANT_DO_RIGHT_NOW;
}
[[fallthrough]];
case CLASS_DEATH_KNIGHT:
case CLASS_PALADIN:
subclassToCompare = ITEM_SUBCLASS_ARMOR_PLATE;
break;
case CLASS_HUNTER:
case CLASS_SHAMAN:
subclassToCompare = ITEM_SUBCLASS_ARMOR_MAIL;
break;
case CLASS_ROGUE:
if (proto->HasStat(ITEM_MOD_SPELL_POWER) || proto->HasSpellPowerStat())
{
return EQUIP_ERR_CANT_DO_RIGHT_NOW;
}
[[fallthrough]];
case CLASS_DRUID:
subclassToCompare = ITEM_SUBCLASS_ARMOR_LEATHER;
break;
default:
break;
subclassToCompare = ITEM_SUBCLASS_ARMOR_PLATE;
}
else if (IsClass(CLASS_WARRIOR, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
{
if ((proto->HasStat(ITEM_MOD_SPELL_POWER) || proto->HasSpellPowerStat()))
{
return EQUIP_ERR_CANT_DO_RIGHT_NOW;
}
subclassToCompare = ITEM_SUBCLASS_ARMOR_PLATE;
}
else if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_EQUIP_ARMOR_CLASS) || IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
{
subclassToCompare = ITEM_SUBCLASS_ARMOR_MAIL;
}
else if (IsClass(CLASS_DRUID, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
{
subclassToCompare = ITEM_SUBCLASS_ARMOR_LEATHER;
}
else if (IsClass(CLASS_ROGUE, CLASS_CONTEXT_EQUIP_ARMOR_CLASS))
{
if (proto->HasStat(ITEM_MOD_SPELL_POWER) || proto->HasSpellPowerStat())
{
return EQUIP_ERR_CANT_DO_RIGHT_NOW;
}
subclassToCompare = ITEM_SUBCLASS_ARMOR_LEATHER;
}
if (proto->SubClass > subclassToCompare)
@ -2772,7 +2768,7 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
if (pProto && IsInCombat() && (pProto->Class == ITEM_CLASS_WEAPON || pProto->InventoryType == INVTYPE_RELIC) && m_weaponChangeTimer == 0)
{
uint32 cooldownSpell = getClass() == CLASS_ROGUE ? 6123 : 6119;
uint32 cooldownSpell = IsClass(CLASS_ROGUE, CLASS_CONTEXT_WEAPON_SWAP) ? 6123 : 6119;
SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell);
if (!spellProto)
@ -4645,7 +4641,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
}
case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon
{
if (getClass() == CLASS_SHAMAN)
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_ABILITY))
{
float addValue = 0.0f;
if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)

View file

@ -346,134 +346,127 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
switch (getClass())
if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS))
{
case CLASS_HUNTER:
val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f;
break;
case CLASS_ROGUE:
case CLASS_WARRIOR:
val2 = level + GetStat(STAT_AGILITY) - 10.0f;
break;
case CLASS_DRUID:
switch (GetShapeshiftForm())
{
case FORM_CAT:
case FORM_BEAR:
case FORM_DIREBEAR:
val2 = 0.0f;
break;
default:
val2 = GetStat(STAT_AGILITY) - 10.0f;
break;
}
val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f;
}
else if (IsClass(CLASS_ROGUE, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARRIOR, CLASS_CONTEXT_STATS))
{
val2 = level + GetStat(STAT_AGILITY) - 10.0f;
}
else if (IsClass(CLASS_DRUID, CLASS_CONTEXT_STATS))
{
switch (GetShapeshiftForm())
{
case FORM_CAT:
case FORM_BEAR:
case FORM_DIREBEAR:
val2 = 0.0f;
break;
default:
val2 = GetStat(STAT_AGILITY) - 10.0f;
break;
}
}
else
{
val2 = GetStat(STAT_AGILITY) - 10.0f;
}
}
else
{
switch (getClass())
if (IsClass(CLASS_PALADIN, CLASS_CONTEXT_STATS) || IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARRIOR, CLASS_CONTEXT_STATS))
{
case CLASS_PALADIN:
case CLASS_DEATH_KNIGHT:
case CLASS_WARRIOR:
val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
break;
case CLASS_HUNTER:
case CLASS_SHAMAN:
case CLASS_ROGUE:
val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f;
break;
case CLASS_DRUID:
val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
}
else if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS) || IsClass(CLASS_SHAMAN, CLASS_CONTEXT_STATS) || IsClass(CLASS_ROGUE, CLASS_CONTEXT_STATS))
{
val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f;
}
else if (IsClass(CLASS_DRUID, CLASS_CONTEXT_STATS))
{
// Check if Predatory Strikes is skilled
float mLevelMult = 0.0f;
float weapon_bonus = 0.0f;
if (IsInFeralForm())
{
Unit::AuraEffectList const& mDummy = GetAuraEffectsByType(SPELL_AURA_DUMMY);
for (Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
{
// Check if Predatory Strikes is skilled
float mLevelMult = 0.0f;
float weapon_bonus = 0.0f;
if (IsInFeralForm())
AuraEffect* aurEff = *itr;
if (aurEff->GetSpellInfo()->SpellIconID == 1563)
{
Unit::AuraEffectList const& mDummy = GetAuraEffectsByType(SPELL_AURA_DUMMY);
for (Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
switch (aurEff->GetEffIndex())
{
AuraEffect* aurEff = *itr;
if (aurEff->GetSpellInfo()->SpellIconID == 1563)
case 0: // Predatory Strikes (effect 0)
mLevelMult = CalculatePct(1.0f, aurEff->GetAmount());
break;
case 1: // Predatory Strikes (effect 1)
if (Item* mainHand = m_items[EQUIPMENT_SLOT_MAINHAND])
{
switch (aurEff->GetEffIndex())
// also gains % attack power from equipped weapon
ItemTemplate const* proto = mainHand->GetTemplate();
if (!proto)
continue;
uint32 ap = proto->getFeralBonus();
// Get AP Bonuses from weapon
for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
{
case 0: // Predatory Strikes (effect 0)
mLevelMult = CalculatePct(1.0f, aurEff->GetAmount());
if (i >= proto->StatsCount)
break;
case 1: // Predatory Strikes (effect 1)
if (Item* mainHand = m_items[EQUIPMENT_SLOT_MAINHAND])
{
// also gains % attack power from equipped weapon
ItemTemplate const* proto = mainHand->GetTemplate();
if (!proto)
continue;
uint32 ap = proto->getFeralBonus();
// Get AP Bonuses from weapon
for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
{
if (i >= proto->StatsCount)
break;
if (proto->ItemStat[i].ItemStatType == ITEM_MOD_ATTACK_POWER)
ap += proto->ItemStat[i].ItemStatValue;
}
// Get AP Bonuses from weapon spells
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
// no spell
if (!proto->Spells[i].SpellId || proto->Spells[i].SpellTrigger != ITEM_SPELLTRIGGER_ON_EQUIP)
continue;
// check if it is valid spell
SpellInfo const* spellproto = sSpellMgr->GetSpellInfo(proto->Spells[i].SpellId);
if (!spellproto)
continue;
for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
if (spellproto->Effects[j].ApplyAuraName == SPELL_AURA_MOD_ATTACK_POWER)
ap += spellproto->Effects[j].CalcValue();
}
weapon_bonus = CalculatePct(float(ap), aurEff->GetAmount());
}
break;
default:
break;
if (proto->ItemStat[i].ItemStatType == ITEM_MOD_ATTACK_POWER)
ap += proto->ItemStat[i].ItemStatValue;
}
}
}
}
switch (GetShapeshiftForm())
{
case FORM_CAT:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f + GetStat(STAT_AGILITY) - 20.0f + weapon_bonus + m_baseFeralAP;
break;
case FORM_BEAR:
case FORM_DIREBEAR:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + weapon_bonus + m_baseFeralAP;
break;
case FORM_MOONKIN:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + m_baseFeralAP;
// Get AP Bonuses from weapon spells
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
// no spell
if (!proto->Spells[i].SpellId || proto->Spells[i].SpellTrigger != ITEM_SPELLTRIGGER_ON_EQUIP)
continue;
// check if it is valid spell
SpellInfo const* spellproto = sSpellMgr->GetSpellInfo(proto->Spells[i].SpellId);
if (!spellproto)
continue;
for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
if (spellproto->Effects[j].ApplyAuraName == SPELL_AURA_MOD_ATTACK_POWER)
ap += spellproto->Effects[j].CalcValue();
}
weapon_bonus = CalculatePct(float(ap), aurEff->GetAmount());
}
break;
default:
val2 = GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
break;
}
}
break;
}
case CLASS_MAGE:
case CLASS_PRIEST:
case CLASS_WARLOCK:
val2 = GetStat(STAT_STRENGTH) - 10.0f;
}
switch (GetShapeshiftForm())
{
case FORM_CAT:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f + GetStat(STAT_AGILITY) - 20.0f + weapon_bonus + m_baseFeralAP;
break;
case FORM_BEAR:
case FORM_DIREBEAR:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + weapon_bonus + m_baseFeralAP;
break;
case FORM_MOONKIN:
val2 = (GetLevel() * mLevelMult) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + m_baseFeralAP;
break;
default:
val2 = GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
break;
}
}
else if (IsClass(CLASS_MAGE, CLASS_CONTEXT_STATS) || IsClass(CLASS_PRIEST, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARLOCK, CLASS_CONTEXT_STATS))
{
val2 = GetStat(STAT_STRENGTH) - 10.0f;
}
}
@ -521,7 +514,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
UpdateDamagePhysical(BASE_ATTACK);
if (CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
UpdateDamagePhysical(OFF_ATTACK);
if (getClass() == CLASS_SHAMAN || getClass() == CLASS_PALADIN) // mental quickness
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_STATS) || IsClass(CLASS_PALADIN, CLASS_CONTEXT_STATS)) // mental quickness
UpdateSpellDamageAndHealingBonus();
}
}

View file

@ -8834,7 +8834,7 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp
// Convert recently used Blood Rune to Death Rune
if (Player* player = ToPlayer())
{
if (player->getClass() != CLASS_DEATH_KNIGHT)
if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return false;
// xinef: not true
@ -9565,7 +9565,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
// Item - Death Knight T10 Melee 4P Bonus
if (auraSpellInfo->Id == 70656)
{
if (GetTypeId() != TYPEID_PLAYER || getClass() != CLASS_DEATH_KNIGHT)
if (GetTypeId() != TYPEID_PLAYER || !IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return false;
for (uint8 i = 0; i < MAX_RUNES; ++i)
@ -9576,7 +9576,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
else if (auraSpellInfo->SpellIconID == 85)
{
Player* plr = ToPlayer();
if (!plr || plr->getClass() != CLASS_DEATH_KNIGHT || !procSpell)
if (!plr || !plr->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY) || !procSpell)
return false;
if (!plr->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD))
@ -13823,7 +13823,7 @@ void Unit::ClearInCombat()
else if (Player* player = ToPlayer())
{
player->UpdatePotionCooldown();
if (player->getClass() == CLASS_DEATH_KNIGHT)
if (player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
for (uint8 i = 0; i < MAX_RUNES; ++i)
player->SetGracePeriod(i, 0);
}
@ -16361,7 +16361,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
if (procExtra & PROC_EX_DODGE)
{
// Update AURA_STATE on dodge
if (getClass() != CLASS_ROGUE) // skip Rogue Riposte
if (!IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY_REACTIVE)) // skip Rogue Riposte
{
ModifyAuraState(AURA_STATE_DEFENSE, true);
StartReactiveTimer(REACTIVE_DEFENSE);
@ -16371,7 +16371,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
if (procExtra & PROC_EX_PARRY)
{
// For Hunters only Counterattack (skip Mongoose bite)
if (getClass() == CLASS_HUNTER)
if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_ABILITY_REACTIVE))
{
ModifyAuraState(AURA_STATE_HUNTER_PARRY, true);
StartReactiveTimer(REACTIVE_HUNTER_PARRY);
@ -16394,7 +16394,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
// Overpower on victim dodge
if (procExtra & PROC_EX_DODGE)
{
if (getClass() == CLASS_WARRIOR)
if (IsClass(CLASS_WARRIOR, CLASS_CONTEXT_ABILITY_REACTIVE))
{
AddComboPoints(target, 1);
StartReactiveTimer(REACTIVE_OVERPOWER);
@ -17201,9 +17201,9 @@ void Unit::ClearAllReactives()
if (HasAuraState(AURA_STATE_DEFENSE))
ModifyAuraState(AURA_STATE_DEFENSE, false);
if (getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY))
if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_ABILITY_REACTIVE) && HasAuraState(AURA_STATE_HUNTER_PARRY))
ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
if (getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER)
if (IsClass(CLASS_WARRIOR, CLASS_CONTEXT_ABILITY_REACTIVE) && GetTypeId() == TYPEID_PLAYER)
ClearComboPoints();
}
@ -17227,11 +17227,11 @@ void Unit::UpdateReactives(uint32 p_time)
ModifyAuraState(AURA_STATE_DEFENSE, false);
break;
case REACTIVE_HUNTER_PARRY:
if (getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY))
if (IsClass(CLASS_HUNTER, CLASS_CONTEXT_ABILITY_REACTIVE) && HasAuraState(AURA_STATE_HUNTER_PARRY))
ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
break;
case REACTIVE_OVERPOWER:
if (getClass() == CLASS_WARRIOR)
if (IsClass(CLASS_WARRIOR, CLASS_CONTEXT_ABILITY_REACTIVE))
{
ClearComboPoints();
}
@ -18096,7 +18096,7 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
// Spirit of Redemption
// if talent known but not triggered (check priest class for speedup check)
bool spiritOfRedemption = false;
if (victim->GetTypeId() == TYPEID_PLAYER && victim->getClass() == CLASS_PRIEST && !victim->ToPlayer()->HasPlayerFlag(PLAYER_FLAGS_IS_OUT_OF_BOUNDS))
if (victim->GetTypeId() == TYPEID_PLAYER && victim->IsClass(CLASS_PRIEST, CLASS_CONTEXT_ABILITY) && !victim->ToPlayer()->HasPlayerFlag(PLAYER_FLAGS_IS_OUT_OF_BOUNDS))
{
if (AuraEffect* aurEff = victim->GetAuraEffectDummy(20711))
{
@ -18704,7 +18704,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
GetMotionMaster()->MoveIdle();
StopMoving();
if (charmer->GetTypeId() == TYPEID_PLAYER && charmer->getClass() == CLASS_WARLOCK && ToCreature()->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON)
if (charmer->GetTypeId() == TYPEID_PLAYER && charmer->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET_CHARM) && ToCreature()->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON)
{
// Disable CreatureAI/SmartAI and switch to CharmAI when charmed by warlock
Creature* charmed = ToCreature();
@ -18770,7 +18770,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
playerCharmer->PossessSpellInitialize();
break;
case CHARM_TYPE_CHARM:
if (GetTypeId() == TYPEID_UNIT && charmer->getClass() == CLASS_WARLOCK)
if (GetTypeId() == TYPEID_UNIT && charmer->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET_CHARM))
{
CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate();
if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
@ -18892,7 +18892,7 @@ void Unit::RemoveCharmedBy(Unit* charmer)
ClearUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
break;
case CHARM_TYPE_CHARM:
if (GetTypeId() == TYPEID_UNIT && charmer->getClass() == CLASS_WARLOCK)
if (GetTypeId() == TYPEID_UNIT && charmer->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET_CHARM))
{
CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate();
if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)

View file

@ -440,6 +440,29 @@ enum DamageEffectType : uint8
SELF_DAMAGE = 5
};
// Used for IsClass hook
enum ClassContext : uint8
{
CLASS_CONTEXT_NONE = 0, // Default
CLASS_CONTEXT_INIT = 1,
CLASS_CONTEXT_TELEPORT = 2,
CLASS_CONTEXT_QUEST = 3,
CLASS_CONTEXT_STATS = 4,
CLASS_CONTEXT_TAXI = 5,
CLASS_CONTEXT_SKILL = 6,
CLASS_CONTEXT_TALENT_POINT_CALC = 7,
CLASS_CONTEXT_ABILITY = 8,
CLASS_CONTEXT_ABILITY_REACTIVE = 9,
CLASS_CONTEXT_PET = 10,
CLASS_CONTEXT_PET_CHARM = 11,
CLASS_CONTEXT_EQUIP_RELIC = 12,
CLASS_CONTEXT_EQUIP_SHIELDS = 13,
CLASS_CONTEXT_EQUIP_ARMOR_CLASS = 14,
CLASS_CONTEXT_WEAPON_SWAP = 15,
CLASS_CONTEXT_GRAVEYARD = 16,
CLASS_CONTEXT_CLASS_TRAINER = 17
};
// Value masks for UNIT_FIELD_FLAGS
// EnumUtils: DESCRIBE THIS
enum UnitFlags : uint32
@ -1436,6 +1459,7 @@ public:
void setRace(uint8 race);
[[nodiscard]] uint32 getRaceMask() const { return 1 << (getRace(true) - 1); }
[[nodiscard]] uint8 getClass() const { return GetByteValue(UNIT_FIELD_BYTES_0, 1); }
[[nodiscard]] virtual bool IsClass(Classes unitClass, [[maybe_unused]] ClassContext context = CLASS_CONTEXT_NONE) const { return (getClass() == unitClass); }
[[nodiscard]] uint32 getClassMask() const { return 1 << (getClass() - 1); }
[[nodiscard]] uint8 getGender() const { return GetByteValue(UNIT_FIELD_BYTES_0, 2); }
[[nodiscard]] DisplayRace GetDisplayRaceFromModelId(uint32 modelId) const;

View file

@ -72,7 +72,7 @@ void Vehicle::Install()
{
if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(_vehicleInfo->m_powerDisplayId))
_me->setPowerType(Powers(powerDisplay->PowerType));
else if (_me->getClass() == CLASS_ROGUE)
else if (_me->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY))
_me->setPowerType(POWER_ENERGY);
}

View file

@ -1983,7 +1983,7 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
return ERR_IN_NON_RANDOM_BG;
// don't let Death Knights join BG queues when they are not allowed to be teleported yet
if (member->getClass() == CLASS_DEATH_KNIGHT && member->GetMapId() == 609 && !member->IsGameMaster() && !member->HasSpell(50977))
if (member->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TELEPORT) && member->GetMapId() == 609 && !member->IsGameMaster() && !member->HasSpell(50977))
return ERR_GROUP_JOIN_BATTLEGROUND_FAIL;
if (!member->GetBGAccessByLevel(bgTemplate->GetBgTypeID()))

View file

@ -184,7 +184,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
err = ERR_BATTLEGROUND_QUEUED_FOR_RATED;
}
// don't let Death Knights join BG queues when they are not allowed to be teleported yet
else if (_player->getClass() == CLASS_DEATH_KNIGHT && _player->GetMapId() == 609 && !_player->IsGameMaster() && !_player->HasSpell(50977))
else if (_player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TELEPORT) && _player->GetMapId() == 609 && !_player->IsGameMaster() && !_player->HasSpell(50977))
{
err = ERR_BATTLEGROUND_NONE;
}

View file

@ -83,7 +83,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
{
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
bool lootAllowed = creature && creature->IsAlive() == (player->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY) && creature->loot.loot_type == LOOT_PICKPOCKETING);
if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
{
player->SendLootError(lguid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL);
@ -162,7 +162,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
case HighGuid::Vehicle:
{
Creature* creature = player->GetMap()->GetCreature(guid);
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
bool lootAllowed = creature && creature->IsAlive() == (player->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY) && creature->loot.loot_type == LOOT_PICKPOCKETING);
if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE))
{
loot = &creature->loot;
@ -382,7 +382,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
{
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
bool lootAllowed = creature && creature->IsAlive() == (player->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY) && creature->loot.loot_type == LOOT_PICKPOCKETING);
if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
return;

View file

@ -202,7 +202,7 @@ GraveyardStruct const* Graveyard::GetClosestGraveyard(Player* player, TeamId tea
GRAVEYARD_ARCHERUS = 1405
};
if (player->getClass() != CLASS_DEATH_KNIGHT && (graveyardLink.safeLocId == GRAVEYARD_EBON_HOLD || graveyardLink.safeLocId == GRAVEYARD_ARCHERUS))
if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_GRAVEYARD) && (graveyardLink.safeLocId == GRAVEYARD_EBON_HOLD || graveyardLink.safeLocId == GRAVEYARD_ARCHERUS))
{
continue;
}

View file

@ -1038,6 +1038,19 @@ bool ScriptMgr::CanRepopAtGraveyard(Player* player)
return true;
}
Optional<bool> ScriptMgr::OnPlayerIsClass(Player const* player, Classes unitClass, ClassContext context)
{
if (ScriptRegistry<PlayerScript>::ScriptPointerList.empty())
return {};
for (auto const& [scriptID, script] : ScriptRegistry<PlayerScript>::ScriptPointerList)
{
Optional<bool> scriptResult = script->OnPlayerIsClass(player, unitClass, context);
if (scriptResult)
return scriptResult;
}
return {};
}
void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure)
{
ExecuteScript<PlayerScript>([&](PlayerScript* script)

View file

@ -322,6 +322,8 @@ public:
[[nodiscard]] virtual bool CanRepopAtGraveyard(Player* /*player*/) { return true; }
[[nodiscard]] virtual Optional<bool> OnPlayerIsClass(Player const* /*player*/, Classes /*playerClass*/, ClassContext /*context*/) { return std::nullopt; }
virtual void OnGetMaxSkillValue(Player* /*player*/, uint32 /*skill*/, int32& /*result*/, bool /*IsPure*/) { }
[[nodiscard]] virtual bool OnPlayerHasActivePowerType(Player const* /*player*/, Powers /*power*/) { return false; }

View file

@ -401,6 +401,7 @@ public: /* PlayerScript */
bool CanGiveMailRewardAtGiveLevel(Player* player, uint8 level);
void OnDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid);
bool CanRepopAtGraveyard(Player* player);
std::optional<bool> OnPlayerIsClass(Player const* player, Classes playerClass, ClassContext context);
void OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure);
bool OnPlayerHasActivePowerType(Player const* player, Powers power);
void OnUpdateGatheringSkill(Player* player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32& gain);

View file

@ -79,6 +79,7 @@ class WorldSocket;
enum ArenaTeamInfoType : uint8;
enum AuraRemoveMode : uint8;
enum BattlegroundDesertionType : uint8;
enum ClassContext : uint8;
enum ContentLevels : uint8;
enum DamageEffectType : uint8;
enum EnchantmentSlot : uint8;

View file

@ -2027,7 +2027,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
if (!target->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT))
{
target->SetShapeshiftForm(FORM_NONE);
if (target->getClass() == CLASS_DRUID)
if (target->IsClass(CLASS_DRUID, CLASS_CONTEXT_ABILITY))
{
target->setPowerType(POWER_MANA);
// Remove movement impairing effects also when shifting out
@ -2106,7 +2106,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
if (target->GetTypeId() == TYPEID_PLAYER)
target->ToPlayer()->InitDataForForm();
if (target->getClass() == CLASS_DRUID)
if (target->IsClass(CLASS_DRUID, CLASS_CONTEXT_ABILITY))
{
// Dash
if (AuraEffect* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, 0, 0, 0x8))
@ -6038,7 +6038,7 @@ void AuraEffect::HandleAuraConvertRune(AuraApplication const* aurApp, uint8 mode
Player* player = target->ToPlayer();
if (player->getClass() != CLASS_DEATH_KNIGHT)
if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return;
uint32 runes = m_amount;
@ -6310,7 +6310,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const
{
if (target->GetTypeId() != TYPEID_PLAYER)
return;
if (target->ToPlayer()->getClass() != CLASS_DEATH_KNIGHT)
if (!target->ToPlayer()->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return;
// timer expired - remove death runes

View file

@ -1876,7 +1876,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
break;
if (target->GetTypeId() != TYPEID_PLAYER)
break;
if (target->ToPlayer()->getClass() != CLASS_DEATH_KNIGHT)
if (!target->ToPlayer()->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
break;
// aura removed - remove death runes

View file

@ -4807,7 +4807,7 @@ void Spell::SendSpellGo()
}
if ((m_caster->GetTypeId() == TYPEID_PLAYER)
&& (m_caster->getClass() == CLASS_DEATH_KNIGHT)
&& (m_caster->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
&& m_spellInfo->RuneCostID
&& m_spellInfo->PowerType == POWER_RUNE)
{
@ -5396,7 +5396,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 RuneCostID)
return SPELL_CAST_OK;
}
if (player->getClass() != CLASS_DEATH_KNIGHT)
if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return SPELL_CAST_OK;
SpellRuneCostEntry const* src = sSpellRuneCostStore.LookupEntry(RuneCostID);
@ -5437,7 +5437,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 RuneCostID)
void Spell::TakeRunePower(bool didHit)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER || m_caster->getClass() != CLASS_DEATH_KNIGHT)
if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_caster->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return;
SpellRuneCostEntry const* runeCostData = sSpellRuneCostStore.LookupEntry(m_spellInfo->RuneCostID);
@ -6408,7 +6408,7 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_ALREADY_HAVE_CHARM;
}
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARLOCK && strict)
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->IsClass(CLASS_WARLOCK, CLASS_CONTEXT_PET) && strict)
if (Pet* pet = m_caster->ToPlayer()->GetPet())
pet->CastSpell(pet, 32752, true, nullptr, nullptr, pet->GetGUID()); //starting cast, trigger pet stun (cast by pet so it doesn't attack player)

View file

@ -3077,7 +3077,7 @@ void Spell::EffectTameCreature(SpellEffIndex /*effIndex*/)
if (creatureTarget->IsPet())
return;
if (m_caster->getClass() != CLASS_HUNTER)
if (!m_caster->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
return;
// cast finish successfully
@ -3209,7 +3209,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex)
pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
// Reset cooldowns
if (owner->getClass() != CLASS_HUNTER)
if (!owner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
{
pet->m_CreatureSpellCooldowns.clear();
owner->PetSpellInitialize();
@ -5746,7 +5746,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
Player* player = m_caster->ToPlayer();
if (player->getClass() != CLASS_DEATH_KNIGHT)
if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
return;
// needed later
@ -5814,7 +5814,7 @@ void Spell::EffectCreateTamedPet(SpellEffIndex effIndex)
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->GetPetGUID() || unitTarget->getClass() != CLASS_HUNTER)
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->GetPetGUID() || !unitTarget->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET))
return;
uint32 creatureEntry = m_spellInfo->Effects[effIndex].MiscValue;

View file

@ -140,7 +140,7 @@ public:
uint8 oldLevel = playerTarget->GetLevel();
// set starting level
uint32 startLevel = playerTarget->getClass() != CLASS_DEATH_KNIGHT
uint32 startLevel = !playerTarget->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT)
? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)
: sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);

View file

@ -1029,7 +1029,7 @@ class spell_class_call_handler : public SpellScript
targets.remove_if([spellInfo](WorldObject const* target) -> bool
{
Player const* player = target->ToPlayer();
if (!player || player->getClass() == CLASS_DEATH_KNIGHT) // ignore all death knights from whatever spell, for some reason the condition below is not working x.x
if (!player || player->IsClass(CLASS_DEATH_KNIGHT)) // ignore all death knights from whatever spell, for some reason the condition below is not working x.x
{
return true;
}

View file

@ -447,9 +447,9 @@ public:
PlayerAbility_Timer = urand(8000, 10000);
PlayerClass = target->getClass() - 1;
if (PlayerClass == CLASS_DRUID - 1)
if (target->IsClass(CLASS_DRUID))
PlayerClass = CLASS_DRUID;
else if (PlayerClass == CLASS_PRIEST - 1 && target->HasSpell(15473))
else if (target->IsClass(CLASS_PRIEST) && target->HasSpell(15473))
PlayerClass = CLASS_PRIEST; // shadow priest
SiphonSoul_Timer = 99999; // buff lasts 30 sec

View file

@ -65,7 +65,7 @@ public:
{
case GOSSIP_ACTION_INFO_DEF + 1:
CloseGossipMenuFor(player);
if (player->getClass() == CLASS_DRUID && player->GetTeamId() == TEAM_HORDE)
if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_TAXI) && player->GetTeamId() == TEAM_HORDE)
player->ActivateTaxiPathTo(TAXI_PATH_ID_HORDE);
break;
case GOSSIP_ACTION_INFO_DEF + 2:
@ -80,29 +80,42 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->getClass() != CLASS_DRUID)
if (player->GetTeamId() != TEAM_HORDE)
{
SendGossipMenuFor(player, 4916, creature->GetGUID());
}
else if (player->GetTeamId() != TEAM_HORDE)
{
if (player->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE)
if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_QUEST) && player->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE)
{
AddGossipItemFor(player, 4042, 2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
}
SendGossipMenuFor(player, 4917, creature->GetGUID());
if (player->IsClass(CLASS_DRUID))
{
SendGossipMenuFor(player, 4917, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 4916, creature->GetGUID());
}
}
else if (player->getClass() == CLASS_DRUID && player->GetTeamId() == TEAM_HORDE)
else if (player->GetTeamId() == TEAM_HORDE)
{
AddGossipItemFor(player, 4042, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_TAXI))
{
AddGossipItemFor(player, 4042, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
}
if (player->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE)
if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_QUEST) && player->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE)
{
AddGossipItemFor(player, 4042, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
}
SendGossipMenuFor(player, 4918, creature->GetGUID());
if (player->IsClass(CLASS_DRUID))
{
SendGossipMenuFor(player, 4918, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 4916, creature->GetGUID());
}
}
return true;
}
@ -176,7 +189,7 @@ public:
{
case GOSSIP_ACTION_INFO_DEF + 1:
CloseGossipMenuFor(player);
if (player->getClass() == CLASS_DRUID && player->GetTeamId() == TEAM_ALLIANCE)
if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_TAXI) && player->GetTeamId() == TEAM_ALLIANCE)
player->ActivateTaxiPathTo(TAXI_PATH_ID_ALLY);
break;
case GOSSIP_ACTION_INFO_DEF + 2:
@ -191,29 +204,41 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->getClass() != CLASS_DRUID)
if (player->GetTeamId() != TEAM_ALLIANCE)
{
SendGossipMenuFor(player, 4913, creature->GetGUID());
}
else if (player->GetTeamId() != TEAM_ALLIANCE)
{
if (player->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE)
if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_QUEST) && player->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE)
{
AddGossipItemFor(player, 4041, 2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
}
SendGossipMenuFor(player, 4915, creature->GetGUID());
if (player->IsClass(CLASS_DRUID))
{
SendGossipMenuFor(player, 4915, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 4913, creature->GetGUID());
}
}
else if (player->getClass() == CLASS_DRUID && player->GetTeamId() == TEAM_ALLIANCE)
else if (player->GetTeamId() == TEAM_ALLIANCE)
{
AddGossipItemFor(player, 4041, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_TAXI))
{
AddGossipItemFor(player, 4041, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
}
if (player->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE)
if (player->IsClass(CLASS_DRUID, CLASS_CONTEXT_QUEST) && player->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE)
{
AddGossipItemFor(player, 4041, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
}
SendGossipMenuFor(player, 4914, creature->GetGUID());
if (player->IsClass(CLASS_DRUID))
{
SendGossipMenuFor(player, 4914, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 4913, creature->GetGUID());
}
}
return true;
}

View file

@ -853,12 +853,12 @@ public:
{
if (p->getPowerType() != POWER_MANA)
return true;
if (p->getClass() == CLASS_HUNTER)
if (p->IsClass(CLASS_HUNTER))
return true;
uint8 maxIndex = p->GetMostPointsTalentTree();
if ((p->getClass() == CLASS_PALADIN && maxIndex >= 1) || (p->getClass() == CLASS_SHAMAN && maxIndex == 1) || (p->getClass() == CLASS_DRUID && maxIndex == 1))
if ((p->IsClass(CLASS_PALADIN) && maxIndex >= 1) || (p->IsClass(CLASS_SHAMAN) && maxIndex == 1) || (p->IsClass(CLASS_DRUID) && maxIndex == 1))
return true;
if (_removeHealers == ((p->getClass() == CLASS_DRUID && maxIndex == 2) || (p->getClass() == CLASS_PALADIN && maxIndex == 0) || (p->getClass() == CLASS_PRIEST && maxIndex <= 1) || (p->getClass() == CLASS_SHAMAN && maxIndex == 2)))
if (_removeHealers == ((p->IsClass(CLASS_DRUID) && maxIndex == 2) || (p->IsClass(CLASS_PALADIN) && maxIndex == 0) || (p->IsClass(CLASS_PRIEST) && maxIndex <= 1) || (p->IsClass(CLASS_SHAMAN) && maxIndex == 2)))
return true;
return false;

View file

@ -2856,8 +2856,7 @@ public:
{
c->AI()->AttackStart(target);
DoZoneInCombat(c);
uint8 Class = target->getClass();
if (Class != CLASS_DRUID)
if (!target->IsClass(CLASS_DRUID))
if (Player* p = target->ToPlayer())
{
if (Item* i = p->GetWeaponForAttack(BASE_ATTACK))
@ -2869,7 +2868,7 @@ public:
target->CastSpell(c, 60352, true); // Mirror Image, clone visual appearance
}
c->AI()->DoAction(Class);
c->AI()->DoAction(target->getClass());
}
}
}

View file

@ -1014,7 +1014,7 @@ class spell_dk_blood_boil : public SpellScript
bool Load() override
{
_executed = false;
return GetCaster()->GetTypeId() == TYPEID_PLAYER && GetCaster()->getClass() == CLASS_DEATH_KNIGHT;
return GetCaster()->GetTypeId() == TYPEID_PLAYER && GetCaster()->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY);
}
void HandleAfterHit()
@ -1258,7 +1258,7 @@ class spell_dk_death_gate : public SpellScript
SpellCastResult CheckClass()
{
if (GetCaster()->getClass() != CLASS_DEATH_KNIGHT)
if (!GetCaster()->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
{
SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_MUST_BE_DEATH_KNIGHT);
return SPELL_FAILED_CUSTOM_ERROR;

View file

@ -446,7 +446,7 @@ class spell_pet_hit_expertise_scalling : public AuraScript
{
if (Player* modOwner = GetUnitOwner()->GetSpellModOwner())
{
if (modOwner->getClass() == CLASS_HUNTER)
if (modOwner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS))
amount = CalculatePercent(modOwner->m_modRangedHitChance, 8.0f, 8.0f);
else if (modOwner->getPowerType() == POWER_MANA)
amount = CalculatePercent(modOwner->m_modSpellHitChance, 17.0f, 8.0f);
@ -459,7 +459,7 @@ class spell_pet_hit_expertise_scalling : public AuraScript
{
if (Player* modOwner = GetUnitOwner()->GetSpellModOwner())
{
if (modOwner->getClass() == CLASS_HUNTER)
if (modOwner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS))
amount = CalculatePercent(modOwner->m_modRangedHitChance, 8.0f, 17.0f);
else if (modOwner->getPowerType() == POWER_MANA)
amount = CalculatePercent(modOwner->m_modSpellHitChance, 17.0f, 17.0f);
@ -472,7 +472,7 @@ class spell_pet_hit_expertise_scalling : public AuraScript
{
if (Player* modOwner = GetUnitOwner()->GetSpellModOwner())
{
if (modOwner->getClass() == CLASS_HUNTER)
if (modOwner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_STATS))
amount = CalculatePercent(modOwner->m_modRangedHitChance, 8.0f, 26.0f);
else if (modOwner->getPowerType() == POWER_MANA)
amount = CalculatePercent(modOwner->m_modSpellHitChance, 17.0f, 26.0f);
@ -1673,7 +1673,7 @@ class spell_gen_pet_summoned : public SpellScript
Player* player = GetCaster()->ToPlayer();
if (player->GetLastPetNumber() && player->CanResummonPet(player->GetLastPetSpell()))
{
PetType newPetType = (player->getClass() == CLASS_HUNTER) ? HUNTER_PET : SUMMON_PET;
PetType newPetType = (player->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET)) ? HUNTER_PET : SUMMON_PET;
Pet* newPet = new Pet(player, newPetType);
if (newPet->LoadPetFromDB(player, 0, player->GetLastPetNumber(), true, 100))
{
@ -3545,11 +3545,11 @@ class spell_gen_on_tournament_mount : public AuraScript
case NPC_ARGENT_WARHORSE:
{
if (player->HasAchieved(ACHIEVEMENT_CHAMPION_ALLIANCE) || player->HasAchieved(ACHIEVEMENT_CHAMPION_HORDE))
return player->getClass() == CLASS_DEATH_KNIGHT ? SPELL_PENNANT_EBON_BLADE_CHAMPION : SPELL_PENNANT_ARGENT_CRUSADE_CHAMPION;
return player->IsClass(CLASS_DEATH_KNIGHT) ? SPELL_PENNANT_EBON_BLADE_CHAMPION : SPELL_PENNANT_ARGENT_CRUSADE_CHAMPION;
else if (player->HasAchieved(ACHIEVEMENT_ARGENT_VALOR))
return player->getClass() == CLASS_DEATH_KNIGHT ? SPELL_PENNANT_EBON_BLADE_VALIANT : SPELL_PENNANT_ARGENT_CRUSADE_VALIANT;
return player->IsClass(CLASS_DEATH_KNIGHT) ? SPELL_PENNANT_EBON_BLADE_VALIANT : SPELL_PENNANT_ARGENT_CRUSADE_VALIANT;
else
return player->getClass() == CLASS_DEATH_KNIGHT ? SPELL_PENNANT_EBON_BLADE_ASPIRANT : SPELL_PENNANT_ARGENT_CRUSADE_ASPIRANT;
return player->IsClass(CLASS_DEATH_KNIGHT) ? SPELL_PENNANT_EBON_BLADE_ASPIRANT : SPELL_PENNANT_ARGENT_CRUSADE_ASPIRANT;
}
default:
return 0;

View file

@ -3469,7 +3469,7 @@ class spell_item_refocus : public SpellScript
{
Player* caster = GetCaster()->ToPlayer();
if (!caster || caster->getClass() != CLASS_HUNTER)
if (!caster || !caster->IsClass(CLASS_HUNTER, CLASS_CONTEXT_ABILITY))
return;
caster->RemoveCategoryCooldown(SPELL_CATEGORY_AIMED_MULTI);