Core/Datastores: backported hotfix system implementation
This commit is contained in:
1 parent
4bc9c07407
commit
d9b854ad59
87 files changed
+2227
-2251
No files matched your search
@@ -10,8 +10,9 @@
|
||||
#define _BUILD_DIRECTORY R"(@BUILDDIR@)"
|
||||
#define _MYSQL_EXECUTABLE R"(@MYSQL_EXECUTABLE@)"
|
||||
#define _FULL_DATABASE "TDB_full_world_434.34_2018_09_15.sql"
|
||||
#define _HOTFIXES_DATABASE "TDB_full_hotfixes_434.01_2020_02_21.sql"
|
||||
#define VER_COMPANYNAME_STR "TrinityCore Developers"
|
||||
#define VER_LEGALCOPYRIGHT_STR "(c)2008-2018 TrinityCore"
|
||||
#define VER_LEGALCOPYRIGHT_STR "(c)2008-2020 TrinityCore"
|
||||
#define VER_FILEVERSION 0,0,0
|
||||
#define VER_FILEVERSION_STR "@rev_hash@ @rev_date@ (@rev_branch@ branch)"
|
||||
#define VER_PRODUCTVERSION VER_FILEVERSION
|
||||
|
||||
@@ -6,8 +6,12 @@ CREATE DATABASE `characters` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
|
||||
CREATE DATABASE `auth` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
|
||||
CREATE DATABASE `hotfixes` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
|
||||
GRANT ALL PRIVILEGES ON `world` . * TO 'trinity'@'localhost' WITH GRANT OPTION;
|
||||
|
||||
GRANT ALL PRIVILEGES ON `characters` . * TO 'trinity'@'localhost' WITH GRANT OPTION;
|
||||
|
||||
GRANT ALL PRIVILEGES ON `auth` . * TO 'trinity'@'localhost' WITH GRANT OPTION;
|
||||
|
||||
GRANT ALL PRIVILEGES ON `hotfixes` . * TO 'trinity'@'localhost' WITH GRANT OPTION;
|
||||
@@ -12,6 +12,10 @@ REVOKE ALL PRIVILEGES ON `auth` . * FROM 'trinity'@'localhost';
|
||||
|
||||
REVOKE GRANT OPTION ON `auth` . * FROM 'trinity'@'localhost';
|
||||
|
||||
REVOKE ALL PRIVILEGES ON `hotfixes` . * FROM 'trinity'@'localhost';
|
||||
|
||||
REVOKE GRANT OPTION ON `hotfixes` . * FROM 'trinity'@'localhost';
|
||||
|
||||
DROP USER 'trinity'@'localhost';
|
||||
|
||||
DROP DATABASE IF EXISTS `world`;
|
||||
@@ -19,3 +23,5 @@ DROP DATABASE IF EXISTS `world`;
|
||||
DROP DATABASE IF EXISTS `characters`;
|
||||
|
||||
DROP DATABASE IF EXISTS `auth`;
|
||||
|
||||
DROP DATABASE IF EXISTS `hotfixes`;
|
||||
@@ -0,0 +1,4 @@
|
||||
DROP TABLE IF EXISTS `hotfix_data`;
|
||||
DROP TABLE IF EXISTS `keychain_db2`;
|
||||
DROP TABLE IF EXISTS `item_template`;
|
||||
DROP TABLE IF EXISTS `item_template_locale`;
|
||||
@@ -68,6 +68,11 @@ char const* GitRevision::GetFullDatabase()
|
||||
return _FULL_DATABASE;
|
||||
}
|
||||
|
||||
char const* GitRevision::GetHotfixesDatabase()
|
||||
{
|
||||
return _HOTFIXES_DATABASE;
|
||||
}
|
||||
|
||||
#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
|
||||
# ifdef _WIN64
|
||||
# define TRINITY_PLATFORM_STR "Win64"
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace GitRevision
|
||||
TC_COMMON_API char const* GetSourceDirectory();
|
||||
TC_COMMON_API char const* GetMySQLExecutable();
|
||||
TC_COMMON_API char const* GetFullDatabase();
|
||||
TC_COMMON_API char const* GetHotfixesDatabase();
|
||||
TC_COMMON_API char const* GetFullVersion();
|
||||
TC_COMMON_API char const* GetCompanyNameStr();
|
||||
TC_COMMON_API char const* GetLegalCopyrightStr();
|
||||
|
||||
@@ -20,3 +20,4 @@
|
||||
DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabase;
|
||||
DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabase;
|
||||
DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabase;
|
||||
DatabaseWorkerPool<HotfixDatabaseConnection> HotfixDatabase;
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "Implementation/LoginDatabase.h"
|
||||
#include "Implementation/CharacterDatabase.h"
|
||||
#include "Implementation/WorldDatabase.h"
|
||||
#include "Implementation/HotfixDatabase.h"
|
||||
|
||||
#include "Field.h"
|
||||
#include "PreparedStatement.h"
|
||||
@@ -37,5 +38,7 @@ TC_DATABASE_API extern DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabase
|
||||
TC_DATABASE_API extern DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabase;
|
||||
/// Accessor to the realm/login database
|
||||
TC_DATABASE_API extern DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabase;
|
||||
/// Accessor to the hotfix database
|
||||
TC_DATABASE_API extern DatabaseWorkerPool<HotfixDatabaseConnection> HotfixDatabase;
|
||||
|
||||
#endif
|
||||
@@ -184,3 +184,5 @@ template TC_DATABASE_API
|
||||
DatabaseLoader& DatabaseLoader::AddDatabase<CharacterDatabaseConnection>(DatabaseWorkerPool<CharacterDatabaseConnection>&, std::string const&);
|
||||
template TC_DATABASE_API
|
||||
DatabaseLoader& DatabaseLoader::AddDatabase<WorldDatabaseConnection>(DatabaseWorkerPool<WorldDatabaseConnection>&, std::string const&);
|
||||
template TC_DATABASE_API
|
||||
DatabaseLoader& DatabaseLoader::AddDatabase<HotfixDatabaseConnection>(DatabaseWorkerPool<HotfixDatabaseConnection>&, std::string const&);
|
||||
@@ -48,8 +48,9 @@ public:
|
||||
DATABASE_LOGIN = 1,
|
||||
DATABASE_CHARACTER = 2,
|
||||
DATABASE_WORLD = 4,
|
||||
DATABASE_HOTFIX = 5,
|
||||
|
||||
DATABASE_MASK_ALL = DATABASE_LOGIN | DATABASE_CHARACTER | DATABASE_WORLD
|
||||
DATABASE_MASK_ALL = DATABASE_LOGIN | DATABASE_CHARACTER | DATABASE_WORLD | DATABASE_HOTFIX
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "Implementation/LoginDatabase.h"
|
||||
#include "Implementation/WorldDatabase.h"
|
||||
#include "Implementation/CharacterDatabase.h"
|
||||
#include "Implementation/HotfixDatabase.h"
|
||||
#include "Log.h"
|
||||
#include "PreparedStatement.h"
|
||||
#include "ProducerConsumerQueue.h"
|
||||
@@ -470,3 +471,5 @@ void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction& trans, PreparedState
|
||||
template class TC_DATABASE_API DatabaseWorkerPool<LoginDatabaseConnection>;
|
||||
template class TC_DATABASE_API DatabaseWorkerPool<WorldDatabaseConnection>;
|
||||
template class TC_DATABASE_API DatabaseWorkerPool<CharacterDatabaseConnection>;
|
||||
template class TC_DATABASE_API DatabaseWorkerPool<HotfixDatabaseConnection>;
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// DO NOT EDIT!
|
||||
// Autogenerated from DB2Structure.h
|
||||
|
||||
#include "HotfixDatabase.h"
|
||||
|
||||
// Force locale statments to appear exactly in locale declaration order, right after normal data fetch statement
|
||||
#define PREPARE_LOCALE_STMT(stmtBase, sql, con) \
|
||||
static_assert(stmtBase + 1 == stmtBase##_LOCALE, "Invalid prepared statement index for " #stmtBase "_LOCALE"); \
|
||||
PrepareStatement(stmtBase##_LOCALE, sql, con);
|
||||
|
||||
void HotfixDatabaseConnection::DoPrepareStatements()
|
||||
{
|
||||
if (!m_reconnecting)
|
||||
m_stmts.resize(MAX_HOTFIXDATABASE_STATEMENTS);
|
||||
|
||||
// KeyChain.db2
|
||||
PrepareStatement(HOTFIX_SEL_KEY_CHAIN, "SELECT Id, Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9, Key10, Key11, Key12, Key13, Key14, Key15, Key16, "
|
||||
"Key17, Key18, Key19, Key20, Key21, Key22, Key23, Key24, Key25, Key26, Key27, Key28, Key29, Key30, Key31, Key32 FROM key_chain ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
|
||||
// Item.db2
|
||||
PrepareStatement(HOTFIX_SEL_ITEM, "SELECT ID, Class, SubClass, SoundOverrideSubclass, Material, InventoryType, Sheath FROM item ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
|
||||
// ItemCurrencyCost.db2
|
||||
PrepareStatement(HOTFIX_SEL_ITEM_CURRENCY_COST, "SELECT ID, ItemID FROM item_currency_cost ORDER BY ItemID DESC", CONNECTION_SYNCH);
|
||||
|
||||
// ItemExtendedCost.db2
|
||||
PrepareStatement(HOTFIX_SEL_ITEM_EXTENDED_COST, "SELECT ID, RequiredHonorPoints, RequiredArenaPoints, RequiredArenaSlot, "
|
||||
"RequiredItem1, RequiredItem2, RequiredItem3, RequiredItem4, RequiredItem5, "
|
||||
"RequiredItemCount1, RequiredItemCount2, RequiredItemCount3, RequiredItemCount4, RequiredItemCount5, "
|
||||
"RequiredPersonalArenaRating, ItemPurchaseGroup, "
|
||||
"RequiredCurrency1, RequiredCurrency2, RequiredCurrency3, RequiredCurrency4, RequiredCurrency5, "
|
||||
"RequiredCurrencyCount1, RequiredCurrencyCount2, RequiredCurrencyCount3, RequiredCurrencyCount4, RequiredCurrencyCount5, "
|
||||
"RequiredFactionId, RequiredFactionStanding, RequirementFlags, RequiredAchievement FROM item_extended_cost ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
|
||||
// Item-sparse.db2
|
||||
PrepareStatement(HOTFIX_SEL_ITEM_SPARSE, "SELECT ID, Quality, Flags1, Flags2, Unk1, Unk2, BuyCount, BuyPrice, SellPrice, InventoryType, "
|
||||
"AllowableClass, AllowableRace, ItemLevel, RequiredLevel, RequiredSkill, RequiredSkillRank, RequiredSpell, RequiredHonorRank, "
|
||||
"RequiredCityRank, RequiredReputationFaction, RequiredReputationRank, MaxCount, Stackable, ContainerSlots, "
|
||||
"ItemStatType1, ItemStatType2, ItemStatType3, ItemStatType4, ItemStatType5, "
|
||||
"ItemStatType6, ItemStatType7, ItemStatType8, ItemStatType9, ItemStatType10, "
|
||||
"ItemStatValue1, ItemStatValue2, ItemStatValue3, ItemStatValue4, ItemStatValue5, "
|
||||
"ItemStatValue6, ItemStatValue7, ItemStatValue8, ItemStatValue9, ItemStatValue10, "
|
||||
"ItemStatAllocation1, ItemStatAllocation2, ItemStatAllocation3, ItemStatAllocation4, ItemStatAllocation5, "
|
||||
"ItemStatAllocation6, ItemStatAllocation7, ItemStatAllocation8, ItemStatAllocation9, ItemStatAllocation10, "
|
||||
"ItemStatSocketCostMultiplier1, ItemStatSocketCostMultiplier2, ItemStatSocketCostMultiplier3, ItemStatSocketCostMultiplier4, ItemStatSocketCostMultiplier5, "
|
||||
"ItemStatSocketCostMultiplier6, ItemStatSocketCostMultiplier7, ItemStatSocketCostMultiplier8, ItemStatSocketCostMultiplier9, ItemStatSocketCostMultiplier10, "
|
||||
"ScalingStatDistribution, DamageType, Delay, RangedModRange, "
|
||||
"SpellID1, SpellID2, SpellID3, SpellID4, SpellID5, "
|
||||
"SpellTrigger1, SpellTrigger2, SpellTrigger3, SpellTrigger4, SpellTrigger5, "
|
||||
"SpellCharges1, SpellCharges2, SpellCharges3, SpellCharges4, SpellCharges5, "
|
||||
"SpellCooldown1, SpellCooldown2, SpellCooldown3, SpellCooldown4, SpellCooldown5, "
|
||||
"SpellCategory1, SpellCategory2, SpellCategory3, SpellCategory4, SpellCategory5, "
|
||||
"SpellCategoryCooldown1, SpellCategoryCooldown2, SpellCategoryCooldown3, SpellCategoryCooldown4, SpellCategoryCooldown5, "
|
||||
"Bonding, Name, Name2, Name3, Name4, Description, PageText, LanguageID, PageMaterial, StartQuest, LockID, Material, Sheath, RandomProperty, RandomSuffix, ItemSet, "
|
||||
"Area, Map, BagFamily, TotemCategory, SocketColor1, SocketColor2, SocketColor3, Content1, Content2, Content3, SocketBonus, GemProperties, ArmorDamageModifier, "
|
||||
"Duration, ItemLimitCategory, HolidayID, StatScalingFactor, CurrencySubstitutionID, CurrencySubstitutionCount FROM item_sparse ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
PREPARE_LOCALE_STMT(HOTFIX_SEL_ITEM_SPARSE, "SELECT ID, Name_lang, Name2_lang, Name3_lang, Name4_lang, Description_lang FROM item_sparse_locale WHERE locale = ?", CONNECTION_SYNCH);
|
||||
}
|
||||
|
||||
HotfixDatabaseConnection::HotfixDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HotfixDatabaseConnection::HotfixDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo)
|
||||
{
|
||||
}
|
||||
|
||||
HotfixDatabaseConnection::~HotfixDatabaseConnection()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// DO NOT EDIT!
|
||||
// Autogenerated from DB2Structure.h
|
||||
|
||||
#ifndef _HOTFIXDATABASE_H
|
||||
#define _HOTFIXDATABASE_H
|
||||
|
||||
#include "MySQLConnection.h"
|
||||
|
||||
enum HotfixDatabaseStatements : uint32
|
||||
{
|
||||
/* Naming standard for defines:
|
||||
{DB}_{SEL/INS/UPD/DEL/REP}_{Summary of data changed}
|
||||
When updating more than one field, consider looking at the calling function
|
||||
name for a suiting suffix.
|
||||
|
||||
DB2 locale loading statements must have the name of base statement with locale enum value name suffix
|
||||
*/
|
||||
|
||||
HOTFIX_SEL_KEY_CHAIN,
|
||||
HOTFIX_SEL_ITEM,
|
||||
HOTFIX_SEL_ITEM_CURRENCY_COST,
|
||||
HOTFIX_SEL_ITEM_EXTENDED_COST,
|
||||
HOTFIX_SEL_ITEM_SPARSE,
|
||||
HOTFIX_SEL_ITEM_SPARSE_LOCALE,
|
||||
MAX_HOTFIXDATABASE_STATEMENTS
|
||||
};
|
||||
|
||||
class TC_DATABASE_API HotfixDatabaseConnection : public MySQLConnection
|
||||
{
|
||||
public:
|
||||
typedef HotfixDatabaseStatements Statements;
|
||||
|
||||
//- Constructors for sync and async connections
|
||||
HotfixDatabaseConnection(MySQLConnectionInfo& connInfo);
|
||||
HotfixDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo);
|
||||
~HotfixDatabaseConnection();
|
||||
|
||||
//- Loads database type specific prepared statements
|
||||
void DoPrepareStatements() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -79,7 +79,6 @@ void WorldDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, permission, help FROM command", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_CREATURE_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM creature WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH);
|
||||
|
||||
@@ -84,7 +84,6 @@ enum WorldDatabaseStatements : uint32
|
||||
WORLD_SEL_COMMANDS,
|
||||
WORLD_SEL_CREATURE_TEMPLATE,
|
||||
WORLD_SEL_WAYPOINT_SCRIPT_BY_ID,
|
||||
WORLD_SEL_ITEM_TEMPLATE_BY_NAME,
|
||||
WORLD_SEL_CREATURE_BY_ID,
|
||||
WORLD_SEL_GAMEOBJECT_NEAREST,
|
||||
WORLD_SEL_CREATURE_NEAREST,
|
||||
|
||||
@@ -150,6 +150,38 @@ bool DBUpdater<CharacterDatabaseConnection>::IsEnabled(uint32 const updateMask)
|
||||
return (updateMask & DatabaseLoader::DATABASE_CHARACTER) ? true : false;
|
||||
}
|
||||
|
||||
// Hotfix Database
|
||||
template<>
|
||||
std::string DBUpdater<HotfixDatabaseConnection>::GetConfigEntry()
|
||||
{
|
||||
return "Updates.Hotfix";
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string DBUpdater<HotfixDatabaseConnection>::GetTableName()
|
||||
{
|
||||
return "Hotfixes";
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string DBUpdater<HotfixDatabaseConnection>::GetBaseFile()
|
||||
{
|
||||
return GitRevision::GetHotfixesDatabase();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool DBUpdater<HotfixDatabaseConnection>::IsEnabled(uint32 const updateMask)
|
||||
{
|
||||
// This way silences warnings under msvc
|
||||
return (updateMask & DatabaseLoader::DATABASE_HOTFIX) ? true : false;
|
||||
}
|
||||
|
||||
template<>
|
||||
BaseLocation DBUpdater<HotfixDatabaseConnection>::GetBaseLocationType()
|
||||
{
|
||||
return LOCATION_DOWNLOAD;
|
||||
}
|
||||
|
||||
// All
|
||||
template<class T>
|
||||
BaseLocation DBUpdater<T>::GetBaseLocationType()
|
||||
@@ -391,3 +423,4 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
|
||||
template class TC_DATABASE_API DBUpdater<LoginDatabaseConnection>;
|
||||
template class TC_DATABASE_API DBUpdater<WorldDatabaseConnection>;
|
||||
template class TC_DATABASE_API DBUpdater<CharacterDatabaseConnection>;
|
||||
template class TC_DATABASE_API DBUpdater<HotfixDatabaseConnection>;
|
||||
@@ -509,7 +509,7 @@ bool PlayerAI::IsPlayerRangedAttacker(Player const* who)
|
||||
// check if we have a ranged weapon equipped
|
||||
Item const* rangedSlot = who->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
|
||||
if (ItemTemplate const* rangedTemplate = rangedSlot ? rangedSlot->GetTemplate() : nullptr)
|
||||
if ((1 << rangedTemplate->SubClass) & ITEM_SUBCLASS_MASK_WEAPON_RANGED)
|
||||
if ((1 << rangedTemplate->GetSubClass()) & ITEM_SUBCLASS_MASK_WEAPON_RANGED)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -640,7 +640,7 @@ void PlayerAI::DoRangedAttackIfReady()
|
||||
Item const* rangedItem = me->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
|
||||
if (ItemTemplate const* rangedTemplate = rangedItem ? rangedItem->GetTemplate() : nullptr)
|
||||
{
|
||||
switch (rangedTemplate->SubClass)
|
||||
switch (rangedTemplate->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_BOW:
|
||||
case ITEM_SUBCLASS_WEAPON_GUN:
|
||||
|
||||
@@ -559,7 +559,7 @@ enum RBACPermissions
|
||||
RBAC_PERM_COMMAND_RELOAD_CRETURE_TEXT_LOCALE = 659,
|
||||
RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_TEMPLATE_LOCALE = 660,
|
||||
RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION_LOCALE = 661,
|
||||
RBAC_PERM_COMMAND_RELOAD_ITEM_TEMPLATE_LOCALE = 662,
|
||||
// UNUSED
|
||||
RBAC_PERM_COMMAND_RELOAD_ITEM_SET_NAME_LOCALE = 663,
|
||||
RBAC_PERM_COMMAND_RELOAD_NPC_TEXT_LOCALE = 664,
|
||||
RBAC_PERM_COMMAND_RELOAD_PAGE_TEXT_LOCALE = 665,
|
||||
|
||||
@@ -366,7 +366,7 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
|
||||
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscValue1);
|
||||
if (!pProto)
|
||||
return false;
|
||||
return pProto->ItemLevel >= equipped_item.item_level && pProto->Quality >= equipped_item.item_quality;
|
||||
return pProto->GetBaseItemLevel() >= equipped_item.item_level && pProto->GetQuality() >= equipped_item.item_quality;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID:
|
||||
return source->GetMapId() == map_id.mapId;
|
||||
@@ -382,7 +382,7 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
|
||||
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscValue1);
|
||||
if (!pProto)
|
||||
return false;
|
||||
return pProto->Quality == item.item_quality;
|
||||
return pProto->GetQuality() == item.item_quality;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@@ -2844,7 +2844,7 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
|
||||
if (!go || go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE)
|
||||
return false;
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(uint32(miscValue1));
|
||||
if (!proto || proto->Class == ITEM_CLASS_QUEST)
|
||||
if (!proto || proto->GetClass() == ITEM_CLASS_QUEST)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@@ -2867,7 +2867,7 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_LEVEL: // 3
|
||||
{
|
||||
ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1));
|
||||
if (!item || item->ItemLevel < reqValue)
|
||||
if (!item || item->GetBaseItemLevel() < reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@@ -2902,7 +2902,7 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
{
|
||||
// miscValue1 is itemid
|
||||
ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1));
|
||||
if (!item || item->Quality < reqValue)
|
||||
if (!item || item->GetQuality() < reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@@ -2910,7 +2910,7 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
{
|
||||
// miscValue1 is itemid
|
||||
ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1));
|
||||
if (!item || item->Quality != reqValue)
|
||||
if (!item || item->GetQuality() != reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@@ -2972,14 +2972,14 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_CLASS: // 33
|
||||
{
|
||||
ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1));
|
||||
if (!item || item->Class != reqValue)
|
||||
if (!item || item->GetClass() != reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_SUBCLASS: // 34
|
||||
{
|
||||
ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1));
|
||||
if (!item || item->SubClass != reqValue)
|
||||
if (!item || item->GetSubClass() != reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ AuctionHouseObject* AuctionHouseMgr::GetAuctionsMapByHouseId(uint8 auctionHouseI
|
||||
|
||||
uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 time, Item* pItem, uint32 count)
|
||||
{
|
||||
uint32 MSV = pItem->GetTemplate()->SellPrice;
|
||||
uint32 MSV = pItem->GetTemplate()->GetSellPrice();
|
||||
|
||||
if (MSV <= 0)
|
||||
return AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT);
|
||||
@@ -158,7 +158,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction&
|
||||
uint32 ownerAccId = sCharacterCache->GetCharacterAccountIdByGuid(ownerGuid);
|
||||
|
||||
sLog->outCommand(bidderAccId, "GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)",
|
||||
bidderName.c_str(), bidderAccId, pItem->GetTemplate()->Name1.c_str(), pItem->GetEntry(), pItem->GetCount(), auction->bid, ownerName.c_str(), ownerAccId);
|
||||
bidderName.c_str(), bidderAccId, pItem->GetTemplate()->GetDefaultLocaleName(), pItem->GetEntry(), pItem->GetCount(), auction->bid, ownerName.c_str(), ownerAccId);
|
||||
}
|
||||
|
||||
// receiver exist
|
||||
@@ -707,9 +707,6 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
|
||||
uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality,
|
||||
uint32& count, uint32& totalcount, bool getall)
|
||||
{
|
||||
LocaleConstant localeConstant = player->GetSession()->GetSessionDbLocaleIndex();
|
||||
int locdbc_idx = player->GetSession()->GetSessionDbcLocale();
|
||||
|
||||
time_t curTime = GameTime::GetGameTime();
|
||||
|
||||
PlayerGetAllThrottleMap::const_iterator itr = GetAllThrottleMap.find(player->GetGUID());
|
||||
@@ -752,19 +749,19 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
|
||||
|
||||
ItemTemplate const* proto = item->GetTemplate();
|
||||
|
||||
if (itemClass != 0xffffffff && proto->Class != itemClass)
|
||||
if (itemClass != 0xffffffff && proto->GetClass() != itemClass)
|
||||
continue;
|
||||
|
||||
if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass)
|
||||
if (itemSubClass != 0xffffffff && proto->GetSubClass() != itemSubClass)
|
||||
continue;
|
||||
|
||||
if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType)
|
||||
if (inventoryType != 0xffffffff && proto->GetInventoryType() != inventoryType)
|
||||
continue;
|
||||
|
||||
if (quality != 0xffffffff && proto->Quality != quality)
|
||||
if (quality != 0xffffffff && proto->GetQuality() != quality)
|
||||
continue;
|
||||
|
||||
if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax)))
|
||||
if (levelmin != 0x00 && (proto->GetRequiredLevel() < levelmin || (levelmax != 0 && proto->GetRequiredLevel() > levelmax)))
|
||||
continue;
|
||||
|
||||
if (usable != 0x00 && player->CanUseItem(item) != EQUIP_ERR_OK)
|
||||
@@ -774,15 +771,10 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
|
||||
// No need to do any of this if no search term was entered
|
||||
if (!wsearchedname.empty())
|
||||
{
|
||||
std::string name = proto->Name1;
|
||||
std::string name = proto->GetName(player->GetSession()->GetSessionDbcLocale());
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
// local name
|
||||
if (localeConstant != LOCALE_enUS)
|
||||
if (ItemLocale const* il = sObjectMgr->GetItemLocale(proto->ItemId))
|
||||
ObjectMgr::GetLocaleString(il->Name, localeConstant, name);
|
||||
|
||||
// DO NOT use GetItemEnchantMod(proto->RandomProperty) as it may return a result
|
||||
// that matches the search but it may not equal item->GetItemRandomPropertyId()
|
||||
// used in BuildAuctionInfo() which then causes wrong items to be listed
|
||||
@@ -815,7 +807,7 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
|
||||
// Append the suffix (ie: of the Monkey) to the name using localization
|
||||
// or default enUS if localization is invalid
|
||||
name += ' ';
|
||||
name += suffix[locdbc_idx >= 0 ? locdbc_idx : LOCALE_enUS];
|
||||
name += suffix;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -478,8 +478,8 @@ void AuctionHouseBot::PrepareStatusInfos(AuctionHouseBotStatusInfo& statusInfo)
|
||||
ItemTemplate const* prototype = item->GetTemplate();
|
||||
if (!auctionEntry->owner || sAuctionBotConfig->IsBotChar(auctionEntry->owner)) // Add only ahbot items
|
||||
{
|
||||
if (prototype->Quality < MAX_AUCTION_QUALITY)
|
||||
++statusInfo[i].QualityInfo[prototype->Quality];
|
||||
if (prototype->GetQuality() < MAX_AUCTION_QUALITY)
|
||||
++statusInfo[i].QualityInfo[prototype->GetQuality()];
|
||||
|
||||
++statusInfo[i].ItemsCount;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ bool AuctionBotBuyer::RollBuyChance(BuyerItemInfo const* ahInfo, Item const* ite
|
||||
return false;
|
||||
|
||||
float itemBuyPrice = float(auction->buyout / item->GetCount());
|
||||
float itemPrice = float(item->GetTemplate()->SellPrice ? item->GetTemplate()->SellPrice : GetVendorPrice(item->GetTemplate()->Quality));
|
||||
float itemPrice = float(item->GetTemplate()->GetSellPrice() ? item->GetTemplate()->GetSellPrice() : GetVendorPrice(item->GetTemplate()->GetQuality()));
|
||||
// The AH cut needs to be added to the price, but we dont want a 100% chance to buy if the price is exactly AH default
|
||||
itemPrice *= 1.4f;
|
||||
|
||||
@@ -188,7 +188,7 @@ bool AuctionBotBuyer::RollBuyChance(BuyerItemInfo const* ahInfo, Item const* ite
|
||||
}
|
||||
|
||||
// Add config weigh in for quality
|
||||
chance *= GetChanceMultiplier(item->GetTemplate()->Quality) / 100.0f;
|
||||
chance *= GetChanceMultiplier(item->GetTemplate()->GetQuality()) / 100.0f;
|
||||
|
||||
float rand = frand(0.f, 100.f);
|
||||
bool win = rand <= chance;
|
||||
@@ -200,7 +200,7 @@ bool AuctionBotBuyer::RollBuyChance(BuyerItemInfo const* ahInfo, Item const* ite
|
||||
bool AuctionBotBuyer::RollBidChance(BuyerItemInfo const* ahInfo, Item const* item, AuctionEntry const* auction, uint32 bidPrice)
|
||||
{
|
||||
float itemBidPrice = float(bidPrice / item->GetCount());
|
||||
float itemPrice = float(item->GetTemplate()->SellPrice ? item->GetTemplate()->SellPrice : GetVendorPrice(item->GetTemplate()->Quality));
|
||||
float itemPrice = float(item->GetTemplate()->GetSellPrice() ? item->GetTemplate()->GetSellPrice() : GetVendorPrice(item->GetTemplate()->GetQuality()));
|
||||
// The AH cut needs to be added to the price, but we dont want a 100% chance to buy if the price is exactly AH default
|
||||
itemPrice *= 1.4f;
|
||||
|
||||
@@ -224,7 +224,7 @@ bool AuctionBotBuyer::RollBidChance(BuyerItemInfo const* ahInfo, Item const* ite
|
||||
chance = chance / 5.f;
|
||||
|
||||
// Add config weigh in for quality
|
||||
chance *= GetChanceMultiplier(item->GetTemplate()->Quality) / 100.0f;
|
||||
chance *= GetChanceMultiplier(item->GetTemplate()->GetQuality()) / 100.0f;
|
||||
|
||||
float rand = frand(0.f, 100.f);
|
||||
bool win = rand <= chance;
|
||||
|
||||
@@ -118,7 +118,7 @@ bool AuctionBotSeller::Initialize()
|
||||
continue;
|
||||
|
||||
// skip items with too high quality (code can't properly work with its)
|
||||
if (prototype->Quality >= MAX_AUCTION_QUALITY)
|
||||
if (prototype->GetQuality() >= MAX_AUCTION_QUALITY)
|
||||
continue;
|
||||
|
||||
// forced exclude filter
|
||||
@@ -138,13 +138,13 @@ bool AuctionBotSeller::Initialize()
|
||||
|
||||
if (isForcedIncludeItem)
|
||||
{
|
||||
_itemPool[prototype->Quality][prototype->Class].push_back(itemId);
|
||||
_itemPool[prototype->GetQuality()][prototype->GetClass()].push_back(itemId);
|
||||
++itemsAdded;
|
||||
continue;
|
||||
}
|
||||
|
||||
// bounding filters
|
||||
switch (prototype->Bonding)
|
||||
switch (prototype->GetBonding())
|
||||
{
|
||||
case BIND_NONE:
|
||||
if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BIND_NO))
|
||||
@@ -171,7 +171,7 @@ bool AuctionBotSeller::Initialize()
|
||||
}
|
||||
|
||||
bool allowZero = false;
|
||||
switch (prototype->Class)
|
||||
switch (prototype->GetClass())
|
||||
{
|
||||
case ITEM_CLASS_CONSUMABLE:
|
||||
allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_ALLOW_ZERO); break;
|
||||
@@ -210,12 +210,12 @@ bool AuctionBotSeller::Initialize()
|
||||
{
|
||||
if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_SELLER))
|
||||
{
|
||||
if (prototype->SellPrice == 0)
|
||||
if (prototype->GetSellPrice() == 0)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prototype->BuyPrice == 0)
|
||||
if (prototype->GetBuyPrice() == 0)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -263,28 +263,28 @@ bool AuctionBotSeller::Initialize()
|
||||
}
|
||||
|
||||
// item class/subclass specific filters
|
||||
switch (prototype->Class)
|
||||
switch (prototype->GetClass())
|
||||
{
|
||||
case ITEM_CLASS_ARMOR:
|
||||
case ITEM_CLASS_WEAPON:
|
||||
{
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_ITEM_LEVEL))
|
||||
if (prototype->ItemLevel < value)
|
||||
if (prototype->GetBaseItemLevel() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_ITEM_LEVEL))
|
||||
if (prototype->ItemLevel > value)
|
||||
if (prototype->GetBaseItemLevel() > value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL))
|
||||
if (prototype->RequiredLevel < value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL))
|
||||
if (prototype->GetRequiredLevel() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL))
|
||||
if (prototype->RequiredLevel > value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL))
|
||||
if (prototype->GetRequiredLevel() > value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_SKILL_RANK))
|
||||
if (prototype->RequiredSkillRank < value)
|
||||
if (prototype->GetRequiredSkillRank() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_SKILL_RANK))
|
||||
if (prototype->RequiredSkillRank > value)
|
||||
if (prototype->GetRequiredSkillRank() > value)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
@@ -292,41 +292,41 @@ bool AuctionBotSeller::Initialize()
|
||||
case ITEM_CLASS_CONSUMABLE:
|
||||
case ITEM_CLASS_PROJECTILE:
|
||||
{
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL))
|
||||
if (prototype->RequiredLevel < value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL))
|
||||
if (prototype->GetRequiredLevel() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL))
|
||||
if (prototype->RequiredLevel > value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL))
|
||||
if (prototype->GetRequiredLevel() > value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_SKILL_RANK))
|
||||
if (prototype->RequiredSkillRank < value)
|
||||
if (prototype->GetRequiredSkillRank() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_SKILL_RANK))
|
||||
if (prototype->RequiredSkillRank > value)
|
||||
if (prototype->GetRequiredSkillRank() > value)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
case ITEM_CLASS_MISCELLANEOUS:
|
||||
if (prototype->SubClass == ITEM_SUBCLASS_JUNK_MOUNT)
|
||||
if (prototype->GetSubClass() == ITEM_SUBCLASS_JUNK_MOUNT)
|
||||
{
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL))
|
||||
if (prototype->RequiredLevel < value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL))
|
||||
if (prototype->GetRequiredLevel() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL))
|
||||
if (prototype->RequiredLevel > value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL))
|
||||
if (prototype->GetRequiredLevel() > value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_SKILL_RANK))
|
||||
if (prototype->RequiredSkillRank < value)
|
||||
if (prototype->GetRequiredSkillRank() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_SKILL_RANK))
|
||||
if (prototype->RequiredSkillRank > value)
|
||||
if (prototype->GetRequiredSkillRank() > value)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prototype->Flags & ITEM_FLAG_HAS_LOOT)
|
||||
if (prototype->GetFlags() & ITEM_FLAG_HAS_LOOT)
|
||||
{
|
||||
// skip any not locked lootable items (mostly quest specific or reward cases)
|
||||
if (!prototype->LockID)
|
||||
if (!prototype->GetLockID())
|
||||
continue;
|
||||
|
||||
if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_LOCKBOX_ENABLED))
|
||||
@@ -336,27 +336,27 @@ bool AuctionBotSeller::Initialize()
|
||||
break;
|
||||
case ITEM_CLASS_GLYPH:
|
||||
{
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_REQ_LEVEL))
|
||||
if (prototype->RequiredLevel < value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_REQ_LEVEL))
|
||||
if (prototype->GetRequiredLevel() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_REQ_LEVEL))
|
||||
if (prototype->RequiredLevel > value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_REQ_LEVEL))
|
||||
if (prototype->GetRequiredLevel() > value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_ITEM_LEVEL))
|
||||
if (prototype->RequiredLevel < value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_ITEM_LEVEL))
|
||||
if (prototype->GetRequiredLevel() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_ITEM_LEVEL))
|
||||
if (prototype->RequiredLevel > value)
|
||||
if (int32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_ITEM_LEVEL))
|
||||
if (prototype->GetRequiredLevel() > value)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
case ITEM_CLASS_TRADE_GOODS:
|
||||
{
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_MIN_ITEM_LEVEL))
|
||||
if (prototype->ItemLevel < value)
|
||||
if (prototype->GetBaseItemLevel() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL))
|
||||
if (prototype->ItemLevel > value)
|
||||
if (prototype->GetBaseItemLevel() > value)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
@@ -364,16 +364,16 @@ bool AuctionBotSeller::Initialize()
|
||||
case ITEM_CLASS_QUIVER:
|
||||
{
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL))
|
||||
if (prototype->ItemLevel < value)
|
||||
if (prototype->GetBaseItemLevel() < value)
|
||||
continue;
|
||||
if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL))
|
||||
if (prototype->ItemLevel > value)
|
||||
if (prototype->GetBaseItemLevel() > value)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_itemPool[prototype->Quality][prototype->Class].push_back(itemId);
|
||||
_itemPool[prototype->GetQuality()][prototype->GetClass()].push_back(itemId);
|
||||
++itemsAdded;
|
||||
}
|
||||
|
||||
@@ -644,7 +644,7 @@ uint32 AuctionBotSeller::SetStat(SellerConfiguration& config)
|
||||
ItemTemplate const* prototype = item->GetTemplate();
|
||||
if (prototype)
|
||||
if (!auctionEntry->owner || sAuctionBotConfig->IsBotChar(auctionEntry->owner)) // Add only ahbot items
|
||||
++itemsSaved[prototype->Quality][prototype->Class];
|
||||
++itemsSaved[prototype->GetQuality()][prototype->GetClass()];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,12 +702,12 @@ bool AuctionBotSeller::GetItemsToSell(SellerConfiguration& config, ItemsToSellAr
|
||||
// Set items price. All important value are passed by address.
|
||||
void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConfiguration& config, uint32& buyp, uint32& bidp, uint32 stackCount)
|
||||
{
|
||||
uint32 classRatio = config.GetPriceRatioPerClass(ItemClass(itemProto->Class));
|
||||
uint32 qualityRatio = config.GetPriceRatioPerQuality(AuctionQuality(itemProto->Quality));
|
||||
uint32 classRatio = config.GetPriceRatioPerClass(ItemClass(itemProto->GetClass()));
|
||||
uint32 qualityRatio = config.GetPriceRatioPerQuality(AuctionQuality(itemProto->GetQuality()));
|
||||
float priceRatio = (classRatio * qualityRatio) / 10000.0f;
|
||||
|
||||
float buyPrice = itemProto->BuyPrice;
|
||||
float sellPrice = itemProto->SellPrice;
|
||||
float buyPrice = itemProto->GetBuyPrice();
|
||||
float sellPrice = itemProto->GetSellPrice();
|
||||
|
||||
if (buyPrice == 0)
|
||||
{
|
||||
@@ -715,9 +715,9 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf
|
||||
buyPrice = sellPrice * GetSellModifier(itemProto);
|
||||
else
|
||||
{
|
||||
float divisor = ((itemProto->Class == ITEM_CLASS_WEAPON || itemProto->Class == ITEM_CLASS_ARMOR) ? 284.0f : 80.0f);
|
||||
float tempLevel = (itemProto->ItemLevel == 0 ? 1.0f : itemProto->ItemLevel);
|
||||
float tempQuality = (itemProto->Quality == 0 ? 1.0f : itemProto->Quality);
|
||||
float divisor = ((itemProto->GetClass() == ITEM_CLASS_WEAPON || itemProto->GetClass() == ITEM_CLASS_ARMOR) ? 284.0f : 80.0f);
|
||||
float tempLevel = (itemProto->GetBaseItemLevel() == 0 ? 1.0f : itemProto->GetBaseItemLevel());
|
||||
float tempQuality = (itemProto->GetQuality() == 0 ? 1.0f : itemProto->GetQuality());
|
||||
|
||||
buyPrice = tempLevel * tempQuality * static_cast<float>(GetBuyModifier(itemProto))* tempLevel / divisor;
|
||||
}
|
||||
@@ -729,7 +729,7 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf
|
||||
if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_SELLER))
|
||||
buyPrice = sellPrice;
|
||||
|
||||
float basePriceFloat = buyPrice * stackCount / (itemProto->Class == 6 ? 200.0f : static_cast<float>(itemProto->BuyCount));
|
||||
float basePriceFloat = buyPrice * stackCount / (itemProto->GetClass() == 6 ? 200.0f : static_cast<float>(itemProto->GetBuyCount()));
|
||||
basePriceFloat *= priceRatio;
|
||||
|
||||
float range = basePriceFloat * 0.04f;
|
||||
@@ -747,7 +747,7 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf
|
||||
// Determines the stack size to use for the item
|
||||
uint32 AuctionBotSeller::GetStackSizeForItem(ItemTemplate const* itemProto, SellerConfiguration& config) const
|
||||
{
|
||||
if (config.GetRandomStackRatioPerClass(ItemClass(itemProto->Class)) > urand(0, 99))
|
||||
if (config.GetRandomStackRatioPerClass(ItemClass(itemProto->GetClass())) > urand(0, 99))
|
||||
return urand(1, itemProto->GetMaxStackSize());
|
||||
else
|
||||
return 1;
|
||||
@@ -756,7 +756,7 @@ uint32 AuctionBotSeller::GetStackSizeForItem(ItemTemplate const* itemProto, Sell
|
||||
// Determine the multiplier for the sell price of any weapon without a buy price.
|
||||
uint32 AuctionBotSeller::GetSellModifier(ItemTemplate const* prototype)
|
||||
{
|
||||
switch (prototype->Class)
|
||||
switch (prototype->GetClass())
|
||||
{
|
||||
case ITEM_CLASS_WEAPON:
|
||||
case ITEM_CLASS_ARMOR:
|
||||
@@ -771,11 +771,11 @@ uint32 AuctionBotSeller::GetSellModifier(ItemTemplate const* prototype)
|
||||
// Return the modifier by which the item's level and quality will be modified by to derive a relatively accurate price.
|
||||
uint32 AuctionBotSeller::GetBuyModifier(ItemTemplate const* prototype)
|
||||
{
|
||||
switch (prototype->Class)
|
||||
switch (prototype->GetClass())
|
||||
{
|
||||
case ITEM_CLASS_CONSUMABLE:
|
||||
{
|
||||
switch (prototype->SubClass)
|
||||
switch (prototype->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_CONSUMABLE:
|
||||
return 100;
|
||||
@@ -793,7 +793,7 @@ uint32 AuctionBotSeller::GetBuyModifier(ItemTemplate const* prototype)
|
||||
}
|
||||
case ITEM_CLASS_WEAPON:
|
||||
{
|
||||
switch (prototype->SubClass)
|
||||
switch (prototype->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_AXE:
|
||||
case ITEM_SUBCLASS_WEAPON_MACE:
|
||||
@@ -815,7 +815,7 @@ uint32 AuctionBotSeller::GetBuyModifier(ItemTemplate const* prototype)
|
||||
}
|
||||
case ITEM_CLASS_ARMOR:
|
||||
{
|
||||
switch (prototype->SubClass)
|
||||
switch (prototype->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_ARMOR_MISCELLANEOUS:
|
||||
case ITEM_SUBCLASS_ARMOR_CLOTH:
|
||||
@@ -836,7 +836,7 @@ uint32 AuctionBotSeller::GetBuyModifier(ItemTemplate const* prototype)
|
||||
return 50;
|
||||
case ITEM_CLASS_TRADE_GOODS:
|
||||
{
|
||||
switch (prototype->SubClass)
|
||||
switch (prototype->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_TRADE_GOODS:
|
||||
case ITEM_SUBCLASS_PARTS:
|
||||
|
||||
@@ -122,9 +122,9 @@ bool ItemChatLink::Initialize(std::istringstream& iss)
|
||||
return false;
|
||||
}
|
||||
// Validate item's color
|
||||
if (_color != ItemQualityColors[_item->Quality])
|
||||
if (_color != ItemQualityColors[_item->GetQuality()])
|
||||
{
|
||||
TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked item has color %u, but user claims %u", iss.str().c_str(), ItemQualityColors[_item->Quality], _color);
|
||||
TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked item has color %u, but user claims %u", iss.str().c_str(), ItemQualityColors[_item->GetQuality()], _color);
|
||||
return false;
|
||||
}
|
||||
// Number of various item properties after item entry
|
||||
@@ -168,13 +168,10 @@ bool ItemChatLink::Initialize(std::istringstream& iss)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::string ItemChatLink::FormatName(uint8 index, ItemLocale const* locale, char* suffixStrings) const
|
||||
inline std::string ItemChatLink::FormatName(uint8 index, char* suffixStrings) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
if (locale == nullptr || index >= locale->Name.size())
|
||||
ss << _item->Name1;
|
||||
else
|
||||
ss << locale->Name[index];
|
||||
ss << _item->GetName(LocaleConstant(index));
|
||||
if (suffixStrings)
|
||||
ss << ' ' << suffixStrings[index];
|
||||
return ss.str();
|
||||
@@ -186,13 +183,12 @@ bool ItemChatLink::ValidateName(char* buffer, char const* context)
|
||||
|
||||
char* suffixStrings = _suffix ? _suffix->Name : (_property ? _property->Name : nullptr);
|
||||
|
||||
bool res = (FormatName(LOCALE_enUS, nullptr, suffixStrings) == buffer);
|
||||
bool res = (FormatName(LOCALE_enUS, suffixStrings) == buffer);
|
||||
if (!res)
|
||||
{
|
||||
ItemLocale const* il = sObjectMgr->GetItemLocale(_item->ItemId);
|
||||
for (uint8 index = LOCALE_koKR; index < TOTAL_LOCALES; ++index)
|
||||
{
|
||||
if (FormatName(index, il, suffixStrings) == buffer)
|
||||
if (FormatName(index, suffixStrings) == buffer)
|
||||
{
|
||||
res = true;
|
||||
break;
|
||||
@@ -200,7 +196,7 @@ bool ItemChatLink::ValidateName(char* buffer, char const* context)
|
||||
}
|
||||
}
|
||||
if (!res)
|
||||
TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked item (id: %u) name wasn't found in any localization", context, _item->ItemId);
|
||||
TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked item (id: %u) name wasn't found in any localization", context, _item->GetId());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
virtual bool ValidateName(char* buffer, char const* context) override;
|
||||
|
||||
protected:
|
||||
std::string FormatName(uint8 index, ItemLocale const* locale, char* suffixStrings) const;
|
||||
std::string FormatName(uint8 index, char* suffixStrings) const;
|
||||
|
||||
ItemTemplate const* _item;
|
||||
int32 _data[8];
|
||||
|
||||
@@ -18,91 +18,80 @@
|
||||
#include "DB2Stores.h"
|
||||
#include "Common.h"
|
||||
#include "DB2fmt.h"
|
||||
#include "DB2Utility.h"
|
||||
#include "Errors.h"
|
||||
#include "Log.h"
|
||||
#include "World.h"
|
||||
#include <sstream>
|
||||
|
||||
DB2Storage<ItemEntry> sItemStore(Itemfmt, &DB2Utilities::HasItemEntry, &DB2Utilities::WriteItemDbReply);
|
||||
DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore(ItemCurrencyCostfmt);
|
||||
DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
|
||||
DB2Storage<ItemSparseEntry> sItemSparseStore(ItemSparsefmt, &DB2Utilities::HasItemSparseEntry, &DB2Utilities::WriteItemSparseDbReply);
|
||||
DB2Storage<KeyChainEntry> sKeyChainStore(KeyChainfmt);
|
||||
DB2Storage<ItemEntry> sItemStore("Item.db2", Itemfmt, HOTFIX_SEL_ITEM);
|
||||
DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore("ItemCurrencyCost.db2", ItemCurrencyCostfmt, HOTFIX_SEL_ITEM_CURRENCY_COST);
|
||||
DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore("ItemExtendedCost.db2", ItemExtendedCostEntryfmt, HOTFIX_SEL_ITEM_EXTENDED_COST);
|
||||
DB2Storage<ItemSparseEntry> sItemSparseStore("Item-sparse.db2", ItemSparsefmt, HOTFIX_SEL_ITEM_SPARSE);
|
||||
DB2Storage<KeyChainEntry> sKeyChainStore("KeyChain.db2", KeyChainfmt, HOTFIX_SEL_KEY_CHAIN);
|
||||
|
||||
typedef std::list<std::string> DB2StoreProblemList;
|
||||
|
||||
typedef std::map<uint32 /*hash*/, DB2StorageBase*> DB2StorageMap;
|
||||
DB2StorageMap DB2Stores;
|
||||
|
||||
uint32 DB2FilesCount = 0;
|
||||
|
||||
static bool LoadDB2_assert_print(uint32 fsize, uint32 rsize, std::string const& filename)
|
||||
{
|
||||
TC_LOG_ERROR("misc", "Size of '%s' setted by format string (%u) not equal size of C++ structure (%u).", filename.c_str(), fsize, rsize);
|
||||
|
||||
// ASSERT must fail after function call
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void LoadDB2(uint32& availableDb2Locales, DB2StoreProblemList& errlist, DB2Storage<T>& storage, std::string const& db2_path, std::string const& filename)
|
||||
inline void LoadDB2(uint32& availableDb2Locales, DB2StoreProblemList& errlist, DB2Manager::StorageMap& stores, DB2Storage<T>* storage, std::string const& db2_path)
|
||||
{
|
||||
// compatibility format and C++ structure sizes
|
||||
ASSERT(DB2FileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDB2_assert_print(DB2FileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename));
|
||||
ASSERT(DB2FileLoader::GetFormatRecordSize(storage->GetFormat()) == sizeof(T),
|
||||
"Size of '%s' set by format string (%u) not equal size of C++ structure (" SZFMTD ").",
|
||||
storage->GetFileName().c_str(), DB2FileLoader::GetFormatRecordSize(storage->GetFormat()), sizeof(T));
|
||||
|
||||
++DB2FilesCount;
|
||||
|
||||
std::string db2_filename = db2_path + filename;
|
||||
if (storage.Load(db2_filename.c_str(), LocaleConstant(sWorld->GetDefaultDbcLocale())))
|
||||
if (storage->Load(db2_path, uint32(sWorld->GetDefaultDbcLocale())))
|
||||
{
|
||||
storage->LoadFromDB();
|
||||
|
||||
for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
|
||||
{
|
||||
if (!(availableDb2Locales & (1 << i)))
|
||||
continue;
|
||||
|
||||
if (uint32(sWorld->GetDefaultDbcLocale()) == i)
|
||||
continue;
|
||||
|
||||
std::string localizedName(db2_path);
|
||||
localizedName.append(localeNames[i]);
|
||||
localizedName.push_back('/');
|
||||
localizedName.append(filename);
|
||||
if (availableDb2Locales & (1 << i))
|
||||
if (!storage->LoadStringsFrom((db2_path + localeNames[i] + '/'), i))
|
||||
availableDb2Locales &= ~(1 << i); // mark as not available for speedup next checks
|
||||
|
||||
if (!storage.LoadStringsFrom(localizedName.c_str(), i))
|
||||
availableDb2Locales &= ~(1<<i); // mark as not available for speedup next checks
|
||||
storage->LoadStringsFromDB(LocaleConstant(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// sort problematic db2 to (1) non compatible and (2) nonexistent
|
||||
if (FILE* f = fopen(db2_filename.c_str(), "rb"))
|
||||
if (FILE* f = fopen((db2_path + storage->GetFileName()).c_str(), "rb"))
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << db2_filename << " exists, and has " << storage.GetFieldCount() << " field(s) (expected " << strlen(storage.GetFormat()) << "). Extracted file might be from wrong client version.";
|
||||
stream << storage->GetFileName() << " exists, and has " << storage->GetFieldCount() << " field(s) (expected " << strlen(storage->GetFormat())
|
||||
<< "). Extracted file might be from wrong client version.";
|
||||
std::string buf = stream.str();
|
||||
errlist.push_back(buf);
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
errlist.push_back(db2_filename);
|
||||
errlist.push_back(storage->GetFileName());
|
||||
}
|
||||
|
||||
DB2Stores[storage.GetHash()] = &storage;
|
||||
stores[storage->GetHash()] = storage;
|
||||
}
|
||||
|
||||
void LoadDB2Stores(std::string const& dataPath)
|
||||
void DB2Manager::LoadStores(std::string const& dataPath)
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
std::string db2Path = dataPath + "dbc/";
|
||||
|
||||
DB2StoreProblemList bad_db2_files;
|
||||
uint32 availableDb2Locales = 0xFF;
|
||||
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, sItemStore, db2Path, "Item.db2");
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, sItemCurrencyCostStore, db2Path, "ItemCurrencyCost.db2");
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, sItemSparseStore, db2Path, "Item-sparse.db2");
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, sItemExtendedCostStore, db2Path, "ItemExtendedCost.db2");
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, sKeyChainStore, db2Path, "KeyChain.db2");
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemStore, db2Path);
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemCurrencyCostStore, db2Path);
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemSparseStore, db2Path);
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemExtendedCostStore, db2Path);
|
||||
LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sKeyChainStore, db2Path);
|
||||
|
||||
// error checks
|
||||
if (bad_db2_files.size() >= DB2FilesCount)
|
||||
@@ -128,14 +117,64 @@ void LoadDB2Stores(std::string const& dataPath)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
TC_LOG_INFO("misc", ">> Initialized %d DB2 data stores.", DB2FilesCount);
|
||||
TC_LOG_INFO("server.loading", ">> Initialized %d DB2 data stores in %u ms", DB2FilesCount, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
DB2StorageBase const* GetDB2Storage(uint32 type)
|
||||
DB2StorageBase const* DB2Manager::GetStorage(uint32 type) const
|
||||
{
|
||||
DB2StorageMap::const_iterator itr = DB2Stores.find(type);
|
||||
if (itr != DB2Stores.end())
|
||||
StorageMap::const_iterator itr = _stores.find(type);
|
||||
if (itr != _stores.end())
|
||||
return itr->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DB2Manager::LoadHotfixData()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
QueryResult result = HotfixDatabase.Query("SELECT TableHash, RecordID, `Timestamp`, Deleted FROM hotfix_data");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_INFO("misc", ">> Loaded 0 hotfix info entries.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
_hotfixData.reserve(result->GetRowCount());
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
HotfixNotify info;
|
||||
info.TableHash = fields[0].GetUInt32();
|
||||
info.Entry = fields[1].GetUInt32();
|
||||
info.Timestamp = fields[2].GetUInt32();
|
||||
_hotfixData.push_back(info);
|
||||
|
||||
if (fields[3].GetBool())
|
||||
{
|
||||
auto itr = _stores.find(info.TableHash);
|
||||
if (itr != _stores.end())
|
||||
itr->second->EraseRecord(info.Entry);
|
||||
}
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
TC_LOG_INFO("misc", ">> Loaded %u hotfix info entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
time_t DB2Manager::GetHotfixDate(uint32 entry, uint32 type) const
|
||||
{
|
||||
time_t ret = 0;
|
||||
for (HotfixNotify const& hotfix : _hotfixData)
|
||||
if (hotfix.Entry == entry && hotfix.TableHash == type)
|
||||
if (time_t(hotfix.Timestamp) > ret)
|
||||
ret = time_t(hotfix.Timestamp);
|
||||
|
||||
return ret ? ret : time(nullptr);
|
||||
}
|
||||
@@ -22,14 +22,44 @@
|
||||
#include "DB2Structure.h"
|
||||
#include <string>
|
||||
|
||||
extern DB2Storage<ItemEntry> sItemStore;
|
||||
extern DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore;
|
||||
extern DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore;
|
||||
extern DB2Storage<ItemSparseEntry> sItemSparseStore;
|
||||
extern DB2Storage<KeyChainEntry> sKeyChainStore;
|
||||
TC_GAME_API extern DB2Storage<ItemEntry> sItemStore;
|
||||
TC_GAME_API extern DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore;
|
||||
TC_GAME_API extern DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore;
|
||||
TC_GAME_API extern DB2Storage<ItemSparseEntry> sItemSparseStore;
|
||||
TC_GAME_API extern DB2Storage<KeyChainEntry> sKeyChainStore;
|
||||
|
||||
void LoadDB2Stores(std::string const& dataPath);
|
||||
struct HotfixNotify
|
||||
{
|
||||
uint32 TableHash;
|
||||
uint32 Timestamp;
|
||||
uint32 Entry;
|
||||
};
|
||||
|
||||
DB2StorageBase const* GetDB2Storage(uint32 type);
|
||||
typedef std::vector<HotfixNotify> HotfixData;
|
||||
|
||||
class TC_GAME_API DB2Manager
|
||||
{
|
||||
public:
|
||||
typedef std::map<uint32 /*hash*/, DB2StorageBase*> StorageMap;
|
||||
|
||||
static DB2Manager& Instance()
|
||||
{
|
||||
static DB2Manager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void LoadStores(std::string const& dataPath);
|
||||
DB2StorageBase const* GetStorage(uint32 type) const;
|
||||
|
||||
void LoadHotfixData();
|
||||
HotfixData const* GetHotfixData() const { return &_hotfixData; }
|
||||
time_t GetHotfixDate(uint32 entry, uint32 type) const;
|
||||
|
||||
private:
|
||||
StorageMap _stores;
|
||||
HotfixData _hotfixData;
|
||||
};
|
||||
|
||||
#define sDB2Manager DB2Manager::Instance()
|
||||
|
||||
#endif
|
||||
@@ -19,105 +19,102 @@
|
||||
#define TRINITY_DB2STRUCTURE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "ItemTemplate.h"
|
||||
|
||||
// GCC has alternative #pragma pack(N) syntax and old gcc version does not support pack(push, N), also any gcc version does not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
// Structures used to access raw DB2 data and required packing to portability
|
||||
#define MAX_ITEM_PROTO_SOCKETS 3
|
||||
#define MAX_ITEM_PROTO_SPELLS 5
|
||||
#define MAX_ITEM_PROTO_STATS 10
|
||||
|
||||
struct ItemEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 Class; // 1
|
||||
uint32 SubClass; // 2
|
||||
int32 SoundOverrideSubclass; // 3
|
||||
uint32 ClassID; // 1
|
||||
uint32 SubclassID; // 2
|
||||
int32 SoundOverrideSubclassID; // 3
|
||||
int32 Material; // 4
|
||||
uint32 DisplayId; // 5
|
||||
uint32 DisplayInfoID; // 5
|
||||
uint32 InventoryType; // 6
|
||||
uint32 Sheath; // 7
|
||||
uint32 SheatheType; // 7
|
||||
};
|
||||
|
||||
struct ItemCurrencyCostEntry
|
||||
{
|
||||
//uint32 Id;
|
||||
uint32 ItemId;
|
||||
uint32 ID;
|
||||
uint32 ItemID;
|
||||
};
|
||||
|
||||
struct ItemSparseEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 Quality; // 1
|
||||
uint32 Flags; // 2
|
||||
uint32 Flags2; // 3
|
||||
float Unk430_1;
|
||||
float Unk430_2;
|
||||
uint32 BuyCount;
|
||||
uint32 BuyPrice; // 4
|
||||
uint32 SellPrice; // 5
|
||||
uint32 InventoryType; // 6
|
||||
int32 AllowableClass; // 7
|
||||
int32 AllowableRace; // 8
|
||||
uint32 ItemLevel; // 9
|
||||
int32 RequiredLevel; // 10
|
||||
uint32 RequiredSkill; // 11
|
||||
uint32 RequiredSkillRank; // 12
|
||||
uint32 RequiredSpell; // 13
|
||||
uint32 RequiredHonorRank; // 14
|
||||
uint32 RequiredCityRank; // 15
|
||||
uint32 RequiredReputationFaction; // 16
|
||||
uint32 RequiredReputationRank; // 17
|
||||
uint32 MaxCount; // 18
|
||||
uint32 Stackable; // 19
|
||||
uint32 ContainerSlots; // 20
|
||||
int32 ItemStatType[MAX_ITEM_PROTO_STATS]; // 21 - 30
|
||||
uint32 ItemStatValue[MAX_ITEM_PROTO_STATS]; // 31 - 40
|
||||
int32 ItemStatAllocation[MAX_ITEM_PROTO_STATS]; // 41 - 50
|
||||
int32 ItemStatSocketCostMultiplier[MAX_ITEM_PROTO_STATS]; // 51 - 60
|
||||
uint32 ScalingStatDistribution; // 61
|
||||
uint32 DamageType; // 62
|
||||
uint32 Delay; // 63
|
||||
float RangedModRange; // 64
|
||||
int32 SpellId[MAX_ITEM_PROTO_SPELLS]; // 65 - 69
|
||||
int32 SpellTrigger[MAX_ITEM_PROTO_SPELLS]; // 70 - 74
|
||||
int32 SpellCharges[MAX_ITEM_PROTO_SPELLS]; // 75 - 79
|
||||
int32 SpellCooldown[MAX_ITEM_PROTO_SPELLS]; // 80 - 84
|
||||
int32 SpellCategory[MAX_ITEM_PROTO_SPELLS]; // 85 - 89
|
||||
int32 SpellCategoryCooldown[MAX_ITEM_PROTO_SPELLS]; // 90 - 94
|
||||
uint32 Bonding; // 95
|
||||
LocalizedString* Name; // 96
|
||||
LocalizedString* Name2; // 97
|
||||
LocalizedString* Name3; // 98
|
||||
LocalizedString* Name4; // 99
|
||||
LocalizedString* Description; // 100
|
||||
uint32 PageText; // 101
|
||||
uint32 LanguageID; // 102
|
||||
uint32 PageMaterial; // 103
|
||||
uint32 StartQuest; // 104
|
||||
uint32 LockID; // 105
|
||||
int32 Material; // 106
|
||||
uint32 Sheath; // 107
|
||||
uint32 RandomProperty; // 108
|
||||
uint32 RandomSuffix; // 109
|
||||
uint32 ItemSet; // 110
|
||||
uint32 Area; // 112
|
||||
uint32 Map; // 113
|
||||
uint32 BagFamily; // 114
|
||||
uint32 TotemCategory; // 115
|
||||
uint32 Color[MAX_ITEM_PROTO_SOCKETS]; // 116 - 118
|
||||
uint32 Content[MAX_ITEM_PROTO_SOCKETS]; // 119 - 121
|
||||
int32 SocketBonus; // 122
|
||||
uint32 GemProperties; // 123
|
||||
float ArmorDamageModifier; // 124
|
||||
uint32 Duration; // 125
|
||||
uint32 ItemLimitCategory; // 126
|
||||
uint32 HolidayId; // 127
|
||||
float StatScalingFactor; // 128
|
||||
int32 CurrencySubstitutionId; // 129
|
||||
int32 CurrencySubstitutionCount; // 130
|
||||
uint32 ID; // 0
|
||||
uint32 Quality; // 1
|
||||
uint32 Flags; // 2
|
||||
uint32 Flags2; // 3
|
||||
float Unk1; // 4
|
||||
float Unk2; // 5
|
||||
uint32 BuyCount; // 6
|
||||
uint32 BuyPrice; // 7
|
||||
uint32 SellPrice; // 8
|
||||
uint32 InventoryType; // 9
|
||||
int32 AllowableClass; // 10
|
||||
int32 AllowableRace; // 11
|
||||
uint32 ItemLevel; // 12
|
||||
int32 RequiredLevel; // 13
|
||||
uint32 RequiredSkill; // 14
|
||||
uint32 RequiredSkillRank; // 15
|
||||
uint32 RequiredSpell; // 16
|
||||
uint32 RequiredHonorRank; // 17
|
||||
uint32 RequiredCityRank; // 18
|
||||
uint32 RequiredReputationFaction; // 19
|
||||
uint32 RequiredReputationRank; // 20
|
||||
uint32 MaxCount; // 21
|
||||
uint32 Stackable; // 22
|
||||
uint32 ContainerSlots; // 23
|
||||
int32 ItemStatType[MAX_ITEM_PROTO_STATS]; // 24 - 33
|
||||
int32 ItemStatValue[MAX_ITEM_PROTO_STATS]; // 34 - 43
|
||||
int32 ItemStatAllocation[MAX_ITEM_PROTO_STATS]; // 44 - 53
|
||||
float ItemStatSocketCostMultiplier[MAX_ITEM_PROTO_STATS]; // 54 - 63
|
||||
uint32 ScalingStatDistribution; // 64
|
||||
uint32 DamageType; // 65
|
||||
uint32 Delay; // 66
|
||||
float RangedModRange; // 67
|
||||
int32 SpellID[MAX_ITEM_PROTO_SPELLS]; // 68 - 72
|
||||
int32 SpellTrigger[MAX_ITEM_PROTO_SPELLS]; // 73 - 77
|
||||
int32 SpellCharges[MAX_ITEM_PROTO_SPELLS]; // 78 - 82
|
||||
int32 SpellCooldown[MAX_ITEM_PROTO_SPELLS]; // 83 - 87
|
||||
int32 SpellCategory[MAX_ITEM_PROTO_SPELLS]; // 88 - 92
|
||||
int32 SpellCategoryCooldown[MAX_ITEM_PROTO_SPELLS]; // 93 - 94
|
||||
uint32 Bonding; // 95
|
||||
LocalizedString* Name; // 96
|
||||
LocalizedString* Name2; // 97
|
||||
LocalizedString* Name3; // 98
|
||||
LocalizedString* Name4; // 99
|
||||
LocalizedString* Description; // 100
|
||||
uint32 PageText; // 101
|
||||
uint32 LanguageID; // 102
|
||||
uint32 PageMaterial; // 103
|
||||
uint32 StartQuest; // 104
|
||||
uint32 LockID; // 105
|
||||
int32 Material; // 106
|
||||
uint32 Sheath; // 107
|
||||
uint32 RandomProperty; // 108
|
||||
uint32 RandomSuffix; // 109
|
||||
uint32 ItemSet; // 110
|
||||
uint32 Area; // 112
|
||||
uint32 Map; // 113
|
||||
uint32 BagFamily; // 114
|
||||
uint32 TotemCategory; // 115
|
||||
uint32 SocketColor[MAX_ITEM_PROTO_SOCKETS]; // 116 - 118
|
||||
uint32 Content[MAX_ITEM_PROTO_SOCKETS]; // 119 - 121
|
||||
int32 SocketBonus; // 122
|
||||
uint32 GemProperties; // 123
|
||||
float ArmorDamageModifier; // 124
|
||||
uint32 Duration; // 125
|
||||
uint32 ItemLimitCategory; // 126
|
||||
uint32 HolidayID; // 127
|
||||
float StatScalingFactor; // 128
|
||||
int32 CurrencySubstitutionID; // 129
|
||||
int32 CurrencySubstitutionCount; // 130
|
||||
};
|
||||
|
||||
#define MAX_ITEM_EXT_COST_ITEMS 5
|
||||
@@ -125,15 +122,15 @@ struct ItemSparseEntry
|
||||
|
||||
struct ItemExtendedCostEntry
|
||||
{
|
||||
uint32 ID; // 0 extended-cost entry id
|
||||
//uint32 reqhonorpoints; // 1 required honor points
|
||||
//uint32 reqarenapoints; // 2 required arena points
|
||||
uint32 RequiredArenaSlot; // 3 arena slot restrictions (min slot value)
|
||||
uint32 RequiredItem[MAX_ITEM_EXT_COST_ITEMS]; // 4-8 required item id
|
||||
uint32 RequiredItemCount[MAX_ITEM_EXT_COST_ITEMS]; // 9-13 required count of 1st item
|
||||
uint32 RequiredPersonalArenaRating; // 14 required personal arena rating
|
||||
//uint32 ItemPurchaseGroup; // 15
|
||||
uint32 RequiredCurrency[MAX_ITEM_EXT_COST_CURRENCIES];// 16-20 required curency id
|
||||
uint32 ID; // 0 extended-cost entry id
|
||||
uint32 RequiredHonorPoints; // 1 required honor points
|
||||
uint32 RequiredArenaPoints; // 2 required arena points
|
||||
uint32 RequiredArenaSlot; // 3 arena slot restrictions (min slot value)
|
||||
uint32 RequiredItem[MAX_ITEM_EXT_COST_ITEMS]; // 4-8 required item id
|
||||
uint32 RequiredItemCount[MAX_ITEM_EXT_COST_ITEMS]; // 9-13 required count of 1st item
|
||||
uint32 RequiredPersonalArenaRating; // 14 required personal arena rating
|
||||
uint32 ItemPurchaseGroup; // 15
|
||||
uint32 RequiredCurrency[MAX_ITEM_EXT_COST_CURRENCIES]; // 16-20 required curency id
|
||||
uint32 RequiredCurrencyCount[MAX_ITEM_EXT_COST_CURRENCIES];// 21-25 required curency count
|
||||
uint32 RequiredFactionId;
|
||||
uint32 RequiredFactionStanding;
|
||||
@@ -146,15 +143,10 @@ struct ItemExtendedCostEntry
|
||||
|
||||
struct KeyChainEntry
|
||||
{
|
||||
uint32 Id;
|
||||
uint32 ID;
|
||||
uint8 Key[KEYCHAIN_SIZE];
|
||||
};
|
||||
|
||||
// GCC has alternative #pragma pack(N) syntax and old gcc version does not support pack(push, N), also any gcc version does not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "DB2Utility.h"
|
||||
#include "ObjectMgr.h"
|
||||
|
||||
inline bool ItemExists(uint32 id)
|
||||
{
|
||||
return sObjectMgr->GetItemTemplate(id) != nullptr;
|
||||
}
|
||||
|
||||
bool DB2Utilities::HasItemEntry(DB2Storage<ItemEntry> const& /*store*/, uint32 id)
|
||||
{
|
||||
return ItemExists(id);
|
||||
}
|
||||
|
||||
bool DB2Utilities::HasItemSparseEntry(DB2Storage<ItemSparseEntry> const& /*store*/, uint32 id)
|
||||
{
|
||||
return ItemExists(id);
|
||||
}
|
||||
|
||||
void DB2Utilities::WriteItemDbReply(DB2Storage<ItemEntry> const& /*store*/, uint32 id, LocaleConstant /*localeConstant*/, ByteBuffer& buffer)
|
||||
{
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(id);
|
||||
ASSERT(proto);
|
||||
|
||||
buffer << uint32(proto->ItemId);
|
||||
buffer << uint32(proto->Class);
|
||||
buffer << uint32(proto->SubClass);
|
||||
buffer << int32(proto->SoundOverrideSubclass);
|
||||
buffer << uint32(proto->Material);
|
||||
buffer << uint32(proto->DisplayInfoID);
|
||||
buffer << uint32(proto->InventoryType);
|
||||
buffer << uint32(proto->Sheath);
|
||||
}
|
||||
|
||||
void DB2Utilities::WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& /*store*/, uint32 id, LocaleConstant localeConstant, ByteBuffer& buffer)
|
||||
{
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(id);
|
||||
ASSERT(proto);
|
||||
|
||||
ItemLocale const* localeData = localeConstant ? sObjectMgr->GetItemLocale(id) : nullptr;
|
||||
|
||||
buffer << uint32(proto->ItemId);
|
||||
buffer << uint32(proto->Quality);
|
||||
buffer << uint32(proto->Flags);
|
||||
buffer << uint32(proto->Flags2);
|
||||
buffer << float(proto->Unk430_1);
|
||||
buffer << float(proto->Unk430_2);
|
||||
buffer << uint32(proto->BuyCount);
|
||||
buffer << int32(proto->BuyPrice);
|
||||
buffer << uint32(proto->SellPrice);
|
||||
buffer << uint32(proto->InventoryType);
|
||||
buffer << int32(proto->AllowableClass);
|
||||
buffer << int32(proto->AllowableRace);
|
||||
buffer << uint32(proto->ItemLevel);
|
||||
buffer << uint32(proto->RequiredLevel);
|
||||
buffer << uint32(proto->RequiredSkill);
|
||||
buffer << uint32(proto->RequiredSkillRank);
|
||||
buffer << uint32(proto->RequiredSpell);
|
||||
buffer << uint32(proto->RequiredHonorRank);
|
||||
buffer << uint32(proto->RequiredCityRank);
|
||||
buffer << uint32(proto->RequiredReputationFaction);
|
||||
buffer << uint32(proto->RequiredReputationRank);
|
||||
buffer << int32(proto->MaxCount);
|
||||
buffer << int32(proto->Stackable);
|
||||
buffer << uint32(proto->ContainerSlots);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x)
|
||||
buffer << uint32(proto->ItemStat[x].ItemStatType);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x)
|
||||
buffer << int32(proto->ItemStat[x].ItemStatValue);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x)
|
||||
buffer << int32(proto->ItemStat[x].ItemStatAllocation);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x)
|
||||
buffer << int32(proto->ItemStat[x].ItemStatSocketCostMultiplier);
|
||||
|
||||
buffer << uint32(proto->ScalingStatDistribution);
|
||||
buffer << uint32(proto->DamageType);
|
||||
buffer << uint32(proto->Delay);
|
||||
buffer << float(proto->RangedModRange);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
|
||||
buffer << int32(proto->Spells[x].SpellId);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
|
||||
buffer << uint32(proto->Spells[x].SpellTrigger);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
|
||||
buffer << int32(proto->Spells[x].SpellCharges);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
|
||||
buffer << int32(proto->Spells[x].SpellCooldown);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
|
||||
buffer << uint32(proto->Spells[x].SpellCategory);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
|
||||
buffer << int32(proto->Spells[x].SpellCategoryCooldown);
|
||||
|
||||
buffer << uint32(proto->Bonding);
|
||||
|
||||
// item name
|
||||
std::string name = proto->Name1;
|
||||
if (localeData)
|
||||
ObjectMgr::GetLocaleString(localeData->Name, localeConstant, name);
|
||||
|
||||
buffer << uint16(name.length());
|
||||
if (name.length())
|
||||
buffer << name;
|
||||
|
||||
for (uint32 i = 0; i < 3; ++i) // other 3 names
|
||||
buffer << uint16(0);
|
||||
|
||||
std::string desc = proto->Description;
|
||||
if (localeData)
|
||||
ObjectMgr::GetLocaleString(localeData->Description, localeConstant, desc);
|
||||
|
||||
buffer << uint16(desc.length());
|
||||
if (desc.length())
|
||||
buffer << desc;
|
||||
|
||||
buffer << uint32(proto->PageText);
|
||||
buffer << uint32(proto->LanguageID);
|
||||
buffer << uint32(proto->PageMaterial);
|
||||
buffer << uint32(proto->StartQuest);
|
||||
buffer << uint32(proto->LockID);
|
||||
buffer << int32(proto->Material);
|
||||
buffer << uint32(proto->Sheath);
|
||||
buffer << int32(proto->RandomProperty);
|
||||
buffer << int32(proto->RandomSuffix);
|
||||
buffer << uint32(proto->ItemSet);
|
||||
|
||||
buffer << uint32(proto->Area);
|
||||
buffer << uint32(proto->Map);
|
||||
buffer << uint32(proto->BagFamily);
|
||||
buffer << uint32(proto->TotemCategory);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_SOCKETS; ++x)
|
||||
buffer << uint32(proto->Socket[x].Color);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_SOCKETS; ++x)
|
||||
buffer << uint32(proto->Socket[x].Content);
|
||||
|
||||
buffer << uint32(proto->socketBonus);
|
||||
buffer << uint32(proto->GemProperties);
|
||||
buffer << float(proto->ArmorDamageModifier);
|
||||
buffer << int32(proto->Duration);
|
||||
buffer << uint32(proto->ItemLimitCategory);
|
||||
buffer << uint32(proto->HolidayId);
|
||||
buffer << float(proto->StatScalingFactor); // StatScalingFactor
|
||||
buffer << uint32(proto->CurrencySubstitutionId);
|
||||
buffer << uint32(proto->CurrencySubstitutionCount);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DB2PACKETWRITER_H
|
||||
#define DB2PACKETWRITER_H
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
template<class T>
|
||||
class DB2Storage;
|
||||
class ByteBuffer;
|
||||
struct ItemEntry;
|
||||
struct ItemSparseEntry;
|
||||
enum LocaleConstant : uint8;
|
||||
|
||||
namespace DB2Utilities
|
||||
{
|
||||
//
|
||||
bool HasItemEntry(DB2Storage<ItemEntry> const& store, uint32 id);
|
||||
bool HasItemSparseEntry(DB2Storage<ItemSparseEntry> const& store, uint32 id);
|
||||
|
||||
//
|
||||
void WriteItemDbReply(DB2Storage<ItemEntry> const& store, uint32 id, LocaleConstant localeConstant, ByteBuffer& buffer);
|
||||
void WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& store, uint32 id, LocaleConstant localeConstant, ByteBuffer& buffer);
|
||||
}
|
||||
|
||||
#endif // DB2PACKETWRITER_H
|
||||
@@ -19,9 +19,9 @@
|
||||
#define TRINITY_DB2SFRM_H
|
||||
|
||||
char const Itemfmt[]="niiiiiii";
|
||||
char const ItemCurrencyCostfmt[]="xn";
|
||||
char const ItemSparsefmt[]="niiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiisssssiiiiiiiiiiiiiiiiiiiiiifiiifii";
|
||||
char const ItemExtendedCostEntryfmt[]="nxxiiiiiiiiiiiixiiiiiiiiiiiiiii";
|
||||
char const ItemCurrencyCostfmt[]="in";
|
||||
char const ItemSparsefmt[]="niiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffffffiiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiisssssiiiiiiiiiiiiiiiiiiiiiifiiifii";
|
||||
char const ItemExtendedCostEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
|
||||
char const KeyChainfmt[]="nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
|
||||
|
||||
#endif
|
||||
@@ -1342,10 +1342,10 @@ bool IsInArea(uint32 objectAreaId, uint32 areaId)
|
||||
|
||||
uint32 ItemTemplate::GetEffectiveArmor(Player const* owner) const
|
||||
{
|
||||
if (Quality > ITEM_QUALITY_ARTIFACT)
|
||||
if (GetQuality() > ITEM_QUALITY_ARTIFACT)
|
||||
return 0;
|
||||
|
||||
uint32 level = ItemLevel;
|
||||
uint32 level = GetBaseItemLevel();
|
||||
if (owner)
|
||||
{
|
||||
uint32 maxItemLevel = owner->GetUInt32Value(UNIT_FIELD_MAXITEMLEVEL);
|
||||
@@ -1353,14 +1353,14 @@ uint32 ItemTemplate::GetEffectiveArmor(Player const* owner) const
|
||||
level = maxItemLevel;
|
||||
}
|
||||
|
||||
if (Class != ITEM_CLASS_ARMOR || SubClass != ITEM_SUBCLASS_ARMOR_SHIELD)
|
||||
if (GetClass() != ITEM_CLASS_ARMOR || GetSubClass() != ITEM_SUBCLASS_ARMOR_SHIELD)
|
||||
{
|
||||
ItemArmorQualityEntry const* armorQuality = sItemArmorQualityStore.LookupEntry(level);
|
||||
ItemArmorTotalEntry const* armorTotal = sItemArmorTotalStore.LookupEntry(level);
|
||||
if (!armorQuality || !armorTotal)
|
||||
return 0;
|
||||
|
||||
uint32 invType = InventoryType;
|
||||
uint32 invType = GetInventoryType();
|
||||
if (invType == INVTYPE_ROBE)
|
||||
invType = INVTYPE_CHEST;
|
||||
|
||||
@@ -1368,26 +1368,26 @@ uint32 ItemTemplate::GetEffectiveArmor(Player const* owner) const
|
||||
if (!location)
|
||||
return 0;
|
||||
|
||||
if (SubClass < ITEM_SUBCLASS_ARMOR_CLOTH || SubClass > ITEM_SUBCLASS_ARMOR_PLATE)
|
||||
if (GetSubClass() < ITEM_SUBCLASS_ARMOR_CLOTH || GetSubClass() > ITEM_SUBCLASS_ARMOR_PLATE)
|
||||
return 0;
|
||||
|
||||
return uint32(armorQuality->Qualitymod[Quality] * armorTotal->Value[SubClass - ITEM_SUBCLASS_ARMOR_CLOTH] * location->Value[SubClass - ITEM_SUBCLASS_ARMOR_CLOTH] + 0.5f);
|
||||
return uint32(armorQuality->Qualitymod[GetQuality()] * armorTotal->Value[GetSubClass() - ITEM_SUBCLASS_ARMOR_CLOTH] * location->Value[GetSubClass() - ITEM_SUBCLASS_ARMOR_CLOTH] + 0.5f);
|
||||
}
|
||||
|
||||
ItemArmorShieldEntry const* shield = sItemArmorShieldStore.LookupEntry(level);
|
||||
if (!shield)
|
||||
return 0;
|
||||
|
||||
return uint32(shield->Quality[Quality] + 0.5f);
|
||||
return uint32(shield->Quality[GetQuality()] + 0.5f);
|
||||
}
|
||||
|
||||
bool ItemTemplate::GetWeaponDamage(Player const* owner, float& minValue, float& maxValue, float& dps) const
|
||||
{
|
||||
minValue = maxValue = 0.0f;
|
||||
if (Class != ITEM_CLASS_WEAPON || Quality > ITEM_QUALITY_ARTIFACT)
|
||||
if (GetClass() != ITEM_CLASS_WEAPON || GetQuality() > ITEM_QUALITY_ARTIFACT)
|
||||
return false;
|
||||
|
||||
uint32 level = ItemLevel;
|
||||
uint32 level = GetBaseItemLevel();
|
||||
if (owner)
|
||||
{
|
||||
uint32 maxItemLevel = owner->GetUInt32Value(UNIT_FIELD_MAXITEMLEVEL);
|
||||
@@ -1397,13 +1397,13 @@ bool ItemTemplate::GetWeaponDamage(Player const* owner, float& minValue, float&
|
||||
|
||||
DBCStorage<ItemDamageEntry>* store = nullptr;
|
||||
|
||||
switch (InventoryType)
|
||||
switch (GetInventoryType())
|
||||
{
|
||||
case INVTYPE_AMMO:
|
||||
store = &sItemDamageAmmoStore;
|
||||
break;
|
||||
case INVTYPE_2HWEAPON:
|
||||
if (Flags2 & ITEM_FLAG2_CASTER_WEAPON)
|
||||
if (GetFlags2() & ITEM_FLAG2_CASTER_WEAPON)
|
||||
store = &sItemDamageTwoHandCasterStore;
|
||||
else
|
||||
store = &sItemDamageTwoHandStore;
|
||||
@@ -1411,7 +1411,7 @@ bool ItemTemplate::GetWeaponDamage(Player const* owner, float& minValue, float&
|
||||
case INVTYPE_RANGED:
|
||||
case INVTYPE_THROWN:
|
||||
case INVTYPE_RANGEDRIGHT:
|
||||
switch (SubClass)
|
||||
switch (GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_WAND:
|
||||
store = &sItemDamageWandStore;
|
||||
@@ -1431,7 +1431,7 @@ bool ItemTemplate::GetWeaponDamage(Player const* owner, float& minValue, float&
|
||||
case INVTYPE_WEAPON:
|
||||
case INVTYPE_WEAPONMAINHAND:
|
||||
case INVTYPE_WEAPONOFFHAND:
|
||||
if (Flags2 & ITEM_FLAG2_CASTER_WEAPON)
|
||||
if (GetFlags2() & ITEM_FLAG2_CASTER_WEAPON)
|
||||
store = &sItemDamageOneHandCasterStore;
|
||||
else
|
||||
store = &sItemDamageOneHandStore;
|
||||
@@ -1447,25 +1447,25 @@ bool ItemTemplate::GetWeaponDamage(Player const* owner, float& minValue, float&
|
||||
if (!damageInfo)
|
||||
return false;
|
||||
|
||||
dps = damageInfo->Quality[Quality];
|
||||
dps = damageInfo->Quality[GetQuality()];
|
||||
|
||||
float avgDamage = Delay * damageInfo->Quality[Quality] * 0.001f;
|
||||
float scaled_stat = std::floor((StatScalingFactor * 0.5f + 1.f) * avgDamage + 0.5f);
|
||||
if (Delay && ArmorDamageModifier != 0.f)
|
||||
float avgDamage = GetDelay() * damageInfo->Quality[GetQuality()] * 0.001f;
|
||||
float scaled_stat = std::floor((GetStatScalingFactor() * 0.5f + 1.f) * avgDamage + 0.5f);
|
||||
if (GetDelay() && GetArmorDamageModifier() != 0.f)
|
||||
{
|
||||
float invMsDelay = 1000.0f / float(Delay);
|
||||
float invMsDelay = 1000.0f / float(GetDelay());
|
||||
|
||||
float v16 = (invMsDelay * ((1.f - (StatScalingFactor * 0.5f)) * avgDamage)) + ArmorDamageModifier;
|
||||
float v16 = (invMsDelay * ((1.f - (GetStatScalingFactor() * 0.5f)) * avgDamage)) + GetArmorDamageModifier();
|
||||
v16 = std::max(v16, 1.f);
|
||||
|
||||
minValue = (1.0f / invMsDelay) * v16;
|
||||
|
||||
maxValue = (1.0f / invMsDelay) * (((1000.f / float(Delay)) * scaled_stat) + ArmorDamageModifier);
|
||||
maxValue = (1.0f / invMsDelay) * (((1000.f / float(GetDelay())) * scaled_stat) + GetArmorDamageModifier());
|
||||
}
|
||||
else
|
||||
{
|
||||
maxValue = scaled_stat;
|
||||
minValue = (1.f - (StatScalingFactor * 0.5f)) * avgDamage;
|
||||
minValue = (1.f - (GetStatScalingFactor() * 0.5f)) * avgDamage;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1548,9 +1548,9 @@ uint32 GetItemScalingModifier(uint32 maxIlvl, ItemQualities quality, InventoryTy
|
||||
uint32 ItemTemplate::GetStatValue(uint32 index, Player const* owner /*= nullptr*/) const
|
||||
{
|
||||
if (!owner)
|
||||
return ItemStat[index].ItemStatValue;
|
||||
return GetItemStatValue(index);
|
||||
|
||||
ScalingStatDistributionEntry const* ssd = ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(ScalingStatDistribution) : nullptr;
|
||||
ScalingStatDistributionEntry const* ssd = GetScalingStatDistribution() ? sScalingStatDistributionStore.LookupEntry(GetScalingStatDistribution()) : nullptr;
|
||||
// req. check at equip, but allow use for extended range if range limit max level, set proper level
|
||||
uint32 ssdLevel = owner->getLevel();
|
||||
|
||||
@@ -1569,24 +1569,24 @@ uint32 ItemTemplate::GetStatValue(uint32 index, Player const* owner /*= nullptr*
|
||||
if (ssd->StatID[index] < 0)
|
||||
return 0; // What do we do ?
|
||||
|
||||
statBaseValue = ssv->GetStatMultiplier(InventoryType) * ssd->Bonus[index] / 10000;
|
||||
statBaseValue = ssv->GetStatMultiplier(GetInventoryType()) * ssd->Bonus[index] / 10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
statBaseValue = ItemStat[index].ItemStatValue;
|
||||
statBaseValue = GetItemStatValue(index);
|
||||
|
||||
uint32 itemLevel = ItemLevel;
|
||||
uint32 itemLevel = GetBaseItemLevel();
|
||||
uint32 maxItemLevel = owner->GetUInt32Value(UNIT_FIELD_MAXITEMLEVEL);
|
||||
if (!maxItemLevel || maxItemLevel >= itemLevel) // TODO: This might work if >=. Check.
|
||||
return statBaseValue;
|
||||
|
||||
float minScaler = GetItemScalingModifier(ItemLevel, ItemQualities(Quality), ::InventoryType(InventoryType));
|
||||
float maxScaler = GetItemScalingModifier(maxItemLevel, ItemQualities(Quality), ::InventoryType(InventoryType));
|
||||
float minScaler = GetItemScalingModifier(GetBaseItemLevel(), ItemQualities(GetQuality()), ::InventoryType(GetInventoryType()));
|
||||
float maxScaler = GetItemScalingModifier(maxItemLevel, ItemQualities(GetQuality()), ::InventoryType(GetInventoryType()));
|
||||
|
||||
if (maxScaler != 0.f && minScaler != 0.f)
|
||||
{
|
||||
float statAllocation = ItemStat[index].ItemStatAllocation * maxScaler * 0.0001f;
|
||||
return std::ceil(statAllocation - ((maxScaler / minScaler) * ItemStat[index].ItemStatSocketCostMultiplier));
|
||||
float statAllocation = GetItemStatAllocation(index) * maxScaler * 0.0001f;
|
||||
return std::ceil(statAllocation - ((maxScaler / minScaler) * GetItemStatSocketCostMultiplier(index)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ std::string CreatureMovementData::ToString() const
|
||||
|
||||
bool VendorItem::IsGoldRequired(ItemTemplate const* pProto) const
|
||||
{
|
||||
return (pProto->Flags2 & ITEM_FLAG2_DONT_IGNORE_BUY_PRICE) || !ExtendedCost;
|
||||
return (pProto->GetFlags2() & ITEM_FLAG2_DONT_IGNORE_BUY_PRICE) || !ExtendedCost;
|
||||
}
|
||||
|
||||
bool VendorItemData::RemoveItem(uint32 item_id, uint8 type)
|
||||
@@ -2700,13 +2700,13 @@ uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem)
|
||||
if (ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(vItem->item))
|
||||
{
|
||||
uint32 diff = uint32((ptime - vCount->lastIncrementTime)/vItem->incrtime);
|
||||
if ((vCount->count + diff * pProto->BuyCount) >= vItem->maxcount)
|
||||
if ((vCount->count + diff * pProto->GetBuyCount()) >= vItem->maxcount)
|
||||
{
|
||||
m_vendorItemCounts.erase(itr);
|
||||
return vItem->maxcount;
|
||||
}
|
||||
|
||||
vCount->count += diff * pProto->BuyCount;
|
||||
vCount->count += diff * pProto->GetBuyCount();
|
||||
vCount->lastIncrementTime = ptime;
|
||||
}
|
||||
|
||||
@@ -2738,8 +2738,8 @@ uint32 Creature::UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 us
|
||||
if (ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(vItem->item))
|
||||
{
|
||||
uint32 diff = uint32((ptime - vCount->lastIncrementTime)/vItem->incrtime);
|
||||
if ((vCount->count + diff * pProto->BuyCount) < vItem->maxcount)
|
||||
vCount->count += diff * pProto->BuyCount;
|
||||
if ((vCount->count + diff * pProto->GetBuyCount()) < vItem->maxcount)
|
||||
vCount->count += diff * pProto->GetBuyCount();
|
||||
else
|
||||
vCount->count = vItem->maxcount;
|
||||
}
|
||||
|
||||
@@ -730,7 +730,7 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
|
||||
|
||||
uint32 displayId = 0;
|
||||
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i]))
|
||||
displayId = itemTemplate->DisplayInfoID;
|
||||
displayId = itemTemplate->GetDisplayID();
|
||||
|
||||
if (data.ItemCount[i] < quest->RequiredItemCount[i] && !_session->GetPlayer()->HasItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i]))
|
||||
collectObjectiveComplete = false;
|
||||
|
||||
@@ -72,7 +72,7 @@ bool Bag::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner
|
||||
{
|
||||
ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(itemid);
|
||||
|
||||
if (!itemProto || itemProto->ContainerSlots > MAX_BAG_SIZE)
|
||||
if (!itemProto || itemProto->GetContainerSlots() > MAX_BAG_SIZE)
|
||||
return false;
|
||||
|
||||
Object::_Create(guidlow, 0, HighGuid::Container);
|
||||
@@ -91,7 +91,7 @@ bool Bag::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner
|
||||
SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1);
|
||||
|
||||
// Setting the number of Slots the Container has
|
||||
SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->ContainerSlots);
|
||||
SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->GetContainerSlots());
|
||||
|
||||
// Cleaning 20 slots
|
||||
for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
|
||||
@@ -114,7 +114,7 @@ bool Bag::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fie
|
||||
return false;
|
||||
|
||||
ItemTemplate const* itemProto = GetTemplate(); // checked in Item::LoadFromDB
|
||||
SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->ContainerSlots);
|
||||
SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->GetContainerSlots());
|
||||
// cleanup bag content related item value fields (its will be filled correctly from `character_inventory`)
|
||||
for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
|
||||
{
|
||||
@@ -201,12 +201,12 @@ uint32 Bag::GetItemCount(uint32 item, Item* eItem) const
|
||||
count += pItem->GetCount();
|
||||
}
|
||||
|
||||
if (eItem && eItem->GetTemplate()->GemProperties)
|
||||
if (eItem && eItem->GetTemplate()->GetGemProperties())
|
||||
{
|
||||
for (uint32 i=0; i < GetBagSize(); ++i)
|
||||
{
|
||||
pItem = m_bagslot[i];
|
||||
if (pItem && pItem != eItem && pItem->GetTemplate()->Socket[0].Color)
|
||||
if (pItem && pItem != eItem && pItem->GetTemplate()->ExtendedData->SocketColor[0])
|
||||
count += pItem->GetGemCountWithID(item);
|
||||
}
|
||||
}
|
||||
@@ -221,7 +221,7 @@ uint32 Bag::GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem)
|
||||
if (Item* pItem = m_bagslot[i])
|
||||
if (pItem != skipItem)
|
||||
if (ItemTemplate const* pProto = pItem->GetTemplate())
|
||||
if (pProto->ItemLimitCategory == limitCategory)
|
||||
if (pProto->GetItemLimitCategory() == limitCategory)
|
||||
count += m_bagslot[i]->GetCount();
|
||||
|
||||
return count;
|
||||
|
||||
@@ -66,6 +66,6 @@ class TC_GAME_API Bag : public Item
|
||||
|
||||
inline Item* NewItemOrBag(ItemTemplate const* proto)
|
||||
{
|
||||
return (proto->InventoryType == INVTYPE_BAG) ? new Bag : new Item;
|
||||
return (proto->GetInventoryType() == INVTYPE_BAG) ? new Bag : new Item;
|
||||
}
|
||||
#endif
|
||||
@@ -40,13 +40,13 @@
|
||||
void AddItemsSetItem(Player* player, Item* item)
|
||||
{
|
||||
ItemTemplate const* proto = item->GetTemplate();
|
||||
uint32 setid = proto->ItemSet;
|
||||
uint32 setid = proto->GetItemSet();
|
||||
|
||||
ItemSetEntry const* set = sItemSetStore.LookupEntry(setid);
|
||||
|
||||
if (!set)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Item set %u for item (id %u) not found, mods not applied.", setid, proto->ItemId);
|
||||
TC_LOG_ERROR("sql.sql", "Item set %u for item (id %u) not found, mods not applied.", setid, proto->GetId());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,13 +122,13 @@ void AddItemsSetItem(Player* player, Item* item)
|
||||
|
||||
void RemoveItemsSetItem(Player*player, ItemTemplate const* proto)
|
||||
{
|
||||
uint32 setid = proto->ItemSet;
|
||||
uint32 setid = proto->GetItemSet();
|
||||
|
||||
ItemSetEntry const* set = sItemSetStore.LookupEntry(setid);
|
||||
|
||||
if (!set)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Item set #%u for item #%u not found, mods not removed.", setid, proto->ItemId);
|
||||
TC_LOG_ERROR("sql.sql", "Item set #%u for item #%u not found, mods not removed.", setid, proto->GetId());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,61 +183,61 @@ bool ItemCanGoIntoBag(ItemTemplate const* pProto, ItemTemplate const* pBagProto)
|
||||
if (!pProto || !pBagProto)
|
||||
return false;
|
||||
|
||||
switch (pBagProto->Class)
|
||||
switch (pBagProto->GetClass())
|
||||
{
|
||||
case ITEM_CLASS_CONTAINER:
|
||||
switch (pBagProto->SubClass)
|
||||
switch (pBagProto->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_CONTAINER:
|
||||
return true;
|
||||
case ITEM_SUBCLASS_SOUL_CONTAINER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_SOUL_SHARDS))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_SOUL_SHARDS))
|
||||
return false;
|
||||
return true;
|
||||
case ITEM_SUBCLASS_HERB_CONTAINER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_HERBS))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_HERBS))
|
||||
return false;
|
||||
return true;
|
||||
case ITEM_SUBCLASS_ENCHANTING_CONTAINER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_ENCHANTING_SUPP))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_ENCHANTING_SUPP))
|
||||
return false;
|
||||
return true;
|
||||
case ITEM_SUBCLASS_MINING_CONTAINER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_MINING_SUPP))
|
||||
return false;
|
||||
return true;
|
||||
case ITEM_SUBCLASS_ENGINEERING_CONTAINER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_ENGINEERING_SUPP))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_ENGINEERING_SUPP))
|
||||
return false;
|
||||
return true;
|
||||
case ITEM_SUBCLASS_GEM_CONTAINER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_GEMS))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_GEMS))
|
||||
return false;
|
||||
return true;
|
||||
case ITEM_SUBCLASS_LEATHERWORKING_CONTAINER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_LEATHERWORKING_SUPP))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_LEATHERWORKING_SUPP))
|
||||
return false;
|
||||
return true;
|
||||
case ITEM_SUBCLASS_INSCRIPTION_CONTAINER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_INSCRIPTION_SUPP))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_INSCRIPTION_SUPP))
|
||||
return false;
|
||||
return true;
|
||||
case ITEM_SUBCLASS_TACKLE_CONTAINER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_FISHING_SUPP))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_FISHING_SUPP))
|
||||
return false;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case ITEM_CLASS_QUIVER:
|
||||
switch (pBagProto->SubClass)
|
||||
switch (pBagProto->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_QUIVER:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_ARROWS))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_ARROWS))
|
||||
return false;
|
||||
return true;
|
||||
case ITEM_SUBCLASS_AMMO_POUCH:
|
||||
if (!(pProto->BagFamily & BAG_FAMILY_MASK_BULLETS))
|
||||
if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_BULLETS))
|
||||
return false;
|
||||
return true;
|
||||
default:
|
||||
@@ -288,10 +288,10 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemId, Player const* owne
|
||||
SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability);
|
||||
SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability);
|
||||
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
SetSpellCharges(i, itemProto->Spells[i].SpellCharges);
|
||||
for (uint8 i = 0; i < itemProto->Effects.size(); ++i)
|
||||
SetSpellCharges(i, itemProto->Effects[i].Charges);
|
||||
|
||||
SetUInt32Value(ITEM_FIELD_DURATION, itemProto->Duration);
|
||||
SetUInt32Value(ITEM_FIELD_DURATION, itemProto->GetDuration());
|
||||
SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, owner ? owner->GetTotalPlayedTime() : 0);
|
||||
return true;
|
||||
}
|
||||
@@ -439,9 +439,9 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi
|
||||
uint32 duration = fields[3].GetUInt32();
|
||||
SetUInt32Value(ITEM_FIELD_DURATION, duration);
|
||||
// update duration if need, and remove if not need
|
||||
if ((proto->Duration == 0) != (duration == 0))
|
||||
if ((proto->GetDuration() == 0) != (duration == 0))
|
||||
{
|
||||
SetUInt32Value(ITEM_FIELD_DURATION, proto->Duration);
|
||||
SetUInt32Value(ITEM_FIELD_DURATION, proto->GetDuration());
|
||||
need_save = true;
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi
|
||||
|
||||
SetUInt32Value(ITEM_FIELD_FLAGS, fields[5].GetUInt32());
|
||||
// Remove bind flag for items vs BIND_NONE set
|
||||
if (IsSoulBound() && proto->Bonding == BIND_NONE)
|
||||
if (IsSoulBound() && proto->GetBonding() == BIND_NONE)
|
||||
{
|
||||
ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, false);
|
||||
need_save = true;
|
||||
@@ -753,7 +753,7 @@ InventoryResult Item::CanBeMergedPartlyWith(ItemTemplate const* proto) const
|
||||
return EQUIP_ERR_LOOT_GONE;
|
||||
|
||||
// check item type
|
||||
if (GetEntry() != proto->ItemId)
|
||||
if (GetEntry() != proto->GetId())
|
||||
return EQUIP_ERR_CANT_STACK;
|
||||
|
||||
// check free space (full stacks can't be target of merge
|
||||
@@ -775,12 +775,12 @@ bool Item::IsFitToSpellRequirements(SpellInfo const* spellInfo) const
|
||||
if (spellInfo->IsAbilityOfSkillType(SKILL_ENCHANTING)) // only for enchanting spells
|
||||
return true;
|
||||
|
||||
if (spellInfo->EquippedItemClass != int32(proto->Class))
|
||||
if (spellInfo->EquippedItemClass != int32(proto->GetClass()))
|
||||
return false; // wrong item class
|
||||
|
||||
if (spellInfo->EquippedItemSubClassMask != 0) // 0 == any subclass
|
||||
{
|
||||
if ((spellInfo->EquippedItemSubClassMask & (1 << proto->SubClass)) == 0)
|
||||
if ((spellInfo->EquippedItemSubClassMask & (1 << proto->GetSubClass())) == 0)
|
||||
return false; // subclass not present in mask
|
||||
}
|
||||
}
|
||||
@@ -788,11 +788,11 @@ bool Item::IsFitToSpellRequirements(SpellInfo const* spellInfo) const
|
||||
if (isEnchantSpell && spellInfo->EquippedItemInventoryTypeMask != 0) // 0 == any inventory type
|
||||
{
|
||||
// Special case - accept weapon type for main and offhand requirements
|
||||
if (proto->InventoryType == INVTYPE_WEAPON &&
|
||||
if (proto->GetInventoryType() == INVTYPE_WEAPON &&
|
||||
(spellInfo->EquippedItemInventoryTypeMask & (1 << INVTYPE_WEAPONMAINHAND) ||
|
||||
spellInfo->EquippedItemInventoryTypeMask & (1 << INVTYPE_WEAPONOFFHAND)))
|
||||
return true;
|
||||
else if ((spellInfo->EquippedItemInventoryTypeMask & (1 << proto->InventoryType)) == 0)
|
||||
else if ((spellInfo->EquippedItemInventoryTypeMask & (1 << proto->GetInventoryType())) == 0)
|
||||
return false; // inventory type not present in mask
|
||||
}
|
||||
|
||||
@@ -854,7 +854,7 @@ bool Item::GemsFitSockets() const
|
||||
{
|
||||
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
|
||||
{
|
||||
uint8 SocketColor = GetTemplate()->Socket[enchant_slot-SOCK_ENCHANTMENT_SLOT].Color;
|
||||
uint8 SocketColor = GetTemplate()->GetSocketColor(enchant_slot - SOCK_ENCHANTMENT_SLOT);
|
||||
|
||||
if (!SocketColor) // no socket slot
|
||||
continue;
|
||||
@@ -875,7 +875,7 @@ bool Item::GemsFitSockets() const
|
||||
ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemid);
|
||||
if (gemProto)
|
||||
{
|
||||
GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GemProperties);
|
||||
GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GetGemProperties());
|
||||
if (gemProperty)
|
||||
GemColor = gemProperty->Type;
|
||||
}
|
||||
@@ -923,7 +923,7 @@ uint8 Item::GetGemCountWithLimitCategory(uint32 limitCategory) const
|
||||
if (!gemProto)
|
||||
continue;
|
||||
|
||||
if (gemProto->ItemLimitCategory == limitCategory)
|
||||
if (gemProto->GetItemLimitCategory() == limitCategory)
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
@@ -932,7 +932,7 @@ uint8 Item::GetGemCountWithLimitCategory(uint32 limitCategory) const
|
||||
bool Item::IsLimitedToAnotherMapOrZone(uint32 cur_mapId, uint32 cur_zoneId) const
|
||||
{
|
||||
ItemTemplate const* proto = GetTemplate();
|
||||
return proto && ((proto->Map && proto->Map != cur_mapId) || (proto->Area && proto->Area != cur_zoneId));
|
||||
return proto && ((proto->GetMap() && proto->GetMap() != cur_mapId) || (proto->GetArea() && proto->GetArea() != cur_zoneId));
|
||||
}
|
||||
|
||||
void Item::SendUpdateSockets()
|
||||
@@ -1149,17 +1149,17 @@ bool Item::CanBeTransmogrified() const
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
if (proto->Quality == ITEM_QUALITY_LEGENDARY)
|
||||
if (proto->GetQuality() == ITEM_QUALITY_LEGENDARY)
|
||||
return false;
|
||||
|
||||
if (proto->Class != ITEM_CLASS_ARMOR &&
|
||||
proto->Class != ITEM_CLASS_WEAPON)
|
||||
if (proto->GetClass() != ITEM_CLASS_ARMOR &&
|
||||
proto->GetClass() != ITEM_CLASS_WEAPON)
|
||||
return false;
|
||||
|
||||
if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
|
||||
if (proto->GetClass() == ITEM_CLASS_WEAPON && proto->GetSubClass() == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
|
||||
return false;
|
||||
|
||||
if (proto->Flags2 & ITEM_FLAG2_NO_ALTER_ITEM_VISUAL)
|
||||
if (proto->GetFlags2() & ITEM_FLAG2_NO_ALTER_ITEM_VISUAL)
|
||||
return false;
|
||||
|
||||
if (!HasStats())
|
||||
@@ -1175,20 +1175,20 @@ bool Item::CanTransmogrify() const
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
if (proto->Flags2 & ITEM_FLAG2_NO_SOURCE_FOR_ITEM_VISUAL)
|
||||
if (proto->GetFlags2() & ITEM_FLAG2_NO_SOURCE_FOR_ITEM_VISUAL)
|
||||
return false;
|
||||
|
||||
if (proto->Quality == ITEM_QUALITY_LEGENDARY)
|
||||
if (proto->GetQuality() == ITEM_QUALITY_LEGENDARY)
|
||||
return false;
|
||||
|
||||
if (proto->Class != ITEM_CLASS_ARMOR &&
|
||||
proto->Class != ITEM_CLASS_WEAPON)
|
||||
if (proto->GetClass() != ITEM_CLASS_ARMOR &&
|
||||
proto->GetClass() != ITEM_CLASS_WEAPON)
|
||||
return false;
|
||||
|
||||
if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
|
||||
if (proto->GetClass() == ITEM_CLASS_WEAPON && proto->GetSubClass() == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
|
||||
return false;
|
||||
|
||||
if (proto->Flags2 & ITEM_FLAG2_IGNORE_QUALITY_FOR_ITEM_VISUAL_SOURCE)
|
||||
if (proto->GetFlags2() & ITEM_FLAG2_IGNORE_QUALITY_FOR_ITEM_VISUAL_SOURCE)
|
||||
return true;
|
||||
|
||||
if (!HasStats())
|
||||
@@ -1205,27 +1205,27 @@ bool Item::CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* t
|
||||
ItemTemplate const* proto1 = transmogrifier->GetTemplate(); // source
|
||||
ItemTemplate const* proto2 = transmogrified->GetTemplate(); // dest
|
||||
|
||||
if (proto1->ItemId == proto2->ItemId)
|
||||
if (proto1->GetId() == proto2->GetId())
|
||||
return false;
|
||||
|
||||
if (!transmogrified->CanTransmogrify() || !transmogrifier->CanBeTransmogrified())
|
||||
return false;
|
||||
|
||||
if (proto1->InventoryType == INVTYPE_BAG ||
|
||||
proto1->InventoryType == INVTYPE_RELIC ||
|
||||
proto1->InventoryType == INVTYPE_BODY ||
|
||||
proto1->InventoryType == INVTYPE_FINGER ||
|
||||
proto1->InventoryType == INVTYPE_TRINKET ||
|
||||
proto1->InventoryType == INVTYPE_AMMO ||
|
||||
proto1->InventoryType == INVTYPE_QUIVER)
|
||||
if (proto1->GetInventoryType() == INVTYPE_BAG ||
|
||||
proto1->GetInventoryType() == INVTYPE_RELIC ||
|
||||
proto1->GetInventoryType() == INVTYPE_BODY ||
|
||||
proto1->GetInventoryType() == INVTYPE_FINGER ||
|
||||
proto1->GetInventoryType() == INVTYPE_TRINKET ||
|
||||
proto1->GetInventoryType() == INVTYPE_AMMO ||
|
||||
proto1->GetInventoryType() == INVTYPE_QUIVER)
|
||||
return false;
|
||||
|
||||
if (proto1->SubClass != proto2->SubClass && (proto1->Class != ITEM_CLASS_WEAPON || !proto2->IsRangedWeapon() || !proto1->IsRangedWeapon()))
|
||||
if (proto1->GetSubClass() != proto2->GetSubClass() && (proto1->GetClass() != ITEM_CLASS_WEAPON || !proto2->IsRangedWeapon() || !proto1->IsRangedWeapon()))
|
||||
return false;
|
||||
|
||||
if (proto1->InventoryType != proto2->InventoryType &&
|
||||
(proto1->Class != ITEM_CLASS_WEAPON || (proto2->InventoryType != INVTYPE_WEAPONMAINHAND && proto2->InventoryType != INVTYPE_WEAPONOFFHAND)) &&
|
||||
(proto1->Class != ITEM_CLASS_ARMOR || (proto1->InventoryType != INVTYPE_CHEST && proto2->InventoryType != INVTYPE_ROBE && proto1->InventoryType != INVTYPE_ROBE && proto2->InventoryType != INVTYPE_CHEST)))
|
||||
if (proto1->GetInventoryType() != proto2->GetInventoryType() &&
|
||||
(proto1->GetClass() != ITEM_CLASS_WEAPON || (proto2->GetInventoryType() != INVTYPE_WEAPONMAINHAND && proto2->GetInventoryType() != INVTYPE_WEAPONOFFHAND)) &&
|
||||
(proto1->GetClass() != ITEM_CLASS_ARMOR || (proto1->GetInventoryType() != INVTYPE_CHEST && proto2->GetInventoryType() != INVTYPE_ROBE && proto1->GetInventoryType() != INVTYPE_ROBE && proto2->GetInventoryType() != INVTYPE_CHEST)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -1238,7 +1238,7 @@ bool Item::HasStats() const
|
||||
|
||||
ItemTemplate const* proto = GetTemplate();
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
|
||||
if (proto->ItemStat[i].ItemStatValue != 0)
|
||||
if (proto->GetItemStatValue(i) != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -1249,14 +1249,14 @@ uint32 Item::GetSellPrice(ItemTemplate const* proto, bool& normalSellPrice)
|
||||
{
|
||||
normalSellPrice = true;
|
||||
|
||||
if (proto->Flags2 & ITEM_FLAG2_OVERRIDE_GOLD_COST)
|
||||
if (proto->GetFlags2() & ITEM_FLAG2_OVERRIDE_GOLD_COST)
|
||||
{
|
||||
return proto->BuyPrice;
|
||||
return proto->GetBuyPrice();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImportPriceQualityEntry const* qualityPrice = sImportPriceQualityStore.LookupEntry(proto->Quality + 1);
|
||||
ItemPriceBaseEntry const* basePrice = sItemPriceBaseStore.LookupEntry(proto->ItemLevel);
|
||||
ImportPriceQualityEntry const* qualityPrice = sImportPriceQualityStore.LookupEntry(proto->GetQuality() + 1);
|
||||
ItemPriceBaseEntry const* basePrice = sItemPriceBaseStore.LookupEntry(proto->GetBaseItemLevel());
|
||||
|
||||
if (!qualityPrice || !basePrice)
|
||||
return 0;
|
||||
@@ -1264,7 +1264,7 @@ uint32 Item::GetSellPrice(ItemTemplate const* proto, bool& normalSellPrice)
|
||||
float qualityFactor = qualityPrice->Factor;
|
||||
float baseFactor = 0.0f;
|
||||
|
||||
uint32 inventoryType = proto->InventoryType;
|
||||
uint32 inventoryType = proto->GetInventoryType();
|
||||
|
||||
if (inventoryType == INVTYPE_WEAPON ||
|
||||
inventoryType == INVTYPE_2HWEAPON ||
|
||||
@@ -1299,7 +1299,7 @@ uint32 Item::GetSellPrice(ItemTemplate const* proto, bool& normalSellPrice)
|
||||
if (!armorPrice)
|
||||
return 0;
|
||||
|
||||
switch (proto->SubClass)
|
||||
switch (proto->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_ARMOR_MISCELLANEOUS:
|
||||
case ITEM_SUBCLASS_ARMOR_CLOTH:
|
||||
@@ -1347,7 +1347,7 @@ uint32 Item::GetSellPrice(ItemTemplate const* proto, bool& normalSellPrice)
|
||||
weapType = 4;
|
||||
break;
|
||||
default:
|
||||
return proto->BuyPrice;
|
||||
return proto->GetBuyPrice();
|
||||
}
|
||||
|
||||
if (weapType != -1)
|
||||
@@ -1360,7 +1360,7 @@ uint32 Item::GetSellPrice(ItemTemplate const* proto, bool& normalSellPrice)
|
||||
}
|
||||
|
||||
normalSellPrice = false;
|
||||
return uint32(qualityFactor * proto->Unk430_2 * proto->Unk430_1 * typeFactor * baseFactor);
|
||||
return uint32(qualityFactor * proto->GetUnk1() * proto->GetUnk2() * typeFactor * baseFactor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1368,8 +1368,8 @@ uint32 Item::GetSpecialPrice(ItemTemplate const* proto, uint32 minimumPrice /*=
|
||||
{
|
||||
uint32 cost = 0;
|
||||
|
||||
if (proto->Flags2 & ITEM_FLAG2_OVERRIDE_GOLD_COST)
|
||||
cost = proto->SellPrice;
|
||||
if (proto->GetFlags2() & ITEM_FLAG2_OVERRIDE_GOLD_COST)
|
||||
cost = proto->GetSellPrice();
|
||||
else
|
||||
{
|
||||
bool normalPrice;
|
||||
@@ -1377,19 +1377,19 @@ uint32 Item::GetSpecialPrice(ItemTemplate const* proto, uint32 minimumPrice /*=
|
||||
|
||||
if (!normalPrice)
|
||||
{
|
||||
if (proto->BuyCount <= 1)
|
||||
if (proto->GetBuyCount() <= 1)
|
||||
{
|
||||
ItemClassEntry const* classEntry = sItemClassStore.LookupEntry(proto->Class);
|
||||
ItemClassEntry const* classEntry = sItemClassStore.LookupEntry(proto->GetClass());
|
||||
if (classEntry)
|
||||
cost *= classEntry->PriceModifier;
|
||||
else
|
||||
cost = 0;
|
||||
}
|
||||
else
|
||||
cost /= 4 * proto->BuyCount;
|
||||
cost /= 4 * proto->GetBuyCount();
|
||||
}
|
||||
else
|
||||
cost = proto->SellPrice;
|
||||
cost = proto->GetSellPrice();
|
||||
}
|
||||
|
||||
if (cost < minimumPrice)
|
||||
@@ -1402,8 +1402,8 @@ int32 Item::GetReforgableStat(ItemModType statType) const
|
||||
{
|
||||
ItemTemplate const* proto = GetTemplate();
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
|
||||
if (ItemModType(proto->ItemStat[i].ItemStatType) == statType)
|
||||
return proto->ItemStat[i].ItemStatValue;
|
||||
if (ItemModType(proto->GetItemStatType(i)) == statType)
|
||||
return proto->GetItemStatValue(i);
|
||||
|
||||
int32 randomPropId = GetItemRandomPropertyId();
|
||||
if (!randomPropId)
|
||||
|
||||
@@ -79,8 +79,8 @@ class TC_GAME_API Item : public Object
|
||||
|
||||
void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, val); }
|
||||
bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND); }
|
||||
bool IsBoundAccountWide() const { return (GetTemplate()->Flags & ITEM_FLAG_IS_BOUND_TO_ACCOUNT) != 0; }
|
||||
bool IsBattlenetAccountBound() const { return (GetTemplate()->Flags2 & ITEM_FLAG2_BNET_ACCOUNT_TRADE_OK) != 0; }
|
||||
bool IsBoundAccountWide() const { return (GetTemplate()->GetFlags() & ITEM_FLAG_IS_BOUND_TO_ACCOUNT) != 0; }
|
||||
bool IsBattlenetAccountBound() const { return (GetTemplate()->GetFlags2() & ITEM_FLAG2_BNET_ACCOUNT_TRADE_OK) != 0; }
|
||||
bool IsBindedNotWith(Player const* player) const;
|
||||
bool IsBoundByEnchant() const;
|
||||
virtual void SaveToDB(SQLTransaction& trans);
|
||||
@@ -97,7 +97,7 @@ class TC_GAME_API Item : public Object
|
||||
Bag const* ToBag() const { if (IsBag()) return reinterpret_cast<Bag const*>(this); else return nullptr; }
|
||||
|
||||
bool IsLocked() const { return !HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED); }
|
||||
bool IsBag() const { return GetTemplate()->InventoryType == INVTYPE_BAG; }
|
||||
bool IsBag() const { return GetTemplate()->GetInventoryType() == INVTYPE_BAG; }
|
||||
bool IsCurrencyToken() const { return GetTemplate()->IsCurrencyToken(); }
|
||||
bool IsNotEmptyBag() const;
|
||||
bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; }
|
||||
@@ -169,13 +169,16 @@ class TC_GAME_API Item : public Object
|
||||
uState = state;
|
||||
}
|
||||
|
||||
bool hasQuest(uint32 quest_id) const override { return GetTemplate()->StartQuest == quest_id; }
|
||||
bool hasQuest(uint32 quest_id) const override { return GetTemplate()->GetStartQuest() == quest_id; }
|
||||
bool hasInvolvedQuest(uint32 /*quest_id*/) const override { return false; }
|
||||
bool HasStats() const;
|
||||
bool IsPotion() const { return GetTemplate()->IsPotion(); }
|
||||
bool IsVellum() const { return GetTemplate()->IsVellum(); }
|
||||
bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); }
|
||||
bool IsRangedWeapon() const { return GetTemplate()->IsRangedWeapon(); }
|
||||
uint32 GetItemLevel() const { return GetTemplate()->GetBaseItemLevel(); }
|
||||
uint32 GetDisplayId() const { return GetTemplate()->GetDisplayID(); }
|
||||
|
||||
|
||||
// Item Refund system
|
||||
void SetNotRefundable(Player* owner, bool changestate = true, SQLTransaction* trans = nullptr);
|
||||
|
||||
@@ -126,20 +126,20 @@ int32 GenerateItemRandomPropertyId(uint32 item_id)
|
||||
return 0;
|
||||
|
||||
// item must have one from this field values not null if it can have random enchantments
|
||||
if ((!itemProto->RandomProperty) && (!itemProto->RandomSuffix))
|
||||
if ((!itemProto->GetRandomProperty()) && (!itemProto->GetRandomSuffix()))
|
||||
return 0;
|
||||
|
||||
// item can have not null only one from field values
|
||||
if ((itemProto->RandomProperty) && (itemProto->RandomSuffix))
|
||||
if ((itemProto->GetRandomProperty()) && (itemProto->GetRandomSuffix()))
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Item template %u have RandomProperty == %u and RandomSuffix == %u, but must have one from field =0", itemProto->ItemId, itemProto->RandomProperty, itemProto->RandomSuffix);
|
||||
TC_LOG_ERROR("sql.sql", "Item template %u have RandomProperty == %u and RandomSuffix == %u, but must have one from field =0", itemProto->GetId(), itemProto->GetRandomSuffix(), itemProto->GetRandomSuffix());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// RandomProperty case
|
||||
if (itemProto->RandomProperty)
|
||||
if (itemProto->GetRandomSuffix())
|
||||
{
|
||||
uint32 randomPropId = GetItemEnchantMod(itemProto->RandomProperty);
|
||||
uint32 randomPropId = GetItemEnchantMod(itemProto->GetRandomSuffix());
|
||||
ItemRandomPropertiesEntry const* random_id = sItemRandomPropertiesStore.LookupEntry(randomPropId);
|
||||
if (!random_id)
|
||||
{
|
||||
@@ -152,7 +152,7 @@ int32 GenerateItemRandomPropertyId(uint32 item_id)
|
||||
// RandomSuffix case
|
||||
else
|
||||
{
|
||||
uint32 randomPropId = GetItemEnchantMod(itemProto->RandomSuffix);
|
||||
uint32 randomPropId = GetItemEnchantMod(itemProto->GetRandomSuffix());
|
||||
ItemRandomSuffixEntry const* random_id = sItemRandomSuffixStore.LookupEntry(randomPropId);
|
||||
if (!random_id)
|
||||
{
|
||||
@@ -170,15 +170,15 @@ uint32 GenerateEnchSuffixFactor(uint32 item_id)
|
||||
|
||||
if (!itemProto)
|
||||
return 0;
|
||||
if (!itemProto->RandomSuffix)
|
||||
if (!itemProto->GetRandomSuffix())
|
||||
return 0;
|
||||
|
||||
RandomPropertiesPointsEntry const* randomProperty = sRandomPropertiesPointsStore.LookupEntry(itemProto->ItemLevel);
|
||||
RandomPropertiesPointsEntry const* randomProperty = sRandomPropertiesPointsStore.LookupEntry(itemProto->GetBaseItemLevel());
|
||||
if (!randomProperty)
|
||||
return 0;
|
||||
|
||||
uint32 suffixFactor;
|
||||
switch (itemProto->InventoryType)
|
||||
switch (itemProto->GetInventoryType())
|
||||
{
|
||||
// Items of that type don`t have points
|
||||
case INVTYPE_NON_EQUIP:
|
||||
@@ -226,7 +226,7 @@ uint32 GenerateEnchSuffixFactor(uint32 item_id)
|
||||
return 0;
|
||||
}
|
||||
// Select rare/epic modifier
|
||||
switch (itemProto->Quality)
|
||||
switch (itemProto->GetQuality())
|
||||
{
|
||||
case ITEM_QUALITY_UNCOMMON:
|
||||
return randomProperty->UncommonPropertiesPoints[suffixFactor];
|
||||
|
||||
@@ -15,11 +15,27 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "DBCStores.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "World.h"
|
||||
#include "ItemTemplate.h"
|
||||
|
||||
char const* ItemTemplate::GetName(LocaleConstant locale) const
|
||||
{
|
||||
if (!strlen(ExtendedData->Name->Str[locale]))
|
||||
return GetDefaultLocaleName();
|
||||
|
||||
return ExtendedData->Name->Str[locale];
|
||||
}
|
||||
|
||||
char const* ItemTemplate::GetDefaultLocaleName() const
|
||||
{
|
||||
return ExtendedData->Name->Str[sWorld->GetDefaultDbcLocale()];
|
||||
}
|
||||
|
||||
bool ItemTemplate::CanChangeEquipStateInCombat() const
|
||||
{
|
||||
switch (InventoryType)
|
||||
switch (GetInventoryType())
|
||||
{
|
||||
case INVTYPE_RELIC:
|
||||
case INVTYPE_SHIELD:
|
||||
@@ -27,7 +43,7 @@ bool ItemTemplate::CanChangeEquipStateInCombat() const
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (Class)
|
||||
switch (GetClass())
|
||||
{
|
||||
case ITEM_CLASS_WEAPON:
|
||||
case ITEM_CLASS_PROJECTILE:
|
||||
@@ -39,8 +55,8 @@ bool ItemTemplate::CanChangeEquipStateInCombat() const
|
||||
|
||||
float ItemTemplate::GetItemLevelIncludingQuality() const
|
||||
{
|
||||
float itemLevel(ItemLevel);
|
||||
switch (Quality)
|
||||
float itemLevel(GetBaseItemLevel());
|
||||
switch (GetQuality())
|
||||
{
|
||||
case ITEM_QUALITY_POOR:
|
||||
case ITEM_QUALITY_NORMAL:
|
||||
@@ -77,19 +93,19 @@ uint32 ItemTemplate::GetSkill() const
|
||||
0, SKILL_CLOTH, SKILL_LEATHER, SKILL_MAIL, SKILL_PLATE_MAIL, 0, SKILL_SHIELD, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
switch (Class)
|
||||
switch (GetClass())
|
||||
{
|
||||
case ITEM_CLASS_WEAPON:
|
||||
if (SubClass >= MAX_ITEM_SUBCLASS_WEAPON)
|
||||
if (GetSubClass() >= MAX_ITEM_SUBCLASS_WEAPON)
|
||||
return 0;
|
||||
else
|
||||
return itemWeaponSkills[SubClass];
|
||||
return itemWeaponSkills[GetSubClass()];
|
||||
|
||||
case ITEM_CLASS_ARMOR:
|
||||
if (SubClass >= MAX_ITEM_SUBCLASS_ARMOR)
|
||||
if (GetSubClass() >= MAX_ITEM_SUBCLASS_ARMOR)
|
||||
return 0;
|
||||
else
|
||||
return itemArmorSkills[SubClass];
|
||||
return itemArmorSkills[GetSubClass()];
|
||||
|
||||
default:
|
||||
return 0;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef _ITEMPROTOTYPE_H
|
||||
#define _ITEMPROTOTYPE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "DB2Structure.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <vector>
|
||||
@@ -607,28 +607,14 @@ inline uint8 ItemSubClassToDurabilityMultiplierId(uint32 ItemClass, uint32 ItemS
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct _ItemStat
|
||||
struct ItemEffect
|
||||
{
|
||||
int32 ItemStatType;
|
||||
int32 ItemStatValue;
|
||||
int32 ItemStatAllocation;
|
||||
int32 ItemStatSocketCostMultiplier;
|
||||
};
|
||||
|
||||
struct _Spell
|
||||
{
|
||||
int32 SpellId; // id from Spell.dbc
|
||||
uint32 SpellTrigger;
|
||||
int32 SpellCharges;
|
||||
int32 SpellCooldown;
|
||||
uint32 SpellCategory; // id from SpellCategory.dbc
|
||||
int32 SpellCategoryCooldown;
|
||||
};
|
||||
|
||||
struct _Socket
|
||||
{
|
||||
uint32 Color;
|
||||
uint32 Content;
|
||||
uint32 SpellID;
|
||||
uint32 Trigger;
|
||||
int32 Charges;
|
||||
int32 Cooldown;
|
||||
uint32 Category;
|
||||
int32 CategoryCooldown;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
@@ -640,71 +626,66 @@ struct _Socket
|
||||
|
||||
struct ItemTemplate
|
||||
{
|
||||
uint32 ItemId;
|
||||
uint32 Class; // id from ItemClass.dbc
|
||||
uint32 SubClass; // id from ItemSubClass.dbc
|
||||
int32 SoundOverrideSubclass; // < 0: id from ItemSubClass.dbc, used to override weapon sound from actual SubClass
|
||||
std::string Name1;
|
||||
uint32 DisplayInfoID; // id from ItemDisplayInfo.dbc
|
||||
uint32 Quality;
|
||||
uint32 Flags;
|
||||
uint32 Flags2;
|
||||
float Unk430_1;
|
||||
float Unk430_2;
|
||||
uint32 BuyCount;
|
||||
int32 BuyPrice;
|
||||
uint32 SellPrice;
|
||||
uint32 InventoryType;
|
||||
uint32 AllowableClass;
|
||||
uint32 AllowableRace;
|
||||
uint32 ItemLevel;
|
||||
uint32 RequiredLevel;
|
||||
uint32 RequiredSkill; // id from SkillLine.dbc
|
||||
uint32 RequiredSkillRank;
|
||||
uint32 RequiredSpell; // id from Spell.dbc
|
||||
uint32 RequiredHonorRank;
|
||||
uint32 RequiredCityRank;
|
||||
uint32 RequiredReputationFaction; // id from Faction.dbc
|
||||
uint32 RequiredReputationRank;
|
||||
int32 MaxCount; // <= 0: no limit
|
||||
int32 Stackable; // 0: not allowed, -1: put in player coin info tab and don't limit stacking (so 1 slot)
|
||||
uint32 ContainerSlots;
|
||||
_ItemStat ItemStat[MAX_ITEM_PROTO_STATS];
|
||||
uint32 ScalingStatDistribution; // id from ScalingStatDistribution.dbc
|
||||
uint32 DamageType; // id from Resistances.dbc
|
||||
uint32 Delay;
|
||||
float RangedModRange;
|
||||
_Spell Spells[MAX_ITEM_PROTO_SPELLS];
|
||||
uint32 Bonding;
|
||||
std::string Description;
|
||||
uint32 PageText;
|
||||
uint32 LanguageID;
|
||||
uint32 PageMaterial;
|
||||
uint32 StartQuest; // id from QuestCache.wdb
|
||||
uint32 LockID;
|
||||
int32 Material; // id from Material.dbc
|
||||
uint32 Sheath;
|
||||
int32 RandomProperty; // id from ItemRandomProperties.dbc
|
||||
int32 RandomSuffix; // id from ItemRandomSuffix.dbc
|
||||
uint32 ItemSet; // id from ItemSet.dbc
|
||||
ItemEntry const* BasicData;
|
||||
ItemSparseEntry const* ExtendedData;
|
||||
|
||||
uint32 GetId() const { return BasicData->ID; }
|
||||
uint32 GetClass() const { return BasicData->ClassID; }
|
||||
uint32 GetDisplayID() const { return BasicData->DisplayInfoID; }
|
||||
uint32 GetSubClass() const { return BasicData->SubclassID; }
|
||||
uint32 GetQuality() const { return ExtendedData->Quality; }
|
||||
uint32 GetFlags() const { return ExtendedData->Flags; }
|
||||
uint32 GetFlags2() const { return ExtendedData->Flags2; }
|
||||
float GetUnk1() const { return ExtendedData->Unk1; }
|
||||
float GetUnk2() const { return ExtendedData->Unk2; }
|
||||
uint32 GetBuyCount() const { return std::max(ExtendedData->BuyCount, 1u); }
|
||||
uint32 GetBuyPrice() const { return ExtendedData->BuyPrice; }
|
||||
uint32 GetSellPrice() const { return ExtendedData->SellPrice; }
|
||||
uint8 GetInventoryType() const { return uint8(ExtendedData->InventoryType); }
|
||||
int32 GetAllowableClass() const { return ExtendedData->AllowableClass; }
|
||||
int32 GetAllowableRace() const { return ExtendedData->AllowableRace; }
|
||||
uint32 GetBaseItemLevel() const { return ExtendedData->ItemLevel; }
|
||||
int32 GetRequiredLevel() const { return ExtendedData->RequiredLevel; }
|
||||
uint32 GetRequiredSkill() const { return ExtendedData->RequiredSkill; }
|
||||
uint32 GetRequiredSkillRank() const { return ExtendedData->RequiredSkillRank; }
|
||||
uint32 GetRequiredSpell() const { return ExtendedData->RequiredSpell; }
|
||||
uint32 GetRequiredReputationFaction() const { return ExtendedData->RequiredReputationFaction; }
|
||||
uint32 GetRequiredReputationRank() const { return ExtendedData->RequiredReputationRank; }
|
||||
uint32 GetMaxCount() const { return ExtendedData->MaxCount; }
|
||||
uint32 GetContainerSlots() const { return ExtendedData->ContainerSlots; }
|
||||
int32 GetItemStatType(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_STATS); return ExtendedData->ItemStatType[index]; }
|
||||
int32 GetItemStatValue(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_STATS); return ExtendedData->ItemStatValue[index]; }
|
||||
int32 GetItemStatAllocation(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_STATS); return ExtendedData->ItemStatAllocation[index]; }
|
||||
float GetItemStatSocketCostMultiplier(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_STATS); return ExtendedData->ItemStatSocketCostMultiplier[index]; }
|
||||
uint32 GetScalingStatDistribution() const { return ExtendedData->ScalingStatDistribution; }
|
||||
uint32 GetDamageType() const { return ExtendedData->DamageType; }
|
||||
uint32 GetDelay() const { return ExtendedData->Delay; }
|
||||
ItemBondingType GetBonding() const { return ItemBondingType(ExtendedData->Bonding); }
|
||||
char const* GetName(LocaleConstant locale) const;
|
||||
uint32 GetPageText() const { return ExtendedData->PageText; }
|
||||
uint32 GetStartQuest() const { return ExtendedData->StartQuest; }
|
||||
uint32 GetLockID() const { return ExtendedData->LockID; }
|
||||
uint32 GetRandomProperty() const { return ExtendedData->RandomProperty; }
|
||||
uint32 GetRandomSuffix() const { return ExtendedData->RandomSuffix; }
|
||||
uint32 GetItemSet() const { return ExtendedData->ItemSet; }
|
||||
uint32 GetArea() const { return ExtendedData->Area; }
|
||||
uint32 GetMap() const { return ExtendedData->Map; }
|
||||
uint32 GetBagFamily() const { return ExtendedData->BagFamily; }
|
||||
SocketColor GetSocketColor(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_SOCKETS); return SocketColor(ExtendedData->SocketColor[index]); }
|
||||
uint32 GetSocketBonus() const { return ExtendedData->SocketBonus; }
|
||||
uint32 GetGemProperties() const { return ExtendedData->GemProperties; }
|
||||
float GetArmorDamageModifier() const { return ExtendedData->ArmorDamageModifier; }
|
||||
uint32 GetDuration() const { return ExtendedData->Duration; }
|
||||
uint32 GetItemLimitCategory() const { return ExtendedData->ItemLimitCategory; }
|
||||
HolidayIds GetHolidayID() const { return HolidayIds(ExtendedData->HolidayID); }
|
||||
float GetStatScalingFactor() const { return ExtendedData->StatScalingFactor; }
|
||||
uint32 GetTotemCategory() const { return ExtendedData->TotemCategory; }
|
||||
float GetRangedModRange() const { return ExtendedData->RangedModRange; }
|
||||
|
||||
uint32 MaxDurability;
|
||||
uint32 Area; // id from AreaTable.dbc
|
||||
uint32 Map; // id from Map.dbc
|
||||
uint32 BagFamily; // bit mask (1 << id from ItemBagFamily.dbc)
|
||||
uint32 TotemCategory; // id from TotemCategory.dbc
|
||||
_Socket Socket[MAX_ITEM_PROTO_SOCKETS];
|
||||
uint32 socketBonus; // id from SpellItemEnchantment.dbc
|
||||
uint32 GemProperties; // id from GemProperties.dbc
|
||||
float ArmorDamageModifier;
|
||||
uint32 Duration;
|
||||
uint32 ItemLimitCategory; // id from ItemLimitCategory.dbc
|
||||
uint32 HolidayId; // id from Holidays.dbc
|
||||
float StatScalingFactor;
|
||||
uint32 CurrencySubstitutionId; // May be used instead of a currency
|
||||
uint32 CurrencySubstitutionCount;
|
||||
std::vector<ItemEffect> Effects;
|
||||
|
||||
// extra fields, not part of db2 files
|
||||
float SpellPPMRate;
|
||||
uint32 ScriptId;
|
||||
uint32 DisenchantID;
|
||||
uint32 RequiredDisenchantSkill;
|
||||
@@ -712,42 +693,38 @@ struct ItemTemplate
|
||||
uint32 MinMoneyLoot;
|
||||
uint32 MaxMoneyLoot;
|
||||
uint32 FlagsCu;
|
||||
float SpellPPMRate;
|
||||
|
||||
// helpers
|
||||
bool CanChangeEquipStateInCombat() const;
|
||||
|
||||
bool IsCurrencyToken() const { return (BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) != 0; }
|
||||
bool IsCurrencyToken() const { return (GetBagFamily() & BAG_FAMILY_MASK_CURRENCY_TOKENS) != 0; }
|
||||
|
||||
uint32 GetMaxStackSize() const
|
||||
{
|
||||
return (Stackable == 2147483647 || Stackable <= 0) ? uint32(0x7FFFFFFF-1) : uint32(Stackable);
|
||||
return (ExtendedData->Stackable == 2147483647 || ExtendedData->Stackable <= 0) ? uint32(0x7FFFFFFF - 1) : uint32(ExtendedData->Stackable);
|
||||
}
|
||||
|
||||
float GetItemLevelIncludingQuality() const;
|
||||
|
||||
uint32 GetSkill() const;
|
||||
|
||||
bool IsPotion() const { return Class == ITEM_CLASS_CONSUMABLE && SubClass == ITEM_SUBCLASS_POTION; }
|
||||
bool IsVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_ENCHANTMENT; }
|
||||
bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_FLAG_CONJURED); }
|
||||
bool IsPotion() const { return GetClass() == ITEM_CLASS_CONSUMABLE && GetSubClass() == ITEM_SUBCLASS_POTION; }
|
||||
bool IsVellum() const { return GetClass() == ITEM_CLASS_TRADE_GOODS && GetSubClass() == ITEM_SUBCLASS_ENCHANTMENT; }
|
||||
bool IsConjuredConsumable() const { return GetClass() == ITEM_CLASS_CONSUMABLE && (GetFlags() & ITEM_FLAG_CONJURED); }
|
||||
|
||||
bool IsRangedWeapon() const
|
||||
{
|
||||
return Class == ITEM_CLASS_WEAPON ||
|
||||
SubClass == ITEM_SUBCLASS_WEAPON_BOW ||
|
||||
SubClass == ITEM_SUBCLASS_WEAPON_GUN ||
|
||||
SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW;
|
||||
return GetClass() == ITEM_CLASS_WEAPON ||
|
||||
GetSubClass() == ITEM_SUBCLASS_WEAPON_BOW ||
|
||||
GetSubClass() == ITEM_SUBCLASS_WEAPON_GUN ||
|
||||
GetSubClass() == ITEM_SUBCLASS_WEAPON_CROSSBOW;
|
||||
}
|
||||
|
||||
char const* GetDefaultLocaleName() const;
|
||||
uint32 GetStatValue(uint32 index, Player const* owner = nullptr) const;
|
||||
uint32 GetEffectiveArmor(Player const* owner) const;
|
||||
bool GetWeaponDamage(Player const* owner, float& minValue, float& maxValue, float& dps) const;
|
||||
};
|
||||
|
||||
struct ItemLocale
|
||||
{
|
||||
std::vector<std::string> Name;
|
||||
std::vector<std::string> Description;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -413,7 +413,7 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
|
||||
{
|
||||
float weaponSpeed = BASE_ATTACK_TIME / 1000.f;
|
||||
if (Item* weapon = GetWeaponForAttack(BASE_ATTACK, true))
|
||||
weaponSpeed = weapon->GetTemplate()->Delay / 1000;
|
||||
weaponSpeed = weapon->GetTemplate()->GetDelay() / 1000;
|
||||
|
||||
if (GetShapeshiftForm() == FORM_CAT)
|
||||
{
|
||||
|
||||
@@ -11466,9 +11466,9 @@ float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized)
|
||||
return BASE_ATTACK_TIME / 1000.0f;
|
||||
|
||||
if (!normalized)
|
||||
return weapon->GetTemplate()->Delay / 1000.0f;
|
||||
return weapon->GetTemplate()->GetDelay() / 1000.0f;
|
||||
|
||||
switch (weapon->GetTemplate()->SubClass)
|
||||
switch (weapon->GetTemplate()->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_AXE2:
|
||||
case ITEM_SUBCLASS_WEAPON_MACE2:
|
||||
@@ -11492,7 +11492,7 @@ float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized)
|
||||
case ITEM_SUBCLASS_WEAPON_DAGGER:
|
||||
return 1.7f;
|
||||
default:
|
||||
return weapon->GetTemplate()->Delay / 1000.0f;
|
||||
return weapon->GetTemplate()->GetDelay() / 1000.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2735,38 +2735,6 @@ void ObjectMgr::RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectDat
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadItemLocales()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
_itemLocaleStore.clear(); // need for reload case
|
||||
|
||||
// 0 1 2 3
|
||||
QueryResult result = WorldDatabase.Query("SELECT ID, locale, Name, Description FROM item_template_locale");
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
std::string localeName = fields[1].GetString();
|
||||
std::string Name = fields[2].GetString();
|
||||
std::string Description = fields[3].GetString();
|
||||
|
||||
ItemLocale& data = _itemLocaleStore[id];
|
||||
LocaleConstant locale = GetLocaleByName(localeName);
|
||||
if (locale == LOCALE_enUS)
|
||||
continue;
|
||||
|
||||
AddLocaleString(Name, locale, data.Name);
|
||||
AddLocaleString(Description, locale, data.Description);
|
||||
} while (result->NextRow());
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u Item locale strings in %u ms", uint32(_itemLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
uint32 FillMaxDurability(uint32 itemClass, uint32 itemSubClass, uint32 inventoryType, uint32 quality, uint32 itemLevel)
|
||||
{
|
||||
if (itemClass != ITEM_CLASS_ARMOR && itemClass != ITEM_CLASS_WEAPON)
|
||||
@@ -2854,12 +2822,12 @@ void FillDisenchantFields(uint32* disenchantID, uint32* requiredDisenchantSkill,
|
||||
{
|
||||
*disenchantID = 0;
|
||||
*(int32*)requiredDisenchantSkill = -1;
|
||||
if ((itemTemplate.Flags & (ITEM_FLAG_CONJURED | ITEM_FLAG_NO_DISENCHANT)) ||
|
||||
itemTemplate.Bonding == BIND_QUEST || itemTemplate.Area || itemTemplate.Map ||
|
||||
itemTemplate.Stackable > 1 ||
|
||||
itemTemplate.Quality < ITEM_QUALITY_UNCOMMON || itemTemplate.Quality > ITEM_QUALITY_EPIC ||
|
||||
!(itemTemplate.Class == ITEM_CLASS_ARMOR || itemTemplate.Class == ITEM_CLASS_WEAPON) ||
|
||||
!(Item::GetSpecialPrice(&itemTemplate) || sItemCurrencyCostStore.LookupEntry(itemTemplate.ItemId)))
|
||||
if ((itemTemplate.GetFlags() & (ITEM_FLAG_CONJURED | ITEM_FLAG_NO_DISENCHANT)) ||
|
||||
itemTemplate.GetBonding() == BIND_QUEST || itemTemplate.GetArea() || itemTemplate.GetMap() ||
|
||||
itemTemplate.GetMaxStackSize() > 1 ||
|
||||
itemTemplate.GetQuality() < ITEM_QUALITY_UNCOMMON || itemTemplate.GetQuality() > ITEM_QUALITY_EPIC ||
|
||||
!(itemTemplate.GetClass() == ITEM_CLASS_ARMOR || itemTemplate.GetClass() == ITEM_CLASS_WEAPON) ||
|
||||
!(Item::GetSpecialPrice(&itemTemplate) || sItemCurrencyCostStore.LookupEntry(itemTemplate.GetId())))
|
||||
return;
|
||||
|
||||
for (uint32 i = 0; i < sItemDisenchantLootStore.GetNumRows(); ++i)
|
||||
@@ -2868,19 +2836,19 @@ void FillDisenchantFields(uint32* disenchantID, uint32* requiredDisenchantSkill,
|
||||
if (!disenchant)
|
||||
continue;
|
||||
|
||||
if (disenchant->Class == itemTemplate.Class &&
|
||||
disenchant->Quality == itemTemplate.Quality &&
|
||||
disenchant->MinLevel <= itemTemplate.ItemLevel &&
|
||||
disenchant->MaxLevel >= itemTemplate.ItemLevel)
|
||||
if (disenchant->Class == itemTemplate.GetClass() &&
|
||||
disenchant->Quality == itemTemplate.GetQuality() &&
|
||||
disenchant->MinLevel <= itemTemplate.GetBaseItemLevel() &&
|
||||
disenchant->MaxLevel >= itemTemplate.GetBaseItemLevel())
|
||||
{
|
||||
if (disenchant->ID == 60 || disenchant->ID == 61) // epic item disenchant ilvl range 66-99 (classic)
|
||||
{
|
||||
if (itemTemplate.RequiredLevel > 60 || itemTemplate.RequiredSkillRank > 300)
|
||||
if (itemTemplate.GetRequiredLevel() > 60 || itemTemplate.GetRequiredSkillRank() > 300)
|
||||
continue; // skip to epic item disenchant ilvl range 90-199 (TBC)
|
||||
}
|
||||
else if (disenchant->ID == 66 || disenchant->ID == 67) // epic item disenchant ilvl range 90-199 (TBC)
|
||||
{
|
||||
if (itemTemplate.RequiredLevel <= 60 || (itemTemplate.RequiredSkill && itemTemplate.RequiredSkillRank <= 300))
|
||||
if (itemTemplate.GetRequiredLevel() <= 60 || (itemTemplate.GetRequiredSkill() && itemTemplate.GetRequiredSkillRank() <= 300))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2895,260 +2863,40 @@ void ObjectMgr::LoadItemTemplates()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
uint32 sparseCount = 0;
|
||||
uint32 dbCount = 0;
|
||||
|
||||
for (uint32 itemId = 0; itemId < sItemSparseStore.GetNumRows(); ++itemId)
|
||||
for (ItemSparseEntry const* sparse : sItemSparseStore)
|
||||
{
|
||||
ItemSparseEntry const* sparse = sItemSparseStore.LookupEntry(itemId);
|
||||
ItemEntry const* db2Data = sItemStore.LookupEntry(itemId);
|
||||
if (!sparse || !db2Data)
|
||||
ItemEntry const* db2Data = sItemStore.LookupEntry(sparse->ID);
|
||||
if (!db2Data)
|
||||
continue;
|
||||
|
||||
ItemTemplate& itemTemplate = _itemTemplateStore[itemId];
|
||||
itemTemplate.ItemId = itemId;
|
||||
itemTemplate.Class = db2Data->Class;
|
||||
itemTemplate.SubClass = db2Data->SubClass;
|
||||
itemTemplate.SoundOverrideSubclass = db2Data->SoundOverrideSubclass;
|
||||
itemTemplate.Name1 = sparse->Name->Str[sWorld->GetDefaultDbcLocale()];
|
||||
itemTemplate.DisplayInfoID = db2Data->DisplayId;
|
||||
itemTemplate.Quality = sparse->Quality;
|
||||
itemTemplate.Flags = sparse->Flags;
|
||||
itemTemplate.Flags2 = sparse->Flags2;
|
||||
itemTemplate.Unk430_1 = sparse->Unk430_1;
|
||||
itemTemplate.Unk430_2 = sparse->Unk430_2;
|
||||
itemTemplate.BuyCount = std::max(sparse->BuyCount, 1u);
|
||||
itemTemplate.BuyPrice = sparse->BuyPrice;
|
||||
itemTemplate.SellPrice = sparse->SellPrice;
|
||||
itemTemplate.InventoryType = db2Data->InventoryType;
|
||||
itemTemplate.AllowableClass = sparse->AllowableClass;
|
||||
itemTemplate.AllowableRace = sparse->AllowableRace;
|
||||
itemTemplate.ItemLevel = sparse->ItemLevel;
|
||||
itemTemplate.RequiredLevel = sparse->RequiredLevel;
|
||||
itemTemplate.RequiredSkill = sparse->RequiredSkill;
|
||||
itemTemplate.RequiredSkillRank = sparse->RequiredSkillRank;
|
||||
itemTemplate.RequiredSpell = sparse->RequiredSpell;
|
||||
itemTemplate.RequiredHonorRank = sparse->RequiredHonorRank;
|
||||
itemTemplate.RequiredCityRank = sparse->RequiredCityRank;
|
||||
itemTemplate.RequiredReputationFaction = sparse->RequiredReputationFaction;
|
||||
itemTemplate.RequiredReputationRank = sparse->RequiredReputationRank;
|
||||
itemTemplate.MaxCount = sparse->MaxCount;
|
||||
itemTemplate.Stackable = sparse->Stackable;
|
||||
itemTemplate.ContainerSlots = sparse->ContainerSlots;
|
||||
ItemTemplate& itemTemplate = _itemTemplateStore[sparse->ID];
|
||||
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
|
||||
{
|
||||
itemTemplate.ItemStat[i].ItemStatType = sparse->ItemStatType[i];
|
||||
itemTemplate.ItemStat[i].ItemStatValue = sparse->ItemStatValue[i];
|
||||
itemTemplate.ItemStat[i].ItemStatAllocation = sparse->ItemStatAllocation[i];
|
||||
itemTemplate.ItemStat[i].ItemStatSocketCostMultiplier = sparse->ItemStatSocketCostMultiplier[i];
|
||||
}
|
||||
itemTemplate.BasicData = db2Data;
|
||||
itemTemplate.ExtendedData = sparse;
|
||||
|
||||
itemTemplate.ScalingStatDistribution = sparse->ScalingStatDistribution;
|
||||
|
||||
// cache item damage
|
||||
itemTemplate.DamageType = sparse->DamageType;
|
||||
itemTemplate.Delay = sparse->Delay;
|
||||
itemTemplate.RangedModRange = sparse->RangedModRange;
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
{
|
||||
itemTemplate.Spells[i].SpellId = sparse->SpellId[i];
|
||||
itemTemplate.Spells[i].SpellTrigger = sparse->SpellTrigger[i];
|
||||
itemTemplate.Spells[i].SpellCharges = sparse->SpellCharges[i];
|
||||
itemTemplate.Spells[i].SpellCooldown = sparse->SpellCooldown[i];
|
||||
itemTemplate.Spells[i].SpellCategory = sparse->SpellCategory[i];
|
||||
itemTemplate.Spells[i].SpellCategoryCooldown = sparse->SpellCategoryCooldown[i];
|
||||
}
|
||||
|
||||
itemTemplate.SpellPPMRate = 0.0f;
|
||||
itemTemplate.Bonding = sparse->Bonding;
|
||||
itemTemplate.Description = sparse->Description->Str[sWorld->GetDefaultDbcLocale()];
|
||||
itemTemplate.PageText = sparse->PageText;
|
||||
itemTemplate.LanguageID = sparse->LanguageID;
|
||||
itemTemplate.PageMaterial = sparse->PageMaterial;
|
||||
itemTemplate.StartQuest = sparse->StartQuest;
|
||||
itemTemplate.LockID = sparse->LockID;
|
||||
itemTemplate.Material = sparse->Material;
|
||||
itemTemplate.Sheath = sparse->Sheath;
|
||||
itemTemplate.RandomProperty = sparse->RandomProperty;
|
||||
itemTemplate.RandomSuffix = sparse->RandomSuffix;
|
||||
itemTemplate.ItemSet = sparse->ItemSet;
|
||||
itemTemplate.MaxDurability = FillMaxDurability(db2Data->Class, db2Data->SubClass, sparse->InventoryType, sparse->Quality, sparse->ItemLevel);
|
||||
itemTemplate.Area = sparse->Area;
|
||||
itemTemplate.Map = sparse->Map;
|
||||
itemTemplate.BagFamily = sparse->BagFamily;
|
||||
itemTemplate.TotemCategory = sparse->TotemCategory;
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
|
||||
{
|
||||
itemTemplate.Socket[i].Color = sparse->Color[i];
|
||||
itemTemplate.Socket[i].Content = sparse->Content[i];
|
||||
}
|
||||
|
||||
itemTemplate.socketBonus = sparse->SocketBonus;
|
||||
itemTemplate.GemProperties = sparse->GemProperties;
|
||||
itemTemplate.MaxDurability = FillMaxDurability(db2Data->ClassID, db2Data->SubclassID, sparse->InventoryType, sparse->Quality, sparse->ItemLevel);
|
||||
FillDisenchantFields(&itemTemplate.DisenchantID, &itemTemplate.RequiredDisenchantSkill, itemTemplate);
|
||||
|
||||
itemTemplate.ArmorDamageModifier = sparse->ArmorDamageModifier;
|
||||
itemTemplate.Duration = sparse->Duration;
|
||||
itemTemplate.ItemLimitCategory = sparse->ItemLimitCategory;
|
||||
itemTemplate.HolidayId = sparse->HolidayId;
|
||||
itemTemplate.StatScalingFactor = sparse->StatScalingFactor;
|
||||
itemTemplate.CurrencySubstitutionId = sparse->CurrencySubstitutionId;
|
||||
itemTemplate.CurrencySubstitutionCount = sparse->CurrencySubstitutionCount;
|
||||
itemTemplate.ScriptId = 0;
|
||||
itemTemplate.FoodType = 0;
|
||||
itemTemplate.MinMoneyLoot = 0;
|
||||
itemTemplate.MaxMoneyLoot = 0;
|
||||
++sparseCount;
|
||||
}
|
||||
itemTemplate.FlagsCu = 0;
|
||||
itemTemplate.SpellPPMRate = 0.f;
|
||||
|
||||
// Load missing items from item_template AND overwrite data from Item-sparse.db2 (item_template is supposed to contain Item-sparse.adb data)
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
||||
QueryResult result = WorldDatabase.Query("SELECT entry, Class, SubClass, SoundOverrideSubclass, Name, DisplayId, Quality, Flags, FlagsExtra, Unk430_1, Unk430_2, BuyCount, BuyPrice, SellPrice, "
|
||||
// 14 15 16 17 18 19 20 21
|
||||
"InventoryType, AllowableClass, AllowableRace, ItemLevel, RequiredLevel, RequiredSkill, RequiredSkillRank, RequiredSpell, "
|
||||
// 22 23 24 25 26 27 28
|
||||
"RequiredHonorRank, RequiredCityRank, RequiredReputationFaction, RequiredReputationRank, MaxCount, Stackable, ContainerSlots, "
|
||||
// 29 30 31 32 33 34 35 36
|
||||
"stat_type1, stat_value1, stat_unk1_1, stat_unk2_1, stat_type2, stat_value2, stat_unk1_2, stat_unk2_2, "
|
||||
// 37 38 39 40 41 42 43 44
|
||||
"stat_type3, stat_value3, stat_unk1_3, stat_unk2_3, stat_type4, stat_value4, stat_unk1_4, stat_unk2_4, "
|
||||
// 45 46 47 48 49 50 51 52
|
||||
"stat_type5, stat_value5, stat_unk1_5, stat_unk2_5, stat_type6, stat_value6, stat_unk1_6, stat_unk2_6, "
|
||||
// 53 54 55 56 57 58 59 60
|
||||
"stat_type7, stat_value7, stat_unk1_7, stat_unk2_7, stat_type8, stat_value8, stat_unk1_8, stat_unk2_8, "
|
||||
// 61 62 63 64 65 66 67 68
|
||||
"stat_type9, stat_value9, stat_unk1_9, stat_unk2_9, stat_type10, stat_value10, stat_unk1_10, stat_unk2_10, "
|
||||
// 69 70 71 72
|
||||
"ScalingStatDistribution, DamageType, Delay, RangedModRange, "
|
||||
// 73 74 75 76 77 78
|
||||
"spellid_1, spelltrigger_1, spellcharges_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1, "
|
||||
// 79 80 81 82 83 84
|
||||
"spellid_2, spelltrigger_2, spellcharges_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2, "
|
||||
// 85 86 87 88 89 90
|
||||
"spellid_3, spelltrigger_3, spellcharges_3, spellcooldown_3, spellcategory_3, spellcategorycooldown_3, "
|
||||
// 91 92 93 94 95 96
|
||||
"spellid_4, spelltrigger_4, spellcharges_4, spellcooldown_4, spellcategory_4, spellcategorycooldown_4, "
|
||||
// 97 98 99 100 101 102
|
||||
"spellid_5, spelltrigger_5, spellcharges_5, spellcooldown_5, spellcategory_5, spellcategorycooldown_5, "
|
||||
// 103 104 105 106 107 108 109 110
|
||||
"Bonding, Description, PageText, LanguageID, PageMaterial, StartQuest, LockID, Material, "
|
||||
// 111 112 113 114 115 116 117 118
|
||||
"Sheath, RandomProperty, RandomSuffix, ItemSet, Area, Map, BagFamily, TotemCategory, "
|
||||
// 119 120 121 122 123 124 125
|
||||
"SocketColor_1, SocketContent_1, SocketColor_2, SocketContent_2, SocketColor_3, SocketContent_3, SocketBonus, "
|
||||
// 126 127 128 129 130 131
|
||||
"GemProperties, ArmorDamageModifier, Duration, ItemLimitCategory, HolidayId, StatScalingFactor, "
|
||||
// 132 133
|
||||
"CurrencySubstitutionId, CurrencySubstitutionCount "
|
||||
"FROM item_template");
|
||||
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 itemId = fields[0].GetUInt32();
|
||||
if (_itemTemplateStore.find(itemId) != _itemTemplateStore.end())
|
||||
--sparseCount;
|
||||
ItemEffect effect;
|
||||
effect.SpellID = sparse->SpellID[i];
|
||||
effect.Trigger = sparse->SpellTrigger[i];
|
||||
effect.Charges = sparse->SpellCharges[i];
|
||||
effect.Cooldown = sparse->SpellCooldown[i];
|
||||
effect.Category = sparse->SpellCategory[i];
|
||||
effect.CategoryCooldown = sparse->SpellCategoryCooldown[i];
|
||||
itemTemplate.Effects.push_back(effect);
|
||||
}
|
||||
|
||||
ItemTemplate& itemTemplate = _itemTemplateStore[itemId];
|
||||
|
||||
itemTemplate.ItemId = itemId;
|
||||
itemTemplate.Class = uint32(fields[1].GetUInt8());
|
||||
itemTemplate.SubClass = uint32(fields[2].GetUInt8());
|
||||
itemTemplate.SoundOverrideSubclass = fields[3].GetInt32();
|
||||
itemTemplate.Name1 = fields[4].GetString();
|
||||
itemTemplate.DisplayInfoID = fields[5].GetUInt32();
|
||||
itemTemplate.Quality = uint32(fields[6].GetUInt8());
|
||||
itemTemplate.Flags = fields[7].GetUInt32();
|
||||
itemTemplate.Flags2 = fields[8].GetUInt32();
|
||||
itemTemplate.Unk430_1 = fields[9].GetFloat();
|
||||
itemTemplate.Unk430_2 = fields[10].GetFloat();
|
||||
itemTemplate.BuyCount = uint32(fields[11].GetUInt8());
|
||||
itemTemplate.BuyPrice = int32(fields[12].GetInt64());
|
||||
itemTemplate.SellPrice = fields[13].GetUInt32();
|
||||
|
||||
itemTemplate.InventoryType = uint32(fields[14].GetUInt8());
|
||||
itemTemplate.AllowableClass = fields[15].GetInt32();
|
||||
itemTemplate.AllowableRace = fields[16].GetInt32();
|
||||
itemTemplate.ItemLevel = uint32(fields[17].GetUInt16());
|
||||
itemTemplate.RequiredLevel = uint32(fields[18].GetUInt8());
|
||||
itemTemplate.RequiredSkill = uint32(fields[19].GetUInt16());
|
||||
itemTemplate.RequiredSkillRank = uint32(fields[20].GetUInt16());
|
||||
itemTemplate.RequiredSpell = fields[21].GetUInt32();
|
||||
itemTemplate.RequiredHonorRank = fields[22].GetUInt32();
|
||||
itemTemplate.RequiredCityRank = fields[23].GetUInt32();
|
||||
itemTemplate.RequiredReputationFaction = uint32(fields[24].GetUInt16());
|
||||
itemTemplate.RequiredReputationRank = uint32(fields[25].GetUInt16());
|
||||
itemTemplate.MaxCount = fields[26].GetInt32();
|
||||
itemTemplate.Stackable = fields[27].GetInt32();
|
||||
itemTemplate.ContainerSlots = uint32(fields[28].GetUInt8());
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
|
||||
{
|
||||
itemTemplate.ItemStat[i].ItemStatType = uint32(fields[29 + i * 4 + 0].GetUInt8());
|
||||
itemTemplate.ItemStat[i].ItemStatValue = int32(fields[29 + i * 4 + 1].GetInt16());
|
||||
itemTemplate.ItemStat[i].ItemStatAllocation = fields[29 + i * 4 + 2].GetInt32();
|
||||
itemTemplate.ItemStat[i].ItemStatSocketCostMultiplier = fields[29 + i * 4 + 3].GetInt32();
|
||||
}
|
||||
|
||||
itemTemplate.ScalingStatDistribution = uint32(fields[69].GetUInt16());
|
||||
itemTemplate.DamageType = fields[70].GetUInt8();
|
||||
|
||||
itemTemplate.Delay = fields[71].GetUInt16();
|
||||
itemTemplate.RangedModRange = fields[72].GetFloat();
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
{
|
||||
itemTemplate.Spells[i].SpellId = fields[73 + 6 * i + 0].GetInt32();
|
||||
itemTemplate.Spells[i].SpellTrigger = uint32(fields[73 + 6 * i + 1].GetUInt8());
|
||||
itemTemplate.Spells[i].SpellCharges = int32(fields[73 + 6 * i + 2].GetInt16());
|
||||
itemTemplate.Spells[i].SpellCooldown = fields[73 + 6 * i + 3].GetInt32();
|
||||
itemTemplate.Spells[i].SpellCategory = uint32(fields[73 + 6 * i + 4].GetUInt16());
|
||||
itemTemplate.Spells[i].SpellCategoryCooldown = fields[73 + 6 * i + 5].GetInt32();
|
||||
}
|
||||
|
||||
itemTemplate.SpellPPMRate = 0.0f;
|
||||
itemTemplate.Bonding = uint32(fields[103].GetUInt8());
|
||||
itemTemplate.Description = fields[104].GetString();
|
||||
itemTemplate.PageText = fields[105].GetUInt32();
|
||||
itemTemplate.LanguageID = uint32(fields[106].GetUInt8());
|
||||
itemTemplate.PageMaterial = uint32(fields[107].GetUInt8());
|
||||
itemTemplate.StartQuest = fields[108].GetUInt32();
|
||||
itemTemplate.LockID = fields[109].GetUInt32();
|
||||
itemTemplate.Material = int32(fields[110].GetInt8());
|
||||
itemTemplate.Sheath = uint32(fields[111].GetUInt8());
|
||||
itemTemplate.RandomProperty = fields[112].GetUInt32();
|
||||
itemTemplate.RandomSuffix = fields[113].GetInt32();
|
||||
itemTemplate.ItemSet = fields[114].GetUInt32();
|
||||
itemTemplate.MaxDurability = FillMaxDurability(itemTemplate.Class, itemTemplate.SubClass,
|
||||
itemTemplate.InventoryType, itemTemplate.Quality, itemTemplate.ItemLevel);
|
||||
|
||||
itemTemplate.Area = fields[115].GetUInt32();
|
||||
itemTemplate.Map = uint32(fields[116].GetUInt16());
|
||||
itemTemplate.BagFamily = fields[117].GetUInt32();
|
||||
itemTemplate.TotemCategory = fields[118].GetUInt32();
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
|
||||
{
|
||||
itemTemplate.Socket[i].Color = uint32(fields[119 + i*2].GetUInt8());
|
||||
itemTemplate.Socket[i].Content = fields[119 + i * 2 + 1].GetUInt32();
|
||||
}
|
||||
|
||||
itemTemplate.socketBonus = fields[125].GetUInt32();
|
||||
itemTemplate.GemProperties = fields[126].GetUInt32();
|
||||
FillDisenchantFields(&itemTemplate.DisenchantID, &itemTemplate.RequiredDisenchantSkill, itemTemplate);
|
||||
|
||||
itemTemplate.ArmorDamageModifier = fields[127].GetFloat();
|
||||
itemTemplate.Duration = fields[128].GetUInt32();
|
||||
itemTemplate.ItemLimitCategory = uint32(fields[129].GetInt16());
|
||||
itemTemplate.HolidayId = fields[130].GetUInt32();
|
||||
itemTemplate.StatScalingFactor = fields[131].GetFloat();
|
||||
itemTemplate.CurrencySubstitutionId = fields[132].GetInt32();
|
||||
itemTemplate.CurrencySubstitutionCount = fields[133].GetInt32();
|
||||
itemTemplate.ScriptId = 0;
|
||||
itemTemplate.FoodType = 0;
|
||||
itemTemplate.MinMoneyLoot = 0;
|
||||
itemTemplate.MaxMoneyLoot = 0;
|
||||
++dbCount;
|
||||
} while (result->NextRow());
|
||||
++sparseCount;
|
||||
}
|
||||
|
||||
// Check if item templates for DBC referenced character start outfit are present
|
||||
@@ -3172,9 +2920,9 @@ void ObjectMgr::LoadItemTemplates()
|
||||
}
|
||||
|
||||
for (std::set<uint32>::const_iterator itr = notFoundOutfit.begin(); itr != notFoundOutfit.end(); ++itr)
|
||||
TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not exist in `item_template` but is referenced in `CharStartOutfit.dbc`", *itr);
|
||||
TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not exist in `item.db2` but is referenced in `CharStartOutfit.dbc`", *itr);
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u item templates from Item-sparse.db2 and %u from database in %u ms", sparseCount, dbCount, GetMSTimeDiffToNow(oldMSTime));
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u item templates in %u ms", sparseCount, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadItemTemplateAddon()
|
||||
@@ -7284,17 +7032,6 @@ inline void CheckGOConsumable(GameObjectTemplate const* goInfo, uint32 dataN, ui
|
||||
goInfo->entry, goInfo->type, N, dataN);
|
||||
}
|
||||
|
||||
time_t ObjectMgr::GetHotfixDate(uint32 entry, uint32 type) const
|
||||
{
|
||||
time_t ret = 0;
|
||||
for (HotfixData::const_iterator itr = _hotfixData.begin(); itr != _hotfixData.end(); ++itr)
|
||||
if (itr->Entry == entry && itr->Type == type)
|
||||
if (time_t(itr->Timestamp) > ret)
|
||||
ret = time_t(itr->Timestamp);
|
||||
|
||||
return ret ? ret : GameTime::GetGameTime();
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadGameObjectTemplate()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
@@ -9907,74 +9644,6 @@ void ObjectMgr::LoadFactionChangeReputations()
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u faction change reputation pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadHotfixData()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT entry, type, UNIX_TIMESTAMP(hotfixDate) FROM hotfix_data");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_INFO("server.loading", ">> Loaded 0 hotfix info entries. DB table `hotfix_data` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
_hotfixData.reserve(result->GetRowCount());
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
HotfixInfo info;
|
||||
info.Entry = fields[0].GetUInt32();
|
||||
info.Type = fields[1].GetUInt32();
|
||||
info.Timestamp = fields[2].GetUInt64();
|
||||
_hotfixData.push_back(info);
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u hotfix info entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadMissingKeyChains()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT keyId, k1, k2, k3, k4, k5, k6, k7, k8, "
|
||||
"k9, k10, k11, k12, k13, k14, k15, k16, "
|
||||
"k17, k18, k19, k20, k21, k22, k23, k24, "
|
||||
"k25, k26, k27, k28, k29, k30, k31, k32 "
|
||||
"FROM keychain_db2 ORDER BY keyId DESC");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_INFO("server.loading", ">> Loaded 0 KeyChain entries. DB table `keychain_db2` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
|
||||
KeyChainEntry* kce = sKeyChainStore.CreateEntry(id, true);
|
||||
kce->Id = id;
|
||||
for (uint32 i = 0; i < KEYCHAIN_SIZE; ++i)
|
||||
kce->Key[i] = fields[1 + i].GetUInt8();
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u KeyChain entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadFactionChangeSpells()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Corpse.h"
|
||||
#include "CreatureData.h"
|
||||
#include "DatabaseEnvFwd.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "Errors.h"
|
||||
#include "GameObjectData.h"
|
||||
#include "ItemTemplate.h"
|
||||
@@ -555,7 +556,6 @@ typedef std::map<TempSummonGroupKey, std::vector<TempSummonData>> TempSummonData
|
||||
typedef std::unordered_map<uint32, CreatureLocale> CreatureLocaleContainer;
|
||||
typedef std::unordered_map<uint32, GameObjectLocale> GameObjectLocaleContainer;
|
||||
typedef std::unordered_map<uint32, ItemTemplate> ItemTemplateContainer;
|
||||
typedef std::unordered_map<uint32, ItemLocale> ItemLocaleContainer;
|
||||
typedef std::unordered_map<uint32, QuestLocale> QuestLocaleContainer;
|
||||
typedef std::unordered_map<uint32, NpcTextLocale> NpcTextLocaleContainer;
|
||||
typedef std::unordered_map<uint32, PageTextLocale> PageTextLocaleContainer;
|
||||
@@ -864,15 +864,6 @@ struct DungeonEncounter
|
||||
typedef std::list<DungeonEncounter const*> DungeonEncounterList;
|
||||
typedef std::unordered_map<uint32, DungeonEncounterList> DungeonEncounterContainer;
|
||||
|
||||
struct HotfixInfo
|
||||
{
|
||||
uint32 Type;
|
||||
uint32 Timestamp;
|
||||
uint32 Entry;
|
||||
};
|
||||
|
||||
typedef std::vector<HotfixInfo> HotfixData;
|
||||
|
||||
struct TerrainSwapInfo
|
||||
{
|
||||
uint32 Id;
|
||||
@@ -1168,7 +1159,6 @@ class TC_GAME_API ObjectMgr
|
||||
void LoadItemTemplates();
|
||||
void LoadItemTemplateAddon();
|
||||
void LoadItemScriptNames();
|
||||
void LoadItemLocales();
|
||||
void LoadQuestLocales();
|
||||
void LoadNpcTextLocales();
|
||||
void LoadPageTextLocales();
|
||||
@@ -1361,12 +1351,6 @@ class TC_GAME_API ObjectMgr
|
||||
if (itr == _gameObjectLocaleStore.end()) return nullptr;
|
||||
return &itr->second;
|
||||
}
|
||||
ItemLocale const* GetItemLocale(uint32 entry) const
|
||||
{
|
||||
ItemLocaleContainer::const_iterator itr = _itemLocaleStore.find(entry);
|
||||
if (itr == _itemLocaleStore.end()) return nullptr;
|
||||
return &itr->second;
|
||||
}
|
||||
QuestLocale const* GetQuestLocale(uint32 entry) const
|
||||
{
|
||||
QuestLocaleContainer::const_iterator itr = _questLocaleStore.find(entry);
|
||||
@@ -1548,12 +1532,6 @@ class TC_GAME_API ObjectMgr
|
||||
|
||||
bool IsTransportMap(uint32 mapId) const { return _transportMaps.count(mapId) != 0; }
|
||||
|
||||
void LoadHotfixData();
|
||||
HotfixData const& GetHotfixData() const { return _hotfixData; }
|
||||
time_t GetHotfixDate(uint32 entry, uint32 type) const;
|
||||
|
||||
void LoadMissingKeyChains();
|
||||
|
||||
uint32 GetGameObjectTypeByEntry(uint32 entry) const;
|
||||
|
||||
VehicleSeatAddon const* GetVehicleSeatAddon(uint32 seatId) const
|
||||
@@ -1713,7 +1691,6 @@ class TC_GAME_API ObjectMgr
|
||||
|
||||
BroadcastTextContainer _broadcastTextStore;
|
||||
ItemTemplateContainer _itemTemplateStore;
|
||||
ItemLocaleContainer _itemLocaleStore;
|
||||
QuestLocaleContainer _questLocaleStore;
|
||||
NpcTextLocaleContainer _npcTextLocaleStore;
|
||||
PageTextLocaleContainer _pageTextLocaleStore;
|
||||
|
||||
@@ -1050,7 +1050,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
|
||||
}
|
||||
|
||||
//roll for over-threshold item if it's one-player loot
|
||||
if (item->Quality >= uint32(m_lootThreshold))
|
||||
if (item->GetQuality() >= uint32(m_lootThreshold))
|
||||
{
|
||||
ObjectGuid newitemGUID = ObjectGuid::Create<HighGuid::Item>(sObjectMgr->GetGenerator<HighGuid::Item>().Generate());
|
||||
|
||||
@@ -1191,7 +1191,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject)
|
||||
item = sObjectMgr->GetItemTemplate(i->itemid);
|
||||
|
||||
//roll for over-threshold item if it's one-player loot
|
||||
if (item->Quality >= uint32(m_lootThreshold))
|
||||
if (item->GetQuality() >= uint32(m_lootThreshold))
|
||||
{
|
||||
ObjectGuid newitemGUID = ObjectGuid::Create<HighGuid::Item>(sObjectMgr->GetGenerator<HighGuid::Item>().Generate());
|
||||
|
||||
@@ -1224,7 +1224,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject)
|
||||
if (item->DisenchantID && m_maxEnchantingLevel >= item->RequiredDisenchantSkill)
|
||||
r->rollVoteMask |= ROLL_FLAG_TYPE_DISENCHANT;
|
||||
|
||||
if (item->Flags2 & ITEM_FLAG2_CAN_ONLY_ROLL_GREED)
|
||||
if (item->GetFlags2() & ITEM_FLAG2_CAN_ONLY_ROLL_GREED)
|
||||
r->rollVoteMask &= ~ROLL_FLAG_TYPE_NEED;
|
||||
|
||||
loot->items[itemSlot].is_blocked = true;
|
||||
|
||||
@@ -1264,7 +1264,7 @@ void Guild::BankMoveItemData::LogAction(MoveItemData* pFrom) const
|
||||
sLog->outCommand(m_pPlayer->GetSession()->GetAccountId(),
|
||||
"GM %s (Guid: %u) (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank named: %s (Guild ID: %u)",
|
||||
m_pPlayer->GetName().c_str(), m_pPlayer->GetGUID().GetCounter(), m_pPlayer->GetSession()->GetAccountId(),
|
||||
pFrom->GetItem()->GetTemplate()->Name1.c_str(), pFrom->GetItem()->GetEntry(), pFrom->GetItem()->GetCount(),
|
||||
pFrom->GetItem()->GetTemplate()->GetDefaultLocaleName(), pFrom->GetItem()->GetEntry(), pFrom->GetItem()->GetCount(),
|
||||
m_pGuild->GetName().c_str(), m_pGuild->GetId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,11 +230,11 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
if (itemEntry == 0)
|
||||
itemEntry = item->GetTemplate()->ItemId;
|
||||
itemEntry = item->GetTemplate()->GetId();
|
||||
|
||||
if (sAuctionMgr->GetAItem(item->GetGUID().GetCounter()) || !item->CanBeTraded() || item->IsNotEmptyBag() ||
|
||||
(item->GetTemplate()->Flags & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION) ||
|
||||
item->GetCount() < count[i] || itemEntry != item->GetTemplate()->ItemId)
|
||||
(item->GetTemplate()->GetFlags() & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION) ||
|
||||
item->GetCount() < count[i] || itemEntry != item->GetTemplate()->GetId())
|
||||
{
|
||||
SendAuctionCommandResult(nullptr, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR);
|
||||
return;
|
||||
@@ -320,7 +320,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
|
||||
if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
|
||||
{
|
||||
sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)",
|
||||
GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount());
|
||||
GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->GetDefaultLocaleName(), item->GetEntry(), item->GetCount());
|
||||
}
|
||||
|
||||
AH->Id = sObjectMgr->GenerateAuctionID();
|
||||
@@ -338,7 +338,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
|
||||
AH->auctionHouseEntry = auctionHouseEntry;
|
||||
|
||||
TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u",
|
||||
_player->GetName().c_str(), _player->GetGUID().GetCounter(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUID().GetCounter(), item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
|
||||
_player->GetName().c_str(), _player->GetGUID().GetCounter(), item->GetTemplate()->GetDefaultLocaleName(), item->GetEntry(), item->GetGUID().GetCounter(), item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
|
||||
|
||||
// Add to pending auctions, or fail with insufficient funds error
|
||||
if (!sAuctionMgr->PendingAuctionAdd(_player, AH, item))
|
||||
@@ -377,7 +377,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
|
||||
if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
|
||||
{
|
||||
sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)",
|
||||
GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount());
|
||||
GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->GetDefaultLocaleName(), newItem->GetEntry(), newItem->GetCount());
|
||||
}
|
||||
|
||||
AH->Id = sObjectMgr->GenerateAuctionID();
|
||||
@@ -395,7 +395,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
|
||||
AH->auctionHouseEntry = auctionHouseEntry;
|
||||
|
||||
TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u",
|
||||
_player->GetName().c_str(), _player->GetGUID().GetCounter(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUID().GetCounter(), newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
|
||||
_player->GetName().c_str(), _player->GetGUID().GetCounter(), newItem->GetTemplate()->GetDefaultLocaleName(), newItem->GetEntry(), newItem->GetGUID().GetCounter(), newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
|
||||
|
||||
// Add to pending auctions, or fail with insufficient funds error
|
||||
if (!sAuctionMgr->PendingAuctionAdd(_player, AH, newItem))
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "Opcodes.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "QueryPackets.h"
|
||||
#include "PlayerDump.h"
|
||||
#include "QueryHolder.h"
|
||||
#include "ReputationMgr.h"
|
||||
@@ -933,17 +934,9 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
|
||||
data << uint64(0);
|
||||
SendPacket(&data);
|
||||
|
||||
data.Initialize(SMSG_HOTFIX_INFO);
|
||||
HotfixData const& hotfix = sObjectMgr->GetHotfixData();
|
||||
data.WriteBits(hotfix.size(), 22);
|
||||
data.FlushBits();
|
||||
for (uint32 i = 0; i < hotfix.size(); ++i)
|
||||
{
|
||||
data << uint32(hotfix[i].Type);
|
||||
data << uint32(hotfix[i].Timestamp);
|
||||
data << uint32(hotfix[i].Entry);
|
||||
}
|
||||
SendPacket(&data);
|
||||
WorldPackets::Query::HotfixNotifyBlob hotfixInfo;
|
||||
hotfixInfo.Hotfixes = sDB2Manager.GetHotfixData();
|
||||
SendPacket(hotfixInfo.Write());
|
||||
|
||||
pCurrChar->SendInitialPacketsBeforeAddToMap();
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ void WorldSession::HandleDestroyItemOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
if (pItem->GetTemplate()->Flags & ITEM_FLAG_NO_USER_DESTROY)
|
||||
if (pItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_USER_DESTROY)
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_DROP_BOUND_ITEM, nullptr, nullptr);
|
||||
return;
|
||||
@@ -314,7 +314,7 @@ void WorldSession::HandleReadItem(WorldPacket& recvData)
|
||||
|
||||
Item* pItem = _player->GetItemByPos(bag, slot);
|
||||
|
||||
if (pItem && pItem->GetTemplate()->PageText)
|
||||
if (pItem && pItem->GetTemplate()->GetPageText())
|
||||
{
|
||||
WorldPacket data;
|
||||
|
||||
@@ -412,7 +412,7 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
ItemTemplate const* pProto = pItem->GetTemplate();
|
||||
if (pProto)
|
||||
{
|
||||
if (pProto->SellPrice > 0)
|
||||
if (pProto->GetSellPrice() > 0)
|
||||
{
|
||||
if (count < pItem->GetCount()) // need split items
|
||||
{
|
||||
@@ -442,7 +442,7 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
_player->AddItemToBuyBackSlot(pItem);
|
||||
}
|
||||
|
||||
uint32 money = pProto->SellPrice * count;
|
||||
uint32 money = pProto->GetSellPrice() * count;
|
||||
_player->ModifyMoney(money);
|
||||
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money);
|
||||
}
|
||||
@@ -642,12 +642,12 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid)
|
||||
if (!_player->IsGameMaster()) // ignore conditions if GM on
|
||||
{
|
||||
// Respect allowed class
|
||||
if (!(itemTemplate->AllowableClass & _player->getClassMask()) && itemTemplate->Bonding == BIND_ON_ACQUIRE)
|
||||
if (!(itemTemplate->GetAllowableClass() & _player->getClassMask()) && itemTemplate->GetBonding() == BIND_ON_ACQUIRE)
|
||||
continue;
|
||||
|
||||
// Only display items in vendor lists for the team the player is on
|
||||
if ((itemTemplate->Flags2 & ITEM_FLAG2_FACTION_HORDE && _player->GetTeam() == ALLIANCE) ||
|
||||
(itemTemplate->Flags2 & ITEM_FLAG2_FACTION_ALLIANCE && _player->GetTeam() == HORDE))
|
||||
if ((itemTemplate->GetFlags2() & ITEM_FLAG2_FACTION_HORDE && _player->GetTeam() == ALLIANCE) ||
|
||||
(itemTemplate->GetFlags2() & ITEM_FLAG2_FACTION_ALLIANCE && _player->GetTeam() == HORDE))
|
||||
continue;
|
||||
|
||||
// Items sold out are not displayed in list
|
||||
@@ -661,7 +661,7 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid)
|
||||
continue;
|
||||
}
|
||||
|
||||
int32 price = vendorItem->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->BuyPrice * discountMod)) : 0;
|
||||
int32 price = vendorItem->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->GetBuyPrice() * discountMod)) : 0;
|
||||
|
||||
if (int32 priceMod = _player->GetTotalAuraModifier(SPELL_AURA_MOD_VENDOR_ITEMS_PRICES))
|
||||
price -= CalculatePct(price, priceMod);
|
||||
@@ -682,10 +682,10 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid)
|
||||
itemsData << uint32(vendorItem->item);
|
||||
itemsData << uint32(vendorItem->Type); // 1 is items, 2 is currency
|
||||
itemsData << uint32(price);
|
||||
itemsData << uint32(itemTemplate->DisplayInfoID);
|
||||
itemsData << uint32(itemTemplate->GetDisplayID());
|
||||
// if (!unk "enabler") data << uint32(something);
|
||||
itemsData << int32(leftInStock);
|
||||
itemsData << uint32(itemTemplate->BuyCount);
|
||||
itemsData << uint32(itemTemplate->GetBuyCount());
|
||||
|
||||
if (++count >= MAX_VENDOR_ITEMS)
|
||||
break;
|
||||
@@ -989,7 +989,7 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(gift->GetTemplate()->Flags & ITEM_FLAG_IS_WRAPPER)) // cheating: non-wrapper wrapper
|
||||
if (!(gift->GetTemplate()->GetFlags() & ITEM_FLAG_IS_WRAPPER)) // cheating: non-wrapper wrapper
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, nullptr);
|
||||
return;
|
||||
@@ -1040,7 +1040,7 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
// maybe not correct check (it is better than nothing)
|
||||
if (item->GetTemplate()->MaxCount > 0)
|
||||
if (item->GetTemplate()->GetMaxCount() > 0)
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_CANT_WRAP_UNIQUE, item, nullptr);
|
||||
return;
|
||||
@@ -1118,11 +1118,11 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
|
||||
GemPropertiesEntry const* GemProps[MAX_GEM_SOCKETS];
|
||||
for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage
|
||||
GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetTemplate()->GemProperties) : nullptr;
|
||||
GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetTemplate()->GetGemProperties()) : nullptr;
|
||||
|
||||
// Find first prismatic socket
|
||||
int32 firstPrismatic = 0;
|
||||
while (firstPrismatic < MAX_GEM_SOCKETS && itemProto->Socket[firstPrismatic].Color)
|
||||
while (firstPrismatic < MAX_GEM_SOCKETS && itemProto->GetSocketColor(firstPrismatic))
|
||||
++firstPrismatic;
|
||||
|
||||
for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe
|
||||
@@ -1131,7 +1131,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
continue;
|
||||
|
||||
// tried to put gem in socket where no socket exists (take care about prismatic sockets)
|
||||
if (!itemProto->Socket[i].Color)
|
||||
if (!itemProto->GetSocketColor(i))
|
||||
{
|
||||
// no prismatic socket
|
||||
if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
|
||||
@@ -1142,19 +1142,19 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
// tried to put normal gem in meta socket
|
||||
if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->Type != SOCKET_COLOR_META)
|
||||
if (itemProto->GetSocketColor(i) == SOCKET_COLOR_META && GemProps[i]->Type != SOCKET_COLOR_META)
|
||||
return;
|
||||
|
||||
// tried to put meta gem in normal socket
|
||||
if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->Type == SOCKET_COLOR_META)
|
||||
if (itemProto->GetSocketColor(i) != SOCKET_COLOR_META && GemProps[i]->Type == SOCKET_COLOR_META)
|
||||
return;
|
||||
|
||||
// tried to put normal gem in cogwheel socket
|
||||
if (itemProto->Socket[i].Color == SOCKET_COLOR_COGWHEEL && GemProps[i]->Type != SOCKET_COLOR_COGWHEEL)
|
||||
if (itemProto->GetSocketColor(i) == SOCKET_COLOR_COGWHEEL && GemProps[i]->Type != SOCKET_COLOR_COGWHEEL)
|
||||
return;
|
||||
|
||||
// tried to put cogwheel gem in normal socket
|
||||
if (itemProto->Socket[i].Color != SOCKET_COLOR_COGWHEEL && GemProps[i]->Type == SOCKET_COLOR_COGWHEEL)
|
||||
if (itemProto->GetSocketColor(i) != SOCKET_COLOR_COGWHEEL && GemProps[i]->Type == SOCKET_COLOR_COGWHEEL)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1176,7 +1176,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
ItemTemplate const* iGemProto = Gems[i]->GetTemplate();
|
||||
|
||||
// unique item (for new and already placed bit removed enchantments
|
||||
if (iGemProto->Flags & ITEM_FLAG_UNIQUE_EQUIPPABLE)
|
||||
if (iGemProto->GetFlags() & ITEM_FLAG_UNIQUE_EQUIPPABLE)
|
||||
{
|
||||
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
|
||||
{
|
||||
@@ -1185,7 +1185,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
|
||||
if (Gems[j])
|
||||
{
|
||||
if (iGemProto->ItemId == Gems[j]->GetEntry())
|
||||
if (iGemProto->GetId() == Gems[j]->GetEntry())
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, nullptr);
|
||||
return;
|
||||
@@ -1195,7 +1195,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
{
|
||||
if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
|
||||
{
|
||||
if (iGemProto->ItemId == enchantEntry->Src_itemID)
|
||||
if (iGemProto->GetId() == enchantEntry->Src_itemID)
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, nullptr);
|
||||
return;
|
||||
@@ -1207,9 +1207,9 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
|
||||
// unique limit type item
|
||||
int32 limit_newcount = 0;
|
||||
if (iGemProto->ItemLimitCategory)
|
||||
if (iGemProto->GetItemLimitCategory())
|
||||
{
|
||||
if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory))
|
||||
if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->GetItemLimitCategory()))
|
||||
{
|
||||
// NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case
|
||||
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
|
||||
@@ -1217,7 +1217,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
if (Gems[j])
|
||||
{
|
||||
// new gem
|
||||
if (iGemProto->ItemLimitCategory == Gems[j]->GetTemplate()->ItemLimitCategory)
|
||||
if (iGemProto->GetItemLimitCategory() == Gems[j]->GetTemplate()->GetItemLimitCategory())
|
||||
++limit_newcount;
|
||||
}
|
||||
else if (OldEnchants[j])
|
||||
@@ -1225,7 +1225,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
// existing gem
|
||||
if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
|
||||
if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(enchantEntry->Src_itemID))
|
||||
if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
|
||||
if (iGemProto->GetItemLimitCategory() == jProto->GetItemLimitCategory())
|
||||
++limit_newcount;
|
||||
}
|
||||
}
|
||||
@@ -1278,7 +1278,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change...
|
||||
{
|
||||
_player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false);
|
||||
itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->socketBonus : 0), 0, 0, _player->GetGUID());
|
||||
itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->GetSocketBonus() : 0), 0, 0, _player->GetGUID());
|
||||
_player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, true);
|
||||
//it is not displayed, client has an inbuilt system to determine if the bonus is activated
|
||||
}
|
||||
@@ -1542,7 +1542,7 @@ void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData)
|
||||
transmogrified[i]->SetNotRefundable(player);
|
||||
transmogrified[i]->ClearSoulboundTradeable(player);
|
||||
|
||||
if (transmogrifier[i]->GetTemplate()->Bonding == BIND_ON_EQUIP || transmogrifier[i]->GetTemplate()->Bonding == BIND_ON_USE)
|
||||
if (transmogrifier[i]->GetTemplate()->GetBonding() == BIND_ON_EQUIP || transmogrifier[i]->GetTemplate()->GetBonding() == BIND_ON_USE)
|
||||
transmogrifier[i]->SetBinding(true);
|
||||
|
||||
transmogrifier[i]->SetOwnerGUID(player->GetGUID());
|
||||
|
||||
@@ -378,7 +378,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
|
||||
ItemTemplate const* proto = pItem->GetTemplate();
|
||||
|
||||
// destroy only 5 items from stack in case prospecting and milling
|
||||
if (proto->Flags & (ITEM_FLAG_IS_PROSPECTABLE | ITEM_FLAG_IS_MILLABLE))
|
||||
if (proto->GetFlags() & (ITEM_FLAG_IS_PROSPECTABLE | ITEM_FLAG_IS_MILLABLE))
|
||||
{
|
||||
pItem->m_lootGenerated = false;
|
||||
pItem->loot.clear();
|
||||
@@ -394,7 +394,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
|
||||
else
|
||||
{
|
||||
// Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item
|
||||
if (pItem->loot.isLooted() || !(proto->Flags & ITEM_FLAG_HAS_LOOT))
|
||||
if (pItem->loot.isLooted() || !(proto->GetFlags() & ITEM_FLAG_HAS_LOOT))
|
||||
player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
|
||||
}
|
||||
return; // item can be looted only single player
|
||||
|
||||
@@ -251,7 +251,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
|
||||
if (Item* item = player->GetItemByGuid(itemGUIDs[i]))
|
||||
{
|
||||
ItemTemplate const* itemProto = item->GetTemplate();
|
||||
if (!itemProto || !(itemProto->Flags & ITEM_FLAG_IS_BOUND_TO_ACCOUNT))
|
||||
if (!itemProto || !(itemProto->GetFlags() & ITEM_FLAG_IS_BOUND_TO_ACCOUNT))
|
||||
{
|
||||
accountBound = false;
|
||||
break;
|
||||
@@ -305,7 +305,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
|
||||
}
|
||||
}
|
||||
|
||||
if (item->GetTemplate()->Flags & ITEM_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION))
|
||||
if (item->GetTemplate()->GetFlags() & ITEM_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION))
|
||||
{
|
||||
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM);
|
||||
return;
|
||||
@@ -349,7 +349,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
|
||||
{
|
||||
sLog->outCommand(GetAccountId(), "GM %s (GUID: %u) (Account: %u) mail item: %s (Entry: %u Count: %u) "
|
||||
"to: %s (%s) (Account: %u)", GetPlayerName().c_str(), GetGUIDLow(), GetAccountId(),
|
||||
item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(),
|
||||
item->GetTemplate()->GetDefaultLocaleName(), item->GetEntry(), item->GetCount(),
|
||||
receiverName.c_str(), receiverGuid.ToString().c_str(), receiverAccountId);
|
||||
}
|
||||
|
||||
@@ -575,7 +575,7 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData)
|
||||
sender_name = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN);
|
||||
}
|
||||
sLog->outCommand(GetAccountId(), "GM %s (Account: %u) receiver mail item: %s (Entry: %u Count: %u) and send COD money: " UI64FMTD " to player: %s (Account: %u)",
|
||||
GetPlayerName().c_str(), GetAccountId(), it->GetTemplate()->Name1.c_str(), it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId);
|
||||
GetPlayerName().c_str(), GetAccountId(), it->GetTemplate()->GetDefaultLocaleName(), it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId);
|
||||
}
|
||||
else if (!receiver)
|
||||
sender_accId = sCharacterCache->GetCharacterAccountIdByGuid(sender_guid);
|
||||
|
||||
@@ -1641,74 +1641,6 @@ void WorldSession::HandleInstanceLockResponse(WorldPacket& recvPacket)
|
||||
_player->SetPendingBind(0, 0);
|
||||
}
|
||||
|
||||
void WorldSession::HandleRequestHotfix(WorldPacket& recvPacket)
|
||||
{
|
||||
uint32 type, count;
|
||||
recvPacket >> type;
|
||||
|
||||
DB2StorageBase const* store = GetDB2Storage(type);
|
||||
if (!store)
|
||||
{
|
||||
TC_LOG_ERROR("network", "CMSG_REQUEST_HOTFIX: Received unknown hotfix type: %u", type);
|
||||
recvPacket.rfinish();
|
||||
return;
|
||||
}
|
||||
|
||||
count = recvPacket.ReadBits(23);
|
||||
|
||||
ObjectGuid* guids = new ObjectGuid[count];
|
||||
for (uint32 i = 0; i < count; ++i)
|
||||
{
|
||||
guids[i][0] = recvPacket.ReadBit();
|
||||
guids[i][4] = recvPacket.ReadBit();
|
||||
guids[i][7] = recvPacket.ReadBit();
|
||||
guids[i][2] = recvPacket.ReadBit();
|
||||
guids[i][5] = recvPacket.ReadBit();
|
||||
guids[i][3] = recvPacket.ReadBit();
|
||||
guids[i][6] = recvPacket.ReadBit();
|
||||
guids[i][1] = recvPacket.ReadBit();
|
||||
}
|
||||
|
||||
uint32 entry;
|
||||
for (uint32 i = 0; i < count; ++i)
|
||||
{
|
||||
recvPacket.ReadByteSeq(guids[i][5]);
|
||||
recvPacket.ReadByteSeq(guids[i][6]);
|
||||
recvPacket.ReadByteSeq(guids[i][7]);
|
||||
recvPacket.ReadByteSeq(guids[i][0]);
|
||||
recvPacket.ReadByteSeq(guids[i][1]);
|
||||
recvPacket.ReadByteSeq(guids[i][3]);
|
||||
recvPacket.ReadByteSeq(guids[i][4]);
|
||||
recvPacket >> entry;
|
||||
recvPacket.ReadByteSeq(guids[i][2]);
|
||||
|
||||
if (!store->HasRecord(entry))
|
||||
{
|
||||
WorldPacket data(SMSG_DB_REPLY, 4 * 4);
|
||||
data << -int32(entry);
|
||||
data << uint32(store->GetHash());
|
||||
data << uint32(GameTime::GetGameTime());
|
||||
data << uint32(0);
|
||||
SendPacket(&data);
|
||||
continue;
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_DB_REPLY);
|
||||
data << int32(entry);
|
||||
data << uint32(store->GetHash());
|
||||
data << uint32(sObjectMgr->GetHotfixDate(entry, store->GetHash()));
|
||||
|
||||
size_t sizePos = data.wpos();
|
||||
data << uint32(0); // size of next block
|
||||
store->WriteRecord(entry, LocaleConstant(GetSessionDbcLocale()), data);
|
||||
data.put<uint32>(sizePos, data.wpos() - sizePos - 4);
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
delete[] guids;
|
||||
}
|
||||
|
||||
void WorldSession::HandleUpdateMissileTrajectory(WorldPacket& recvPacket)
|
||||
{
|
||||
TC_LOG_DEBUG("network", "WORLD: CMSG_UPDATE_MISSILE_TRAJECTORY");
|
||||
|
||||
@@ -184,7 +184,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
ItemPosCountVec dest;
|
||||
InventoryResult msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount);
|
||||
InventoryResult msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->GetBuyCount());
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
{
|
||||
_player->SendEquipError(msg, nullptr, nullptr, charterid);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "QueryPackets.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
@@ -542,3 +543,34 @@ void WorldSession::HandleQuestPOIQuery(WorldPacket& recvData)
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleDBQueryBulk(WorldPackets::Query::DBQueryBulk& packet)
|
||||
{
|
||||
DB2StorageBase const* store = sDB2Manager.GetStorage(packet.TableHash);
|
||||
if (!store)
|
||||
{
|
||||
TC_LOG_ERROR("network", "CMSG_DB_QUERY_BULK: Received unknown hotfix type: %u", packet.TableHash);
|
||||
return;
|
||||
}
|
||||
|
||||
for (WorldPackets::Query::DBQueryRecord const& rec : packet.Queries)
|
||||
{
|
||||
WorldPackets::Query::DBReply response;
|
||||
response.TableHash = packet.TableHash;
|
||||
|
||||
if (store->HasRecord(rec.RecordID))
|
||||
{
|
||||
response.RecordID = rec.RecordID;
|
||||
response.Timestamp = sDB2Manager.GetHotfixDate(rec.RecordID, packet.TableHash);
|
||||
store->WriteRecord(rec.RecordID, GetSessionDbcLocale(), response.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
TC_LOG_ERROR("network", "CMSG_DB_QUERY_BULK: Entry %u does not exist in datastore: %u", rec.RecordID, packet.TableHash);
|
||||
response.RecordID = -int32(rec.RecordID);
|
||||
response.Timestamp = GameTime::GetGameTime();
|
||||
}
|
||||
|
||||
SendPacket(response.Write());
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
|
||||
}
|
||||
|
||||
// some item classes can be used only in equipped state
|
||||
if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped())
|
||||
if (proto->GetInventoryType() != INVTYPE_NON_EQUIP && !pItem->IsEquipped())
|
||||
{
|
||||
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, nullptr);
|
||||
return;
|
||||
@@ -147,14 +147,14 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
|
||||
}
|
||||
|
||||
// only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
|
||||
if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAG_IGNORE_DEFAULT_ARENA_RESTRICTIONS) && pUser->InArena())
|
||||
if (proto->GetClass() == ITEM_CLASS_CONSUMABLE && !(proto->GetFlags() & ITEM_FLAG_IGNORE_DEFAULT_ARENA_RESTRICTIONS) && pUser->InArena())
|
||||
{
|
||||
pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// don't allow items banned in arena
|
||||
if ((proto->Flags & ITEM_FLAG_NOT_USEABLE_IN_ARENA) && pUser->InArena())
|
||||
if ((proto->GetFlags() & ITEM_FLAG_NOT_USEABLE_IN_ARENA) && pUser->InArena())
|
||||
{
|
||||
pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, nullptr);
|
||||
return;
|
||||
@@ -162,9 +162,9 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
|
||||
|
||||
if (pUser->IsInCombat())
|
||||
{
|
||||
for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
for (ItemEffect const& effect : proto->Effects)
|
||||
{
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[i].SpellId))
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effect.SpellID))
|
||||
{
|
||||
if (!spellInfo->CanBeUsedInCombat())
|
||||
{
|
||||
@@ -176,7 +176,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
|
||||
}
|
||||
|
||||
// check also BIND_ON_ACQUIRE and BIND_QUEST for .additem or .additemset case by GM (not binded at adding to inventory)
|
||||
if (pItem->GetTemplate()->Bonding == BIND_ON_USE || pItem->GetTemplate()->Bonding == BIND_ON_ACQUIRE || pItem->GetTemplate()->Bonding == BIND_QUEST)
|
||||
if (pItem->GetTemplate()->GetBonding() == BIND_ON_USE || pItem->GetTemplate()->GetBonding() == BIND_ON_ACQUIRE || pItem->GetTemplate()->GetBonding() == BIND_QUEST)
|
||||
{
|
||||
if (!pItem->IsSoulBound())
|
||||
{
|
||||
@@ -234,16 +234,16 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
|
||||
}
|
||||
|
||||
// Verify that the bag is an actual bag or wrapped item that can be used "normally"
|
||||
if (!(proto->Flags & ITEM_FLAG_HAS_LOOT) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))
|
||||
if (!(proto->GetFlags() & ITEM_FLAG_HAS_LOOT) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))
|
||||
{
|
||||
player->SendEquipError(EQUIP_ERR_CLIENT_LOCKED_OUT, item, nullptr);
|
||||
TC_LOG_INFO("entities.player.cheat", "Possible hacking attempt: Player %s [guid: %u] tried to open item [guid: %u, entry: %u] which is not openable!",
|
||||
player->GetName().c_str(), player->GetGUID().GetCounter(), item->GetGUID().GetCounter(), proto->ItemId);
|
||||
player->GetName().c_str(), player->GetGUID().GetCounter(), item->GetGUID().GetCounter(), proto->GetId());
|
||||
return;
|
||||
}
|
||||
|
||||
// locked item
|
||||
uint32 lockId = proto->LockID;
|
||||
uint32 lockId = proto->GetLockID();
|
||||
if (lockId)
|
||||
{
|
||||
LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
|
||||
@@ -724,7 +724,7 @@ void WorldSession::HandleMirrorImageDataRequest(WorldPacket& recvData)
|
||||
else if (*itr == EQUIPMENT_SLOT_BACK && player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
|
||||
data << uint32(0);
|
||||
else if (Item const* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr))
|
||||
data << uint32(item->GetTemplate()->DisplayInfoID);
|
||||
data << uint32(item->GetTemplate()->GetDisplayID());
|
||||
else
|
||||
data << uint32(0);
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ void WorldSession::SendUpdateTrade(bool trader_data /*= true*/)
|
||||
data.WriteBit(creatorGuid[2]);
|
||||
data.WriteBit(creatorGuid[3]);
|
||||
data.WriteBit(creatorGuid[5]);
|
||||
data.WriteBit(item->GetTemplate()->LockID != 0);
|
||||
data.WriteBit(item->GetTemplate()->GetLockID() != 0);
|
||||
data.WriteBit(creatorGuid[0]);
|
||||
|
||||
itemData.WriteByteSeq(creatorGuid[1]);
|
||||
@@ -182,7 +182,7 @@ void WorldSession::SendUpdateTrade(bool trader_data /*= true*/)
|
||||
itemData.WriteByteSeq(giftCreatorGuid[7]);
|
||||
itemData.WriteByteSeq(giftCreatorGuid[4]);
|
||||
|
||||
itemData << uint32(item->GetTemplate()->ItemId);
|
||||
itemData << uint32(item->GetTemplate()->GetId());
|
||||
|
||||
itemData.WriteByteSeq(giftCreatorGuid[0]);
|
||||
|
||||
@@ -230,7 +230,7 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
|
||||
{
|
||||
sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
|
||||
_player->GetName().c_str(), _player->GetSession()->GetAccountId(),
|
||||
myItems[i]->GetTemplate()->Name1.c_str(), myItems[i]->GetEntry(), myItems[i]->GetCount(),
|
||||
myItems[i]->GetTemplate()->GetDefaultLocaleName(), myItems[i]->GetEntry(), myItems[i]->GetCount(),
|
||||
trader->GetName().c_str(), trader->GetSession()->GetAccountId());
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
|
||||
{
|
||||
sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
|
||||
trader->GetName().c_str(), trader->GetSession()->GetAccountId(),
|
||||
hisItems[i]->GetTemplate()->Name1.c_str(), hisItems[i]->GetEntry(), hisItems[i]->GetCount(),
|
||||
hisItems[i]->GetTemplate()->GetDefaultLocaleName(), hisItems[i]->GetEntry(), hisItems[i]->GetCount(),
|
||||
_player->GetName().c_str(), _player->GetSession()->GetAccountId());
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ LootItem::LootItem(LootStoreItem const& li)
|
||||
if (!is_currency)
|
||||
{
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid);
|
||||
freeforall = proto && (proto->Flags & ITEM_FLAG_MULTI_DROP);
|
||||
freeforall = proto && (proto->GetFlags() & ITEM_FLAG_MULTI_DROP);
|
||||
follow_loot_rules = proto && (proto->FlagsCu & ITEM_FLAGS_CU_FOLLOW_LOOT_RULES);
|
||||
}
|
||||
else
|
||||
@@ -74,18 +74,18 @@ bool LootItem::AllowedForPlayer(Player const* player) const
|
||||
return false;
|
||||
|
||||
// not show loot for players without profession or those who already know the recipe
|
||||
if ((pProto->Flags & ITEM_FLAG_HIDE_UNUSABLE_RECIPE) && (!player->HasSkill(pProto->RequiredSkill) || player->HasSpell(pProto->Spells[1].SpellId)))
|
||||
if ((pProto->GetFlags() & ITEM_FLAG_HIDE_UNUSABLE_RECIPE) && (!player->HasSkill(pProto->GetRequiredSkill()) || player->HasSpell(pProto->Effects[1].SpellID)))
|
||||
return false;
|
||||
|
||||
// not show loot for not own team
|
||||
if ((pProto->Flags2 & ITEM_FLAG2_FACTION_HORDE) && player->GetTeam() != HORDE)
|
||||
if ((pProto->GetFlags2() & ITEM_FLAG2_FACTION_HORDE) && player->GetTeam() != HORDE)
|
||||
return false;
|
||||
|
||||
if ((pProto->Flags2 & ITEM_FLAG2_FACTION_ALLIANCE) && player->GetTeam() != ALLIANCE)
|
||||
if ((pProto->GetFlags2() & ITEM_FLAG2_FACTION_ALLIANCE) && player->GetTeam() != ALLIANCE)
|
||||
return false;
|
||||
|
||||
// check quest requirements
|
||||
if (!(pProto->FlagsCu & ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && ((needs_quest || (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid)))
|
||||
if (!(pProto->FlagsCu & ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && ((needs_quest || (pProto->GetStartQuest() && player->GetQuestStatus(pProto->GetStartQuest()) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -156,7 +156,7 @@ void Loot::AddItem(LootStoreItem const& item)
|
||||
// non-conditional one-player only items are counted here,
|
||||
// free for all items are counted in FillFFALoot(),
|
||||
// non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
|
||||
if (!item.needs_quest && item.conditions.empty() && !(proto->Flags & ITEM_FLAG_MULTI_DROP))
|
||||
if (!item.needs_quest && item.conditions.empty() && !(proto->GetFlags() & ITEM_FLAG_MULTI_DROP))
|
||||
++unlootedCount;
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
|
||||
for (uint8 i = 0; i < items.size(); ++i)
|
||||
{
|
||||
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(items[i].itemid))
|
||||
if (proto->Quality < uint32(group->GetLootThreshold()))
|
||||
if (proto->GetQuality() < uint32(group->GetLootThreshold()))
|
||||
items[i].is_underthreshold = true;
|
||||
}
|
||||
}
|
||||
@@ -575,7 +575,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
|
||||
{
|
||||
b << uint32(li.itemid);
|
||||
b << uint32(li.count); // nr of items of this type
|
||||
b << uint32(ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(li.itemid))->DisplayInfoID);
|
||||
b << uint32(ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(li.itemid))->GetDisplayID());
|
||||
b << uint32(li.randomSuffix);
|
||||
b << uint32(li.randomPropertyId);
|
||||
//b << uint8(0); // slot type - will send after this function call
|
||||
|
||||
@@ -296,7 +296,7 @@ bool LootStoreItem::Roll(bool rate) const
|
||||
|
||||
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
|
||||
|
||||
float qualityModifier = pProto && rate ? sWorld->getRate(qualityToRate[pProto->Quality]) : 1.0f;
|
||||
float qualityModifier = pProto && rate ? sWorld->getRate(qualityToRate[pProto->GetQuality()]) : 1.0f;
|
||||
|
||||
return roll_chance_f(chance*qualityModifier);
|
||||
}
|
||||
@@ -935,8 +935,8 @@ void LoadLootTemplates_Item()
|
||||
// remove real entries and check existence loot
|
||||
ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
|
||||
for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
|
||||
if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end() && itr->second.Flags & ITEM_FLAG_HAS_LOOT)
|
||||
lootIdSet.erase(itr->second.ItemId);
|
||||
if (lootIdSet.find(itr->second.GetId()) != lootIdSet.end() && itr->second.GetFlags() & ITEM_FLAG_HAS_LOOT)
|
||||
lootIdSet.erase(itr->second.GetId());
|
||||
|
||||
// output error for any still listed (not referenced from appropriate table) ids
|
||||
LootTemplates_Item.ReportUnusedIds(lootIdSet);
|
||||
@@ -960,11 +960,11 @@ void LoadLootTemplates_Milling()
|
||||
ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
|
||||
for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
|
||||
{
|
||||
if (!(itr->second.Flags & ITEM_FLAG_IS_MILLABLE))
|
||||
if (!(itr->second.GetFlags() & ITEM_FLAG_IS_MILLABLE))
|
||||
continue;
|
||||
|
||||
if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end())
|
||||
lootIdSet.erase(itr->second.ItemId);
|
||||
if (lootIdSet.find(itr->second.GetId()) != lootIdSet.end())
|
||||
lootIdSet.erase(itr->second.GetId());
|
||||
}
|
||||
|
||||
// output error for any still listed (not referenced from appropriate table) ids
|
||||
@@ -1023,11 +1023,11 @@ void LoadLootTemplates_Prospecting()
|
||||
ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
|
||||
for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
|
||||
{
|
||||
if (!(itr->second.Flags & ITEM_FLAG_IS_PROSPECTABLE))
|
||||
if (!(itr->second.GetFlags() & ITEM_FLAG_IS_PROSPECTABLE))
|
||||
continue;
|
||||
|
||||
if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end())
|
||||
lootIdSet.erase(itr->second.ItemId);
|
||||
if (lootIdSet.find(itr->second.GetId()) != lootIdSet.end())
|
||||
lootIdSet.erase(itr->second.GetId());
|
||||
}
|
||||
|
||||
// output error for any still listed (not referenced from appropriate table) ids
|
||||
|
||||
@@ -297,7 +297,7 @@ void Quest::BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player
|
||||
rewards.ChoiceItems[i].ItemID = RewardChoiceItemId[i];
|
||||
rewards.ChoiceItems[i].Quantity = RewardChoiceItemCount[i];
|
||||
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(RewardChoiceItemId[i]))
|
||||
rewards.ChoiceItems[i].DisplayID = itemTemplate->DisplayInfoID;
|
||||
rewards.ChoiceItems[i].DisplayID = itemTemplate->GetDisplayID();
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REWARDS_COUNT; ++i)
|
||||
@@ -305,7 +305,7 @@ void Quest::BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player
|
||||
rewards.ItemID[i] = RewardItemId[i];
|
||||
rewards.ItemQty[i] = RewardItemIdCount[i];
|
||||
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(RewardItemId[i]))
|
||||
rewards.ItemDisplayID[i] = itemTemplate->DisplayInfoID;
|
||||
rewards.ItemDisplayID[i] = itemTemplate->GetDisplayID();
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "MovementPackets.h"
|
||||
#include "NPCPackets.h"
|
||||
#include "QuestPackets.h"
|
||||
#include "QueryPackets.h"
|
||||
#include "SystemPackets.h"
|
||||
|
||||
#endif // AllPackets_h__
|
||||
@@ -114,8 +114,8 @@ WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Fiel
|
||||
break;
|
||||
}
|
||||
|
||||
VisualItems[slot].InvType = proto->InventoryType;
|
||||
VisualItems[slot].DisplayID = proto->DisplayInfoID;
|
||||
VisualItems[slot].InvType = proto->GetInventoryType();
|
||||
VisualItems[slot].DisplayID = proto->GetDisplayID();
|
||||
VisualItems[slot].DisplayEnchantID = enchant ? enchant->ItemVisual : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LfgPlayerQuestReward
|
||||
{
|
||||
ItemTemplate const* item = sObjectMgr->GetItemTemplate(playerQuestRewardItem.ItemID);
|
||||
data << int32(playerQuestRewardItem.ItemID);
|
||||
data << int32(item ? item->DisplayInfoID : 0);
|
||||
data << int32(item ? item->GetDisplayID() : 0);
|
||||
data << int32(playerQuestRewardItem.Quantity);
|
||||
data << uint8(0);
|
||||
|
||||
@@ -452,7 +452,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::LFG::LFGPlayerRewards con
|
||||
{
|
||||
ItemTemplate const* item = !lfgPlayerRewards.IsCurrency ? sObjectMgr->GetItemTemplate(lfgPlayerRewards.RewardItem) : nullptr;
|
||||
data << uint32(lfgPlayerRewards.RewardItem);
|
||||
data << uint32(item ? item->DisplayInfoID : 0);
|
||||
data << uint32(item ? item->GetDisplayID() : 0);
|
||||
data << uint32(lfgPlayerRewards.RewardItemQuantity);
|
||||
data << uint8(lfgPlayerRewards.IsCurrency);
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "QueryPackets.h"
|
||||
|
||||
void WorldPackets::Query::DBQueryBulk::Read()
|
||||
{
|
||||
_worldPacket >> TableHash;
|
||||
|
||||
uint32 count = _worldPacket.ReadBits(23);
|
||||
Queries.resize(count);
|
||||
|
||||
for (uint32 i = 0; i < count; ++i)
|
||||
{
|
||||
Queries[i].GUID[0] = _worldPacket.ReadBit();
|
||||
Queries[i].GUID[4] = _worldPacket.ReadBit();
|
||||
Queries[i].GUID[7] = _worldPacket.ReadBit();
|
||||
Queries[i].GUID[2] = _worldPacket.ReadBit();
|
||||
Queries[i].GUID[5] = _worldPacket.ReadBit();
|
||||
Queries[i].GUID[3] = _worldPacket.ReadBit();
|
||||
Queries[i].GUID[6] = _worldPacket.ReadBit();
|
||||
Queries[i].GUID[1] = _worldPacket.ReadBit();
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < count; ++i)
|
||||
{
|
||||
_worldPacket.ReadByteSeq(Queries[i].GUID[5]);
|
||||
_worldPacket.ReadByteSeq(Queries[i].GUID[6]);
|
||||
_worldPacket.ReadByteSeq(Queries[i].GUID[7]);
|
||||
_worldPacket.ReadByteSeq(Queries[i].GUID[0]);
|
||||
_worldPacket.ReadByteSeq(Queries[i].GUID[1]);
|
||||
_worldPacket.ReadByteSeq(Queries[i].GUID[3]);
|
||||
_worldPacket.ReadByteSeq(Queries[i].GUID[4]);
|
||||
_worldPacket >> Queries[i].RecordID;
|
||||
_worldPacket.ReadByteSeq(Queries[i].GUID[2]);
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Query::DBReply::Write()
|
||||
{
|
||||
_worldPacket << RecordID;
|
||||
_worldPacket << TableHash;
|
||||
_worldPacket << Timestamp;
|
||||
_worldPacket << uint32(Data.size());
|
||||
_worldPacket.append(Data);
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Query::HotfixNotifyBlob::Write()
|
||||
{
|
||||
_worldPacket.WriteBits(Hotfixes->size(), 22);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
for (HotfixNotify const& hotfix : *Hotfixes)
|
||||
{
|
||||
_worldPacket << uint32(hotfix.TableHash);
|
||||
_worldPacket << uint32(hotfix.Timestamp);
|
||||
_worldPacket << int32(hotfix.Entry);
|
||||
}
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QueryPackets_h__
|
||||
#define QueryPackets_h__
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
namespace WorldPackets
|
||||
{
|
||||
namespace Query
|
||||
{
|
||||
struct DBQueryRecord
|
||||
{
|
||||
ObjectGuid GUID;
|
||||
uint32 RecordID;
|
||||
};
|
||||
|
||||
class DBQueryBulk final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
DBQueryBulk(WorldPacket&& packet) : ClientPacket(CMSG_DB_QUERY_BULK, std::move(packet)) { }
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint32 TableHash = 0;
|
||||
std::vector<DBQueryRecord> Queries;
|
||||
};
|
||||
|
||||
class DBReply final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
DBReply() : ServerPacket(SMSG_DB_REPLY, 12) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
uint32 TableHash = 0;
|
||||
uint32 Timestamp = 0;
|
||||
int32 RecordID = 0;
|
||||
ByteBuffer Data;
|
||||
};
|
||||
|
||||
class HotfixNotifyBlob final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
HotfixNotifyBlob() : ServerPacket(SMSG_HOTFIX_NOTIFY_BLOB, 4) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
HotfixData const* Hotfixes = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QueryPackets_h__
|
||||
@@ -283,6 +283,7 @@ void OpcodeTable::Initialize()
|
||||
DEFINE_HANDLER(CMSG_CORPSE_MAP_POSITION_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCorpseMapPositionQuery );
|
||||
DEFINE_HANDLER(CMSG_CREATURE_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleCreatureQueryOpcode );
|
||||
DEFINE_HANDLER(CMSG_DANCE_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||
DEFINE_HANDLER(CMSG_DB_QUERY_BULK, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleDBQueryBulk );
|
||||
DEFINE_HANDLER(CMSG_DEL_FRIEND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDelFriendOpcode );
|
||||
DEFINE_HANDLER(CMSG_DEL_IGNORE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDelIgnoreOpcode );
|
||||
DEFINE_HANDLER(CMSG_DEL_VOICE_IGNORE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||
@@ -539,7 +540,6 @@ void OpcodeTable::Initialize()
|
||||
DEFINE_HANDLER(CMSG_REQUEST_CATEGORY_COOLDOWNS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestCategoryCooldowns );
|
||||
DEFINE_HANDLER(CMSG_REQUEST_CEMETERY_LIST, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestCemeteryList );
|
||||
DEFINE_HANDLER(CMSG_REQUEST_GUILD_REWARDS_LIST, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestGuildRewardsList );
|
||||
DEFINE_HANDLER(CMSG_REQUEST_HOTFIX, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleRequestHotfix );
|
||||
DEFINE_HANDLER(CMSG_REQUEST_INSPECT_RATED_BG_STATS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||
DEFINE_HANDLER(CMSG_REQUEST_PARTY_MEMBER_STATS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPartyMemberStatsOpcode);
|
||||
DEFINE_HANDLER(CMSG_REQUEST_PET_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPetInfoOpcode );
|
||||
@@ -932,8 +932,8 @@ void OpcodeTable::Initialize()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_XP_GAIN, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_HEALTH_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_HIGHEST_THREAT_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_INFO, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_NOTIFY, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_HOTFIX_NOTIFY_BLOB, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIALIZE_FACTIONS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INITIAL_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SETUP_CURRENCY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
|
||||
@@ -174,6 +174,7 @@ enum OpcodeClient : uint16
|
||||
CMSG_CORPSE_MAP_POSITION_QUERY = 0x6205,
|
||||
CMSG_CREATURE_QUERY = 0x2706,
|
||||
CMSG_DANCE_QUERY = 0x4E07,
|
||||
CMSG_DB_QUERY_BULK = 0x2401,
|
||||
CMSG_DECLINE_CHANNEL_INVITE = 0x0000,
|
||||
CMSG_DEL_FRIEND = 0x6A15,
|
||||
CMSG_DEL_IGNORE = 0x6D26,
|
||||
@@ -456,7 +457,6 @@ enum OpcodeClient : uint16
|
||||
CMSG_REQUEST_CATEGORY_COOLDOWNS = 0x7102,
|
||||
CMSG_REQUEST_CEMETERY_LIST = 0x720A,
|
||||
CMSG_REQUEST_GUILD_REWARDS_LIST = 0x3012,
|
||||
CMSG_REQUEST_HOTFIX = 0x2401,
|
||||
CMSG_REQUEST_INSPECT_RATED_BG_STATS = 0x3010,
|
||||
CMSG_REQUEST_PARTY_MEMBER_STATS = 0x0C04,
|
||||
CMSG_REQUEST_PET_INFO = 0x4924,
|
||||
@@ -874,8 +874,8 @@ enum OpcodeServer
|
||||
SMSG_GUILD_XP_UPDATE = 0x0000,
|
||||
SMSG_HEALTH_UPDATE = 0x4734,
|
||||
SMSG_HIGHEST_THREAT_UPDATE = 0x4104,
|
||||
SMSG_HOTFIX_INFO = 0x19B5,
|
||||
SMSG_HOTFIX_NOTIFY = 0x55A7,
|
||||
SMSG_HOTFIX_NOTIFY_BLOB = 0x19B5,
|
||||
SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x0125,
|
||||
SMSG_IGNORE_REQUIREMENTS_CHEAT = 0x4E36,
|
||||
SMSG_INITIALIZE_FACTIONS = 0x4634,
|
||||
|
||||
@@ -164,6 +164,11 @@ namespace WorldPackets
|
||||
class QuestConfirmAccept;
|
||||
class QueryQuestInfo;
|
||||
}
|
||||
|
||||
namespace Query
|
||||
{
|
||||
class DBQueryBulk;
|
||||
}
|
||||
}
|
||||
|
||||
enum AccountDataType
|
||||
@@ -1166,7 +1171,6 @@ class TC_GAME_API WorldSession
|
||||
void HandleEjectPassenger(WorldPacket& data);
|
||||
void HandleEnterPlayerVehicle(WorldPacket& data);
|
||||
void HandleUpdateProjectilePosition(WorldPacket& recvPacket);
|
||||
void HandleRequestHotfix(WorldPacket& recvPacket);
|
||||
void HandleUpdateMissileTrajectory(WorldPacket& recvPacket);
|
||||
void HandleViolenceLevel(WorldPacket& recvPacket);
|
||||
void HandleObjectUpdateFailedOpcode(WorldPacket& recvPacket);
|
||||
@@ -1175,6 +1179,9 @@ class TC_GAME_API WorldSession
|
||||
void HandleRequestResearchHistory(WorldPacket& recv_data);
|
||||
int32 HandleEnableNagleAlgorithm();
|
||||
|
||||
// Query
|
||||
void HandleDBQueryBulk(WorldPackets::Query::DBQueryBulk& packet);
|
||||
|
||||
union ConnectToKey
|
||||
{
|
||||
struct
|
||||
|
||||
@@ -583,7 +583,7 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
|
||||
// wand case
|
||||
if ((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
if (Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK))
|
||||
m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->DamageType);
|
||||
m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->GetDamageType());
|
||||
|
||||
if (originalCasterGUID)
|
||||
m_originalCasterGUID = originalCasterGUID;
|
||||
@@ -4032,8 +4032,8 @@ void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo con
|
||||
item = itemType;
|
||||
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
|
||||
if (proto && proto->ItemLimitCategory)
|
||||
data << uint32(proto->ItemLimitCategory);
|
||||
if (proto && proto->GetItemLimitCategory())
|
||||
data << uint32(proto->GetItemLimitCategory());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -4422,9 +4422,9 @@ void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo)
|
||||
Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK);
|
||||
if (pItem)
|
||||
{
|
||||
ammoInventoryType = pItem->GetTemplate()->InventoryType;
|
||||
ammoInventoryType = pItem->GetTemplate()->GetInventoryType();
|
||||
if (ammoInventoryType == INVTYPE_THROWN)
|
||||
ammoDisplayID = pItem->GetTemplate()->DisplayInfoID;
|
||||
ammoDisplayID = pItem->GetTemplate()->GetDisplayID();
|
||||
else if (m_caster->HasAura(46699)) // Requires No Ammo
|
||||
{
|
||||
ammoDisplayID = 5996; // normal arrow
|
||||
@@ -4440,12 +4440,12 @@ void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo)
|
||||
{
|
||||
if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
|
||||
{
|
||||
if (itemEntry->Class == ITEM_CLASS_WEAPON)
|
||||
if (itemEntry->ClassID == ITEM_CLASS_WEAPON)
|
||||
{
|
||||
switch (itemEntry->SubClass)
|
||||
switch (itemEntry->SubclassID)
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_THROWN:
|
||||
ammoDisplayID = itemEntry->DisplayId;
|
||||
ammoDisplayID = itemEntry->DisplayInfoID;
|
||||
ammoInventoryType = itemEntry->InventoryType;
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_BOW:
|
||||
@@ -4786,30 +4786,27 @@ void Spell::TakeCastItem()
|
||||
bool expendable = false;
|
||||
bool withoutCharges = false;
|
||||
|
||||
for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
for (uint8 i = 0; i < proto->Effects.size(); ++i)
|
||||
{
|
||||
if (proto->Spells[i].SpellId > 0)
|
||||
// item has limited charges
|
||||
if (proto->Effects[i].Charges)
|
||||
{
|
||||
// item has limited charges
|
||||
if (proto->Spells[i].SpellCharges)
|
||||
if (proto->Effects[i].Charges < 0)
|
||||
expendable = true;
|
||||
|
||||
int32 charges = m_CastItem->GetSpellCharges(i);
|
||||
|
||||
// item has charges left
|
||||
if (charges)
|
||||
{
|
||||
if (proto->Spells[i].SpellCharges < 0)
|
||||
expendable = true;
|
||||
|
||||
int32 charges = m_CastItem->GetSpellCharges(i);
|
||||
|
||||
// item has charges left
|
||||
if (charges)
|
||||
{
|
||||
(charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use
|
||||
if (proto->Stackable == 1)
|
||||
m_CastItem->SetSpellCharges(i, charges);
|
||||
m_CastItem->SetState(ITEM_CHANGED, player);
|
||||
}
|
||||
|
||||
// all charges used
|
||||
withoutCharges = (charges == 0);
|
||||
(charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use
|
||||
if (proto->GetMaxStackSize() == 1)
|
||||
m_CastItem->SetSpellCharges(i, charges);
|
||||
m_CastItem->SetState(ITEM_CHANGED, player);
|
||||
}
|
||||
|
||||
// all charges used
|
||||
withoutCharges = (charges == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4912,12 +4909,12 @@ void Spell::TakeAmmo()
|
||||
Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK);
|
||||
|
||||
// wands don't have ammo
|
||||
if (!pItem || pItem->IsBroken() || pItem->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_WAND)
|
||||
if (!pItem || pItem->IsBroken() || pItem->GetTemplate()->GetSubClass() == ITEM_SUBCLASS_WEAPON_WAND)
|
||||
return;
|
||||
|
||||
if ((pItem->GetTemplate()->InventoryType == INVTYPE_THROWN ||
|
||||
pItem->GetTemplate()->InventoryType == INVTYPE_RANGED ||
|
||||
pItem->GetTemplate()->InventoryType == INVTYPE_RANGEDRIGHT)
|
||||
if ((pItem->GetTemplate()->GetInventoryType() == INVTYPE_THROWN ||
|
||||
pItem->GetTemplate()->GetInventoryType() == INVTYPE_RANGED ||
|
||||
pItem->GetTemplate()->GetInventoryType() == INVTYPE_RANGEDRIGHT)
|
||||
&& roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
|
||||
{
|
||||
if (pItem->GetMaxStackCount() == 1)
|
||||
@@ -5092,7 +5089,7 @@ void Spell::TakeReagents()
|
||||
ItemTemplate const* castItemTemplate = m_CastItem ? m_CastItem->GetTemplate() : nullptr;
|
||||
|
||||
// do not take reagents for these item casts
|
||||
if (castItemTemplate && castItemTemplate->Flags & ITEM_FLAG_NO_REAGENT_COST)
|
||||
if (castItemTemplate && castItemTemplate->GetFlags() & ITEM_FLAG_NO_REAGENT_COST)
|
||||
return;
|
||||
|
||||
Player* p_caster = m_caster->ToPlayer();
|
||||
@@ -5108,13 +5105,13 @@ void Spell::TakeReagents()
|
||||
uint32 itemcount = m_spellInfo->ReagentCount[x];
|
||||
|
||||
// if CastItem is also spell reagent
|
||||
if (castItemTemplate && castItemTemplate->ItemId == itemid)
|
||||
if (castItemTemplate && castItemTemplate->GetId() == itemid)
|
||||
{
|
||||
for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
|
||||
for (uint8 s = 0; s < castItemTemplate->Effects.size(); ++s)
|
||||
{
|
||||
// CastItem will be used up and does not count as reagent
|
||||
int32 charges = m_CastItem->GetSpellCharges(s);
|
||||
if (castItemTemplate->Spells[s].SpellCharges < 0 && abs(charges) < 2)
|
||||
if (castItemTemplate->Effects[s].Charges < 0 && abs(charges) < 2)
|
||||
{
|
||||
++itemcount;
|
||||
break;
|
||||
@@ -5665,7 +5662,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
|
||||
if (!pet->HaveInDiet(foodItem->GetTemplate()))
|
||||
return SPELL_FAILED_WRONG_PET_FOOD;
|
||||
|
||||
if (!pet->GetCurrentFoodBenefitLevel(foodItem->GetTemplate()->ItemLevel))
|
||||
if (!pet->GetCurrentFoodBenefitLevel(foodItem->GetTemplate()->GetBaseItemLevel()))
|
||||
return SPELL_FAILED_FOOD_LOWLEVEL;
|
||||
|
||||
if (m_caster->IsInCombat() || pet->IsInCombat())
|
||||
@@ -5769,7 +5766,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
|
||||
// we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM_TARGET
|
||||
if (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET &&
|
||||
!m_targets.GetGOTarget() &&
|
||||
(!pTempItem || !pTempItem->GetTemplate()->LockID || !pTempItem->IsLocked()))
|
||||
(!pTempItem || !pTempItem->GetTemplate()->GetLockID() || !pTempItem->IsLocked()))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (m_spellInfo->Id != 1842 || (m_targets.GetGOTarget() &&
|
||||
@@ -5787,7 +5784,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
else if (Item* itm = m_targets.GetItemTarget())
|
||||
lockId = itm->GetTemplate()->LockID;
|
||||
lockId = itm->GetTemplate()->GetLockID();
|
||||
|
||||
SkillType skillId = SKILL_NONE;
|
||||
int32 reqSkillValue = 0;
|
||||
@@ -6526,7 +6523,7 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
if (Item* ranged = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK, true))
|
||||
maxRange *= ranged->GetTemplate()->RangedModRange * 0.01f;
|
||||
maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f;
|
||||
|
||||
if (Player* modOwner = m_caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, const_cast<Spell*>(this));
|
||||
@@ -6593,13 +6590,13 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
if (!proto)
|
||||
return SPELL_FAILED_ITEM_NOT_READY;
|
||||
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
if (proto->Spells[i].SpellCharges)
|
||||
for (uint8 i = 0; i < proto->Effects.size(); ++i)
|
||||
if (proto->Effects[i].Charges)
|
||||
if (m_CastItem->GetSpellCharges(i) == 0)
|
||||
return SPELL_FAILED_NO_CHARGES_REMAIN;
|
||||
|
||||
// consumable cast item checks
|
||||
if (proto->Class == ITEM_CLASS_CONSUMABLE && m_targets.GetUnitTarget())
|
||||
if (proto->GetClass() == ITEM_CLASS_CONSUMABLE && m_targets.GetUnitTarget())
|
||||
{
|
||||
// such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example
|
||||
SpellCastResult failReason = SPELL_CAST_OK;
|
||||
@@ -6669,7 +6666,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
}
|
||||
|
||||
// do not take reagents for these item casts
|
||||
if (!(m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_FLAG_NO_REAGENT_COST))
|
||||
if (!(m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_REAGENT_COST))
|
||||
{
|
||||
bool checkReagents = !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST) && !player->CanNoReagentCast(m_spellInfo);
|
||||
// Not own traded item (in trader trade slot) requires reagents even if triggered spell
|
||||
@@ -6695,11 +6692,11 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
ItemTemplate const* proto = m_CastItem->GetTemplate();
|
||||
if (!proto)
|
||||
return SPELL_FAILED_ITEM_NOT_READY;
|
||||
for (uint8 s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
|
||||
for (uint8 s = 0; s < proto->Effects.size(); ++s)
|
||||
{
|
||||
// CastItem will be used up and does not count as reagent
|
||||
int32 charges = m_CastItem->GetSpellCharges(s);
|
||||
if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)
|
||||
if (proto->Effects[s].Charges < 0 && abs(charges) < 2)
|
||||
{
|
||||
++itemcount;
|
||||
break;
|
||||
@@ -6735,7 +6732,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
{
|
||||
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(m_spellInfo->Effects[i].ItemType);
|
||||
/// @todo Needs review
|
||||
if (pProto && !(pProto->ItemLimitCategory))
|
||||
if (pProto && !(pProto->GetItemLimitCategory()))
|
||||
{
|
||||
player->SendEquipError(msg, nullptr, nullptr, m_spellInfo->Effects[i].ItemType);
|
||||
return SPELL_FAILED_DONT_REPORT;
|
||||
@@ -6765,7 +6762,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
if (m_targets.GetItemTarget()->GetOwner() != m_caster)
|
||||
return SPELL_FAILED_NOT_TRADEABLE;
|
||||
// do not allow to enchant vellum from scroll made by vellum-prevent exploit
|
||||
if (m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_FLAG_NO_REAGENT_COST)
|
||||
if (m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_REAGENT_COST)
|
||||
return SPELL_FAILED_TOTEM_CATEGORY;
|
||||
ItemPosCountVec dest;
|
||||
InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->Effects[i].ItemType, 1);
|
||||
@@ -6783,16 +6780,16 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
return SPELL_FAILED_ITEM_NOT_FOUND;
|
||||
|
||||
// required level has to be checked also! Exploit fix
|
||||
if (targetItem->GetTemplate()->ItemLevel < m_spellInfo->BaseLevel)
|
||||
if (targetItem->GetTemplate()->GetBaseItemLevel() < m_spellInfo->BaseLevel)
|
||||
return SPELL_FAILED_LOWLEVEL;
|
||||
|
||||
bool isItemUsable = false;
|
||||
for (uint8 e = 0; e < MAX_ITEM_PROTO_SPELLS; ++e)
|
||||
ItemTemplate const* proto = targetItem->GetTemplate();
|
||||
for (uint8 e = 0; e < proto->Effects.size(); ++e)
|
||||
{
|
||||
ItemTemplate const* proto = targetItem->GetTemplate();
|
||||
if (proto->Spells[e].SpellId > 0 && (
|
||||
proto->Spells[e].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE ||
|
||||
proto->Spells[e].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE))
|
||||
if (proto->Effects[e].SpellID && (
|
||||
proto->Effects[e].Trigger == ITEM_SPELLTRIGGER_ON_USE ||
|
||||
proto->Effects[e].Trigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE))
|
||||
{
|
||||
isItemUsable = true;
|
||||
break;
|
||||
@@ -6815,7 +6812,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
{
|
||||
uint32 numSockets = 0;
|
||||
for (uint32 socket = 0; socket < MAX_ITEM_PROTO_SOCKETS; ++socket)
|
||||
if (targetItem->GetTemplate()->Socket[socket].Color)
|
||||
if (targetItem->GetTemplate()->GetSocketColor(socket))
|
||||
++numSockets;
|
||||
|
||||
if (numSockets == MAX_ITEM_PROTO_SOCKETS || targetItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
|
||||
@@ -6855,9 +6852,9 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
// Apply item level restriction if the enchanting spell has max level restrition set
|
||||
if (m_CastItem && m_spellInfo->MaxLevel > 0)
|
||||
{
|
||||
if (item->GetTemplate()->ItemLevel < m_CastItem->GetTemplate()->RequiredLevel)
|
||||
if (int32(item->GetTemplate()->GetBaseItemLevel()) < m_CastItem->GetTemplate()->GetRequiredLevel())
|
||||
return SPELL_FAILED_LOWLEVEL;
|
||||
if (item->GetTemplate()->ItemLevel > m_spellInfo->MaxLevel)
|
||||
if (item->GetTemplate()->GetBaseItemLevel() > m_spellInfo->MaxLevel)
|
||||
return SPELL_FAILED_HIGHLEVEL;
|
||||
}
|
||||
break;
|
||||
@@ -6878,7 +6875,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
if (!itemProto)
|
||||
return SPELL_FAILED_CANT_BE_DISENCHANTED;
|
||||
|
||||
uint32 item_quality = itemProto->Quality;
|
||||
uint32 item_quality = itemProto->GetQuality();
|
||||
// 2.0.x addon: Check player enchanting level against the item disenchanting requirements
|
||||
uint32 item_disenchantskilllevel = itemProto->RequiredDisenchantSkill;
|
||||
if (item_disenchantskilllevel == uint32(-1))
|
||||
@@ -6887,7 +6884,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
return SPELL_FAILED_LOW_CASTLEVEL;
|
||||
if (item_quality > 4 || item_quality < 2)
|
||||
return SPELL_FAILED_CANT_BE_DISENCHANTED;
|
||||
if (itemProto->Class != ITEM_CLASS_WEAPON && itemProto->Class != ITEM_CLASS_ARMOR)
|
||||
if (itemProto->GetClass() != ITEM_CLASS_WEAPON && itemProto->GetClass() != ITEM_CLASS_ARMOR)
|
||||
return SPELL_FAILED_CANT_BE_DISENCHANTED;
|
||||
if (!itemProto->DisenchantID)
|
||||
return SPELL_FAILED_CANT_BE_DISENCHANTED;
|
||||
@@ -6899,13 +6896,13 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
if (!item)
|
||||
return SPELL_FAILED_CANT_BE_PROSPECTED;
|
||||
//ensure item is a prospectable ore
|
||||
if (!(item->GetTemplate()->Flags & ITEM_FLAG_IS_PROSPECTABLE))
|
||||
if (!(item->GetTemplate()->GetFlags() & ITEM_FLAG_IS_PROSPECTABLE))
|
||||
return SPELL_FAILED_CANT_BE_PROSPECTED;
|
||||
//prevent prospecting in trade slot
|
||||
if (item->GetOwnerGUID() != m_caster->GetGUID())
|
||||
return SPELL_FAILED_CANT_BE_PROSPECTED;
|
||||
//Check for enough skill in jewelcrafting
|
||||
uint32 item_prospectingskilllevel = item->GetTemplate()->RequiredSkillRank;
|
||||
uint32 item_prospectingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
|
||||
if (item_prospectingskilllevel > player->GetSkillValue(SKILL_JEWELCRAFTING))
|
||||
return SPELL_FAILED_LOW_CASTLEVEL;
|
||||
//make sure the player has the required ores in inventory
|
||||
@@ -6930,13 +6927,13 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
if (!item)
|
||||
return SPELL_FAILED_CANT_BE_MILLED;
|
||||
//ensure item is a millable herb
|
||||
if (!(item->GetTemplate()->Flags & ITEM_FLAG_IS_MILLABLE))
|
||||
if (!(item->GetTemplate()->GetFlags() & ITEM_FLAG_IS_MILLABLE))
|
||||
return SPELL_FAILED_CANT_BE_MILLED;
|
||||
//prevent milling in trade slot
|
||||
if (item->GetOwnerGUID() != m_caster->GetGUID())
|
||||
return SPELL_FAILED_CANT_BE_MILLED;
|
||||
//Check for enough skill in inscription
|
||||
uint32 item_millingskilllevel = item->GetTemplate()->RequiredSkillRank;
|
||||
uint32 item_millingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
|
||||
if (item_millingskilllevel > player->GetSkillValue(SKILL_INSCRIPTION))
|
||||
return SPELL_FAILED_LOW_CASTLEVEL;
|
||||
//make sure the player has the required herbs in inventory
|
||||
@@ -6965,7 +6962,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
if (!pItem || pItem->IsBroken())
|
||||
return SPELL_FAILED_EQUIPPED_ITEM;
|
||||
|
||||
switch (pItem->GetTemplate()->SubClass)
|
||||
switch (pItem->GetTemplate()->GetSubClass())
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_THROWN:
|
||||
{
|
||||
@@ -6994,8 +6991,8 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
|
||||
|
||||
if (Item* pitem = player->GetItemByEntry(item_id))
|
||||
{
|
||||
for (int x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
|
||||
if (pProto->Spells[x].SpellCharges != 0 && pitem->GetSpellCharges(x) == pProto->Spells[x].SpellCharges)
|
||||
for (uint8 x = 0; x < pProto->Effects.size(); ++x)
|
||||
if (pProto->Effects[x].Charges != 0 && pitem->GetSpellCharges(x) == pProto->Effects[x].Charges)
|
||||
return SPELL_FAILED_ITEM_AT_MAX_CHARGES;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1289,7 +1289,7 @@ void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype)
|
||||
player->CompleteArchProject(projectId);
|
||||
|
||||
// set the "Crafted by ..." property of the item
|
||||
if (pItem->GetTemplate()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetTemplate()->Class != ITEM_CLASS_QUEST && newitemid != 6265 && newitemid != 6948)
|
||||
if (pItem->GetTemplate()->GetClass() != ITEM_CLASS_CONSUMABLE && pItem->GetTemplate()->GetClass() != ITEM_CLASS_QUEST && newitemid != 6265 && newitemid != 6948)
|
||||
pItem->SetGuidValue(ITEM_FIELD_CREATOR, player->GetGUID());
|
||||
|
||||
// send info to the client
|
||||
@@ -1297,8 +1297,8 @@ void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype)
|
||||
|
||||
if (Guild* guild = player->GetGuild())
|
||||
{
|
||||
if (pProto->Quality > ITEM_QUALITY_EPIC || (pProto->Quality == ITEM_QUALITY_EPIC && pProto->ItemLevel >= MinNewsItemLevel[sWorld->getIntConfig(CONFIG_EXPANSION)]))
|
||||
guild->AddGuildNews(GUILD_NEWS_ITEM_CRAFTED, player->GetGUID(), 0, pProto->ItemId);
|
||||
if (pProto->GetQuality() > ITEM_QUALITY_EPIC || (pProto->GetQuality() == ITEM_QUALITY_EPIC && pProto->GetBaseItemLevel() >= MinNewsItemLevel[sWorld->getIntConfig(CONFIG_EXPANSION)]))
|
||||
guild->AddGuildNews(GUILD_NEWS_ITEM_CRAFTED, player->GetGUID(), 0, pProto->GetId());
|
||||
|
||||
guild->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD, pItem->GetEntry(), num_to_add, 0, nullptr, player);
|
||||
}
|
||||
@@ -1626,7 +1626,7 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex)
|
||||
}
|
||||
else if (itemTarget)
|
||||
{
|
||||
lockId = itemTarget->GetTemplate()->LockID;
|
||||
lockId = itemTarget->GetTemplate()->GetLockID();
|
||||
guid = itemTarget->GetGUID();
|
||||
}
|
||||
else
|
||||
@@ -2298,7 +2298,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex)
|
||||
else
|
||||
{
|
||||
// do not increase skill if vellum used
|
||||
if (!(m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_FLAG_NO_REAGENT_COST))
|
||||
if (!(m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_REAGENT_COST))
|
||||
player->UpdateCraftSkill(m_spellInfo->Id);
|
||||
|
||||
uint32 enchant_id = m_spellInfo->Effects[effIndex].MiscValue;
|
||||
@@ -2318,7 +2318,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex)
|
||||
{
|
||||
sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
|
||||
player->GetName().c_str(), player->GetSession()->GetAccountId(),
|
||||
itemTarget->GetTemplate()->Name1.c_str(), itemTarget->GetEntry(),
|
||||
itemTarget->GetTemplate()->GetDefaultLocaleName(), itemTarget->GetEntry(),
|
||||
item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
|
||||
}
|
||||
|
||||
@@ -2383,7 +2383,7 @@ void Spell::EffectEnchantItemPrismatic(SpellEffIndex effIndex)
|
||||
{
|
||||
sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
|
||||
player->GetName().c_str(), player->GetSession()->GetAccountId(),
|
||||
itemTarget->GetTemplate()->Name1.c_str(), itemTarget->GetEntry(),
|
||||
itemTarget->GetTemplate()->GetDefaultLocaleName(), itemTarget->GetEntry(),
|
||||
item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
|
||||
}
|
||||
|
||||
@@ -2464,7 +2464,7 @@ void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex)
|
||||
{
|
||||
sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
|
||||
player->GetName().c_str(), player->GetSession()->GetAccountId(),
|
||||
itemTarget->GetTemplate()->Name1.c_str(), itemTarget->GetEntry(),
|
||||
itemTarget->GetTemplate()->GetDefaultLocaleName(), itemTarget->GetEntry(),
|
||||
item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
|
||||
}
|
||||
|
||||
@@ -2741,7 +2741,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
|
||||
// 45% more damage with daggers
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
if (Item* item = m_caster->ToPlayer()->GetWeaponForAttack(m_attackType, true))
|
||||
if (item->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
|
||||
if (item->GetTemplate()->GetSubClass() == ITEM_SUBCLASS_WEAPON_DAGGER)
|
||||
totalDamagePercentMod *= 1.45f;
|
||||
}
|
||||
break;
|
||||
@@ -3988,7 +3988,7 @@ void Spell::EffectFeedPet(SpellEffIndex effIndex)
|
||||
if (!pet->IsAlive())
|
||||
return;
|
||||
|
||||
int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetTemplate()->ItemLevel);
|
||||
int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetTemplate()->GetBaseItemLevel());
|
||||
if (benefit <= 0)
|
||||
return;
|
||||
|
||||
@@ -4888,7 +4888,7 @@ void Spell::EffectProspecting(SpellEffIndex /*effIndex*/)
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
if (!itemTarget || !(itemTarget->GetTemplate()->Flags & ITEM_FLAG_IS_PROSPECTABLE))
|
||||
if (!itemTarget || !(itemTarget->GetTemplate()->GetFlags() & ITEM_FLAG_IS_PROSPECTABLE))
|
||||
return;
|
||||
|
||||
if (itemTarget->GetCount() < 5)
|
||||
@@ -4897,7 +4897,7 @@ void Spell::EffectProspecting(SpellEffIndex /*effIndex*/)
|
||||
if (sWorld->getBoolConfig(CONFIG_SKILL_PROSPECTING))
|
||||
{
|
||||
uint32 SkillValue = player->GetPureSkillValue(SKILL_JEWELCRAFTING);
|
||||
uint32 reqSkillValue = itemTarget->GetTemplate()->RequiredSkillRank;
|
||||
uint32 reqSkillValue = itemTarget->GetTemplate()->GetRequiredSkillRank();
|
||||
player->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
|
||||
}
|
||||
|
||||
@@ -4913,7 +4913,7 @@ void Spell::EffectMilling(SpellEffIndex /*effIndex*/)
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
if (!itemTarget || !(itemTarget->GetTemplate()->Flags & ITEM_FLAG_IS_MILLABLE))
|
||||
if (!itemTarget || !(itemTarget->GetTemplate()->GetFlags() & ITEM_FLAG_IS_MILLABLE))
|
||||
return;
|
||||
|
||||
if (itemTarget->GetCount() < 5)
|
||||
@@ -4922,7 +4922,7 @@ void Spell::EffectMilling(SpellEffIndex /*effIndex*/)
|
||||
if (sWorld->getBoolConfig(CONFIG_SKILL_MILLING))
|
||||
{
|
||||
uint32 SkillValue = player->GetPureSkillValue(SKILL_INSCRIPTION);
|
||||
uint32 reqSkillValue = itemTarget->GetTemplate()->RequiredSkillRank;
|
||||
uint32 reqSkillValue = itemTarget->GetTemplate()->GetRequiredSkillRank();
|
||||
player->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
|
||||
}
|
||||
|
||||
@@ -5302,7 +5302,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const*
|
||||
// level of pet summoned using engineering item based at engineering skill level
|
||||
if (m_CastItem && caster->GetTypeId() == TYPEID_PLAYER)
|
||||
if (ItemTemplate const* proto = m_CastItem->GetTemplate())
|
||||
if (proto->RequiredSkill == SKILL_ENGINEERING)
|
||||
if (proto->GetRequiredSkill() == SKILL_ENGINEERING)
|
||||
if (uint16 skill202 = caster->ToPlayer()->GetSkillValue(SKILL_ENGINEERING))
|
||||
level = skill202 / 5;
|
||||
|
||||
@@ -5545,8 +5545,8 @@ void Spell::EffectRechargeManaGem(SpellEffIndex /*effIndex*/)
|
||||
|
||||
if (Item* pItem = player->GetItemByEntry(item_id))
|
||||
{
|
||||
for (int x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
|
||||
pItem->SetSpellCharges(x, pProto->Spells[x].SpellCharges);
|
||||
for (uint8 x = 0; x < pProto->Effects.size(); ++x)
|
||||
pItem->SetSpellCharges(x, pProto->Effects[x].Charges);
|
||||
pItem->SetState(ITEM_CHANGED, player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,11 +705,11 @@ void SpellHistory::GetCooldownDurations(SpellInfo const* spellInfo, uint32 itemI
|
||||
{
|
||||
for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx)
|
||||
{
|
||||
if (uint32(proto->Spells[idx].SpellId) == spellInfo->Id)
|
||||
if (uint32(proto->Effects[idx].SpellID) == spellInfo->Id)
|
||||
{
|
||||
tmpCooldown = proto->Spells[idx].SpellCooldown;
|
||||
tmpCategoryId = proto->Spells[idx].SpellCategory;
|
||||
tmpCategoryCooldown = proto->Spells[idx].SpellCategoryCooldown;
|
||||
tmpCooldown = proto->Effects[idx].Cooldown;
|
||||
tmpCategoryId = proto->Effects[idx].Category;
|
||||
tmpCategoryCooldown = proto->Effects[idx].CategoryCooldown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1652,7 +1652,13 @@ void World::SetInitialWorldSettings()
|
||||
///- Load the DBC files
|
||||
TC_LOG_INFO("server.loading", "Initialize data stores...");
|
||||
LoadDBCStores(m_dataPath);
|
||||
LoadDB2Stores(m_dataPath);
|
||||
sDB2Manager.LoadStores(m_dataPath);
|
||||
|
||||
TC_LOG_INFO("misc", "Loading hotfix info...");
|
||||
sDB2Manager.LoadHotfixData();
|
||||
|
||||
// Close hotfix database - it is only used during DB2 loading
|
||||
HotfixDatabase.Close();
|
||||
|
||||
// Load M2 fly by cameras
|
||||
LoadM2Cameras(m_dataPath);
|
||||
@@ -1725,7 +1731,6 @@ void World::SetInitialWorldSettings()
|
||||
uint32 oldMSTime = getMSTime();
|
||||
sObjectMgr->LoadCreatureLocales();
|
||||
sObjectMgr->LoadGameObjectLocales();
|
||||
sObjectMgr->LoadItemLocales();
|
||||
sObjectMgr->LoadQuestLocales();
|
||||
sObjectMgr->LoadNpcTextLocales();
|
||||
sObjectMgr->LoadPageTextLocales();
|
||||
@@ -2274,12 +2279,6 @@ void World::SetInitialWorldSettings()
|
||||
});
|
||||
}
|
||||
|
||||
TC_LOG_INFO("misc", "Loading hotfix info...");
|
||||
sObjectMgr->LoadHotfixData();
|
||||
|
||||
TC_LOG_INFO("server.loading", "Loading missing KeyChains...");
|
||||
sObjectMgr->LoadMissingKeyChains();
|
||||
|
||||
uint32 startupDuration = GetMSTimeDiffToNow(startupBegin);
|
||||
|
||||
TC_LOG_INFO("server.worldserver", "World initialized in %u minutes %u seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000));
|
||||
|
||||
@@ -374,39 +374,7 @@ public:
|
||||
ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
|
||||
for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
|
||||
{
|
||||
int localeIndex = handler->GetSessionDbLocaleIndex();
|
||||
if (localeIndex >= 0)
|
||||
{
|
||||
uint8 ulocaleIndex = uint8(localeIndex);
|
||||
if (ItemLocale const* il = sObjectMgr->GetItemLocale(itr->second.ItemId))
|
||||
{
|
||||
if (il->Name.size() > ulocaleIndex && !il->Name[ulocaleIndex].empty())
|
||||
{
|
||||
std::string name = il->Name[ulocaleIndex];
|
||||
|
||||
if (Utf8FitTo(name, wNamePart))
|
||||
{
|
||||
if (maxResults && count++ == maxResults)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_LOOKUP_MAX_RESULTS, maxResults);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (handler->GetSession())
|
||||
handler->PSendSysMessage(LANG_ITEM_LIST_CHAT, itr->second.ItemId, itr->second.ItemId, name.c_str());
|
||||
else
|
||||
handler->PSendSysMessage(LANG_ITEM_LIST_CONSOLE, itr->second.ItemId, name.c_str());
|
||||
|
||||
if (!found)
|
||||
found = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string name = itr->second.Name1;
|
||||
std::string name = itr->second.GetName(handler->GetSessionDbcLocale());
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
@@ -419,9 +387,9 @@ public:
|
||||
}
|
||||
|
||||
if (handler->GetSession())
|
||||
handler->PSendSysMessage(LANG_ITEM_LIST_CHAT, itr->second.ItemId, itr->second.ItemId, name.c_str());
|
||||
handler->PSendSysMessage(LANG_ITEM_LIST_CHAT, itr->second.GetId(), itr->second.GetId(), name.c_str());
|
||||
else
|
||||
handler->PSendSysMessage(LANG_ITEM_LIST_CONSOLE, itr->second.ItemId, name.c_str());
|
||||
handler->PSendSysMessage(LANG_ITEM_LIST_CONSOLE, itr->second.GetId(), name.c_str());
|
||||
|
||||
if (!found)
|
||||
found = true;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "ChaseMovementGenerator.h"
|
||||
#include "Chat.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "DisableMgr.h"
|
||||
#include "FollowMovementGenerator.h"
|
||||
#include "GridNotifiers.h"
|
||||
@@ -1226,20 +1227,23 @@ public:
|
||||
|
||||
if (itemNameStr && itemNameStr[0])
|
||||
{
|
||||
std::string itemName = itemNameStr+1;
|
||||
WorldDatabase.EscapeString(itemName);
|
||||
|
||||
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME);
|
||||
stmt->setString(0, itemName);
|
||||
PreparedQueryResult result = WorldDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
std::string itemName = itemNameStr + 1;
|
||||
auto itr = std::find_if(sItemSparseStore.begin(), sItemSparseStore.end(), [&itemName](ItemSparseEntry const* sparse)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_COULDNOTFIND, itemNameStr+1);
|
||||
for (uint32 i = 0; i < MAX_LOCALES; ++i)
|
||||
if (itemName == sparse->Name->Str[i])
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (itr == sItemSparseStore.end())
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_COULDNOTFIND, itemNameStr + 1);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
itemId = result->Fetch()->GetUInt32();
|
||||
|
||||
itemId = itr->ID;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
@@ -1352,14 +1356,14 @@ public:
|
||||
ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
|
||||
for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
|
||||
{
|
||||
if (itr->second.ItemSet == itemSetId)
|
||||
if (itr->second.GetItemSet() == itemSetId)
|
||||
{
|
||||
found = true;
|
||||
ItemPosCountVec dest;
|
||||
InventoryResult msg = playerTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itr->second.ItemId, 1);
|
||||
InventoryResult msg = playerTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itr->second.GetId(), 1);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
{
|
||||
Item* item = playerTarget->StoreNewItem(dest, itr->second.ItemId, true);
|
||||
Item* item = playerTarget->StoreNewItem(dest, itr->second.GetId(), true);
|
||||
|
||||
// remove binding (let GM give it to another player later)
|
||||
if (player == playerTarget)
|
||||
@@ -1371,8 +1375,8 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
player->SendEquipError(msg, nullptr, nullptr, itr->second.ItemId);
|
||||
handler->PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itr->second.ItemId, 1);
|
||||
player->SendEquipError(msg, nullptr, nullptr, itr->second.GetId());
|
||||
handler->PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itr->second.GetId(), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +446,7 @@ public:
|
||||
|
||||
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
|
||||
|
||||
handler->PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, itemId, itemTemplate->Name1.c_str(), maxcount, incrtime, extendedcost);
|
||||
handler->PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, itemId, itemTemplate->GetDefaultLocaleName(), maxcount, incrtime, extendedcost);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -636,7 +636,7 @@ public:
|
||||
|
||||
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
|
||||
|
||||
handler->PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST, itemId, itemTemplate->Name1.c_str());
|
||||
handler->PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST, itemId, itemTemplate->GetDefaultLocaleName());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1579,16 +1579,11 @@ public:
|
||||
static void _ShowLootEntry(ChatHandler* handler, uint32 itemId, uint8 itemCount, bool alternateString = false)
|
||||
{
|
||||
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
|
||||
ItemLocale const* itemLocale = sObjectMgr->GetItemLocale(itemId);
|
||||
char const* name = nullptr;
|
||||
if (itemLocale)
|
||||
name = itemLocale->Name[handler->GetSessionDbcLocale()].c_str();
|
||||
if ((!name || !*name) && itemTemplate)
|
||||
name = itemTemplate->Name1.c_str();
|
||||
char const* name = itemTemplate->GetName(handler->GetSessionDbcLocale());
|
||||
if (!name)
|
||||
name = "Unknown item";
|
||||
handler->PSendSysMessage(alternateString ? LANG_COMMAND_NPC_SHOWLOOT_ENTRY_2 : LANG_COMMAND_NPC_SHOWLOOT_ENTRY,
|
||||
itemCount, ItemQualityColors[itemTemplate ? itemTemplate->Quality : ITEM_QUALITY_POOR], itemId, name, itemId);
|
||||
itemCount, ItemQualityColors[itemTemplate ? itemTemplate->GetQuality() : ITEM_QUALITY_POOR], itemId, name, itemId);
|
||||
}
|
||||
static void _IterateNotNormalLootMap(ChatHandler* handler, NotNormalLootItemMap const& map, std::vector<LootItem> const& items)
|
||||
{
|
||||
|
||||
@@ -85,12 +85,12 @@ public:
|
||||
ItemTemplateContainer const* itc = sObjectMgr->GetItemTemplateStore();
|
||||
ItemTemplateContainer::const_iterator result = std::find_if(itc->begin(), itc->end(), [quest](ItemTemplateContainer::value_type const& value)
|
||||
{
|
||||
return value.second.StartQuest == quest->GetQuestId();
|
||||
return value.second.GetStartQuest() == quest->GetQuestId();
|
||||
});
|
||||
|
||||
if (result != itc->end())
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_QUEST_STARTFROMITEM, entry, result->second.ItemId);
|
||||
handler->PSendSysMessage(LANG_COMMAND_QUEST_STARTFROMITEM, entry, result->second.GetId());
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,6 @@ public:
|
||||
{ "creature_text_locale", rbac::RBAC_PERM_COMMAND_RELOAD_CRETURE_TEXT_LOCALE, true, &HandleReloadLocalesCreatureTextCommand, "" },
|
||||
{ "gameobject_template_locale", rbac::RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_TEMPLATE_LOCALE, true, &HandleReloadLocalesGameobjectCommand, "" },
|
||||
{ "gossip_menu_option_locale", rbac::RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION_LOCALE, true, &HandleReloadLocalesGossipMenuOptionCommand, "" },
|
||||
{ "item_template_locale", rbac::RBAC_PERM_COMMAND_RELOAD_ITEM_TEMPLATE_LOCALE, true, &HandleReloadLocalesItemCommand, "" },
|
||||
{ "npc_text_locale", rbac::RBAC_PERM_COMMAND_RELOAD_NPC_TEXT_LOCALE, true, &HandleReloadLocalesNpcTextCommand, "" },
|
||||
{ "page_text_locale", rbac::RBAC_PERM_COMMAND_RELOAD_PAGE_TEXT_LOCALE, true, &HandleReloadLocalesPageTextCommand, "" },
|
||||
{ "points_of_interest_locale", rbac::RBAC_PERM_COMMAND_RELOAD_POINTS_OF_INTEREST_LOCALE, true, &HandleReloadLocalesPointsOfInterestCommand, "" },
|
||||
@@ -315,7 +314,6 @@ public:
|
||||
HandleReloadLocalesCreatureTextCommand(handler, "a");
|
||||
HandleReloadLocalesGameobjectCommand(handler, "a");
|
||||
HandleReloadLocalesGossipMenuOptionCommand(handler, "a");
|
||||
HandleReloadLocalesItemCommand(handler, "a");
|
||||
HandleReloadLocalesNpcTextCommand(handler, "a");
|
||||
HandleReloadLocalesPageTextCommand(handler, "a");
|
||||
HandleReloadLocalesPointsOfInterestCommand(handler, "a");
|
||||
@@ -1062,14 +1060,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReloadLocalesItemCommand(ChatHandler* handler, char const* /*args*/)
|
||||
{
|
||||
TC_LOG_INFO("misc", "Re-Loading Item Template Locale... ");
|
||||
sObjectMgr->LoadItemLocales();
|
||||
handler->SendGlobalGMSysMessage("DB table `item_template_locale` reloaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReloadLocalesNpcTextCommand(ChatHandler* handler, char const* /*args*/)
|
||||
{
|
||||
TC_LOG_INFO("misc", "Re-Loading NPC Text Locale... ");
|
||||
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
}
|
||||
|
||||
uint32 itemCount = itemCountStr ? atoi(itemCountStr) : 1;
|
||||
if (itemCount < 1 || (item_proto->MaxCount > 0 && itemCount > uint32(item_proto->MaxCount)))
|
||||
if (itemCount < 1 || (item_proto->GetMaxCount() > 0 && itemCount > uint32(item_proto->GetMaxCount())))
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_INVALID_ITEM_COUNT, itemCount, itemId);
|
||||
handler->SetSentErrorMessage(true);
|
||||
|
||||
@@ -721,8 +721,8 @@ class instance_ulduar : public InstanceMapScript
|
||||
if (Player* player = itr->GetSource())
|
||||
for (uint8 slot = EQUIPMENT_SLOT_MAINHAND; slot <= EQUIPMENT_SLOT_RANGED; ++slot)
|
||||
if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||
if (item->GetTemplate()->ItemLevel > _maxWeaponItemLevel)
|
||||
_maxWeaponItemLevel = item->GetTemplate()->ItemLevel;
|
||||
if (item->GetTemplate()->GetBaseItemLevel() > _maxWeaponItemLevel)
|
||||
_maxWeaponItemLevel = item->GetTemplate()->GetBaseItemLevel();
|
||||
}
|
||||
else if (state == IN_PROGRESS)
|
||||
{
|
||||
@@ -741,11 +741,11 @@ class instance_ulduar : public InstanceMapScript
|
||||
{
|
||||
if (slot >= EQUIPMENT_SLOT_MAINHAND && slot <= EQUIPMENT_SLOT_RANGED)
|
||||
{
|
||||
if (item->GetTemplate()->ItemLevel > _maxWeaponItemLevel)
|
||||
_maxWeaponItemLevel = item->GetTemplate()->ItemLevel;
|
||||
if (item->GetTemplate()->GetBaseItemLevel() > _maxWeaponItemLevel)
|
||||
_maxWeaponItemLevel = item->GetTemplate()->GetBaseItemLevel();
|
||||
}
|
||||
else if (item->GetTemplate()->ItemLevel > _maxArmorItemLevel)
|
||||
_maxArmorItemLevel = item->GetTemplate()->ItemLevel;
|
||||
else if (item->GetTemplate()->GetBaseItemLevel() > _maxArmorItemLevel)
|
||||
_maxArmorItemLevel = item->GetTemplate()->GetBaseItemLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ bool EquippedOk(Player* player, uint32 spellId)
|
||||
for (uint8 j = EQUIPMENT_SLOT_START; j < EQUIPMENT_SLOT_END; ++j)
|
||||
{
|
||||
item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, j);
|
||||
if (item && item->GetTemplate()->RequiredSpell == reqSpell)
|
||||
if (item && item->GetTemplate()->GetRequiredSpell() == reqSpell)
|
||||
{
|
||||
//player has item equipped that require specialty. Not allow to unlearn, player has to unequip first
|
||||
TC_LOG_DEBUG("scripts", "player attempt to unlearn spell %u, but item %u is equipped.", reqSpell, item->GetEntry());
|
||||
|
||||
@@ -1,422 +0,0 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "DB2FileLoader.h"
|
||||
|
||||
DB2FileLoader::DB2FileLoader()
|
||||
{
|
||||
recordSize = 0;
|
||||
recordCount = 0;
|
||||
fieldCount = 0;
|
||||
stringSize = 0;
|
||||
stringTable = nullptr;
|
||||
|
||||
tableHash = 0;
|
||||
build = 0;
|
||||
|
||||
unk1 = 0;
|
||||
minIndex = 0;
|
||||
maxIndex = 0;
|
||||
locale = 0;
|
||||
unk5 = 0;
|
||||
|
||||
data = nullptr;
|
||||
fieldsOffset = nullptr;
|
||||
}
|
||||
|
||||
bool DB2FileLoader::Load(char const* filename, char const* fmt)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
delete [] data;
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
FILE* f = fopen(filename, "rb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
uint32 header;
|
||||
if (fread(&header, 4, 1, f) != 1) // Signature
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(header);
|
||||
|
||||
if (header != 0x32424457)
|
||||
{
|
||||
fclose(f);
|
||||
return false; //'WDB2'
|
||||
}
|
||||
|
||||
if (fread(&recordCount, 4, 1, f) != 1) // Number of records
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(recordCount);
|
||||
|
||||
if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(fieldCount);
|
||||
|
||||
if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(recordSize);
|
||||
|
||||
if (fread(&stringSize, 4, 1, f) != 1) // String size
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(stringSize);
|
||||
|
||||
/* NEW WDB2 FIELDS*/
|
||||
if (fread(&tableHash, 4, 1, f) != 1) // Table hash
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(tableHash);
|
||||
|
||||
if (fread(&build, 4, 1, f) != 1) // Build
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(build);
|
||||
|
||||
if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(unk1);
|
||||
|
||||
if (build > 12880)
|
||||
{
|
||||
if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
EndianConvert(minIndex);
|
||||
|
||||
if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
EndianConvert(maxIndex);
|
||||
|
||||
if (fread(&locale, 4, 1, f) != 1) // Locales
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
EndianConvert(locale);
|
||||
|
||||
if (fread(&unk5, 4, 1, f) != 1) // Unknown WDB2
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
EndianConvert(unk5);
|
||||
}
|
||||
|
||||
if (maxIndex != 0)
|
||||
{
|
||||
int32 diff = maxIndex - minIndex + 1;
|
||||
fseek(f, diff * 4 + diff * 2, SEEK_CUR); // diff * 4: an index for rows, diff * 2: a memory allocation bank
|
||||
}
|
||||
|
||||
fieldsOffset = new uint32[fieldCount];
|
||||
fieldsOffset[0] = 0;
|
||||
for (uint32 i = 1; i < fieldCount; i++)
|
||||
{
|
||||
fieldsOffset[i] = fieldsOffset[i - 1];
|
||||
if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X')
|
||||
fieldsOffset[i] += 1;
|
||||
else
|
||||
fieldsOffset[i] += 4;
|
||||
}
|
||||
|
||||
data = new unsigned char[recordSize*recordCount+stringSize];
|
||||
stringTable = data + recordSize*recordCount;
|
||||
|
||||
if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
DB2FileLoader::~DB2FileLoader()
|
||||
{
|
||||
if (data)
|
||||
delete [] data;
|
||||
if (fieldsOffset)
|
||||
delete [] fieldsOffset;
|
||||
}
|
||||
|
||||
DB2FileLoader::Record DB2FileLoader::getRecord(size_t id)
|
||||
{
|
||||
assert(data);
|
||||
return Record(*this, data + id*recordSize);
|
||||
}
|
||||
|
||||
uint32 DB2FileLoader::GetFormatRecordSize(char const* format, int32* index_pos)
|
||||
{
|
||||
uint32 recordsize = 0;
|
||||
int32 i = -1;
|
||||
for (uint32 x=0; format[x]; ++x)
|
||||
{
|
||||
switch (format[x])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
case FT_INT:
|
||||
recordsize += 4;
|
||||
break;
|
||||
case FT_STRING:
|
||||
recordsize += sizeof(char*);
|
||||
break;
|
||||
case FT_SORT:
|
||||
i = x;
|
||||
break;
|
||||
case FT_IND:
|
||||
i = x;
|
||||
recordsize += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
recordsize += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index_pos)
|
||||
*index_pos = i;
|
||||
|
||||
return recordsize;
|
||||
}
|
||||
|
||||
uint32 DB2FileLoader::GetFormatStringsFields(char const* format)
|
||||
{
|
||||
uint32 stringfields = 0;
|
||||
for (uint32 x=0; format[x]; ++x)
|
||||
if (format[x] == FT_STRING)
|
||||
++stringfields;
|
||||
|
||||
return stringfields;
|
||||
}
|
||||
|
||||
char* DB2FileLoader::AutoProduceData(char const* format, uint32& records, char**& indexTable)
|
||||
{
|
||||
typedef char * ptr;
|
||||
if (strlen(format) != fieldCount)
|
||||
return nullptr;
|
||||
|
||||
//get struct size and index pos
|
||||
int32 i;
|
||||
uint32 recordsize=GetFormatRecordSize(format, &i);
|
||||
|
||||
if (i >= 0)
|
||||
{
|
||||
uint32 maxi = 0;
|
||||
//find max index
|
||||
for (uint32 y = 0; y < recordCount; y++)
|
||||
{
|
||||
uint32 ind=getRecord(y).getUInt(i);
|
||||
if (ind>maxi)
|
||||
maxi = ind;
|
||||
}
|
||||
|
||||
++maxi;
|
||||
records = maxi;
|
||||
indexTable = new ptr[maxi];
|
||||
memset(indexTable, 0, maxi * sizeof(ptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
records = recordCount;
|
||||
indexTable = new ptr[recordCount];
|
||||
}
|
||||
|
||||
char* dataTable = new char[recordCount * recordsize];
|
||||
|
||||
uint32 offset=0;
|
||||
|
||||
for (uint32 y =0; y < recordCount; y++)
|
||||
{
|
||||
if (i>=0)
|
||||
{
|
||||
indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
|
||||
}
|
||||
else
|
||||
indexTable[y] = &dataTable[offset];
|
||||
|
||||
for (uint32 x = 0; x < fieldCount; x++)
|
||||
{
|
||||
switch (format[x])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
*((float*)(&dataTable[offset])) = getRecord(y).getFloat(x);
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
*((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x);
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
*((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x);
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
*((char**)(&dataTable[offset])) = nullptr; // will be replaces non-empty or "" strings in AutoProduceStrings
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
static char const* const nullStr = "";
|
||||
|
||||
char* DB2FileLoader::AutoProduceStringsArrayHolders(char const* format, char* dataTable)
|
||||
{
|
||||
if (strlen(format) != fieldCount)
|
||||
return nullptr;
|
||||
|
||||
// we store flat holders pool as single memory block
|
||||
size_t stringFields = GetFormatStringsFields(format);
|
||||
// each string field at load have array of string for each locale
|
||||
size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES;
|
||||
size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize;
|
||||
size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount;
|
||||
|
||||
char* stringHoldersPool = new char[stringHoldersPoolSize];
|
||||
|
||||
// DB2 strings expected to have at least empty string
|
||||
for (size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
|
||||
((char const**)stringHoldersPool)[i] = nullStr;
|
||||
|
||||
uint32 offset=0;
|
||||
|
||||
// assign string holders to string field slots
|
||||
for (uint32 y = 0; y < recordCount; y++)
|
||||
{
|
||||
uint32 stringFieldNum = 0;
|
||||
|
||||
for (uint32 x = 0; x < fieldCount; x++)
|
||||
switch (format[x])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
// init db2 string field slots by pointers to string holders
|
||||
char const*** slot = (char const***)(&dataTable[offset]);
|
||||
*slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringHolderSize*stringFieldNum]);
|
||||
++stringFieldNum;
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
case FT_NA:
|
||||
case FT_NA_BYTE:
|
||||
case FT_SORT:
|
||||
break;
|
||||
default:
|
||||
assert(false && "unknown format character");
|
||||
}
|
||||
}
|
||||
|
||||
//send as char* for store in char* pool list for free at unload
|
||||
return stringHoldersPool;
|
||||
}
|
||||
|
||||
char* DB2FileLoader::AutoProduceStrings(char const* format, char* dataTable, uint32 locale)
|
||||
{
|
||||
if (strlen(format) != fieldCount)
|
||||
return nullptr;
|
||||
|
||||
char* stringPool= new char[stringSize];
|
||||
memcpy(stringPool, stringTable, stringSize);
|
||||
|
||||
uint32 offset = 0;
|
||||
|
||||
for (uint32 y =0; y < recordCount; y++)
|
||||
{
|
||||
for (uint32 x = 0; x < fieldCount; x++)
|
||||
switch (format[x])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
// fill only not filled entries
|
||||
LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]);
|
||||
if (db2str->Str[locale] == nullStr)
|
||||
{
|
||||
const char * st = getRecord(y).getString(x);
|
||||
db2str->Str[locale] = stringPool + (st - (char const*)stringTable);
|
||||
}
|
||||
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringPool;
|
||||
}
|
||||
@@ -0,0 +1,651 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "DB2StorageLoader.h"
|
||||
#include "Database/Implementation/HotfixDatabase.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
|
||||
DB2FileLoader::DB2FileLoader()
|
||||
{
|
||||
recordSize = 0;
|
||||
recordCount = 0;
|
||||
fieldCount = 0;
|
||||
stringSize = 0;
|
||||
stringTable = nullptr;
|
||||
|
||||
tableHash = 0;
|
||||
build = 0;
|
||||
|
||||
unk1 = 0;
|
||||
minIndex = 0;
|
||||
maxIndex = 0;
|
||||
locale = 0;
|
||||
unk5 = 0;
|
||||
|
||||
data = nullptr;
|
||||
fieldsOffset = nullptr;
|
||||
}
|
||||
|
||||
bool DB2FileLoader::Load(char const* filename, char const* fmt)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
delete [] data;
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
FILE* f = fopen(filename, "rb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
uint32 header;
|
||||
if (fread(&header, 4, 1, f) != 1) // Signature
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(header);
|
||||
|
||||
if (header != 0x32424457)
|
||||
{
|
||||
fclose(f);
|
||||
return false; //'WDB2'
|
||||
}
|
||||
|
||||
if (fread(&recordCount, 4, 1, f) != 1) // Number of records
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(recordCount);
|
||||
|
||||
if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(fieldCount);
|
||||
|
||||
if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(recordSize);
|
||||
|
||||
if (fread(&stringSize, 4, 1, f) != 1) // String size
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(stringSize);
|
||||
|
||||
/* NEW WDB2 FIELDS*/
|
||||
if (fread(&tableHash, 4, 1, f) != 1) // Table hash
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(tableHash);
|
||||
|
||||
if (fread(&build, 4, 1, f) != 1) // Build
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(build);
|
||||
|
||||
if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EndianConvert(unk1);
|
||||
|
||||
if (build > 12880)
|
||||
{
|
||||
if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
EndianConvert(minIndex);
|
||||
|
||||
if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
EndianConvert(maxIndex);
|
||||
|
||||
if (fread(&locale, 4, 1, f) != 1) // Locales
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
EndianConvert(locale);
|
||||
|
||||
if (fread(&unk5, 4, 1, f) != 1) // Unknown WDB2
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
EndianConvert(unk5);
|
||||
}
|
||||
|
||||
if (maxIndex != 0)
|
||||
{
|
||||
int32 diff = maxIndex - minIndex + 1;
|
||||
fseek(f, diff * 4 + diff * 2, SEEK_CUR); // diff * 4: an index for rows, diff * 2: a memory allocation bank
|
||||
}
|
||||
|
||||
fieldsOffset = new uint32[fieldCount];
|
||||
fieldsOffset[0] = 0;
|
||||
for (uint32 i = 1; i < fieldCount; i++)
|
||||
{
|
||||
fieldsOffset[i] = fieldsOffset[i - 1];
|
||||
if (fmt[i - 1] == 'b')
|
||||
fieldsOffset[i] += 1;
|
||||
else
|
||||
fieldsOffset[i] += 4;
|
||||
}
|
||||
|
||||
data = new unsigned char[recordSize * recordCount + stringSize];
|
||||
stringTable = data + recordSize * recordCount;
|
||||
|
||||
if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
|
||||
{
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
DB2FileLoader::~DB2FileLoader()
|
||||
{
|
||||
if (data)
|
||||
delete [] data;
|
||||
if (fieldsOffset)
|
||||
delete [] fieldsOffset;
|
||||
}
|
||||
|
||||
DB2FileLoader::Record DB2FileLoader::getRecord(size_t id)
|
||||
{
|
||||
assert(data);
|
||||
return Record(*this, data + id*recordSize);
|
||||
}
|
||||
|
||||
uint32 DB2FileLoader::GetFormatRecordSize(char const* format, int32* index_pos)
|
||||
{
|
||||
uint32 recordsize = 0;
|
||||
int32 i = -1;
|
||||
for (uint32 x=0; format[x]; ++x)
|
||||
{
|
||||
switch (format[x])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
case FT_INT:
|
||||
recordsize += 4;
|
||||
break;
|
||||
case FT_STRING:
|
||||
recordsize += sizeof(char*);
|
||||
break;
|
||||
case FT_SORT:
|
||||
i = x;
|
||||
break;
|
||||
case FT_IND:
|
||||
i = x;
|
||||
recordsize += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
recordsize += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index_pos)
|
||||
*index_pos = i;
|
||||
|
||||
return recordsize;
|
||||
}
|
||||
|
||||
uint32 DB2FileLoader::GetFormatStringFieldCount(char const* format)
|
||||
{
|
||||
uint32 stringfields = 0;
|
||||
for (uint32 x = 0; format[x]; ++x)
|
||||
if (format[x] == FT_STRING)
|
||||
++stringfields;
|
||||
|
||||
return stringfields;
|
||||
}
|
||||
|
||||
char* DB2FileLoader::AutoProduceData(char const* format, uint32& records, char**& indexTable)
|
||||
{
|
||||
typedef char * ptr;
|
||||
if (strlen(format) != fieldCount)
|
||||
return nullptr;
|
||||
|
||||
//get struct size and index pos
|
||||
int32 indexField;
|
||||
uint32 recordsize = GetFormatRecordSize(format, &indexField);
|
||||
|
||||
if (indexField >= 0)
|
||||
{
|
||||
uint32 maxi = 0;
|
||||
//find max index
|
||||
for (uint32 y = 0; y < recordCount; y++)
|
||||
{
|
||||
uint32 ind = getRecord(y).getUInt(indexField);
|
||||
if (ind > maxi)
|
||||
maxi = ind;
|
||||
}
|
||||
|
||||
++maxi;
|
||||
records = maxi;
|
||||
indexTable = new ptr[maxi];
|
||||
memset(indexTable, 0, maxi * sizeof(ptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
records = recordCount;
|
||||
indexTable = new ptr[recordCount];
|
||||
}
|
||||
|
||||
char* dataTable = new char[recordCount * recordsize];
|
||||
|
||||
uint32 offset = 0;
|
||||
|
||||
for (uint32 y = 0; y < recordCount; y++)
|
||||
{
|
||||
if (indexField >= 0)
|
||||
indexTable[getRecord(y).getUInt(indexField)] = &dataTable[offset];
|
||||
else
|
||||
indexTable[y] = &dataTable[offset];
|
||||
|
||||
for (uint32 x = 0; x < fieldCount; x++)
|
||||
{
|
||||
switch (format[x])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
*((float*)(&dataTable[offset])) = getRecord(y).getFloat(x);
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
*((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x);
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
*((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x);
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
*((char**)(&dataTable[offset])) = nullptr; // will be replaces non-empty or "" strings in AutoProduceStrings
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
static char const* const nullStr = "";
|
||||
|
||||
char* DB2FileLoader::AutoProduceStringsArrayHolders(char const* format, char* dataTable)
|
||||
{
|
||||
if (strlen(format) != fieldCount)
|
||||
return nullptr;
|
||||
|
||||
// we store flat holders pool as single memory block
|
||||
size_t stringFields = GetFormatStringFieldCount(format);
|
||||
if (!stringFields)
|
||||
return nullptr;
|
||||
|
||||
// each string field at load have array of string for each locale
|
||||
size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES;
|
||||
size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize;
|
||||
size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount;
|
||||
|
||||
char* stringHoldersPool = new char[stringHoldersPoolSize];
|
||||
|
||||
// DB2 strings expected to have at least empty string
|
||||
for (size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
|
||||
((char const**)stringHoldersPool)[i] = nullStr;
|
||||
|
||||
uint32 offset = 0;
|
||||
|
||||
// assign string holders to string field slots
|
||||
for (uint32 y = 0; y < recordCount; y++)
|
||||
{
|
||||
uint32 stringFieldNum = 0;
|
||||
|
||||
for (uint32 x = 0; x < fieldCount; x++)
|
||||
{
|
||||
switch (format[x])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
// init db2 string field slots by pointers to string holders
|
||||
char const*** slot = (char const***)(&dataTable[offset]);
|
||||
*slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringHolderSize * stringFieldNum]);
|
||||
++stringFieldNum;
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(false, "unknown format character %c", format[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//send as char* for store in char* pool list for free at unload
|
||||
return stringHoldersPool;
|
||||
}
|
||||
|
||||
char* DB2FileLoader::AutoProduceStrings(char const* format, char* dataTable, uint32 locale)
|
||||
{
|
||||
if (strlen(format) != fieldCount)
|
||||
return nullptr;
|
||||
|
||||
char* stringPool = new char[stringSize];
|
||||
memcpy(stringPool, stringTable, stringSize);
|
||||
|
||||
uint32 offset = 0;
|
||||
|
||||
for (uint32 y = 0; y < recordCount; y++)
|
||||
{
|
||||
for (uint32 x = 0; x < fieldCount; x++)
|
||||
{
|
||||
switch (format[x])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
// fill only not filled entries
|
||||
LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]);
|
||||
if (db2str->Str[locale] == nullStr)
|
||||
{
|
||||
const char* st = getRecord(y).getString(x);
|
||||
db2str->Str[locale] = stringPool + (st - (const char*)stringTable);
|
||||
}
|
||||
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringPool;
|
||||
}
|
||||
|
||||
char* DB2DatabaseLoader::Load(const char* format, int32 preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::list<char*>& stringPool)
|
||||
{
|
||||
// Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format
|
||||
PreparedQueryResult result = HotfixDatabase.Query(HotfixDatabase.GetPreparedStatement(HotfixDatabaseStatements(preparedStatement)));
|
||||
if (!result)
|
||||
return nullptr;
|
||||
|
||||
uint32 const fieldCount = strlen(format);
|
||||
if (fieldCount != result->GetFieldCount())
|
||||
return nullptr;
|
||||
|
||||
// get struct size and index pos
|
||||
int32 indexField;
|
||||
uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField);
|
||||
|
||||
// we store flat holders pool as single memory block
|
||||
size_t stringFields = DB2FileLoader::GetFormatStringFieldCount(format);
|
||||
|
||||
// each string field at load have array of string for each locale
|
||||
size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES;
|
||||
size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize;
|
||||
|
||||
if (stringFields)
|
||||
{
|
||||
size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount();
|
||||
stringHolders = new char[stringHoldersPoolSize];
|
||||
|
||||
// DB2 strings expected to have at least empty string
|
||||
for (size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
|
||||
((char const**)stringHolders)[i] = nullStr;
|
||||
}
|
||||
else
|
||||
stringHolders = nullptr;
|
||||
|
||||
// Resize index table
|
||||
// database query *MUST* contain ORDER BY `index_field` DESC clause
|
||||
uint32 indexTableSize;
|
||||
if (indexField >= 0)
|
||||
{
|
||||
indexTableSize = (*result)[indexField].GetUInt32() + 1;
|
||||
if (indexTableSize < records)
|
||||
indexTableSize = records;
|
||||
}
|
||||
else
|
||||
indexTableSize = records + result->GetRowCount();
|
||||
|
||||
if (indexTableSize > records)
|
||||
{
|
||||
char** tmpIdxTable = new char* [indexTableSize];
|
||||
memset(tmpIdxTable, 0, indexTableSize * sizeof(char*));
|
||||
memcpy(tmpIdxTable, indexTable, records * sizeof(char*));
|
||||
delete[] indexTable;
|
||||
indexTable = tmpIdxTable;
|
||||
}
|
||||
|
||||
char* tempDataTable = new char[result->GetRowCount() * recordSize];
|
||||
uint32* newIndexes = new uint32[result->GetRowCount()];
|
||||
uint32 rec = 0;
|
||||
uint32 newRecords = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 offset = 0;
|
||||
uint32 stringFieldNumInRecord = 0;
|
||||
|
||||
uint32 indexValue;
|
||||
if (indexField >= 0)
|
||||
indexValue = fields[indexField].GetUInt32();
|
||||
else
|
||||
indexValue = records + rec;
|
||||
|
||||
// Attempt to overwrite existing data
|
||||
char* dataValue = indexTable[indexValue];
|
||||
if (!dataValue)
|
||||
{
|
||||
newIndexes[newRecords] = indexValue;
|
||||
dataValue = &tempDataTable[newRecords++ * recordSize];
|
||||
}
|
||||
|
||||
for (uint32 f = 0; f < fieldCount; f++)
|
||||
{
|
||||
switch (format[f])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
*((float*)(&dataValue[offset])) = fields[f].GetFloat();
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
*((int32*)(&dataValue[offset])) = fields[f].GetInt32();
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
*((int8*)(&dataValue[offset])) = fields[f].GetInt8();
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
LocalizedString** slot = (LocalizedString**)(&dataValue[offset]);
|
||||
*slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringHolderSize * stringFieldNumInRecord]);
|
||||
ASSERT(*slot);
|
||||
|
||||
// Value in database in main table field must be for enUS locale
|
||||
if (char* str = AddLocaleString(*slot, LOCALE_enUS, fields[f].GetString()))
|
||||
stringPool.push_back(str);
|
||||
|
||||
++stringFieldNumInRecord;
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(offset == recordSize);
|
||||
++rec;
|
||||
} while (result->NextRow());
|
||||
|
||||
if (!newRecords)
|
||||
{
|
||||
delete[] tempDataTable;
|
||||
delete[] newIndexes;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Compact new data table to only contain new records not previously loaded from file
|
||||
char* dataTable = new char[newRecords * recordSize];
|
||||
memcpy(dataTable, tempDataTable, newRecords * recordSize);
|
||||
|
||||
// insert new records to index table
|
||||
for (uint32 i = 0; i < newRecords; ++i)
|
||||
indexTable[newIndexes[i]] = &dataTable[i * recordSize];
|
||||
|
||||
delete[] tempDataTable;
|
||||
delete[] newIndexes;
|
||||
|
||||
records = indexTableSize;
|
||||
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
void DB2DatabaseLoader::LoadStrings(const char* format, int32 preparedStatement, uint32 locale, char**& indexTable, std::list<char*>& stringPool)
|
||||
{
|
||||
PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(HotfixDatabaseStatements(preparedStatement));
|
||||
stmt->setString(0, localeNames[locale]);
|
||||
PreparedQueryResult result = HotfixDatabase.Query(stmt);
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
size_t stringFields = DB2FileLoader::GetFormatStringFieldCount(format);
|
||||
if (result->GetFieldCount() != stringFields + 1 /*ID*/)
|
||||
return;
|
||||
|
||||
uint32 const fieldCount = strlen(format);
|
||||
int32 indexField;
|
||||
uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField);
|
||||
ASSERT(indexField >= 0, "DB2Storage must be indexed to load localized strings");
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 offset = 0;
|
||||
uint32 stringFieldNumInRecord = 0;
|
||||
uint32 indexValue = fields[0].GetUInt32();
|
||||
|
||||
// Attempt to overwrite existing data
|
||||
if (char* dataValue = indexTable[indexValue])
|
||||
{
|
||||
for (uint32 x = 0; x < fieldCount; x++)
|
||||
{
|
||||
switch (format[x])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
// fill only not filled entries
|
||||
LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]);
|
||||
if (db2str->Str[locale] == nullStr)
|
||||
if (char* str = AddLocaleString(db2str, locale, fields[1 + stringFieldNumInRecord].GetString()))
|
||||
stringPool.push_back(str);
|
||||
|
||||
++stringFieldNumInRecord;
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(offset == recordSize);
|
||||
}
|
||||
else
|
||||
TC_LOG_ERROR("sql.sql", "Hotfix locale table for storage %s references row that does not exist %u!", _storageName.c_str(), indexValue);
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
char* DB2DatabaseLoader::AddLocaleString(LocalizedString* holder, uint32 locale, std::string const& value)
|
||||
{
|
||||
if (!value.empty())
|
||||
{
|
||||
std::size_t existingLength = strlen(holder->Str[locale]);
|
||||
if (existingLength >= value.length())
|
||||
{
|
||||
// Reuse existing storage if there is enough space
|
||||
char* str = const_cast<char*>(holder->Str[locale]);
|
||||
memcpy(str, value.c_str(), value.length());
|
||||
str[value.length()] = '\0';
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* str = new char[value.length() + 1];
|
||||
memcpy(str, value.c_str(), value.length());
|
||||
str[value.length()] = '\0';
|
||||
holder->Str[locale] = str;
|
||||
return str;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
+15
-1
@@ -21,6 +21,7 @@
|
||||
#include "Define.h"
|
||||
#include "Utilities/ByteConverter.h"
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
|
||||
class TC_SHARED_API DB2FileLoader
|
||||
{
|
||||
@@ -82,7 +83,7 @@ class TC_SHARED_API DB2FileLoader
|
||||
char* AutoProduceStringsArrayHolders(char const* fmt, char* dataTable);
|
||||
char* AutoProduceStrings(char const* fmt, char* dataTable, uint32 locale);
|
||||
static uint32 GetFormatRecordSize(char const* format, int32* index_pos = nullptr);
|
||||
static uint32 GetFormatStringsFields(char const* format);
|
||||
static uint32 GetFormatStringFieldCount(const char* format);
|
||||
private:
|
||||
|
||||
uint32 recordSize;
|
||||
@@ -104,4 +105,17 @@ private:
|
||||
int unk5; // WDB2
|
||||
};
|
||||
|
||||
class DB2DatabaseLoader
|
||||
{
|
||||
public:
|
||||
explicit DB2DatabaseLoader(std::string const& storageName) : _storageName(storageName) { }
|
||||
|
||||
char* Load(const char* format, int32 preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::list<char*>& stringPool);
|
||||
void LoadStrings(const char* format, int32 preparedStatement, uint32 locale, char**& indexTable, std::list<char*>& stringPool);
|
||||
static char* AddLocaleString(LocalizedString* holder, uint32 locale, std::string const& value);
|
||||
|
||||
private:
|
||||
std::string _storageName;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -18,8 +18,9 @@
|
||||
#ifndef DB2STORE_H
|
||||
#define DB2STORE_H
|
||||
|
||||
#include "DB2StorageLoader.h"
|
||||
#include "DBStorageIterator.h"
|
||||
#include "Common.h"
|
||||
#include "DB2FileLoader.h"
|
||||
#include "Errors.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include <vector>
|
||||
@@ -30,203 +31,180 @@ class DB2StorageBase
|
||||
public:
|
||||
virtual ~DB2StorageBase() { }
|
||||
|
||||
uint32 GetHash() const { return tableHash; }
|
||||
uint32 GetHash() const { return _tableHash; }
|
||||
|
||||
virtual bool HasRecord(uint32 id) const = 0;
|
||||
|
||||
virtual void WriteRecord(uint32 id, LocaleConstant localeConstant, ByteBuffer& buffer) const = 0;
|
||||
virtual void WriteRecord(uint32 id, uint32 locale, ByteBuffer& buffer) const = 0;
|
||||
|
||||
virtual void EraseRecord(uint32 id) = 0;
|
||||
|
||||
protected:
|
||||
uint32 tableHash;
|
||||
uint32 _tableHash;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class DB2Storage;
|
||||
|
||||
template<class T>
|
||||
bool DB2StorageHasEntry(DB2Storage<T> const& store, uint32 id)
|
||||
{
|
||||
return store.LookupEntry(id) != nullptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void WriteDB2RecordToPacket(DB2Storage<T> const& store, uint32 id, uint32 locale, ByteBuffer& buffer)
|
||||
{
|
||||
uint8 const* entry = (uint8 const*)store.LookupEntry(id);
|
||||
ASSERT(entry);
|
||||
|
||||
std::string format = store.GetFormat();
|
||||
for (uint32 i = 0; i < format.length(); ++i)
|
||||
{
|
||||
switch (format[i])
|
||||
{
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
buffer << *(uint32*)entry;
|
||||
entry += 4;
|
||||
break;
|
||||
case FT_FLOAT:
|
||||
buffer << *(float*)entry;
|
||||
entry += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
buffer << *(uint8*)entry;
|
||||
entry += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
LocalizedString* locStr = *(LocalizedString**)entry;
|
||||
if (locStr->Str[locale][0] == '\0')
|
||||
locale = 0;
|
||||
|
||||
char const* str = locStr->Str[locale];
|
||||
size_t len = strlen(str);
|
||||
buffer << uint16(len);
|
||||
if (len)
|
||||
buffer << str;
|
||||
entry += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
case FT_NA:
|
||||
case FT_SORT:
|
||||
buffer << uint32(0);
|
||||
break;
|
||||
case FT_NA_BYTE:
|
||||
buffer << uint8(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
class DB2Storage : public DB2StorageBase
|
||||
{
|
||||
typedef std::vector<char*> StringPoolList;
|
||||
typedef std::vector<T*> DataTableEx;
|
||||
typedef bool(*EntryChecker)(DB2Storage<T> const&, uint32);
|
||||
typedef void(*PacketWriter)(DB2Storage<T> const&, uint32, LocaleConstant, ByteBuffer&);
|
||||
typedef std::list<char*> StringPoolList;
|
||||
public:
|
||||
DB2Storage(char const* f, EntryChecker checkEntry = nullptr, PacketWriter writePacket = nullptr) :
|
||||
nCount(0), fieldCount(0), fmt(f), m_dataTable(nullptr)
|
||||
typedef DBStorageIterator<T> iterator;
|
||||
|
||||
DB2Storage(char const* fileName, char const* format, uint32 preparedStmtIndex = -1)
|
||||
: _fileName(fileName), _indexTableSize(0), _fieldCount(0), _format(format), _dataTable(nullptr), _dataTableEx(nullptr), _hotfixStatement(preparedStmtIndex)
|
||||
{
|
||||
indexTable.asT = nullptr;
|
||||
CheckEntry = checkEntry ? checkEntry : (EntryChecker)&DB2StorageHasEntry<T>;
|
||||
WritePacket = writePacket ? writePacket : (PacketWriter)&WriteDB2RecordToPacket<T>;
|
||||
_indexTable.AsT = nullptr;
|
||||
}
|
||||
|
||||
~DB2Storage() { Clear(); }
|
||||
|
||||
bool HasRecord(uint32 id) const { return CheckEntry(*this, id); }
|
||||
T const* LookupEntry(uint32 id) const { return (id >= nCount) ? nullptr : indexTable.asT[id]; }
|
||||
uint32 GetNumRows() const { return nCount; }
|
||||
char const* GetFormat() const { return fmt; }
|
||||
uint32 GetFieldCount() const { return fieldCount; }
|
||||
void WriteRecord(uint32 id, LocaleConstant localeConstant, ByteBuffer& buffer) const
|
||||
~DB2Storage()
|
||||
{
|
||||
WritePacket(*this, id, localeConstant, buffer);
|
||||
delete[] reinterpret_cast<char*>(_indexTable.AsT);
|
||||
delete[] reinterpret_cast<char*>(_dataTable);
|
||||
delete[] reinterpret_cast<char*>(_dataTableEx);
|
||||
for (char* stringPool : _stringPoolList)
|
||||
delete[] stringPool;
|
||||
}
|
||||
|
||||
T* CreateEntry(uint32 id, bool evenIfExists = false)
|
||||
bool HasRecord(uint32 id) const override { return id < _indexTableSize && _indexTable.AsT[id] != nullptr; }
|
||||
void WriteRecord(uint32 id, uint32 locale, ByteBuffer& buffer) const override
|
||||
{
|
||||
if (evenIfExists && LookupEntry(id))
|
||||
return nullptr;
|
||||
ASSERT(id < _indexTableSize);
|
||||
char const* entry = _indexTable.AsChar[id];
|
||||
ASSERT(entry);
|
||||
|
||||
if (id >= nCount)
|
||||
std::size_t fields = strlen(_format);
|
||||
for (uint32 i = 0; i < fields; ++i)
|
||||
{
|
||||
// reallocate index table
|
||||
char** tmpIdxTable = new char*[id + 1];
|
||||
memset(tmpIdxTable, 0, (id + 1) * sizeof(char*));
|
||||
memcpy(tmpIdxTable, indexTable.asChar, nCount * sizeof(char*));
|
||||
delete[] reinterpret_cast<char*>(indexTable.asT);
|
||||
nCount = id + 1;
|
||||
indexTable.asChar = tmpIdxTable;
|
||||
}
|
||||
switch (_format[i])
|
||||
{
|
||||
case FT_IND:
|
||||
case FT_INT:
|
||||
buffer << *(uint32*)entry;
|
||||
entry += 4;
|
||||
break;
|
||||
case FT_FLOAT:
|
||||
buffer << *(float*)entry;
|
||||
entry += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
buffer << *(uint8*)entry;
|
||||
entry += 1;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
LocalizedString* locStr = *(LocalizedString**)entry;
|
||||
if (locStr->Str[locale][0] == '\0')
|
||||
locale = 0;
|
||||
|
||||
T* entryDst = new T;
|
||||
m_dataTableEx.push_back(entryDst);
|
||||
indexTable.asT[id] = entryDst;
|
||||
return entryDst;
|
||||
char const* str = locStr->Str[locale];
|
||||
std::size_t len = strlen(str);
|
||||
buffer << uint16(len ? len + 1 : 0);
|
||||
if (len)
|
||||
{
|
||||
buffer.append(str, len);
|
||||
buffer << uint8(0);
|
||||
}
|
||||
entry += sizeof(LocalizedString*);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EraseEntry(uint32 id) { indexTable.asT[id] = nullptr; }
|
||||
void EraseRecord(uint32 id) override { if (id < _indexTableSize) _indexTable.AsT[id] = nullptr; }
|
||||
|
||||
bool Load(char const* fn, LocaleConstant localeConstant)
|
||||
T const* LookupEntry(uint32 id) const { return (id >= _indexTableSize) ? nullptr : _indexTable.AsT[id]; }
|
||||
std::string const& GetFileName() const { return _fileName; }
|
||||
uint32 GetNumRows() const { return _indexTableSize; }
|
||||
char const* GetFormat() const { return _format; }
|
||||
uint32 GetFieldCount() const { return _fieldCount; }
|
||||
|
||||
bool Load(std::string const& path, uint32 locale)
|
||||
{
|
||||
DB2FileLoader db2;
|
||||
// Check if load was sucessful, only then continue
|
||||
if (!db2.Load(fn, fmt))
|
||||
// Check if load was successful, only then continue
|
||||
if (!db2.Load((path + _fileName).c_str(), _format))
|
||||
return false;
|
||||
|
||||
fieldCount = db2.GetCols();
|
||||
tableHash = db2.GetHash();
|
||||
_fieldCount = db2.GetCols();
|
||||
_tableHash = db2.GetHash();
|
||||
|
||||
// load raw non-string data
|
||||
m_dataTable = reinterpret_cast<T*>(db2.AutoProduceData(fmt, nCount, indexTable.asChar));
|
||||
_dataTable = reinterpret_cast<T*>(db2.AutoProduceData(_format, _indexTableSize, _indexTable.AsChar));
|
||||
|
||||
// create string holders for loaded string fields
|
||||
m_stringPoolList.push_back(db2.AutoProduceStringsArrayHolders(fmt, (char*)m_dataTable));
|
||||
if (char* stringHolders = db2.AutoProduceStringsArrayHolders(_format, (char*)_dataTable))
|
||||
{
|
||||
_stringPoolList.push_back(stringHolders);
|
||||
|
||||
// load strings from dbc data
|
||||
m_stringPoolList.push_back(db2.AutoProduceStrings(fmt, (char*)m_dataTable, localeConstant));
|
||||
// load strings from db2 data
|
||||
if (char* stringBlock = db2.AutoProduceStrings(_format, (char*)_dataTable, locale))
|
||||
_stringPoolList.push_back(stringBlock);
|
||||
}
|
||||
|
||||
// error in dbc file at loading if nullptr
|
||||
return indexTable.asT != nullptr;
|
||||
// error in db2 file at loading if nullptr
|
||||
return _indexTable.AsT != nullptr;
|
||||
}
|
||||
|
||||
bool LoadStringsFrom(char const* fn, uint32 locale)
|
||||
bool LoadStringsFrom(std::string const& path, uint32 locale)
|
||||
{
|
||||
// DBC must be already loaded using Load
|
||||
if (!indexTable.asT)
|
||||
// DB2 must be already loaded using Load
|
||||
if (!_indexTable.AsT)
|
||||
return false;
|
||||
|
||||
DB2FileLoader db2;
|
||||
// Check if load was successful, only then continue
|
||||
if (!db2.Load(fn, fmt))
|
||||
if (!db2.Load((path + _fileName).c_str(), _format))
|
||||
return false;
|
||||
|
||||
// load strings from another locale dbc data
|
||||
m_stringPoolList.push_back(db2.AutoProduceStrings(fmt, (char*)m_dataTable, locale));
|
||||
|
||||
// load strings from another locale db2 data
|
||||
if (DB2FileLoader::GetFormatStringFieldCount(_format))
|
||||
if (char* stringBlock = db2.AutoProduceStrings(_format, (char*)_dataTable, locale))
|
||||
_stringPoolList.push_back(stringBlock);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
void LoadFromDB()
|
||||
{
|
||||
if (!indexTable.asT)
|
||||
if (_hotfixStatement == -1)
|
||||
return;
|
||||
|
||||
delete[] reinterpret_cast<char*>(indexTable.asT);
|
||||
indexTable.asT = nullptr;
|
||||
char* extraStringHolders = nullptr;
|
||||
if (char* dataTable = DB2DatabaseLoader(_fileName).Load(_format, _hotfixStatement, _indexTableSize, _indexTable.AsChar, extraStringHolders, _stringPoolList))
|
||||
_dataTableEx = reinterpret_cast<T*>(dataTable);
|
||||
|
||||
delete[] reinterpret_cast<char*>(m_dataTable);
|
||||
m_dataTable = nullptr;
|
||||
|
||||
for (typename DataTableEx::iterator itr = m_dataTableEx.begin(); itr != m_dataTableEx.end(); ++itr)
|
||||
delete *itr;
|
||||
m_dataTableEx.clear();
|
||||
|
||||
for (char* strings : m_stringPoolList)
|
||||
delete[] strings;
|
||||
m_stringPoolList.clear();
|
||||
|
||||
nCount = 0;
|
||||
if (extraStringHolders)
|
||||
_stringPoolList.push_back(extraStringHolders);
|
||||
}
|
||||
|
||||
EntryChecker CheckEntry;
|
||||
PacketWriter WritePacket;
|
||||
void LoadStringsFromDB(LocaleConstant locale)
|
||||
{
|
||||
if (_hotfixStatement == -1)
|
||||
return;
|
||||
|
||||
if (!DB2FileLoader::GetFormatStringFieldCount(_format))
|
||||
return;
|
||||
|
||||
DB2DatabaseLoader(_fileName).LoadStrings(_format, _hotfixStatement + 1, locale, _indexTable.AsChar, _stringPoolList);
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(_indexTable.AsT, _indexTableSize); }
|
||||
iterator end() { return iterator(_indexTable.AsT, _indexTableSize, _indexTableSize); }
|
||||
|
||||
private:
|
||||
uint32 nCount;
|
||||
uint32 fieldCount;
|
||||
char const* fmt;
|
||||
std::string _fileName;
|
||||
uint32 _indexTableSize;
|
||||
uint32 _fieldCount;
|
||||
char const* _format;
|
||||
union
|
||||
{
|
||||
T** asT;
|
||||
char** asChar;
|
||||
} indexTable;
|
||||
T* m_dataTable;
|
||||
DataTableEx m_dataTableEx;
|
||||
StringPoolList m_stringPoolList;
|
||||
T** AsT;
|
||||
char** AsChar;
|
||||
} _indexTable;
|
||||
T* _dataTable;
|
||||
T* _dataTableEx;
|
||||
StringPoolList _stringPoolList;
|
||||
int32 _hotfixStatement;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -565,7 +565,8 @@ bool StartDB()
|
||||
loader
|
||||
.AddDatabase(LoginDatabase, "Login")
|
||||
.AddDatabase(CharacterDatabase, "Character")
|
||||
.AddDatabase(WorldDatabase, "World");
|
||||
.AddDatabase(WorldDatabase, "World")
|
||||
.AddDatabase(HotfixDatabase, "Hotfix");
|
||||
|
||||
if (!loader.Load())
|
||||
return false;
|
||||
@@ -607,6 +608,7 @@ void StopDB()
|
||||
CharacterDatabase.Close();
|
||||
WorldDatabase.Close();
|
||||
LoginDatabase.Close();
|
||||
HotfixDatabase.Close();
|
||||
|
||||
MySQL::Library_End();
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ LogsDir = ""
|
||||
# Default: "127.0.0.1;3306;trinity;trinity;auth" - (LoginDatabaseInfo)
|
||||
# "127.0.0.1;3306;trinity;trinity;world" - (WorldDatabaseInfo)
|
||||
# "127.0.0.1;3306;trinity;trinity;characters" - (CharacterDatabaseInfo)
|
||||
# "127.0.0.1;3306;trinity;trinity;hotfixes" - (HotfixDatabaseInfo)
|
||||
#
|
||||
# Don't change hostname unless you are hosting mysql on a different machine, if you need help
|
||||
# with configuration allowing to connect from diferent machine than the one running server
|
||||
@@ -107,6 +108,7 @@ LogsDir = ""
|
||||
LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth"
|
||||
WorldDatabaseInfo = "127.0.0.1;3306;trinity;trinity;world"
|
||||
CharacterDatabaseInfo = "127.0.0.1;3306;trinity;trinity;characters"
|
||||
HotfixDatabaseInfo = "127.0.0.1;3306;trinity;trinity;hotfixes"
|
||||
|
||||
#
|
||||
# LoginDatabase.WorkerThreads
|
||||
@@ -118,10 +120,12 @@ CharacterDatabaseInfo = "127.0.0.1;3306;trinity;trinity;characters"
|
||||
# Default: 1 - (LoginDatabase.WorkerThreads)
|
||||
# 1 - (WorldDatabase.WorkerThreads)
|
||||
# 1 - (CharacterDatabase.WorkerThreads)
|
||||
# 1 - (HotfixDatabase.WorkerThreads)
|
||||
|
||||
LoginDatabase.WorkerThreads = 1
|
||||
WorldDatabase.WorkerThreads = 1
|
||||
CharacterDatabase.WorkerThreads = 1
|
||||
HotfixDatabase.WorkerThreads = 1
|
||||
|
||||
#
|
||||
# LoginDatabase.SynchThreads
|
||||
@@ -135,6 +139,7 @@ CharacterDatabase.WorkerThreads = 1
|
||||
LoginDatabase.SynchThreads = 1
|
||||
WorldDatabase.SynchThreads = 1
|
||||
CharacterDatabase.SynchThreads = 2
|
||||
HotfixDatabase.SynchThreads = 1
|
||||
|
||||
#
|
||||
# MaxPingTime
|
||||
@@ -1276,12 +1281,13 @@ BirthdayTime = 1222964635
|
||||
# DATABASE_LOGIN = 1, // Auth database
|
||||
# DATABASE_CHARACTER = 2, // Character database
|
||||
# DATABASE_WORLD = 4, // World database
|
||||
# DATABASE_HOTFIX = 8, // Hotfixes database
|
||||
#
|
||||
# Default: 7 - (All enabled)
|
||||
# Default: 15 - (All enabled)
|
||||
# 4 - (Enable world only)
|
||||
# 0 - (All disabled)
|
||||
# 0 - (All Disabled)
|
||||
|
||||
Updates.EnableDatabases = 7
|
||||
Updates.EnableDatabases = 15
|
||||
|
||||
#
|
||||
# Updates.AutoSetup
|
||||
|
||||
Reference in new issue
Block a user