diff --git a/src/server/game/ArenaSpectator/ArenaSpectator.cpp b/src/server/game/ArenaSpectator/ArenaSpectator.cpp index 6048b7636..0f5e11c35 100644 --- a/src/server/game/ArenaSpectator/ArenaSpectator.cpp +++ b/src/server/game/ArenaSpectator/ArenaSpectator.cpp @@ -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; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 3de529c90..d5a275812 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -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()); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index e71ef8759..5c0260411 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -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; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index f58797ac4..416bb2d0b 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -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: diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d4736d5f7..d7dbf6817 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -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 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 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({ 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(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 diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index bb99778be..0358d14f6 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -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; } diff --git a/src/server/game/Entities/Player/PlayerGossip.cpp b/src/server/game/Entities/Player/PlayerGossip.cpp index 77bc1901a..953adca83 100644 --- a/src/server/game/Entities/Player/PlayerGossip.cpp +++ b/src/server/game/Entities/Player/PlayerGossip.cpp @@ -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: diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp index 1aacad7b7..da9c0e338 100644 --- a/src/server/game/Entities/Player/PlayerStorage.cpp +++ b/src/server/game/Entities/Player/PlayerStorage.cpp @@ -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) diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 5e23e2142..f2191b39e 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -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(); } } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b4c6812af..f7576fbdf 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -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) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index ad55d384c..b4e5cc699 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -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; diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index b33502da2..1e7ecbe8b 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -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); } diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index e2208fa84..f6563042e 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -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())) diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index 7bb348caf..dacd0b5c7 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -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; } diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index e4a1b3c3c..70a2e0513 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -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; diff --git a/src/server/game/Misc/GameGraveyard.cpp b/src/server/game/Misc/GameGraveyard.cpp index 5552a05fd..08d9232bc 100644 --- a/src/server/game/Misc/GameGraveyard.cpp +++ b/src/server/game/Misc/GameGraveyard.cpp @@ -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; } diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp index c9574106d..290837d1f 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp @@ -1038,6 +1038,19 @@ bool ScriptMgr::CanRepopAtGraveyard(Player* player) return true; } +Optional ScriptMgr::OnPlayerIsClass(Player const* player, Classes unitClass, ClassContext context) +{ + if (ScriptRegistry::ScriptPointerList.empty()) + return {}; + for (auto const& [scriptID, script] : ScriptRegistry::ScriptPointerList) + { + Optional scriptResult = script->OnPlayerIsClass(player, unitClass, context); + if (scriptResult) + return scriptResult; + } + return {}; +} + void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure) { ExecuteScript([&](PlayerScript* script) diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.h b/src/server/game/Scripting/ScriptDefines/PlayerScript.h index 68c67fa00..48c72f726 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.h +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.h @@ -322,6 +322,8 @@ public: [[nodiscard]] virtual bool CanRepopAtGraveyard(Player* /*player*/) { return true; } + [[nodiscard]] virtual Optional 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; } diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 0df982ea4..2a7766495 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -401,6 +401,7 @@ public: /* PlayerScript */ bool CanGiveMailRewardAtGiveLevel(Player* player, uint8 level); void OnDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid); bool CanRepopAtGraveyard(Player* player); + std::optional 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); diff --git a/src/server/game/Scripting/ScriptObjectFwd.h b/src/server/game/Scripting/ScriptObjectFwd.h index 67c5e8ca7..a7a899e02 100644 --- a/src/server/game/Scripting/ScriptObjectFwd.h +++ b/src/server/game/Scripting/ScriptObjectFwd.h @@ -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; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 130945722..e333b98ee 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -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 diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 093823a1f..5e4e67f51 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -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 diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 75522d2dd..5939c8fc4 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -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) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index aaeb85080..97cbbd4d2 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -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; diff --git a/src/server/scripts/Commands/cs_reset.cpp b/src/server/scripts/Commands/cs_reset.cpp index 3a2ba01ac..81c4e742a 100644 --- a/src/server/scripts/Commands/cs_reset.cpp +++ b/src/server/scripts/Commands/cs_reset.cpp @@ -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); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp index 7f73b5b37..bbc8a0f48 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp @@ -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; } diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp index 8d357de1e..8f6f20e62 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp @@ -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 diff --git a/src/server/scripts/Kalimdor/zone_moonglade.cpp b/src/server/scripts/Kalimdor/zone_moonglade.cpp index c574da421..df9757da8 100644 --- a/src/server/scripts/Kalimdor/zone_moonglade.cpp +++ b/src/server/scripts/Kalimdor/zone_moonglade.cpp @@ -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; } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index b1ab5028e..d21c9935d 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -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; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index cc9516d3a..a8e4c3ce8 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -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()); } } } diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 88a938c40..b8f95822c 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -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; diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 6688c5e31..e8cf44042 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -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; diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index da7c3e997..d0c6880b5 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -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);