aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRat <gmstreetrat@gmail.com>2015-04-13 22:25:35 +0200
committerRat <gmstreetrat@gmail.com>2015-04-13 22:25:35 +0200
commite5675412735a33f05f9c3215fb0cc7327a800c6c (patch)
tree333c9accdaa65a5c5d600f5f7af4823894848f16 /src
parentf20c6530b8ef496259c8e6a6401b11c50efd5940 (diff)
Core/Quests: fixed quest rewarding
* ItemSpec.dbc still needs some research to handle all cases correctly
Diffstat (limited to 'src')
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp11
-rw-r--r--src/server/game/DataStores/DB2Stores.h1
-rw-r--r--src/server/game/DataStores/DB2Structure.h13
-rw-r--r--src/server/game/DataStores/DB2fmt.h1
-rw-r--r--src/server/game/DataStores/DBCStores.cpp9
-rw-r--r--src/server/game/DataStores/DBCStores.h3
-rw-r--r--src/server/game/DataStores/DBCStructure.h23
-rw-r--r--src/server/game/DataStores/DBCfmt.h4
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.cpp17
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h4
-rw-r--r--src/server/game/Entities/Player/Player.cpp98
-rw-r--r--src/server/game/Entities/Player/Player.h1
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp26
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp35
-rw-r--r--src/server/game/Quests/QuestDef.h27
-rw-r--r--src/server/shared/Database/Implementation/HotfixDatabase.cpp3
-rw-r--r--src/server/shared/Database/Implementation/HotfixDatabase.h2
17 files changed, 253 insertions, 25 deletions
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 26f2d8b36c9..71090011c64 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -43,6 +43,7 @@ DB2Storage<KeyChainEntry> sKeyChainStore("KeyChain.db2", KeyCh
DB2Storage<MountEntry> sMountStore("Mount.db2", MountFormat, HOTFIX_SEL_MOUNT);
DB2Storage<OverrideSpellDataEntry> sOverrideSpellDataStore("OverrideSpellData.db2", OverrideSpellDataFormat, HOTFIX_SEL_OVERRIDE_SPELL_DATA);
DB2Storage<PhaseXPhaseGroupEntry> sPhaseXPhaseGroupStore("PhaseXPhaseGroup.db2", PhaseXPhaseGroupFormat, HOTFIX_SEL_PHASE_GROUP);
+DB2Storage<QuestPackageItemEntry> sQuestPackageItemStore("QuestPackageItem.db2", QuestPackageItemfmt, HOTFIX_SEL_QUEST_PACKAGE_ITEM);
DB2Storage<SoundEntriesEntry> sSoundEntriesStore("SoundEntries.db2", SoundEntriesFormat, HOTFIX_SEL_SOUND_ENTRIES);
DB2Storage<SpellAuraRestrictionsEntry> sSpellAuraRestrictionsStore("SpellAuraRestrictions.db2", SpellAuraRestrictionsFormat, HOTFIX_SEL_SPELL_AURA_RESTRICTIONS);
DB2Storage<SpellCastingRequirementsEntry> sSpellCastingRequirementsStore("SpellCastingRequirements.db2", SpellCastingRequirementsFormat, HOTFIX_SEL_SPELL_CASTING_REQUIREMENTS);
@@ -65,6 +66,7 @@ TaxiMask sAllianceTaxiNodesMask;
TaxiMask sDeathKnightTaxiNodesMask;
TaxiPathSetBySource sTaxiPathSetBySource;
TaxiPathNodesByPath sTaxiPathNodesByPath;
+QuestPackageItemMap sQuestPackageItemStoreMap;
typedef std::list<std::string> DB2StoreProblemList;
@@ -144,6 +146,7 @@ void DB2Manager::LoadStores(std::string const& dataPath)
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sMountStore, db2Path);
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sOverrideSpellDataStore, db2Path);
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sPhaseXPhaseGroupStore, db2Path);
+ LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sQuestPackageItemStore, db2Path);
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSoundEntriesStore, db2Path);
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellAuraRestrictionsStore, db2Path);
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellCastingRequirementsStore, db2Path);
@@ -302,6 +305,14 @@ 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)
{
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index 8fdf23ec58c..29dc68a451c 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -51,6 +51,7 @@ extern TaxiMask sAllianceTaxiNodesMask;
extern TaxiMask sDeathKnightTaxiNodesMask;
extern TaxiPathSetBySource sTaxiPathSetBySource;
extern TaxiPathNodesByPath sTaxiPathNodesByPath;
+extern QuestPackageItemMap sQuestPackageItemStoreMap;
struct HotfixNotify
{
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index 9aab120cc63..ee6f4fdcc85 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -296,6 +296,19 @@ struct PhaseXPhaseGroupEntry
uint32 PhaseGroupID;
};
+// QuestPackageItem.db2
+struct QuestPackageItemEntry
+{
+ uint32 ID; // 0
+ uint32 QuestPackageID; // 1
+ uint32 ItemID; // 2
+ uint32 ItemCount; // 3
+ uint32 Unk; // 4
+};
+
+typedef std::vector<QuestPackageItemEntry const*> QuestPackageItemList;
+typedef std::unordered_map<uint32, QuestPackageItemList> QuestPackageItemMap;
+
struct SoundEntriesEntry
{
uint32 ID; // 0
diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h
index baab3cf9302..f59c7b56f56 100644
--- a/src/server/game/DataStores/DB2fmt.h
+++ b/src/server/game/DataStores/DB2fmt.h
@@ -38,6 +38,7 @@ char const KeyChainFormat[] = "nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
char const MountFormat[] = "niiisssiii";
char const OverrideSpellDataFormat[] = "niiiiiiiiiiii";
char const PhaseXPhaseGroupFormat[] = "nii";
+char const QuestPackageItemfmt[] = "niiii";
char const SoundEntriesFormat[] = "nisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiififfiifffffii";
char const SpellAuraRestrictionsFormat[] = "niiiiiiii";
char const SpellCastingRequirementsFormat[] = "niiiiii";
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 919c952f136..805885df51c 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -158,6 +158,9 @@ DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffi
DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt);
DBCStorage <ItemSetSpellEntry> sItemSetSpellStore(ItemSetSpellEntryfmt);
ItemSetSpellsStore sItemSetSpellsStore;
+DBCStorage <ItemSpecOverrideEntry> sItemSpecOverrideStore(ItemSpecOverrideEntryfmt);
+ItemSpecOverridesStore sItemSpecOverridesStore;
+DBCStorage <ItemSpecEntry> sItemSpecStore(ItemSpecEntryfmt);
DBCStorage <LFGDungeonEntry> sLFGDungeonStore(LFGDungeonEntryfmt);
DBCStorage <LightEntry> sLightStore(LightEntryfmt);
@@ -477,6 +480,12 @@ void LoadDBCStores(const std::string& dataPath)
if (ItemSetSpellEntry const* entry = sItemSetSpellStore.LookupEntry(i))
sItemSetSpellsStore[entry->ItemSetID].push_back(entry);
+ LoadDBC(availableDbcLocales, bad_dbc_files, sItemSpecStore, dbcPath, "ItemSpec.dbc");//19116
+ LoadDBC(availableDbcLocales, bad_dbc_files, sItemSpecOverrideStore, dbcPath, "ItemSpecOverride.dbc");//19116
+ for (uint32 i = 0; i < sItemSpecOverrideStore.GetNumRows(); ++i)
+ if (ItemSpecOverrideEntry const* entry = sItemSpecOverrideStore.LookupEntry(i))
+ sItemSpecOverridesStore[entry->ItemID].push_back(entry);
+
LoadDBC(availableDbcLocales, bad_dbc_files, sItemArmorQualityStore, dbcPath, "ItemArmorQuality.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sItemArmorShieldStore, dbcPath, "ItemArmorShield.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sItemArmorTotalStore, dbcPath, "ItemArmorTotal.dbc");//19116
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index f16b56609dd..781b981c4c1 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -211,6 +211,9 @@ extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore;
extern DBCStorage <ItemSetEntry> sItemSetStore;
extern DBCStorage <ItemSetSpellEntry> sItemSetSpellStore;
extern ItemSetSpellsStore sItemSetSpellsStore;
+extern DBCStorage <ItemSpecOverrideEntry> sItemSpecOverrideStore;
+extern ItemSpecOverridesStore sItemSpecOverridesStore;
+extern DBCStorage <ItemSpecEntry> sItemSpecStore;
extern DBCStorage <LFGDungeonEntry> sLFGDungeonStore;
extern DBCStorage <LiquidTypeEntry> sLiquidTypeStore;
extern DBCStorage <LockEntry> sLockStore;
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 0d4ada1ab39..ae6722b7932 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -261,7 +261,7 @@ struct ChrClassesEntry
uint32 AttackPowerPerStrength; // 10 Attack Power bonus per point of strength
uint32 AttackPowerPerAgility; // 11 Attack Power bonus per point of agility
uint32 RangedAttackPowerPerAgility; // 12 Ranged Attack Power bonus per point of agility
- //uint32 DefaultSpec; // 13
+ uint32 DefaultSpec; // 13
//uint32 CreateScreenFileDataID; // 14
//uint32 SelectScreenFileDataID; // 15
//uint32 LowResScreenFileDataID; // 16
@@ -1108,6 +1108,27 @@ struct ItemSetSpellEntry
typedef std::vector<ItemSetSpellEntry const*> ItemSetSpells;
typedef std::unordered_map<uint32, ItemSetSpells> ItemSetSpellsStore;
+struct ItemSpecEntry
+{
+ uint32 ID; // 0
+ uint32 MinLevel; // 1
+ uint32 MaxLevel; // 2
+ uint32 ItemType; // 3
+ uint32 PrimaryStat; // 4
+ uint32 SecondaryStat; // 5
+ uint32 SpecID; // 6
+};
+
+struct ItemSpecOverrideEntry
+{
+ uint32 ID; // 0
+ uint32 ItemID; // 1
+ uint32 SpecID; // 2
+};
+
+typedef std::vector<ItemSpecOverrideEntry const*> ItemSpecOverrides;
+typedef std::unordered_map<uint32, ItemSpecOverrides> ItemSpecOverridesStore;
+
struct LFGDungeonEntry
{
uint32 ID; // 0
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index 98677746c3c..271aca1c43f 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -37,7 +37,7 @@ char const CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiiii";
char const CharSectionsEntryfmt[] = "diiixxxiii";
char const CharTitlesEntryfmt[] = "nxssix";
char const ChatChannelsEntryfmt[] = "nixsx";
-char const ChrClassesEntryfmt[] = "nixsxxxixiiiixxxxxx";
+char const ChrClassesEntryfmt[] = "nixsxxxixiiiiixxxxx";
char const ChrRacesEntryfmt[] = "niixiixxxxxxiisxxxxxxxxxxxxxxxxxxxxxxxxx";
char const ChrClassesXPowerTypesfmt[] = "nii";
char const ChrSpecializationEntryfmt[] = "nxiiiiiiiiixxxii";
@@ -105,6 +105,8 @@ char const ItemRandomPropertiesfmt[] = "nxiiiiis";
char const ItemRandomSuffixfmt[] = "nsxiiiiiiiiii";
char const ItemSetEntryfmt[] = "nsiiiiiiiiiiiiiiiiiii";
char const ItemSetSpellEntryfmt[] = "niiii";
+char const ItemSpecEntryfmt[] = "niiiiii";
+char const ItemSpecOverrideEntryfmt[] = "nii";
char const LFGDungeonEntryfmt[] = "nsiiixxiiiixxixixxxxxxxxxxxxx";
char const LightEntryfmt[] = "nifffxxxxxxxxxx";
char const LiquidTypefmt[] = "nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
diff --git a/src/server/game/Entities/Item/ItemTemplate.cpp b/src/server/game/Entities/Item/ItemTemplate.cpp
index 983a263f725..e0e577f1d38 100644
--- a/src/server/game/Entities/Item/ItemTemplate.cpp
+++ b/src/server/game/Entities/Item/ItemTemplate.cpp
@@ -20,6 +20,7 @@
#include "DB2Stores.h"
#include "World.h"
#include "ItemTemplate.h"
+#include "Player.h"
char const* ItemTemplate::GetName(LocaleConstant locale) const
{
@@ -136,3 +137,19 @@ void ItemTemplate::GetDamage(uint32 itemLevel, float& minDamage, float& maxDamag
minDamage = (GetStatScalingFactor() * -0.5f + 1.0f) * avgDamage;
maxDamage = floor(float(avgDamage * (GetStatScalingFactor() * 0.5f + 1.0f) + 0.5f));
}
+
+bool ItemTemplate::CanWinForPlayer(Player* plr) const
+{
+ if (!Specializations.size())
+ return true;
+
+ uint32 spec = plr->GetSpecId(plr->GetActiveTalentGroup());
+ if (!spec)
+ spec = plr->GetDefaultSpecId();
+
+ if (!spec)
+ return false;
+
+ UsableTalentSpecs::const_iterator itr = Specializations.find(spec);
+ return itr != Specializations.end();
+}
diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h
index eb5fbc2e022..3272de6ac5a 100644
--- a/src/server/game/Entities/Item/ItemTemplate.h
+++ b/src/server/game/Entities/Item/ItemTemplate.h
@@ -584,6 +584,8 @@ const uint32 MaxItemSubclassValues[MAX_ITEM_CLASS] =
#define MIN_ITEM_LEVEL 1
#define MAX_ITEM_LEVEL 1000
+typedef std::set<uint32> UsableTalentSpecs;
+
struct ItemTemplate
{
ItemEntry const* BasicData;
@@ -655,6 +657,7 @@ struct ItemTemplate
uint32 MaxMoneyLoot;
uint32 FlagsCu;
float SpellPPMRate;
+ UsableTalentSpecs Specializations;
// helpers
bool CanChangeEquipStateInCombat() const
@@ -701,6 +704,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;
};
// Benchmarked: Faster than std::map (insert/find)
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 2ef3380a5eb..8305949b352 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -14413,13 +14413,16 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg)
ItemPosCountVec dest;
if (quest->GetRewChoiceItemsCount() > 0)
{
- if (quest->RewardChoiceItemId[reward])
+ for (uint32 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
{
- InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, quest->RewardChoiceItemId[reward], quest->RewardChoiceItemCount[reward]);
- if (res != EQUIP_ERR_OK)
+ if (quest->RewardChoiceItemId[i] && quest->RewardChoiceItemId[i] == reward)
{
- SendEquipError(res, NULL, NULL, quest->RewardChoiceItemId[reward]);
- return false;
+ InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, quest->RewardChoiceItemId[i], quest->RewardChoiceItemCount[i]);
+ if (res != EQUIP_ERR_OK)
+ {
+ SendEquipError(res, NULL, NULL, quest->RewardChoiceItemId[i]);
+ return false;
+ }
}
}
}
@@ -14439,6 +14442,30 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg)
}
}
}
+
+ // QuestPackageItem.db2
+ if (quest->GetQuestPackageID())
+ {
+ if (sQuestPackageItemStoreMap.find(quest->GetQuestPackageID()) != sQuestPackageItemStoreMap.end())
+ {
+ QuestPackageItemList itemList = sQuestPackageItemStoreMap[quest->GetQuestPackageID()];
+ for (QuestPackageItemList::const_iterator itr = itemList.begin(); itr != itemList.end(); ++itr)
+ {
+ if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate((*itr)->ItemID))
+ {
+ if (rewardProto->CanWinForPlayer(this))
+ {
+ InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, (*itr)->ItemID, (*itr)->ItemCount);
+ if (res != EQUIP_ERR_OK)
+ {
+ SendEquipError(res, NULL, NULL, (*itr)->ItemID);
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
return true;
}
@@ -14591,7 +14618,8 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
switch (obj.Type)
{
case QUEST_OBJECTIVE_ITEM:
- DestroyItemCount(obj.ObjectID, obj.Amount, true);
+ if (!(quest->GetFlagsEx() & QUEST_FLAGS_EX_KEEP_ADDITIONAL_ITEMS))
+ DestroyItemCount(obj.ObjectID, obj.Amount, true);
break;
case QUEST_OBJECTIVE_CURRENCY:
ModifyCurrency(obj.ObjectID, -int32(obj.Amount));
@@ -14599,12 +14627,15 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
}
}
- for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
+ if (!(quest->GetFlagsEx() & QUEST_FLAGS_EX_KEEP_ADDITIONAL_ITEMS))
{
- if (quest->ItemDrop[i])
+ for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
{
- uint32 count = quest->ItemDropQuantity[i];
- DestroyItemCount(quest->ItemDrop[i], count ? count : 9999, true);
+ if (quest->ItemDrop[i])
+ {
+ uint32 count = quest->ItemDropQuantity[i];
+ DestroyItemCount(quest->ItemDrop[i], count ? count : 9999, true);
+ }
}
}
@@ -14612,13 +14643,40 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
if (quest->GetRewChoiceItemsCount() > 0)
{
- if (uint32 itemId = quest->RewardChoiceItemId[reward])
+ for (uint32 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
{
- ItemPosCountVec dest;
- if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, quest->RewardChoiceItemCount[reward]) == EQUIP_ERR_OK)
+ if (quest->RewardChoiceItemId[i] && quest->RewardChoiceItemId[i] == reward)
{
- Item* item = StoreNewItem(dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId));
- SendNewItem(item, quest->RewardChoiceItemCount[reward], true, false);
+ ItemPosCountVec dest;
+ if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, reward, quest->RewardChoiceItemCount[i]) == EQUIP_ERR_OK)
+ {
+ Item* item = StoreNewItem(dest, reward, true, Item::GenerateItemRandomPropertyId(reward));
+ SendNewItem(item, quest->RewardChoiceItemCount[i], true, false);
+ }
+ }
+ }
+ }
+
+ // QuestPackageItem.db2
+ if (quest->GetQuestPackageID())
+ {
+ if (sQuestPackageItemStoreMap.find(quest->GetQuestPackageID()) != sQuestPackageItemStoreMap.end())
+ {
+ QuestPackageItemList itemList = sQuestPackageItemStoreMap[quest->GetQuestPackageID()];
+ for (QuestPackageItemList::const_iterator itr = itemList.begin(); itr != itemList.end(); ++itr)
+ {
+ if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate((*itr)->ItemID))
+ {
+ if (rewardProto->CanWinForPlayer(this))
+ {
+ ItemPosCountVec dest;
+ if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, (*itr)->ItemID, (*itr)->ItemCount) == EQUIP_ERR_OK)
+ {
+ Item* item = StoreNewItem(dest, (*itr)->ItemID, true, Item::GenerateItemRandomPropertyId((*itr)->ItemID));
+ SendNewItem(item, (*itr)->ItemCount, true, false);
+ }
+ }
+ }
}
}
}
@@ -26563,4 +26621,12 @@ bool Player::ValidateAppearance(uint8 race, uint8 class_, uint8 gender, uint8 ha
return false;
return true;
-} \ No newline at end of file
+}
+
+uint32 Player::GetDefaultSpecId() const
+{
+ ChrClassesEntry const* entry = sChrClassesStore.LookupEntry(getClass());
+ if (entry)
+ return entry->DefaultSpec;
+ return 0;
+}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 7698cee5a70..9ddcf6ed92d 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1892,6 +1892,7 @@ class Player : public Unit, public GridObject<Player>
void SetActiveTalentGroup(uint8 group){ _talentMgr->ActiveGroup = group; }
uint8 GetTalentGroupsCount() const { return _talentMgr->GroupsCount; }
void SetTalentGroupsCount(uint8 count) { _talentMgr->GroupsCount = count; }
+ uint32 GetDefaultSpecId() const;
bool ResetTalents(bool noCost = false);
uint32 GetNextResetTalentsCost() const;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index eec09b6f7d1..43371c5aff8 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -2439,6 +2439,32 @@ void ObjectMgr::LoadItemTemplates()
itemTemplate.MaxMoneyLoot = 0;
itemTemplate.FlagsCu = 0;
itemTemplate.SpellPPMRate = 0.0f;
+
+ /*for (uint32 i = 0; i < sItemSpecStore.GetNumRows(); ++i)
+ {
+ if (ItemSpecEntry const* spec = sItemSpecStore.LookupEntry(i))
+ {
+ if (itemTemplate.GetBaseItemLevel() >= spec->MinLevel && itemTemplate.GetBaseItemLevel() <= spec->MaxLevel)
+ {
+ // have to research what are these!
+ if (spec->PrimaryStat && spec->SecondaryStat && spec->ItemType)
+ {
+ itemTemplate.Specializations.insert(spec->SpecID);
+ }
+ }
+ }
+ }*/
+
+ ItemSpecOverridesStore::const_iterator spec = sItemSpecOverridesStore.find(itemTemplate.GetId());
+ if (spec != sItemSpecOverridesStore.end())
+ {
+ itemTemplate.Specializations.clear();
+ for (ItemSpecOverrideEntry const* over : (*spec).second)
+ {
+ itemTemplate.Specializations.insert(over->SpecID);
+ }
+ }
+
++sparseCount;
}
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index ee3ccea9460..5e73fb71ae8 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -237,17 +237,38 @@ void WorldSession::HandleQuestQueryOpcode(WorldPackets::Quest::QueryQuestInfo& p
void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::QuestGiverChooseReward& packet)
{
- if (packet.ItemChoiceID >= QUEST_REWARD_CHOICES_COUNT)
- {
- TC_LOG_ERROR("network", "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (%s) tried to get invalid reward (%u) (possible packet-hacking detected)", _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), packet.ItemChoiceID);
- return;
- }
-
TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %s, quest = %u, reward = %u", packet.QuestGiverGUID.ToString().c_str(), packet.QuestID, packet.ItemChoiceID);
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)
+ {
+ ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(packet.ItemChoiceID);
+ if (!rewardProto)
+ {
+ TC_LOG_ERROR("network", "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (%s) tried to get invalid reward item (Item Entry: %u) for quest %u (possible packet-hacking detected)", _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), packet.ItemChoiceID, packet.QuestID);
+ return;
+ }
+
+ bool itemValid = false;
+ for (uint32 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
+ {
+ if (quest->RewardChoiceItemId[i] && quest->RewardChoiceItemId[i] == packet.ItemChoiceID)
+ {
+ 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);
+ return;
+ }
+ }
Object* object = _player;
@@ -643,4 +664,4 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPackets::Quest::Ques
}
SendPacket(response.Write());
-} \ No newline at end of file
+}
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index 3e62348a5c3..8433a549c60 100644
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -163,6 +163,33 @@ enum QuestFlags
// ... 4.x added flags up to 0x80000000 - all unknown for now
};
+// last checked in 19802
+enum QuestFlagsEx
+{
+ QUEST_FLAGS_EX_NONE = 0X000000,
+ QUEST_FLAGS_EX_KEEP_ADDITIONAL_ITEMS = 0X000001,
+ QUEST_FLAGS_EX_SUPPRESS_GOSSIP_COMPLETE = 0X000002,
+ QUEST_FLAGS_EX_SUPPRESS_GOSSIP_ACCEPT = 0X000004,
+ QUEST_FLAGS_EX_DISALLOW_PLAYER_AS_QUESTGIVER = 0X000008,
+ QUEST_FLAGS_EX_DISPLAY_CLASS_CHOICE_REWARDS = 0X000010,
+ QUEST_FLAGS_EX_DISPLAY_SPEC_CHOICE_REWARDS = 0X000020,
+ QUEST_FLAGS_EX_REMOVE_FROM_LOG_ON_PERIDOIC_RESET = 0X000040,
+ QUEST_FLAGS_EX_ACCOUNT_LEVEL_QUEST = 0X000080,
+ QUEST_FLAGS_EX_LEGENDARY_QUEST = 0X000100,
+ QUEST_FLAGS_EX_NO_GUILD_XP = 0X000200,
+ QUEST_FLAGS_EX_RESET_CACHE_ON_ACCEPT = 0X000400,
+ QUEST_FLAGS_EX_NO_ABANDON_ONCE_ANY_OBJECTIVE_COMPLETE = 0X000800,
+ QUEST_FLAGS_EX_RECAST_ACCEPT_SPELL_ON_LOGIN = 0X001000,
+ QUEST_FLAGS_EX_UPDATE_ZONE_AURAS = 0X002000,
+ QUEST_FLAGS_EX_NO_CREDIT_FOR_PROXY = 0X004000,
+ QUEST_FLAGS_EX_DISPLAY_AS_DAILY_QUEST = 0X008000,
+ QUEST_FLAGS_EX_PART_OF_QUEST_LINE = 0X010000,
+ QUEST_FLAGS_EX_QUEST_FOR_INTERNAL_BUILDS_ONLY = 0X020000,
+ QUEST_FLAGS_EX_SUPPRESS_SPELL_LEARN_TEXT_LINE = 0X040000,
+ QUEST_FLAGS_EX_DISPLAY_HEADER_AS_OBJECTIVE_FOR_TASKS = 0X080000,
+ QUEST_FLAGS_EX_GARRISON_NON_OWNERS_ALLOWED = 0X100000
+};
+
enum QuestSpecialFlags
{
QUEST_SPECIAL_FLAGS_NONE = 0x000,
diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.cpp b/src/server/shared/Database/Implementation/HotfixDatabase.cpp
index 7f148f95e00..73441855483 100644
--- a/src/server/shared/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/shared/Database/Implementation/HotfixDatabase.cpp
@@ -118,6 +118,9 @@ void HotfixDatabaseConnection::DoPrepareStatements()
// PhaseGroup.db2
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);
+
// SoundEntries.db2
PrepareStatement(HOTFIX_SEL_SOUND_ENTRIES, "SELECT ID, SoundType, Name, FileDataID1, FileDataID2, FileDataID3, FileDataID4, FileDataID5, "
"FileDataID6, FileDataID7, FileDataID8, FileDataID9, FileDataID10, FileDataID11, FileDataID12, FileDataID13, FileDataID14, FileDataID15, "
diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.h b/src/server/shared/Database/Implementation/HotfixDatabase.h
index 70472537510..3d8e528cd98 100644
--- a/src/server/shared/Database/Implementation/HotfixDatabase.h
+++ b/src/server/shared/Database/Implementation/HotfixDatabase.h
@@ -86,6 +86,8 @@ enum HotfixDatabaseStatements
HOTFIX_SEL_OVERRIDE_SPELL_DATA,
HOTFIX_SEL_PHASE_GROUP,
+
+ HOTFIX_SEL_QUEST_PACKAGE_ITEM,
HOTFIX_SEL_SOUND_ENTRIES,
HOTFIX_SEL_SOUND_ENTRIES_LOCALE,