Core/Quests: Added research results about last field in QuestPackageItem.db2
This commit is contained in:
@@ -0,0 +1 @@
|
||||
ALTER TABLE `quest_package_item` CHANGE `Unk` `FilterType` int(10) unsigned NOT NULL DEFAULT '0';
|
||||
@@ -66,7 +66,6 @@ TaxiMask sAllianceTaxiNodesMask;
|
||||
TaxiMask sDeathKnightTaxiNodesMask;
|
||||
TaxiPathSetBySource sTaxiPathSetBySource;
|
||||
TaxiPathNodesByPath sTaxiPathNodesByPath;
|
||||
QuestPackageItemMap sQuestPackageItemStoreMap;
|
||||
|
||||
typedef std::list<std::string> DB2StoreProblemList;
|
||||
|
||||
@@ -202,6 +201,9 @@ void DB2Manager::LoadStores(std::string const& dataPath)
|
||||
if (PhaseEntry const* phase = sPhaseStore.LookupEntry(group->PhaseID))
|
||||
_phasesByGroup[group->PhaseGroupID].insert(phase->ID);
|
||||
|
||||
for (QuestPackageItemEntry const* questPackageItem : sQuestPackageItemStore)
|
||||
_questPackages[questPackageItem->QuestPackageID].push_back(questPackageItem);
|
||||
|
||||
for (SpellPowerEntry const* power : sSpellPowerStore)
|
||||
{
|
||||
if (SpellPowerDifficultyEntry const* powerDifficulty = sSpellPowerDifficultyStore.LookupEntry(power->ID))
|
||||
@@ -305,14 +307,6 @@ void DB2Manager::LoadStores(std::string const& dataPath)
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < sQuestPackageItemStore.GetNumRows(); ++i)
|
||||
{
|
||||
if (QuestPackageItemEntry const* pack = sQuestPackageItemStore.LookupEntry(i))
|
||||
{
|
||||
sQuestPackageItemStoreMap[pack->QuestPackageID].push_back(pack);
|
||||
}
|
||||
}
|
||||
|
||||
// error checks
|
||||
if (bad_db2_files.size() >= DB2FilesCount)
|
||||
{
|
||||
@@ -499,6 +493,15 @@ MountEntry const* DB2Manager::GetMount(uint32 spellId) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<QuestPackageItemEntry const*> const* DB2Manager::GetQuestPackageItems(uint32 questPackageID) const
|
||||
{
|
||||
auto itr = _questPackages.find(questPackageID);
|
||||
if (itr != _questPackages.end())
|
||||
return &itr->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::set<uint32> DB2Manager::GetPhasesForGroup(uint32 group) const
|
||||
{
|
||||
auto itr = _phasesByGroup.find(group);
|
||||
|
||||
@@ -51,7 +51,6 @@ extern TaxiMask sAllianceTaxiNodesMask;
|
||||
extern TaxiMask sDeathKnightTaxiNodesMask;
|
||||
extern TaxiPathSetBySource sTaxiPathSetBySource;
|
||||
extern TaxiPathNodesByPath sTaxiPathNodesByPath;
|
||||
extern QuestPackageItemMap sQuestPackageItemStoreMap;
|
||||
|
||||
struct HotfixNotify
|
||||
{
|
||||
@@ -75,6 +74,7 @@ public:
|
||||
typedef std::unordered_map<uint32, std::set<ItemBonusTreeNodeEntry const*>> ItemBonusTreeContainer;
|
||||
typedef std::unordered_map<uint32, MountEntry const*> MountContainer;
|
||||
typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer;
|
||||
typedef std::unordered_map<uint32, std::vector<QuestPackageItemEntry const*>> QuestPackageItemContainer;
|
||||
typedef std::unordered_map<uint32, std::vector<SpellPowerEntry const*>> SpellPowerContainer;
|
||||
typedef std::unordered_map<uint32, std::unordered_map<uint32, std::vector<SpellPowerEntry const*>>> SpellPowerDifficultyContainer;
|
||||
|
||||
@@ -98,6 +98,7 @@ public:
|
||||
std::set<uint32> GetItemBonusTree(uint32 itemId, uint32 itemBonusTreeMod) const;
|
||||
uint32 GetItemDisplayId(uint32 itemId, uint32 appearanceModId) const;
|
||||
MountEntry const* GetMount(uint32 spellId) const;
|
||||
std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const;
|
||||
std::set<uint32> GetPhasesForGroup(uint32 group) const;
|
||||
std::vector<SpellPowerEntry const*> GetSpellPowers(uint32 spellId, Difficulty difficulty = DIFFICULTY_NONE, bool* hasDifficultyPowers = nullptr) const;
|
||||
|
||||
@@ -113,6 +114,7 @@ private:
|
||||
ItemToBonusTreeContainer _itemToBonusTree;
|
||||
MountContainer _mountsBySpellId;
|
||||
PhaseGroupContainer _phasesByGroup;
|
||||
QuestPackageItemContainer _questPackages;
|
||||
SpellPowerContainer _spellPowers;
|
||||
SpellPowerDifficultyContainer _spellPowerDifficulties;
|
||||
};
|
||||
|
||||
@@ -296,19 +296,15 @@ struct PhaseXPhaseGroupEntry
|
||||
uint32 PhaseGroupID;
|
||||
};
|
||||
|
||||
// QuestPackageItem.db2
|
||||
struct QuestPackageItemEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 QuestPackageID; // 1
|
||||
uint32 ItemID; // 2
|
||||
uint32 ItemCount; // 3
|
||||
uint32 Unk; // 4
|
||||
uint32 FilterType; // 4
|
||||
};
|
||||
|
||||
typedef std::vector<QuestPackageItemEntry const*> QuestPackageItemList;
|
||||
typedef std::unordered_map<uint32, QuestPackageItemList> QuestPackageItemMap;
|
||||
|
||||
struct SoundEntriesEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
|
||||
@@ -491,6 +491,14 @@ enum MountFlags
|
||||
MOUNT_FLAG_HIDE_IF_UNKNOWN = 0x40
|
||||
};
|
||||
|
||||
enum QuestPackageFilter
|
||||
{
|
||||
QUEST_PACKAGE_FILTER_LOOT_SPECIALIZATION = 0, // Players can select this quest reward if it matches their selected loot specialization
|
||||
QUEST_PACKAGE_FILTER_CLASS = 1, // Players can select this quest reward if it matches their class
|
||||
QUEST_PACKAGE_FILTER_UNMATCHED = 2, // Players can select this quest reward if no class/loot_spec rewards are available
|
||||
QUEST_PACKAGE_FILTER_EVERYONE = 3 // Players can always select this quest reward
|
||||
};
|
||||
|
||||
enum SkillRaceClassInfoFlags
|
||||
{
|
||||
SKILL_FLAG_NO_SKILLUP_MESSAGE = 0x2,
|
||||
|
||||
@@ -138,18 +138,18 @@ void ItemTemplate::GetDamage(uint32 itemLevel, float& minDamage, float& maxDamag
|
||||
maxDamage = floor(float(avgDamage * (GetStatScalingFactor() * 0.5f + 1.0f) + 0.5f));
|
||||
}
|
||||
|
||||
bool ItemTemplate::CanWinForPlayer(Player* plr) const
|
||||
bool ItemTemplate::CanWinForPlayer(Player const* player) const
|
||||
{
|
||||
if (!Specializations.size())
|
||||
return true;
|
||||
|
||||
uint32 spec = plr->GetSpecId(plr->GetActiveTalentGroup());
|
||||
uint32 spec = player->GetSpecId(player->GetActiveTalentGroup());
|
||||
if (!spec)
|
||||
spec = plr->GetDefaultSpecId();
|
||||
spec = player->GetDefaultSpecId();
|
||||
|
||||
if (!spec)
|
||||
return false;
|
||||
|
||||
|
||||
UsableTalentSpecs::const_iterator itr = Specializations.find(spec);
|
||||
return itr != Specializations.end();
|
||||
}
|
||||
|
||||
@@ -584,6 +584,7 @@ const uint32 MaxItemSubclassValues[MAX_ITEM_CLASS] =
|
||||
#define MIN_ITEM_LEVEL 1
|
||||
#define MAX_ITEM_LEVEL 1000
|
||||
|
||||
class Player;
|
||||
typedef std::set<uint32> UsableTalentSpecs;
|
||||
|
||||
struct ItemTemplate
|
||||
@@ -704,7 +705,7 @@ struct ItemTemplate
|
||||
char const* GetDefaultLocaleName() const;
|
||||
uint32 GetArmor(uint32 itemLevel) const;
|
||||
void GetDamage(uint32 itemLevel, float& minDamage, float& maxDamage) const;
|
||||
bool CanWinForPlayer(Player* plr) const;
|
||||
bool CanWinForPlayer(Player const* player) const;
|
||||
};
|
||||
|
||||
// Benchmarked: Faster than std::map (insert/find)
|
||||
|
||||
@@ -14442,23 +14442,25 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// QuestPackageItem.db2
|
||||
if (quest->GetQuestPackageID())
|
||||
{
|
||||
if (sQuestPackageItemStoreMap.find(quest->GetQuestPackageID()) != sQuestPackageItemStoreMap.end())
|
||||
if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(quest->GetQuestPackageID()))
|
||||
{
|
||||
QuestPackageItemList itemList = sQuestPackageItemStoreMap[quest->GetQuestPackageID()];
|
||||
for (QuestPackageItemList::const_iterator itr = itemList.begin(); itr != itemList.end(); ++itr)
|
||||
for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
|
||||
{
|
||||
if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate((*itr)->ItemID))
|
||||
if (questPackageItem->ItemID != reward)
|
||||
continue;
|
||||
|
||||
if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID))
|
||||
{
|
||||
if (rewardProto->CanWinForPlayer(this))
|
||||
{
|
||||
InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, (*itr)->ItemID, (*itr)->ItemCount);
|
||||
InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount);
|
||||
if (res != EQUIP_ERR_OK)
|
||||
{
|
||||
SendEquipError(res, NULL, NULL, (*itr)->ItemID);
|
||||
SendEquipError(res, NULL, NULL, questPackageItem->ItemID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -14660,20 +14662,22 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
// QuestPackageItem.db2
|
||||
if (quest->GetQuestPackageID())
|
||||
{
|
||||
if (sQuestPackageItemStoreMap.find(quest->GetQuestPackageID()) != sQuestPackageItemStoreMap.end())
|
||||
if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(quest->GetQuestPackageID()))
|
||||
{
|
||||
QuestPackageItemList itemList = sQuestPackageItemStoreMap[quest->GetQuestPackageID()];
|
||||
for (QuestPackageItemList::const_iterator itr = itemList.begin(); itr != itemList.end(); ++itr)
|
||||
for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
|
||||
{
|
||||
if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate((*itr)->ItemID))
|
||||
if (questPackageItem->ItemID != reward)
|
||||
continue;
|
||||
|
||||
if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID))
|
||||
{
|
||||
if (rewardProto->CanWinForPlayer(this))
|
||||
{
|
||||
ItemPosCountVec dest;
|
||||
if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, (*itr)->ItemID, (*itr)->ItemCount) == EQUIP_ERR_OK)
|
||||
if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount) == EQUIP_ERR_OK)
|
||||
{
|
||||
Item* item = StoreNewItem(dest, (*itr)->ItemID, true, Item::GenerateItemRandomPropertyId((*itr)->ItemID));
|
||||
SendNewItem(item, (*itr)->ItemCount, true, false);
|
||||
Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, Item::GenerateItemRandomPropertyId(questPackageItem->ItemID));
|
||||
SendNewItem(item, questPackageItem->ItemCount, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::Quest
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID);
|
||||
if (!quest)
|
||||
return;
|
||||
|
||||
|
||||
// This is Real Item Entry, not slot id as pre 5.x
|
||||
if (packet.ItemChoiceID)
|
||||
{
|
||||
@@ -263,6 +263,27 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::Quest
|
||||
}
|
||||
}
|
||||
|
||||
if (quest->GetQuestPackageID())
|
||||
{
|
||||
if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(quest->GetQuestPackageID()))
|
||||
{
|
||||
for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
|
||||
{
|
||||
if (questPackageItem->ItemID != packet.ItemChoiceID)
|
||||
continue;
|
||||
|
||||
if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID))
|
||||
{
|
||||
if (rewardProto->CanWinForPlayer(_player))
|
||||
{
|
||||
itemValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemValid)
|
||||
{
|
||||
TC_LOG_ERROR("network", "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (%s) tried to get reward item (Item Entry: %u) wich is not a reward for quest %u (possible packet-hacking detected)", _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), packet.ItemChoiceID, packet.QuestID);
|
||||
|
||||
@@ -119,7 +119,7 @@ void HotfixDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(HOTFIX_SEL_PHASE_GROUP, "SELECT ID, PhaseID, PhaseGroupID FROM phase_group ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
|
||||
// QuestPackageItem.db2
|
||||
PrepareStatement(HOTFIX_SEL_QUEST_PACKAGE_ITEM, "SELECT ID, QuestPackageID, ItemID, ItemCount, Unk FROM quest_package_item ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
PrepareStatement(HOTFIX_SEL_QUEST_PACKAGE_ITEM, "SELECT ID, QuestPackageID, ItemID, ItemCount, FilterType FROM quest_package_item ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
|
||||
// SoundEntries.db2
|
||||
PrepareStatement(HOTFIX_SEL_SOUND_ENTRIES, "SELECT ID, SoundType, Name, FileDataID1, FileDataID2, FileDataID3, FileDataID4, FileDataID5, "
|
||||
|
||||
Reference in New Issue
Block a user