Core/Quests: Implemented handling all QuestPackageItem types
Closes #18209
This commit is contained in:
@@ -794,7 +794,12 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
|
||||
}
|
||||
|
||||
for (QuestPackageItemEntry const* questPackageItem : sQuestPackageItemStore)
|
||||
_questPackages[questPackageItem->QuestPackageID].push_back(questPackageItem);
|
||||
{
|
||||
if (questPackageItem->FilterType != QUEST_PACKAGE_FILTER_UNMATCHED)
|
||||
_questPackages[questPackageItem->QuestPackageID].first.push_back(questPackageItem);
|
||||
else
|
||||
_questPackages[questPackageItem->QuestPackageID].second.push_back(questPackageItem);
|
||||
}
|
||||
|
||||
for (RulesetItemUpgradeEntry const* rulesetItemUpgrade : sRulesetItemUpgradeStore)
|
||||
_rulesetItemUpgrade[rulesetItemUpgrade->ItemID] = rulesetItemUpgrade->ItemUpgradeID;
|
||||
@@ -1625,7 +1630,16 @@ std::vector<QuestPackageItemEntry const*> const* DB2Manager::GetQuestPackageItem
|
||||
{
|
||||
auto itr = _questPackages.find(questPackageID);
|
||||
if (itr != _questPackages.end())
|
||||
return &itr->second;
|
||||
return &itr->second.first;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<QuestPackageItemEntry const*> const* DB2Manager::GetQuestPackageItemsFallback(uint32 questPackageID) const
|
||||
{
|
||||
auto itr = _questPackages.find(questPackageID);
|
||||
if (itr != _questPackages.end())
|
||||
return &itr->second.second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ public:
|
||||
typedef std::array<std::vector<std::wregex>, TOTAL_LOCALES + 1> NameValidationRegexContainer;
|
||||
typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer;
|
||||
typedef std::array<PowerTypeEntry const*, MAX_POWERS> PowerTypesContainer;
|
||||
typedef std::unordered_map<uint32, std::vector<QuestPackageItemEntry const*>> QuestPackageItemContainer;
|
||||
typedef std::unordered_map<uint32, std::pair<std::vector<QuestPackageItemEntry const*>, std::vector<QuestPackageItemEntry const*>>> QuestPackageItemContainer;
|
||||
typedef std::unordered_map<uint32, uint32> RulesetItemUpgradeContainer;
|
||||
typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRaceClassInfoContainer;
|
||||
typedef std::unordered_map<uint32, std::vector<SpecializationSpellsEntry const*>> SpecializationSpellsContainer;
|
||||
@@ -330,6 +330,7 @@ public:
|
||||
static PvpDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level);
|
||||
static PvpDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id);
|
||||
std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const;
|
||||
std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItemsFallback(uint32 questPackageID) const;
|
||||
uint32 GetQuestUniqueBitFlag(uint32 questId);
|
||||
uint32 GetRulesetItemUpgrade(uint32 itemId) const;
|
||||
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
|
||||
|
||||
@@ -212,9 +212,11 @@ void ItemTemplate::GetDamage(uint32 itemLevel, float& minDamage, float& maxDamag
|
||||
maxDamage = floor(float(avgDamage * (GetStatScalingFactor() * 0.5f + 1.0f) + 0.5f));
|
||||
}
|
||||
|
||||
bool ItemTemplate::IsUsableBySpecialization(Player const* player) const
|
||||
bool ItemTemplate::IsUsableByLootSpecialization(Player const* player) const
|
||||
{
|
||||
uint32 spec = player->GetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID);
|
||||
uint32 spec = player->GetUInt32Value(PLAYER_FIELD_LOOT_SPEC_ID);
|
||||
if (!spec)
|
||||
spec = player->GetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID);
|
||||
if (!spec)
|
||||
spec = player->GetDefaultSpecId();
|
||||
|
||||
@@ -222,7 +224,13 @@ bool ItemTemplate::IsUsableBySpecialization(Player const* player) const
|
||||
if (!chrSpecialization)
|
||||
return false;
|
||||
|
||||
return Specializations[player->getLevel() > 40].test(CalculateItemSpecBit(chrSpecialization));
|
||||
std::size_t levelIndex = 0;
|
||||
if (player->getLevel() >= 110)
|
||||
levelIndex = 2;
|
||||
else if (player->getLevel() > 40)
|
||||
levelIndex = 1;
|
||||
|
||||
return Specializations[levelIndex].test(CalculateItemSpecBit(chrSpecialization));
|
||||
}
|
||||
|
||||
std::size_t ItemTemplate::CalculateItemSpecBit(ChrSpecializationEntry const* spec)
|
||||
|
||||
@@ -776,7 +776,7 @@ struct TC_GAME_API ItemTemplate
|
||||
uint32 MaxMoneyLoot;
|
||||
uint32 FlagsCu;
|
||||
float SpellPPMRate;
|
||||
std::bitset<MAX_CLASSES * MAX_SPECIALIZATIONS> Specializations[2]; // one set for 1-40 level range and another for 41-100
|
||||
std::bitset<MAX_CLASSES * MAX_SPECIALIZATIONS> Specializations[3]; // one set for 1-40 level range and another for 41-109 and one for 110
|
||||
uint32 ItemSpecClassMask;
|
||||
|
||||
// helpers
|
||||
@@ -807,7 +807,7 @@ struct TC_GAME_API ItemTemplate
|
||||
char const* GetDefaultLocaleName() const;
|
||||
uint32 GetArmor(uint32 itemLevel) const;
|
||||
void GetDamage(uint32 itemLevel, float& minDamage, float& maxDamage) const;
|
||||
bool IsUsableBySpecialization(Player const* player) const;
|
||||
bool IsUsableByLootSpecialization(Player const* player) const;
|
||||
static std::size_t CalculateItemSpecBit(ChrSpecializationEntry const* spec);
|
||||
};
|
||||
|
||||
|
||||
@@ -14699,6 +14699,7 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg)
|
||||
// QuestPackageItem.db2
|
||||
if (quest->GetQuestPackageID())
|
||||
{
|
||||
bool hasFilteredQuestPackageReward = false;
|
||||
if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(quest->GetQuestPackageID()))
|
||||
{
|
||||
for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
|
||||
@@ -14706,16 +14707,33 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg)
|
||||
if (questPackageItem->ItemID != reward)
|
||||
continue;
|
||||
|
||||
if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID))
|
||||
if (CanSelectQuestPackageItem(questPackageItem))
|
||||
{
|
||||
if (rewardProto->IsUsableBySpecialization(this))
|
||||
hasFilteredQuestPackageReward = true;
|
||||
InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount);
|
||||
if (res != EQUIP_ERR_OK)
|
||||
{
|
||||
InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount);
|
||||
if (res != EQUIP_ERR_OK)
|
||||
{
|
||||
SendEquipError(res, nullptr, nullptr, questPackageItem->ItemID);
|
||||
return false;
|
||||
}
|
||||
SendEquipError(res, nullptr, nullptr, questPackageItem->ItemID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasFilteredQuestPackageReward)
|
||||
{
|
||||
if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItemsFallback(quest->GetQuestPackageID()))
|
||||
{
|
||||
for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
|
||||
{
|
||||
if (questPackageItem->ItemID != reward)
|
||||
continue;
|
||||
|
||||
InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount);
|
||||
if (res != EQUIP_ERR_OK)
|
||||
{
|
||||
SendEquipError(res, nullptr, nullptr, questPackageItem->ItemID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14865,6 +14883,31 @@ uint32 Player::GetQuestXPReward(Quest const* quest)
|
||||
return XP;
|
||||
}
|
||||
|
||||
bool Player::CanSelectQuestPackageItem(QuestPackageItemEntry const* questPackageItem) const
|
||||
{
|
||||
ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID);
|
||||
if (!rewardProto)
|
||||
return false;
|
||||
|
||||
if ((rewardProto->GetFlags2() & ITEM_FLAG2_FACTION_ALLIANCE && GetTeam() != ALLIANCE) ||
|
||||
(rewardProto->GetFlags2() & ITEM_FLAG2_FACTION_HORDE && GetTeam() != HORDE))
|
||||
return false;
|
||||
|
||||
switch (questPackageItem->FilterType)
|
||||
{
|
||||
case QUEST_PACKAGE_FILTER_LOOT_SPECIALIZATION:
|
||||
return rewardProto->IsUsableByLootSpecialization(this);
|
||||
case QUEST_PACKAGE_FILTER_CLASS:
|
||||
return (rewardProto->ItemSpecClassMask & getClassMask()) != 0;
|
||||
case QUEST_PACKAGE_FILTER_EVERYONE:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce)
|
||||
{
|
||||
//this THING should be here to protect code from quest, which cast on player far teleport as a reward
|
||||
@@ -14901,7 +14944,8 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
|
||||
RemoveTimedQuest(quest_id);
|
||||
|
||||
if (quest->GetRewChoiceItemsCount() > 0)
|
||||
ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(reward);
|
||||
if (rewardProto && quest->GetRewChoiceItemsCount())
|
||||
{
|
||||
for (uint32 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
|
||||
{
|
||||
@@ -14918,8 +14962,9 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
}
|
||||
|
||||
// QuestPackageItem.db2
|
||||
if (quest->GetQuestPackageID())
|
||||
if (rewardProto && quest->GetQuestPackageID())
|
||||
{
|
||||
bool hasFilteredQuestPackageReward = false;
|
||||
if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(quest->GetQuestPackageID()))
|
||||
{
|
||||
for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
|
||||
@@ -14927,16 +14972,33 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
if (questPackageItem->ItemID != reward)
|
||||
continue;
|
||||
|
||||
if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID))
|
||||
if (CanSelectQuestPackageItem(questPackageItem))
|
||||
{
|
||||
if (rewardProto->IsUsableBySpecialization(this))
|
||||
hasFilteredQuestPackageReward = true;
|
||||
ItemPosCountVec dest;
|
||||
if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount) == EQUIP_ERR_OK)
|
||||
{
|
||||
ItemPosCountVec dest;
|
||||
if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount) == EQUIP_ERR_OK)
|
||||
{
|
||||
Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, Item::GenerateItemRandomPropertyId(questPackageItem->ItemID));
|
||||
SendNewItem(item, questPackageItem->ItemCount, true, false);
|
||||
}
|
||||
Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, Item::GenerateItemRandomPropertyId(questPackageItem->ItemID));
|
||||
SendNewItem(item, questPackageItem->ItemCount, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasFilteredQuestPackageReward)
|
||||
{
|
||||
if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItemsFallback(quest->GetQuestPackageID()))
|
||||
{
|
||||
for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
|
||||
{
|
||||
if (questPackageItem->ItemID != reward)
|
||||
continue;
|
||||
|
||||
ItemPosCountVec dest;
|
||||
if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount) == EQUIP_ERR_OK)
|
||||
{
|
||||
Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, Item::GenerateItemRandomPropertyId(questPackageItem->ItemID));
|
||||
SendNewItem(item, questPackageItem->ItemCount, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1529,6 +1529,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void IncompleteQuest(uint32 quest_id);
|
||||
uint32 GetQuestMoneyReward(Quest const* quest) const;
|
||||
uint32 GetQuestXPReward(Quest const* quest);
|
||||
bool CanSelectQuestPackageItem(QuestPackageItemEntry const* questPackageItem) const;
|
||||
void RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce = true);
|
||||
void FailQuest(uint32 quest_id);
|
||||
bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const;
|
||||
|
||||
@@ -2781,7 +2781,12 @@ void ObjectMgr::LoadItemTemplates()
|
||||
if ((1 << (specialization->ClassID - 1)) & sparse->AllowableClass)
|
||||
{
|
||||
itemTemplate.ItemSpecClassMask |= 1 << (specialization->ClassID - 1);
|
||||
itemTemplate.Specializations[itemSpec->MaxLevel > 40].set(ItemTemplate::CalculateItemSpecBit(specialization));
|
||||
std::size_t specBit = ItemTemplate::CalculateItemSpecBit(specialization);
|
||||
itemTemplate.Specializations[0].set(specBit);
|
||||
if (itemSpec->MaxLevel > 40)
|
||||
itemTemplate.Specializations[1].set(specBit);
|
||||
if (itemSpec->MaxLevel >= 110)
|
||||
itemTemplate.Specializations[2].set(specBit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,14 +282,25 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::Quest
|
||||
if (questPackageItem->ItemID != uint32(packet.ItemChoiceID))
|
||||
continue;
|
||||
|
||||
rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID);
|
||||
if (rewardProto)
|
||||
if (_player->CanSelectQuestPackageItem(questPackageItem))
|
||||
{
|
||||
if (rewardProto->IsUsableBySpecialization(_player))
|
||||
{
|
||||
itemValid = true;
|
||||
break;
|
||||
}
|
||||
itemValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemValid)
|
||||
{
|
||||
if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItemsFallback(quest->GetQuestPackageID()))
|
||||
{
|
||||
for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
|
||||
{
|
||||
if (questPackageItem->ItemID != uint32(packet.ItemChoiceID))
|
||||
continue;
|
||||
|
||||
itemValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user