diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-12-02 15:29:02 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2024-12-02 15:29:02 +0100 |
commit | 1fb4acc25ae89360e71d33a8f7cba99bcc028b32 (patch) | |
tree | 6a12714df0e1bd8a96b1f5452fbc4efcb83f7200 | |
parent | 49699bc966e4543044da7f1fd75d57fbebfac4e4 (diff) |
Core/Quests: Implemented QUEST_OBJECTIVE_KILL_WITH_LABEL
-rw-r--r-- | sql/updates/hotfixes/master/2024_12_02_00_hotfixes.sql | 23 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.cpp | 8 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.h | 6 | ||||
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.cpp | 15 | ||||
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.h | 1 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2LoadInfo.h | 24 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 24 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 2 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 14 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 10 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 3 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 10 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 1 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 1 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 16 |
17 files changed, 162 insertions, 3 deletions
diff --git a/sql/updates/hotfixes/master/2024_12_02_00_hotfixes.sql b/sql/updates/hotfixes/master/2024_12_02_00_hotfixes.sql new file mode 100644 index 00000000000..a3946e51902 --- /dev/null +++ b/sql/updates/hotfixes/master/2024_12_02_00_hotfixes.sql @@ -0,0 +1,23 @@ +-- +-- Table structure for table `creature_label` +-- +DROP TABLE IF EXISTS `creature_label`; +CREATE TABLE `creature_label` ( + `ID` int unsigned NOT NULL DEFAULT '0', + `LabelID` int NOT NULL DEFAULT '0', + `CreatureDifficultyID` int unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` int NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Table structure for table `gameobject_label` +-- +DROP TABLE IF EXISTS `gameobject_label`; +CREATE TABLE `gameobject_label` ( + `ID` int unsigned NOT NULL DEFAULT '0', + `LabelID` int NOT NULL DEFAULT '0', + `GameObjectID` int unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` int NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 89abafe7c36..f13443a976f 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -507,6 +507,10 @@ void HotfixDatabaseConnection::DoPrepareStatements() PREPARE_MAX_ID_STMT(HOTFIX_SEL_CREATURE_FAMILY, "SELECT MAX(ID) + 1 FROM creature_family", CONNECTION_SYNCH); PREPARE_LOCALE_STMT(HOTFIX_SEL_CREATURE_FAMILY, "SELECT ID, Name_lang FROM creature_family_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?", CONNECTION_SYNCH); + // CreatureLabel.db2 + PrepareStatement(HOTFIX_SEL_CREATURE_LABEL, "SELECT ID, LabelID, CreatureDifficultyID FROM creature_label WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_CREATURE_LABEL, "SELECT MAX(ID) + 1 FROM creature_label", CONNECTION_SYNCH); + // CreatureModelData.db2 PrepareStatement(HOTFIX_SEL_CREATURE_MODEL_DATA, "SELECT ID, GeoBox1, GeoBox2, GeoBox3, GeoBox4, GeoBox5, GeoBox6, Flags, FileDataID, WalkSpeed, " "RunSpeed, BloodID, FootprintTextureID, FootprintTextureLength, FootprintTextureWidth, FootprintParticleScale, FoleyMaterialID, " @@ -668,6 +672,10 @@ void HotfixDatabaseConnection::DoPrepareStatements() "ClientItemID, Unknown1100 FROM gameobject_display_info WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_GAMEOBJECT_DISPLAY_INFO, "SELECT MAX(ID) + 1 FROM gameobject_display_info", CONNECTION_SYNCH); + // GameobjectLabel.db2 + PrepareStatement(HOTFIX_SEL_GAMEOBJECT_LABEL, "SELECT ID, LabelID, GameObjectID FROM gameobject_label WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_GAMEOBJECT_LABEL, "SELECT MAX(ID) + 1 FROM gameobject_label", CONNECTION_SYNCH); + // Gameobjects.db2 PrepareStatement(HOTFIX_SEL_GAMEOBJECTS, "SELECT Name, PosX, PosY, PosZ, Rot1, Rot2, Rot3, Rot4, ID, OwnerID, DisplayID, Scale, TypeID, " "PhaseUseFlags, PhaseID, PhaseGroupID, Unknown1100, PropValue1, PropValue2, PropValue3, PropValue4, PropValue5, PropValue6, PropValue7, " diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index a77157ff1bd..1a7d158cdd7 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -297,6 +297,9 @@ enum HotfixDatabaseStatements : uint32 HOTFIX_SEL_CREATURE_FAMILY_MAX_ID, HOTFIX_SEL_CREATURE_FAMILY_LOCALE, + HOTFIX_SEL_CREATURE_LABEL, + HOTFIX_SEL_CREATURE_LABEL_MAX_ID, + HOTFIX_SEL_CREATURE_MODEL_DATA, HOTFIX_SEL_CREATURE_MODEL_DATA_MAX_ID, @@ -381,6 +384,9 @@ enum HotfixDatabaseStatements : uint32 HOTFIX_SEL_GAMEOBJECT_DISPLAY_INFO, HOTFIX_SEL_GAMEOBJECT_DISPLAY_INFO_MAX_ID, + HOTFIX_SEL_GAMEOBJECT_LABEL, + HOTFIX_SEL_GAMEOBJECT_LABEL_MAX_ID, + HOTFIX_SEL_GAMEOBJECTS, HOTFIX_SEL_GAMEOBJECTS_MAX_ID, HOTFIX_SEL_GAMEOBJECTS_LOCALE, diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index f431db82c34..60018c25803 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -157,6 +157,7 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND { .Name = "Player Condition", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false }, { .Name = "Private Object", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false }, { .Name = "String ID", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = true }, + { .Name = "Label", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false }, }; ConditionSourceInfo::ConditionSourceInfo(WorldObject const* target0, WorldObject const* target1, WorldObject const* target2) @@ -675,6 +676,14 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const condMeets = go->HasStringId(ConditionStringValue1); break; } + case CONDITION_LABEL: + { + if (Creature const* creature = object->ToCreature()) + condMeets = creature->HasLabel(ConditionValue1); + else if (GameObject const* go = object->ToGameObject()) + condMeets = go->HasLabel(ConditionValue1); + break; + } default: break; } @@ -893,6 +902,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() const case CONDITION_STRING_ID: mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT; break; + case CONDITION_LABEL: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT; + break; default: ABORT_MSG("Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); break; @@ -2592,6 +2604,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const case CONDITION_GAMEMASTER: case CONDITION_PRIVATE_OBJECT: case CONDITION_STRING_ID: + case CONDITION_LABEL: break; case CONDITION_DIFFICULTY_ID: if (!sDifficultyStore.LookupEntry(cond->ConditionValue1)) @@ -3882,7 +3895,7 @@ int32 GetUnitConditionVariable(Unit const* unit, Unit const* otherUnit, UnitCond case UnitConditionVariable::IsMounted: return unit->GetMountDisplayId() != 0; case UnitConditionVariable::Label: - break; + return unit->IsCreature() && unit->ToCreature()->HasLabel(value) ? value : 0; case UnitConditionVariable::IsMySummon: return otherUnit && (otherUnit->GetCharmerGUID() == unit->GetGUID() || otherUnit->GetCreatorGUID() == unit->GetGUID()); case UnitConditionVariable::IsSummoner: diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 98ba91e204b..ed7b83c94e5 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -117,6 +117,7 @@ enum ConditionTypes CONDITION_PLAYER_CONDITION = 56, // PlayerConditionId 0 0 true if player satisfies PlayerCondition CONDITION_PRIVATE_OBJECT = 57, // 0 0 0 true if entity is private object CONDITION_STRING_ID = 58, + CONDITION_LABEL = 59, // Label 0 0 true if creature/gameobject has specified Label in CreatureLabel.db2/GameObjectLabel.db2 CONDITION_MAX }; diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h index d7306aabb70..27297ec5218 100644 --- a/src/server/game/DataStores/DB2LoadInfo.h +++ b/src/server/game/DataStores/DB2LoadInfo.h @@ -1461,6 +1461,18 @@ struct CreatureFamilyLoadInfo static constexpr DB2LoadInfo Instance{ Fields, 11, &CreatureFamilyMeta::Instance, HOTFIX_SEL_CREATURE_FAMILY }; }; +struct CreatureLabelLoadInfo +{ + static constexpr DB2FieldMeta Fields[3] = + { + { false, FT_INT, "ID" }, + { true, FT_INT, "LabelID" }, + { false, FT_INT, "CreatureDifficultyID" }, + }; + + static constexpr DB2LoadInfo Instance{ Fields, 3, &CreatureLabelMeta::Instance, HOTFIX_SEL_CREATURE_LABEL }; +}; + struct CreatureModelDataLoadInfo { static constexpr DB2FieldMeta Fields[41] = @@ -2025,6 +2037,18 @@ struct GameobjectDisplayInfoLoadInfo static constexpr DB2LoadInfo Instance{ Fields, 15, &GameObjectDisplayInfoMeta::Instance, HOTFIX_SEL_GAMEOBJECT_DISPLAY_INFO }; }; +struct GameobjectLabelLoadInfo +{ + static constexpr DB2FieldMeta Fields[3] = + { + { false, FT_INT, "ID" }, + { true, FT_INT, "LabelID" }, + { false, FT_INT, "GameObjectID" }, + }; + + static constexpr DB2LoadInfo Instance{ Fields, 3, &GameObjectLabelMeta::Instance, HOTFIX_SEL_GAMEOBJECT_LABEL }; +}; + struct GameobjectsLoadInfo { static constexpr DB2FieldMeta Fields[25] = diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index c4087827424..dd2f9664503 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -122,6 +122,7 @@ DB2Storage<CorruptionEffectsEntry> sCorruptionEffectsStore("Corrupt DB2Storage<CreatureDisplayInfoEntry> sCreatureDisplayInfoStore("CreatureDisplayInfo.db2", &CreatureDisplayInfoLoadInfo::Instance); DB2Storage<CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore("CreatureDisplayInfoExtra.db2", &CreatureDisplayInfoExtraLoadInfo::Instance); DB2Storage<CreatureFamilyEntry> sCreatureFamilyStore("CreatureFamily.db2", &CreatureFamilyLoadInfo::Instance); +DB2Storage<CreatureLabelEntry> sCreatureLabelStore("CreatureLabel.db2", &CreatureLabelLoadInfo::Instance); DB2Storage<CreatureModelDataEntry> sCreatureModelDataStore("CreatureModelData.db2", &CreatureModelDataLoadInfo::Instance); DB2Storage<CreatureTypeEntry> sCreatureTypeStore("CreatureType.db2", &CreatureTypeLoadInfo::Instance); DB2Storage<CriteriaEntry> sCriteriaStore("Criteria.db2", &CriteriaLoadInfo::Instance); @@ -147,6 +148,7 @@ DB2Storage<FriendshipRepReactionEntry> sFriendshipRepReactionStore("Fri DB2Storage<FriendshipReputationEntry> sFriendshipReputationStore("FriendshipReputation.db2", &FriendshipReputationLoadInfo::Instance); DB2Storage<GameObjectArtKitEntry> sGameObjectArtKitStore("GameObjectArtKit.db2", &GameobjectArtKitLoadInfo::Instance); DB2Storage<GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore("GameObjectDisplayInfo.db2", &GameobjectDisplayInfoLoadInfo::Instance); +DB2Storage<GameObjectLabelEntry> sGameObjectLabelStore("GameObjectLabel.db2", &GameobjectLabelLoadInfo::Instance); DB2Storage<GameObjectsEntry> sGameObjectsStore("GameObjects.db2", &GameobjectsLoadInfo::Instance); DB2Storage<GarrAbilityEntry> sGarrAbilityStore("GarrAbility.db2", &GarrAbilityLoadInfo::Instance); DB2Storage<GarrBuildingEntry> sGarrBuildingStore("GarrBuilding.db2", &GarrBuildingLoadInfo::Instance); @@ -476,6 +478,7 @@ namespace std::unordered_map<int32, ConditionalChrModelEntry const*> _conditionalChrModelsByChrModelId; std::unordered_map<uint32 /*contentTuningId*/, std::vector<ConditionalContentTuningEntry const*>> _conditionalContentTuning; std::unordered_set<std::pair<uint32, int32>> _contentTuningLabels; + std::unordered_map<uint32 /*creatureDifficultyId*/, std::vector<int32>> _creatureLabels; std::unordered_multimap<uint32, CurrencyContainerEntry const*> _currencyContainers; CurvePointsContainer _curvePoints; EmotesTextSoundContainer _emoteTextSounds; @@ -484,6 +487,7 @@ namespace FactionTeamContainer _factionTeams; std::unordered_map<uint32, std::set<FriendshipRepReactionEntry const*, DB2Manager::FriendshipRepReactionEntryComparator>> _friendshipRepReactions; HeirloomItemsContainer _heirlooms; + std::unordered_map<uint32 /*gameobjectId*/, std::vector<int32>> _gameobjectLabels; GlyphBindableSpellsContainer _glyphBindableSpells; GlyphRequiredSpecsContainer _glyphRequiredSpecs; ItemChildEquipmentContainer _itemChildEquipment; @@ -736,6 +740,7 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul LOAD_DB2(sCreatureDisplayInfoStore); LOAD_DB2(sCreatureDisplayInfoExtraStore); LOAD_DB2(sCreatureFamilyStore); + LOAD_DB2(sCreatureLabelStore); LOAD_DB2(sCreatureModelDataStore); LOAD_DB2(sCreatureTypeStore); LOAD_DB2(sCriteriaStore); @@ -762,6 +767,7 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul LOAD_DB2(sGameObjectsStore); LOAD_DB2(sGameObjectArtKitStore); LOAD_DB2(sGameObjectDisplayInfoStore); + LOAD_DB2(sGameObjectLabelStore); LOAD_DB2(sGarrAbilityStore); LOAD_DB2(sGarrBuildingStore); LOAD_DB2(sGarrBuildingPlotInstStore); @@ -1256,6 +1262,9 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul for (ContentTuningXLabelEntry const* contentTuningXLabel : sContentTuningXLabelStore) _contentTuningLabels.emplace(contentTuningXLabel->ContentTuningID, contentTuningXLabel->LabelID); + for (CreatureLabelEntry const* creatureLabel : sCreatureLabelStore) + _creatureLabels[creatureLabel->CreatureDifficultyID].push_back(creatureLabel->LabelID); + for (CurrencyContainerEntry const* currencyContainer : sCurrencyContainerStore) _currencyContainers.emplace(currencyContainer->CurrencyTypesID, currencyContainer); @@ -1297,6 +1306,9 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul std::swap(const_cast<GameObjectDisplayInfoEntry*>(gameObjectDisplayInfo)->GeoBoxMax.Z, const_cast<GameObjectDisplayInfoEntry*>(gameObjectDisplayInfo)->GeoBoxMin.Z); } + for (GameObjectLabelEntry const* gameobjectLabel : sGameObjectLabelStore) + _creatureLabels[gameobjectLabel->GameObjectID].push_back(gameobjectLabel->LabelID); + for (HeirloomEntry const* heirloom : sHeirloomStore) _heirlooms[heirloom->ItemID] = heirloom; @@ -2240,6 +2252,12 @@ char const* DB2Manager::GetCreatureFamilyPetName(uint32 petfamily, LocaleConstan return petFamily->Name[locale][0] != '\0' ? petFamily->Name[locale] : nullptr; } +std::span<int32 const> DB2Manager::GetCreatureLabels(uint32 creatureDifficultyId) const +{ + std::vector<int32> const* labels = Trinity::Containers::MapGetValuePtr(_creatureLabels, creatureDifficultyId); + return labels ? std::span<int32 const>(*labels) : std::span<int32 const>(); +} + CurrencyContainerEntry const* DB2Manager::GetCurrencyContainerForCurrencyQuantity(uint32 currencyId, int32 quantity) const { for (std::pair<uint32 const, CurrencyContainerEntry const*> const& p : Trinity::Containers::MapEqualRange(_currencyContainers, currencyId)) @@ -2567,6 +2585,12 @@ DB2Manager::FriendshipRepReactionSet const* DB2Manager::GetFriendshipRepReaction return Trinity::Containers::MapGetValuePtr(_friendshipRepReactions, friendshipRepID); } +std::span<int32 const> DB2Manager::GetGameObjectLabels(uint32 gameobjectId) const +{ + std::vector<int32> const* labels = Trinity::Containers::MapGetValuePtr(_gameobjectLabels, gameobjectId); + return labels ? std::span<int32 const>(*labels) : std::span<int32 const>(); +} + uint32 DB2Manager::GetGlobalCurveId(GlobalCurve globalCurveType) const { for (GlobalCurveEntry const* globalCurveEntry : sGlobalCurveStore) diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 19a45d46a69..0417e39b443 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -468,6 +468,7 @@ public: Optional<ContentTuningLevels> GetContentTuningData(uint32 contentTuningId, uint32 redirectFlag, bool forItem = false) const; bool HasContentTuningLabel(uint32 contentTuningId, int32 label) const; static char const* GetCreatureFamilyPetName(uint32 petfamily, LocaleConstant locale); + std::span<int32 const> GetCreatureLabels(uint32 creatureDifficultyId) const; CurrencyContainerEntry const* GetCurrencyContainerForCurrencyQuantity(uint32 currencyId, int32 quantity) const; std::pair<float, float> GetCurveXAxisRange(uint32 curveId) const; float GetCurveValueAt(uint32 curveId, float x) const; @@ -476,6 +477,7 @@ public: float EvaluateExpectedStat(ExpectedStatType stat, uint32 level, int32 expansion, uint32 contentTuningId, Classes unitClass, int32 mythicPlusMilestoneSeason) const; std::vector<uint32> const* GetFactionTeamList(uint32 faction) const; FriendshipRepReactionSet const* GetFriendshipRepReactions(uint32 friendshipRepID) const; + std::span<int32 const> GetGameObjectLabels(uint32 gameobjectId) const; uint32 GetGlobalCurveId(GlobalCurve globalCurveType) const; std::vector<uint32> const* GetGlyphBindableSpells(uint32 glyphPropertiesId) const; std::vector<ChrSpecialization> const* GetGlyphRequiredSpecs(uint32 glyphPropertiesId) const; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 7ea04668e5c..533f8afcd61 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -1076,6 +1076,13 @@ struct CreatureFamilyEntry std::array<int16, 2> SkillLine; }; +struct CreatureLabelEntry +{ + uint32 ID; + int32 LabelID; + uint32 CreatureDifficultyID; +}; + struct CreatureModelDataEntry { uint32 ID; @@ -1752,6 +1759,13 @@ struct GameObjectDisplayInfoEntry uint16 Unknown1100; }; +struct GameObjectLabelEntry +{ + uint32 ID; + int32 LabelID; + uint32 GameObjectID; +}; + struct GameObjectsEntry { LocalizedString Name; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 0b8a3483b1f..0a5c0c88612 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -3320,6 +3320,16 @@ std::string Creature::GetNameForLocaleIdx(LocaleConstant locale) const return GetName(); } +bool Creature::HasLabel(int32 cretureLabel) const +{ + return advstd::ranges::contains(GetLabels(), cretureLabel); +} + +std::span<int32 const> Creature::GetLabels() const +{ + return sDB2Manager.GetCreatureLabels(GetCreatureDifficulty()->CreatureDifficultyID); +} + uint8 Creature::GetPetAutoSpellSize() const { return MAX_SPELL_CHARM; diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 02dbef80715..a7f6113aab6 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -279,6 +279,9 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma // override WorldObject function for proper name localization std::string GetNameForLocaleIdx(LocaleConstant locale) const override; + bool HasLabel(int32 cretureLabel) const; + std::span<int32 const> GetLabels() const; + void setDeathState(DeathState s) override; // override virtual Unit::setDeathState bool LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, bool allowDuplicate); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index ce475f4424f..43812641cec 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -3602,6 +3602,16 @@ std::string GameObject::GetNameForLocaleIdx(LocaleConstant locale) const return GetName(); } +bool GameObject::HasLabel(int32 gameobjectLabel) const +{ + return advstd::ranges::contains(GetLabels(), gameobjectLabel); +} + +std::span<int32 const> GameObject::GetLabels() const +{ + return sDB2Manager.GetGameObjectLabels(GetEntry()); +} + void GameObject::UpdatePackedRotation() { static const int32 PACK_YZ = 1 << 20; diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 07db9755d86..00cbe9bfecd 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -223,6 +223,9 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> // overwrite WorldObject function for proper name localization std::string GetNameForLocaleIdx(LocaleConstant locale) const override; + bool HasLabel(int32 gameobjectLabel) const; + std::span<int32 const> GetLabels() const; + void SaveToDB(); void SaveToDB(uint32 mapid, std::vector<Difficulty> const& spawnDifficulties); bool LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, bool = true); // arg4 is unused, only present to match the signature on Creature diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 25f907599ec..c1e5da1041b 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -16666,6 +16666,9 @@ void Player::KilledMonster(Creature const* creature) for (uint8 i = 0; i < MAX_KILL_CREDIT; ++i) if (cInfo->KillCredit[i]) KilledMonsterCredit(cInfo->KillCredit[i], ObjectGuid::Empty); + + for (int32 label : creature->GetLabels()) + UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_KILL_WITH_LABEL, label, 1, creature->GetGUID()); } void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::Empty*/) @@ -17129,6 +17132,7 @@ bool Player::IsQuestObjectiveComplete(uint16 slot, Quest const* quest, QuestObje case QUEST_OBJECTIVE_HAVE_CURRENCY: case QUEST_OBJECTIVE_OBTAIN_CURRENCY: case QUEST_OBJECTIVE_INCREASE_REPUTATION: + case QUEST_OBJECTIVE_KILL_WITH_LABEL: if (GetQuestSlotObjectiveData(slot, objective) < objective.Amount) return false; break; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 32e6e07ec68..b42d5137fdf 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -5010,6 +5010,7 @@ void ObjectMgr::LoadQuests() case QUEST_OBJECTIVE_MONEY: case QUEST_OBJECTIVE_WINPVPPETBATTLES: case QUEST_OBJECTIVE_PROGRESS_BAR: + case QUEST_OBJECTIVE_KILL_WITH_LABEL: break; default: TC_LOG_ERROR("sql.sql", "Quest {} objective {} has unhandled type {}", qinfo->GetQuestId(), obj.ID, obj.Type); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index ef421373259..3e85b39f501 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -372,6 +372,7 @@ class TC_GAME_API Spell void EffectUnlockGuildVaultTab(); void EffectKillCreditPersonal(); void EffectKillCredit(); + void EffectKillCreditLabel(); void EffectQuestFail(); void EffectQuestStart(); void EffectRedirectThreat(); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index c0af44a549a..7b17a52d53b 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -404,8 +404,8 @@ NonDefaultConstructible<SpellEffectHandlerFn> SpellEffectHandlers[TOTAL_SPELL_EF &Spell::EffectNULL, //313 SPELL_EFFECT_CHANGE_ITEM_BONUSES_2 &Spell::EffectNULL, //314 SPELL_EFFECT_ADD_SOCKET_BONUS &Spell::EffectNULL, //315 SPELL_EFFECT_LEARN_TRANSMOG_APPEARANCE_FROM_ITEM_MOD_APPEARANCE_GROUP - &Spell::EffectNULL, //316 SPELL_EFFECT_KILL_CREDIT_LABEL_1 - &Spell::EffectNULL, //317 SPELL_EFFECT_KILL_CREDIT_LABEL_2 + &Spell::EffectKillCreditLabel, //316 SPELL_EFFECT_KILL_CREDIT_LABEL_1 + &Spell::EffectKillCreditLabel, //317 SPELL_EFFECT_KILL_CREDIT_LABEL_2 &Spell::EffectNULL, //318 SPELL_EFFECT_318 &Spell::EffectNULL, //319 SPELL_EFFECT_319 &Spell::EffectNULL, //320 SPELL_EFFECT_320 @@ -4767,6 +4767,18 @@ void Spell::EffectKillCredit() unitTarget->ToPlayer()->RewardPlayerAndGroupAtEvent(creatureEntry, unitTarget); } +void Spell::EffectKillCreditLabel() +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + Player* playerTarget = Object::ToPlayer(unitTarget); + if (!playerTarget) + return; + + playerTarget->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_KILL_WITH_LABEL, effectInfo->MiscValue, std::max(1, effectInfo->MiscValueB)); +} + void Spell::EffectQuestFail() { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) |