Core/Player: Implement PvP Talents
This commit is contained in:
@@ -24,6 +24,8 @@ namespace Framework.Constants
|
|||||||
public const int MaxTalentTiers = 7;
|
public const int MaxTalentTiers = 7;
|
||||||
public const int MaxTalentColumns = 3;
|
public const int MaxTalentColumns = 3;
|
||||||
public const int MaxTalentRank = 5;
|
public const int MaxTalentRank = 5;
|
||||||
|
public const int MaxPvpTalentTiers = 6;
|
||||||
|
public const int MaxPvpTalentColumns = 3;
|
||||||
public const int MinSpecializationLevel = 10;
|
public const int MinSpecializationLevel = 10;
|
||||||
public const int MaxSpecializations = 4;
|
public const int MaxSpecializations = 4;
|
||||||
public const int MaxMasterySpells = 2;
|
public const int MaxMasterySpells = 2;
|
||||||
@@ -67,6 +69,7 @@ namespace Framework.Constants
|
|||||||
|
|
||||||
public const byte MaxHonorLevel = 50;
|
public const byte MaxHonorLevel = 50;
|
||||||
public const byte LevelMinHonor = 110;
|
public const byte LevelMinHonor = 110;
|
||||||
|
public const uint SpellPvpRulesEnabled = 134735;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct MoneyConstants
|
public struct MoneyConstants
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ namespace Framework.Constants
|
|||||||
ModRegenDuringCombat = 116,
|
ModRegenDuringCombat = 116,
|
||||||
ModMechanicResistance = 117,
|
ModMechanicResistance = 117,
|
||||||
ModHealingPct = 118,
|
ModHealingPct = 118,
|
||||||
Unk119 = 119, // Old SharePetTracking
|
PvpTalents = 119,
|
||||||
Untrackable = 120,
|
Untrackable = 120,
|
||||||
Empathy = 121,
|
Empathy = 121,
|
||||||
ModOffhandDamagePct = 122,
|
ModOffhandDamagePct = 122,
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ namespace Framework.Database
|
|||||||
PrepareStatement(CharStatements.SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell FROM character_battleground_data WHERE guid = ?");
|
PrepareStatement(CharStatements.SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell FROM character_battleground_data WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphId FROM character_glyphs WHERE guid = ?");
|
PrepareStatement(CharStatements.SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphId FROM character_glyphs WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.SEL_CHARACTER_TALENTS, "SELECT talentId, talentGroup FROM character_talent WHERE guid = ?");
|
PrepareStatement(CharStatements.SEL_CHARACTER_TALENTS, "SELECT talentId, talentGroup FROM character_talent WHERE guid = ?");
|
||||||
|
PrepareStatement(CharStatements.SEL_CHARACTER_PVP_TALENTS, "SELECT talentId, talentGroup FROM character_pvp_talent WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?");
|
PrepareStatement(CharStatements.SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?");
|
PrepareStatement(CharStatements.SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1");
|
PrepareStatement(CharStatements.SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1");
|
||||||
@@ -584,6 +585,7 @@ namespace Framework.Database
|
|||||||
PrepareStatement(CharStatements.DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, "DELETE FROM guild_bank_eventlog WHERE PlayerGuid = ?");
|
PrepareStatement(CharStatements.DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, "DELETE FROM guild_bank_eventlog WHERE PlayerGuid = ?");
|
||||||
PrepareStatement(CharStatements.DEL_CHAR_GLYPHS, "DELETE FROM character_glyphs WHERE guid = ?");
|
PrepareStatement(CharStatements.DEL_CHAR_GLYPHS, "DELETE FROM character_glyphs WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.DEL_CHAR_TALENT, "DELETE FROM character_talent WHERE guid = ?");
|
PrepareStatement(CharStatements.DEL_CHAR_TALENT, "DELETE FROM character_talent WHERE guid = ?");
|
||||||
|
PrepareStatement(CharStatements.DEL_CHAR_PVP_TALENT, "DELETE FROM character_pvp_talent WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.DEL_CHAR_SKILLS, "DELETE FROM character_skills WHERE guid = ?");
|
PrepareStatement(CharStatements.DEL_CHAR_SKILLS, "DELETE FROM character_skills WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.UPD_CHAR_MONEY, "UPDATE characters SET money = ? WHERE guid = ?");
|
PrepareStatement(CharStatements.UPD_CHAR_MONEY, "UPDATE characters SET money = ? WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.INS_CHAR_ACTION, "INSERT INTO character_action (guid, spec, button, action, type) VALUES (?, ?, ?, ?, ?)");
|
PrepareStatement(CharStatements.INS_CHAR_ACTION, "INSERT INTO character_action (guid, spec, button, action, type) VALUES (?, ?, ?, ?, ?)");
|
||||||
@@ -616,6 +618,7 @@ namespace Framework.Database
|
|||||||
PrepareStatement(CharStatements.DEL_PETITION_SIGNATURE_BY_OWNER, "DELETE FROM petition_sign WHERE ownerguid = ?");
|
PrepareStatement(CharStatements.DEL_PETITION_SIGNATURE_BY_OWNER, "DELETE FROM petition_sign WHERE ownerguid = ?");
|
||||||
PrepareStatement(CharStatements.INS_CHAR_GLYPHS, "INSERT INTO character_glyphs VALUES(?, ?, ?)");
|
PrepareStatement(CharStatements.INS_CHAR_GLYPHS, "INSERT INTO character_glyphs VALUES(?, ?, ?)");
|
||||||
PrepareStatement(CharStatements.INS_CHAR_TALENT, "INSERT INTO character_talent (guid, talentId, talentGroup) VALUES (?, ?, ?)");
|
PrepareStatement(CharStatements.INS_CHAR_TALENT, "INSERT INTO character_talent (guid, talentId, talentGroup) VALUES (?, ?, ?)");
|
||||||
|
PrepareStatement(CharStatements.INS_CHAR_PVP_TALENT, "INSERT INTO character_pvp_talent (guid, talentId, talentGroup) VALUES (?, ?, ?)");
|
||||||
PrepareStatement(CharStatements.UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?");
|
PrepareStatement(CharStatements.UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?");
|
||||||
PrepareStatement(CharStatements.INS_CHAR_FISHINGSTEPS, "INSERT INTO character_fishingsteps (guid, fishingSteps) VALUES (?, ?)");
|
PrepareStatement(CharStatements.INS_CHAR_FISHINGSTEPS, "INSERT INTO character_fishingsteps (guid, fishingSteps) VALUES (?, ?)");
|
||||||
PrepareStatement(CharStatements.DEL_CHAR_FISHINGSTEPS, "DELETE FROM character_fishingsteps WHERE guid = ?");
|
PrepareStatement(CharStatements.DEL_CHAR_FISHINGSTEPS, "DELETE FROM character_fishingsteps WHERE guid = ?");
|
||||||
@@ -827,6 +830,7 @@ namespace Framework.Database
|
|||||||
SEL_CHARACTER_BGDATA,
|
SEL_CHARACTER_BGDATA,
|
||||||
SEL_CHARACTER_GLYPHS,
|
SEL_CHARACTER_GLYPHS,
|
||||||
SEL_CHARACTER_TALENTS,
|
SEL_CHARACTER_TALENTS,
|
||||||
|
SEL_CHARACTER_PVP_TALENTS,
|
||||||
SEL_CHARACTER_TRANSMOG_OUTFITS,
|
SEL_CHARACTER_TRANSMOG_OUTFITS,
|
||||||
SEL_CHARACTER_SKILLS,
|
SEL_CHARACTER_SKILLS,
|
||||||
SEL_CHARACTER_RANDOMBG,
|
SEL_CHARACTER_RANDOMBG,
|
||||||
@@ -1207,6 +1211,7 @@ namespace Framework.Database
|
|||||||
DEL_GUILD_BANK_EVENTLOG_BY_PLAYER,
|
DEL_GUILD_BANK_EVENTLOG_BY_PLAYER,
|
||||||
DEL_CHAR_GLYPHS,
|
DEL_CHAR_GLYPHS,
|
||||||
DEL_CHAR_TALENT,
|
DEL_CHAR_TALENT,
|
||||||
|
DEL_CHAR_PVP_TALENT,
|
||||||
DEL_CHAR_SKILLS,
|
DEL_CHAR_SKILLS,
|
||||||
UPD_CHAR_MONEY,
|
UPD_CHAR_MONEY,
|
||||||
INS_CHAR_ACTION,
|
INS_CHAR_ACTION,
|
||||||
@@ -1237,6 +1242,7 @@ namespace Framework.Database
|
|||||||
DEL_PETITION_SIGNATURE_BY_OWNER,
|
DEL_PETITION_SIGNATURE_BY_OWNER,
|
||||||
INS_CHAR_GLYPHS,
|
INS_CHAR_GLYPHS,
|
||||||
INS_CHAR_TALENT,
|
INS_CHAR_TALENT,
|
||||||
|
INS_CHAR_PVP_TALENT,
|
||||||
UPD_CHAR_LIST_SLOT,
|
UPD_CHAR_LIST_SLOT,
|
||||||
INS_CHAR_FISHINGSTEPS,
|
INS_CHAR_FISHINGSTEPS,
|
||||||
DEL_CHAR_FISHINGSTEPS,
|
DEL_CHAR_FISHINGSTEPS,
|
||||||
|
|||||||
@@ -693,6 +693,14 @@ namespace Framework.Database
|
|||||||
// PvpReward.db2
|
// PvpReward.db2
|
||||||
PrepareStatement(HotfixStatements.SEL_PVP_REWARD, "SELECT ID, HonorLevel, Prestige, RewardPackID FROM pvp_reward ORDER BY ID DESC");
|
PrepareStatement(HotfixStatements.SEL_PVP_REWARD, "SELECT ID, HonorLevel, Prestige, RewardPackID FROM pvp_reward ORDER BY ID DESC");
|
||||||
|
|
||||||
|
// PvpTalent.db2
|
||||||
|
PrepareStatement(HotfixStatements.SEL_PVP_TALENT, "SELECT ID, Description, SpellID, OverridesSpellID, ExtraSpellID, TierID, ColumnIndex, Flags, ClassID, " +
|
||||||
|
"SpecID, Role FROM pvp_talent ORDER BY ID DESC");
|
||||||
|
PrepareStatement(HotfixStatements.SEL_PVP_TALENT_LOCALE, "SELECT ID, Description_lang FROM pvp_talent_locale WHERE locale = ?");
|
||||||
|
|
||||||
|
// PvpTalentUnlock.db2
|
||||||
|
PrepareStatement(HotfixStatements.SEL_PVP_TALENT_UNLOCK, "SELECT ID, TierID, ColumnIndex, HonorLevel FROM pvp_talent_unlock ORDER BY ID DESC");
|
||||||
|
|
||||||
// QuestFactionReward.db2
|
// QuestFactionReward.db2
|
||||||
PrepareStatement(HotfixStatements.SEL_QUEST_FACTION_REWARD, "SELECT ID, QuestRewFactionValue1, QuestRewFactionValue2, QuestRewFactionValue3, " +
|
PrepareStatement(HotfixStatements.SEL_QUEST_FACTION_REWARD, "SELECT ID, QuestRewFactionValue1, QuestRewFactionValue2, QuestRewFactionValue3, " +
|
||||||
"QuestRewFactionValue4, QuestRewFactionValue5, QuestRewFactionValue6, QuestRewFactionValue7, QuestRewFactionValue8, QuestRewFactionValue9, " +
|
"QuestRewFactionValue4, QuestRewFactionValue5, QuestRewFactionValue6, QuestRewFactionValue7, QuestRewFactionValue8, QuestRewFactionValue9, " +
|
||||||
@@ -1385,6 +1393,11 @@ namespace Framework.Database
|
|||||||
|
|
||||||
SEL_PVP_REWARD,
|
SEL_PVP_REWARD,
|
||||||
|
|
||||||
|
SEL_PVP_TALENT,
|
||||||
|
SEL_PVP_TALENT_LOCALE,
|
||||||
|
|
||||||
|
SEL_PVP_TALENT_UNLOCK,
|
||||||
|
|
||||||
SEL_QUEST_FACTION_REWARD,
|
SEL_QUEST_FACTION_REWARD,
|
||||||
|
|
||||||
SEL_QUEST_MONEY_REWARD,
|
SEL_QUEST_MONEY_REWARD,
|
||||||
|
|||||||
@@ -183,6 +183,8 @@ namespace Game.DataStorage
|
|||||||
PrestigeLevelInfoStorage = DBReader.Read<PrestigeLevelInfoRecord>("PrestigeLevelInfo.db2", HotfixStatements.SEL_PRESTIGE_LEVEL_INFO, HotfixStatements.SEL_PRESTIGE_LEVEL_INFO_LOCALE);
|
PrestigeLevelInfoStorage = DBReader.Read<PrestigeLevelInfoRecord>("PrestigeLevelInfo.db2", HotfixStatements.SEL_PRESTIGE_LEVEL_INFO, HotfixStatements.SEL_PRESTIGE_LEVEL_INFO_LOCALE);
|
||||||
PVPDifficultyStorage = DBReader.Read<PVPDifficultyRecord>("PVPDifficulty.db2", HotfixStatements.SEL_PVP_DIFFICULTY);
|
PVPDifficultyStorage = DBReader.Read<PVPDifficultyRecord>("PVPDifficulty.db2", HotfixStatements.SEL_PVP_DIFFICULTY);
|
||||||
PvpRewardStorage = DBReader.Read<PvpRewardRecord>("PvpReward.db2", HotfixStatements.SEL_PVP_REWARD);
|
PvpRewardStorage = DBReader.Read<PvpRewardRecord>("PvpReward.db2", HotfixStatements.SEL_PVP_REWARD);
|
||||||
|
PvpTalentStorage = DBReader.Read<PvpTalentRecord>("PvpTalent.db2", HotfixStatements.SEL_PVP_TALENT, HotfixStatements.SEL_PVP_TALENT_LOCALE);
|
||||||
|
PvpTalentUnlockStorage = DBReader.Read<PvpTalentUnlockRecord>("PvpTalentUnlock.db2", HotfixStatements.SEL_PVP_TALENT_UNLOCK);
|
||||||
QuestFactionRewardStorage = DBReader.Read<QuestFactionRewardRecord>("QuestFactionReward.db2", HotfixStatements.SEL_QUEST_FACTION_REWARD);
|
QuestFactionRewardStorage = DBReader.Read<QuestFactionRewardRecord>("QuestFactionReward.db2", HotfixStatements.SEL_QUEST_FACTION_REWARD);
|
||||||
QuestMoneyRewardStorage = DBReader.Read<QuestMoneyRewardRecord>("QuestMoneyReward.db2", HotfixStatements.SEL_QUEST_MONEY_REWARD);
|
QuestMoneyRewardStorage = DBReader.Read<QuestMoneyRewardRecord>("QuestMoneyReward.db2", HotfixStatements.SEL_QUEST_MONEY_REWARD);
|
||||||
QuestPackageItemStorage = DBReader.Read<QuestPackageItemRecord>("QuestPackageItem.db2", HotfixStatements.SEL_QUEST_PACKAGE_ITEM);
|
QuestPackageItemStorage = DBReader.Read<QuestPackageItemRecord>("QuestPackageItem.db2", HotfixStatements.SEL_QUEST_PACKAGE_ITEM);
|
||||||
@@ -512,6 +514,8 @@ namespace Game.DataStorage
|
|||||||
public static DB6Storage<PrestigeLevelInfoRecord> PrestigeLevelInfoStorage;
|
public static DB6Storage<PrestigeLevelInfoRecord> PrestigeLevelInfoStorage;
|
||||||
public static DB6Storage<PVPDifficultyRecord> PVPDifficultyStorage;
|
public static DB6Storage<PVPDifficultyRecord> PVPDifficultyStorage;
|
||||||
public static DB6Storage<PvpRewardRecord> PvpRewardStorage;
|
public static DB6Storage<PvpRewardRecord> PvpRewardStorage;
|
||||||
|
public static DB6Storage<PvpTalentRecord> PvpTalentStorage;
|
||||||
|
public static DB6Storage<PvpTalentUnlockRecord> PvpTalentUnlockStorage;
|
||||||
public static DB6Storage<QuestFactionRewardRecord> QuestFactionRewardStorage;
|
public static DB6Storage<QuestFactionRewardRecord> QuestFactionRewardStorage;
|
||||||
public static DB6Storage<QuestMoneyRewardRecord> QuestMoneyRewardStorage;
|
public static DB6Storage<QuestMoneyRewardRecord> QuestMoneyRewardStorage;
|
||||||
public static DB6Storage<QuestPackageItemRecord> QuestPackageItemStorage;
|
public static DB6Storage<QuestPackageItemRecord> QuestPackageItemStorage;
|
||||||
|
|||||||
@@ -48,78 +48,30 @@ namespace Game.DataStorage
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong ReadUInt64(int numBits)
|
public ulong ReadUInt64(int bitWidth, int bitOffset)
|
||||||
{
|
{
|
||||||
ulong result = FastStruct<ulong>.ArrayToStructure(ref m_array[m_readOffset + (m_readPos >> 3)]) << (64 - numBits - (m_readPos & 7)) >> (64 - numBits);
|
int bitsToRead = bitOffset & 7;
|
||||||
m_readPos += numBits;
|
ulong result = FastStruct<ulong>.ArrayToStructure(ref m_array[m_readOffset + (m_readPos >> 3)]) << (64 - bitsToRead - bitWidth) >> (64 - bitWidth);
|
||||||
|
m_readPos += bitWidth;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Value32 ReadValue32(int numBits)
|
public Value64 ReadValue64(int bitWidth, int bitOffset = 0, bool isSigned = false)
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
ulong result = ReadUInt32(numBits);
|
ulong result = ReadUInt64(bitWidth, bitOffset);
|
||||||
return *(Value32*)&result;
|
if (isSigned)
|
||||||
}
|
{
|
||||||
}
|
ulong mask = 1ul << (bitWidth - 1);
|
||||||
|
result = (result ^ mask) - mask;
|
||||||
|
}
|
||||||
|
|
||||||
public Value64 ReadValue64(int numBits)
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
ulong result = ReadUInt64(numBits);
|
|
||||||
return *(Value64*)&result;
|
return *(Value64*)&result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Value32
|
|
||||||
{
|
|
||||||
unsafe fixed byte Value[4];
|
|
||||||
|
|
||||||
public T GetValue<T>() where T : struct
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* ptr = Value)
|
|
||||||
return FastStruct<T>.ArrayToStructure(ref ptr[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] GetBytes(int bitSize)
|
|
||||||
{
|
|
||||||
if (((bitSize + 7) / 8) != NextPow2((bitSize + 7) / 8))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] data = new byte[NextPow2((bitSize + 7) / 8)];
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* ptr = Value)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < data.Length; ++i)
|
|
||||||
data[i] = ptr[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int NextPow2(int v)
|
|
||||||
{
|
|
||||||
v--;
|
|
||||||
v |= v >> 1;
|
|
||||||
v |= v >> 2;
|
|
||||||
v |= v >> 4;
|
|
||||||
v |= v >> 8;
|
|
||||||
v |= v >> 16;
|
|
||||||
v++;
|
|
||||||
return Math.Max(v, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct Value64
|
public struct Value64
|
||||||
{
|
{
|
||||||
unsafe fixed byte Value[8];
|
unsafe fixed byte Value[8];
|
||||||
@@ -135,9 +87,6 @@ namespace Game.DataStorage
|
|||||||
|
|
||||||
public byte[] GetBytes(int bitSize)
|
public byte[] GetBytes(int bitSize)
|
||||||
{
|
{
|
||||||
var val = ((bitSize + 7) / 8);
|
|
||||||
var val1 = NextPow2((bitSize + 7) / 8);
|
|
||||||
|
|
||||||
byte[] data = new byte[NextPow2((bitSize + 7) / 8)];
|
byte[] data = new byte[NextPow2((bitSize + 7) / 8)];
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ namespace Game.DataStorage
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data.AddRange(bitReader.ReadValue64(bitWidth).GetBytes(bitWidth));
|
data.AddRange(bitReader.ReadValue64(bitWidth, ColumnMeta[f].BitOffset, ColumnMeta[f].Cardinality == 1).GetBytes(bitWidth));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -350,6 +350,41 @@ namespace Game.DataStorage
|
|||||||
|
|
||||||
CliDB.PvpRewardStorage.Clear();
|
CliDB.PvpRewardStorage.Clear();
|
||||||
|
|
||||||
|
for (var x = 0; x < (int)Class.Max; ++x)
|
||||||
|
{
|
||||||
|
_pvpTalentsByPosition[x] = new List<PvpTalentRecord>[PlayerConst.MaxPvpTalentTiers][];
|
||||||
|
for (var y = 0; y < PlayerConst.MaxPvpTalentTiers; ++y)
|
||||||
|
{
|
||||||
|
_pvpTalentsByPosition[x][y] = new List<PvpTalentRecord>[PlayerConst.MaxPvpTalentColumns];
|
||||||
|
for (var z = 0; z < PlayerConst.MaxPvpTalentColumns; ++z)
|
||||||
|
_pvpTalentsByPosition[x][y][z] = new List<PvpTalentRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < PlayerConst.MaxPvpTalentTiers; ++i)
|
||||||
|
_pvpTalentUnlock[i] = new uint[PlayerConst.MaxPvpTalentColumns];
|
||||||
|
|
||||||
|
foreach (PvpTalentRecord talentInfo in CliDB.PvpTalentStorage.Values)
|
||||||
|
{
|
||||||
|
//ASSERT(talentInfo->ClassID < MAX_CLASSES);
|
||||||
|
//ASSERT(talentInfo->TierID < MAX_PVP_TALENT_TIERS, "MAX_PVP_TALENT_TIERS must be at least %u", talentInfo.TierID + 1);
|
||||||
|
//ASSERT(talentInfo->ColumnIndex < MAX_PVP_TALENT_COLUMNS, "MAX_PVP_TALENT_COLUMNS must be at least %u", talentInfo.ColumnIndex + 1);
|
||||||
|
if (talentInfo.ClassID == 0)
|
||||||
|
{
|
||||||
|
for (uint i = 1; i < (int)Class.Max; ++i)
|
||||||
|
_pvpTalentsByPosition[i][talentInfo.TierID][talentInfo.ColumnIndex].Add(talentInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_pvpTalentsByPosition[talentInfo.ClassID][talentInfo.TierID][talentInfo.ColumnIndex].Add(talentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (PvpTalentUnlockRecord talentUnlock in CliDB.PvpTalentUnlockStorage.Values)
|
||||||
|
{
|
||||||
|
//ASSERT(talentUnlock->TierID < MAX_PVP_TALENT_TIERS, "MAX_PVP_TALENT_TIERS must be at least %u", talentUnlock->TierID + 1);
|
||||||
|
//ASSERT(talentUnlock->ColumnIndex < MAX_PVP_TALENT_COLUMNS, "MAX_PVP_TALENT_COLUMNS must be at least %u", talentUnlock->ColumnIndex + 1);
|
||||||
|
_pvpTalentUnlock[talentUnlock.TierID][talentUnlock.ColumnIndex] = (uint)talentUnlock.HonorLevel;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (QuestPackageItemRecord questPackageItem in CliDB.QuestPackageItemStorage.Values)
|
foreach (QuestPackageItemRecord questPackageItem in CliDB.QuestPackageItemStorage.Values)
|
||||||
{
|
{
|
||||||
if (!_questPackages.ContainsKey(questPackageItem.QuestPackageID))
|
if (!_questPackages.ContainsKey(questPackageItem.QuestPackageID))
|
||||||
@@ -1146,6 +1181,17 @@ namespace Game.DataStorage
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public uint GetRequiredHonorLevelForPvpTalent(PvpTalentRecord talentInfo)
|
||||||
|
{
|
||||||
|
//ASSERT(talentInfo);
|
||||||
|
return _pvpTalentUnlock[talentInfo.TierID][talentInfo.ColumnIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PvpTalentRecord> GetPvpTalentsByPosition(uint classId, uint tier, uint column)
|
||||||
|
{
|
||||||
|
return _pvpTalentsByPosition[classId][tier][column];
|
||||||
|
}
|
||||||
|
|
||||||
public List<QuestPackageItemRecord> GetQuestPackageItems(uint questPackageID)
|
public List<QuestPackageItemRecord> GetQuestPackageItems(uint questPackageID)
|
||||||
{
|
{
|
||||||
if( _questPackages.ContainsKey(questPackageID))
|
if( _questPackages.ContainsKey(questPackageID))
|
||||||
@@ -1468,6 +1514,8 @@ namespace Game.DataStorage
|
|||||||
MultiMap<uint, uint> _phasesByGroup = new MultiMap<uint, uint>();
|
MultiMap<uint, uint> _phasesByGroup = new MultiMap<uint, uint>();
|
||||||
Dictionary<PowerType, PowerTypeRecord> _powerTypes = new Dictionary<PowerType, PowerTypeRecord>();
|
Dictionary<PowerType, PowerTypeRecord> _powerTypes = new Dictionary<PowerType, PowerTypeRecord>();
|
||||||
Dictionary<Tuple<uint /*prestige level*/, uint /*honor level*/>, uint> _pvpRewardPack = new Dictionary<Tuple<uint, uint>, uint>();
|
Dictionary<Tuple<uint /*prestige level*/, uint /*honor level*/>, uint> _pvpRewardPack = new Dictionary<Tuple<uint, uint>, uint>();
|
||||||
|
List<PvpTalentRecord>[][][] _pvpTalentsByPosition = new List<PvpTalentRecord>[(int)Class.Max][][];
|
||||||
|
uint[][] _pvpTalentUnlock = new uint[PlayerConst.MaxPvpTalentTiers][];
|
||||||
Dictionary<uint, Tuple<List<QuestPackageItemRecord>, List<QuestPackageItemRecord>>> _questPackages = new Dictionary<uint, Tuple<List<QuestPackageItemRecord>, List<QuestPackageItemRecord>>>();
|
Dictionary<uint, Tuple<List<QuestPackageItemRecord>, List<QuestPackageItemRecord>>> _questPackages = new Dictionary<uint, Tuple<List<QuestPackageItemRecord>, List<QuestPackageItemRecord>>>();
|
||||||
MultiMap<uint, RewardPackXItemRecord> _rewardPackItems = new MultiMap<uint, RewardPackXItemRecord>();
|
MultiMap<uint, RewardPackXItemRecord> _rewardPackItems = new MultiMap<uint, RewardPackXItemRecord>();
|
||||||
Dictionary<uint, uint> _rulesetItemUpgrade = new Dictionary<uint, uint>();
|
Dictionary<uint, uint> _rulesetItemUpgrade = new Dictionary<uint, uint>();
|
||||||
|
|||||||
@@ -175,4 +175,27 @@ namespace Game.DataStorage
|
|||||||
public byte Prestige;
|
public byte Prestige;
|
||||||
public ushort RewardPackID;
|
public ushort RewardPackID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class PvpTalentRecord
|
||||||
|
{
|
||||||
|
public uint Id;
|
||||||
|
public LocalizedString Description;
|
||||||
|
public uint SpellID;
|
||||||
|
public uint OverridesSpellID;
|
||||||
|
public int ExtraSpellID;
|
||||||
|
public int TierID;
|
||||||
|
public byte ColumnIndex;
|
||||||
|
public byte Flags;
|
||||||
|
public byte ClassID;
|
||||||
|
public ushort SpecID;
|
||||||
|
public byte Role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class PvpTalentUnlockRecord
|
||||||
|
{
|
||||||
|
public uint Id;
|
||||||
|
public byte TierID;
|
||||||
|
public byte ColumnIndex;
|
||||||
|
public byte HonorLevel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -393,6 +393,9 @@ namespace Game.Entities
|
|||||||
SendMessageToSet(duelWinner, true);
|
SendMessageToSet(duelWinner, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duel.opponent.DisablePvpRules();
|
||||||
|
DisablePvpRules();
|
||||||
|
|
||||||
Global.ScriptMgr.OnPlayerDuelEnd(duel.opponent, this, type);
|
Global.ScriptMgr.OnPlayerDuelEnd(duel.opponent, this, type);
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
|
|||||||
@@ -948,6 +948,20 @@ namespace Game.Entities
|
|||||||
while (result.NextRow());
|
while (result.NextRow());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void _LoadPvpTalents(SQLResult result)
|
||||||
|
{
|
||||||
|
// "SELECT TalentID, TalentGroup FROM character_pvp_talent WHERE guid = ?"
|
||||||
|
if (!result.IsEmpty())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
PvpTalentRecord talent = CliDB.PvpTalentStorage.LookupByKey(result.Read<uint>(0));
|
||||||
|
if (talent != null)
|
||||||
|
AddPvpTalent(talent, result.Read<byte>(1), false);
|
||||||
|
}
|
||||||
|
while (result.NextRow());
|
||||||
|
}
|
||||||
|
}
|
||||||
void _LoadGlyphs(SQLResult result)
|
void _LoadGlyphs(SQLResult result)
|
||||||
{
|
{
|
||||||
// SELECT talentGroup, glyphId from character_glyphs WHERE guid = ?
|
// SELECT talentGroup, glyphId from character_glyphs WHERE guid = ?
|
||||||
@@ -1977,6 +1991,29 @@ namespace Game.Entities
|
|||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_PVP_TALENT);
|
||||||
|
stmt.AddValue(0, GetGUID().GetCounter());
|
||||||
|
trans.Append(stmt);
|
||||||
|
|
||||||
|
for (byte group = 0; group < PlayerConst.MaxSpecializations; ++group)
|
||||||
|
{
|
||||||
|
talents = GetPvpTalentMap(group);
|
||||||
|
foreach (var pair in talents.ToList())
|
||||||
|
{
|
||||||
|
if (pair.Value == PlayerSpellState.Removed)
|
||||||
|
{
|
||||||
|
talents.Remove(pair.Key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_CHAR_PVP_TALENT);
|
||||||
|
stmt.AddValue(0, GetGUID().GetCounter());
|
||||||
|
stmt.AddValue(1, pair.Key);
|
||||||
|
stmt.AddValue(2, group);
|
||||||
|
trans.Append(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public void _SaveMail(SQLTransaction trans)
|
public void _SaveMail(SQLTransaction trans)
|
||||||
{
|
{
|
||||||
@@ -2852,6 +2889,7 @@ namespace Game.Entities
|
|||||||
SetUInt32Value(PlayerFields.CurrentSpecId, spec.Id);
|
SetUInt32Value(PlayerFields.CurrentSpecId, spec.Id);
|
||||||
|
|
||||||
_LoadTalents(holder.GetResult(PlayerLoginQueryLoad.Talents));
|
_LoadTalents(holder.GetResult(PlayerLoginQueryLoad.Talents));
|
||||||
|
_LoadPvpTalents(holder.GetResult(PlayerLoginQueryLoad.PvpTalents));
|
||||||
_LoadSpells(holder.GetResult(PlayerLoginQueryLoad.Spells));
|
_LoadSpells(holder.GetResult(PlayerLoginQueryLoad.Spells));
|
||||||
GetSession().GetCollectionMgr().LoadToys();
|
GetSession().GetCollectionMgr().LoadToys();
|
||||||
GetSession().GetCollectionMgr().LoadHeirlooms();
|
GetSession().GetCollectionMgr().LoadHeirlooms();
|
||||||
@@ -2880,6 +2918,8 @@ namespace Game.Entities
|
|||||||
InitTalentForLevel();
|
InitTalentForLevel();
|
||||||
LearnDefaultSkills();
|
LearnDefaultSkills();
|
||||||
LearnCustomSpells();
|
LearnCustomSpells();
|
||||||
|
if (getLevel() < PlayerConst.LevelMinHonor)
|
||||||
|
ResetPvpTalents();
|
||||||
|
|
||||||
// must be before inventory (some items required reputation check)
|
// must be before inventory (some items required reputation check)
|
||||||
reputationMgr.LoadFromDB(holder.GetResult(PlayerLoginQueryLoad.Reputation));
|
reputationMgr.LoadFromDB(holder.GetResult(PlayerLoginQueryLoad.Reputation));
|
||||||
|
|||||||
@@ -317,11 +317,13 @@ namespace Game.Entities
|
|||||||
for (byte i = 0; i < PlayerConst.MaxSpecializations; ++i)
|
for (byte i = 0; i < PlayerConst.MaxSpecializations; ++i)
|
||||||
{
|
{
|
||||||
Talents[i] = new Dictionary<uint, PlayerSpellState>();
|
Talents[i] = new Dictionary<uint, PlayerSpellState>();
|
||||||
|
PvpTalents[i] = new Dictionary<uint, PlayerSpellState>();
|
||||||
Glyphs[i] = new List<uint>();
|
Glyphs[i] = new List<uint>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<uint, PlayerSpellState>[] Talents = new Dictionary<uint, PlayerSpellState>[PlayerConst.MaxSpecializations];
|
public Dictionary<uint, PlayerSpellState>[] Talents = new Dictionary<uint, PlayerSpellState>[PlayerConst.MaxSpecializations];
|
||||||
|
public Dictionary<uint, PlayerSpellState>[] PvpTalents = new Dictionary<uint, PlayerSpellState>[PlayerConst.MaxSpecializations];
|
||||||
public List<uint>[] Glyphs = new List<uint>[PlayerConst.MaxSpecializations];
|
public List<uint>[] Glyphs = new List<uint>[PlayerConst.MaxSpecializations];
|
||||||
public uint ResetTalentsCost;
|
public uint ResetTalentsCost;
|
||||||
public long ResetTalentsTime;
|
public long ResetTalentsTime;
|
||||||
|
|||||||
@@ -122,6 +122,11 @@ namespace Game.Entities
|
|||||||
UpdateAreaDependentAuras(newArea);
|
UpdateAreaDependentAuras(newArea);
|
||||||
UpdateAreaAndZonePhase();
|
UpdateAreaAndZonePhase();
|
||||||
|
|
||||||
|
if (IsAreaThatActivatesPvpTalents(newArea))
|
||||||
|
EnablePvpRules();
|
||||||
|
else
|
||||||
|
DisablePvpRules();
|
||||||
|
|
||||||
// previously this was in UpdateZone (but after UpdateArea) so nothing will break
|
// previously this was in UpdateZone (but after UpdateArea) so nothing will break
|
||||||
pvpInfo.IsInNoPvPArea = false;
|
pvpInfo.IsInNoPvPArea = false;
|
||||||
if (area != null && area.IsSanctuary()) // in sanctuary
|
if (area != null && area.IsSanctuary()) // in sanctuary
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ using Game.BattleGrounds;
|
|||||||
using Game.DataStorage;
|
using Game.DataStorage;
|
||||||
using Game.Network.Packets;
|
using Game.Network.Packets;
|
||||||
using Game.PvP;
|
using Game.PvP;
|
||||||
|
using Game.Spells;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
@@ -333,6 +334,217 @@ namespace Game.Entities
|
|||||||
public uint GetHonorLevel() { return GetUInt32Value(PlayerFields.HonorLevel); }
|
public uint GetHonorLevel() { return GetUInt32Value(PlayerFields.HonorLevel); }
|
||||||
public bool IsMaxHonorLevelAndPrestige() { return IsMaxPrestige() && GetHonorLevel() == PlayerConst.MaxHonorLevel; }
|
public bool IsMaxHonorLevelAndPrestige() { return IsMaxPrestige() && GetHonorLevel() == PlayerConst.MaxHonorLevel; }
|
||||||
|
|
||||||
|
void ResetPvpTalents()
|
||||||
|
{
|
||||||
|
foreach (var talentInfo in CliDB.PvpTalentStorage.Values)
|
||||||
|
{
|
||||||
|
if (talentInfo.ClassID != 0 && talentInfo.ClassID != (int)GetClass())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
RemovePvpTalent(talentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLTransaction trans = new SQLTransaction();
|
||||||
|
_SaveTalents(trans);
|
||||||
|
_SaveSpells(trans);
|
||||||
|
DB.Characters.CommitTransaction(trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TalentLearnResult LearnPvpTalent(uint talentID, ref uint spellOnCooldown)
|
||||||
|
{
|
||||||
|
if (IsInCombat())
|
||||||
|
return TalentLearnResult.FailedAffectingCombat;
|
||||||
|
|
||||||
|
if (getLevel() < PlayerConst.LevelMinHonor)
|
||||||
|
return TalentLearnResult.FailedUnknown;
|
||||||
|
|
||||||
|
PvpTalentRecord talentInfo = CliDB.PvpTalentStorage.LookupByKey(talentID);
|
||||||
|
if (talentInfo == null)
|
||||||
|
return TalentLearnResult.FailedUnknown;
|
||||||
|
|
||||||
|
if (talentInfo.SpecID != 0)
|
||||||
|
{
|
||||||
|
if (talentInfo.SpecID != GetInt32Value(PlayerFields.CurrentSpecId))
|
||||||
|
return TalentLearnResult.FailedUnknown;
|
||||||
|
}
|
||||||
|
else if (talentInfo.Role < 7)
|
||||||
|
{
|
||||||
|
if (talentInfo.Role != CliDB.ChrSpecializationStorage.LookupByKey(GetUInt32Value(PlayerFields.CurrentSpecId)).Role)
|
||||||
|
return TalentLearnResult.FailedUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent learn talent for different class (cheating)
|
||||||
|
if (talentInfo.ClassID != 0 && talentInfo.ClassID != (int)GetClass())
|
||||||
|
return TalentLearnResult.FailedUnknown;
|
||||||
|
|
||||||
|
if (GetPrestigeLevel() == 0)
|
||||||
|
if (Global.DB2Mgr.GetRequiredHonorLevelForPvpTalent(talentInfo) > GetHonorLevel())
|
||||||
|
return TalentLearnResult.FailedUnknown;
|
||||||
|
|
||||||
|
// Check if player doesn't have any talent in current tier
|
||||||
|
for (uint c = 0; c < PlayerConst.MaxPvpTalentColumns; ++c)
|
||||||
|
{
|
||||||
|
foreach (PvpTalentRecord talent in Global.DB2Mgr.GetPvpTalentsByPosition((uint)GetClass(), (uint)talentInfo.TierID, c))
|
||||||
|
{
|
||||||
|
if (HasPvpTalent(talent.Id, GetActiveTalentGroup()) && !HasFlag(PlayerFields.Flags, PlayerFlags.Resting) && HasFlag(UnitFields.Flags, UnitFlags.ImmuneToNpc))
|
||||||
|
return TalentLearnResult.FailedRestArea;
|
||||||
|
|
||||||
|
if (GetSpellHistory().HasCooldown(talent.SpellID))
|
||||||
|
{
|
||||||
|
spellOnCooldown = talent.SpellID;
|
||||||
|
return TalentLearnResult.FailedCantRemoveTalent;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemovePvpTalent(talent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AddPvpTalent(talentInfo, GetActiveTalentGroup(), true))
|
||||||
|
return TalentLearnResult.FailedUnknown;
|
||||||
|
|
||||||
|
return TalentLearnResult.LearnOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddPvpTalent(PvpTalentRecord talent, byte activeTalentGroup, bool learning)
|
||||||
|
{
|
||||||
|
//ASSERT(talent);
|
||||||
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID);
|
||||||
|
if (spellInfo == null)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Spells, $"Player.AddPvpTalent: Spell (ID: {talent.SpellID}) does not exist.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Global.SpellMgr.IsSpellValid(spellInfo, this, false))
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Spells, $"Player.AddPvpTalent: Spell (ID: {talent.SpellID}) is invalid");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasPvpRulesEnabled())
|
||||||
|
LearnSpell(talent.SpellID, false);
|
||||||
|
|
||||||
|
// Move this to toggle ?
|
||||||
|
if (talent.OverridesSpellID != 0)
|
||||||
|
AddOverrideSpell(talent.OverridesSpellID, talent.SpellID);
|
||||||
|
|
||||||
|
if (learning)
|
||||||
|
GetPvpTalentMap(activeTalentGroup)[talent.Id] = PlayerSpellState.New;
|
||||||
|
else
|
||||||
|
GetPvpTalentMap(activeTalentGroup)[talent.Id] = PlayerSpellState.Unchanged;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemovePvpTalent(PvpTalentRecord talent)
|
||||||
|
{
|
||||||
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID);
|
||||||
|
if (spellInfo == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RemoveSpell(talent.SpellID, true);
|
||||||
|
|
||||||
|
// Move this to toggle ?
|
||||||
|
if (talent.OverridesSpellID != 0)
|
||||||
|
RemoveOverrideSpell(talent.OverridesSpellID, talent.SpellID);
|
||||||
|
|
||||||
|
// if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
|
||||||
|
if (!GetPvpTalentMap(GetActiveTalentGroup()).ContainsKey(talent.Id))
|
||||||
|
GetPvpTalentMap(GetActiveTalentGroup())[talent.Id] = PlayerSpellState.Removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TogglePvpTalents(bool enable)
|
||||||
|
{
|
||||||
|
var pvpTalents = GetPvpTalentMap(GetActiveTalentGroup());
|
||||||
|
foreach (var pair in pvpTalents)
|
||||||
|
{
|
||||||
|
PvpTalentRecord pvpTalentInfo = CliDB.PvpTalentStorage.LookupByKey(pair.Key);
|
||||||
|
if (enable && pair.Value != PlayerSpellState.Removed)
|
||||||
|
LearnSpell(pvpTalentInfo.SpellID, false);
|
||||||
|
else
|
||||||
|
RemoveSpell(pvpTalentInfo.SpellID, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasPvpTalent(uint talentID, byte activeTalentGroup)
|
||||||
|
{
|
||||||
|
return GetPvpTalentMap(activeTalentGroup).ContainsKey(talentID) && GetPvpTalentMap(activeTalentGroup)[talentID] != PlayerSpellState.Removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnablePvpRules(bool dueToCombat = false)
|
||||||
|
{
|
||||||
|
if (HasPvpRulesEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!HasSpell(195710)) // Honorable Medallion
|
||||||
|
CastSpell(this, 208682); // Learn Gladiator's Medallion
|
||||||
|
|
||||||
|
CastSpell(this, PlayerConst.SpellPvpRulesEnabled);
|
||||||
|
if (!dueToCombat)
|
||||||
|
{
|
||||||
|
Aura aura = GetAura(PlayerConst.SpellPvpRulesEnabled);
|
||||||
|
if (aura != null)
|
||||||
|
{
|
||||||
|
aura.SetMaxDuration(-1);
|
||||||
|
aura.SetDuration(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisablePvpRules()
|
||||||
|
{
|
||||||
|
// Don't disable pvp rules when in pvp zone.
|
||||||
|
if (IsInAreaThatActivatesPvpTalents())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (GetCombatTimer() == 0)
|
||||||
|
RemoveAurasDueToSpell(PlayerConst.SpellPvpRulesEnabled);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Aura aura = GetAura(PlayerConst.SpellPvpRulesEnabled);
|
||||||
|
if (aura != null)
|
||||||
|
aura.SetDuration(aura.GetSpellInfo().GetMaxDuration());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasPvpRulesEnabled()
|
||||||
|
{
|
||||||
|
return HasAura(PlayerConst.SpellPvpRulesEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInAreaThatActivatesPvpTalents()
|
||||||
|
{
|
||||||
|
return IsAreaThatActivatesPvpTalents(GetAreaId());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAreaThatActivatesPvpTalents(uint areaID)
|
||||||
|
{
|
||||||
|
if (InBattleground())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(areaID);
|
||||||
|
if (area != null)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (area.IsSanctuary())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (area.Flags[0].HasAnyFlag(AreaFlags.Arena))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (Global.BattleFieldMgr.GetBattlefieldToZoneId(area.Id) != null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
area = CliDB.AreaTableStorage.LookupByKey(area.ParentAreaID);
|
||||||
|
|
||||||
|
} while (area != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<uint, PlayerSpellState> GetPvpTalentMap(uint spec) { return _specializationInfo.PvpTalents[spec]; }
|
||||||
|
|
||||||
//BGs
|
//BGs
|
||||||
public Battleground GetBattleground()
|
public Battleground GetBattleground()
|
||||||
|
|||||||
@@ -306,6 +306,32 @@ namespace Game.Entities
|
|||||||
RemoveOverrideSpell(talentInfo.OverridesSpellID, talentInfo.SpellID);
|
RemoveOverrideSpell(talentInfo.OverridesSpellID, talentInfo.SpellID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var talentInfo in CliDB.PvpTalentStorage.Values)
|
||||||
|
{
|
||||||
|
// unlearn only talents for character class
|
||||||
|
// some spell learned by one class as normal spells or know at creation but another class learn it as talent,
|
||||||
|
// to prevent unexpected lost normal learned spell skip another class talents
|
||||||
|
if (talentInfo.ClassID != 0 && talentInfo.ClassID != (int)GetClass())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (talentInfo.SpellID == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID);
|
||||||
|
if (spellInfo == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
RemoveSpell(talentInfo.SpellID, true);
|
||||||
|
|
||||||
|
// search for spells that the talent teaches and unlearn them
|
||||||
|
foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None))
|
||||||
|
if (effect != null && effect.TriggerSpell > 0 && effect.Effect == SpellEffectName.LearnSpell)
|
||||||
|
RemoveSpell(effect.TriggerSpell, true);
|
||||||
|
|
||||||
|
if (talentInfo.OverridesSpellID != 0)
|
||||||
|
RemoveOverrideSpell(talentInfo.OverridesSpellID, talentInfo.SpellID);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove spec specific spells
|
// Remove spec specific spells
|
||||||
RemoveSpecializationSpells();
|
RemoveSpecializationSpells();
|
||||||
|
|
||||||
@@ -334,6 +360,19 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var talentInfo in CliDB.PvpTalentStorage.Values)
|
||||||
|
{
|
||||||
|
// learn only talents for character class (or x-class talents)
|
||||||
|
if (talentInfo.ClassID != 0 && talentInfo.ClassID != (int)GetClass())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (talentInfo.SpellID == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (HasPvpTalent(talentInfo.Id, GetActiveTalentGroup()))
|
||||||
|
AddPvpTalent(talentInfo, GetActiveTalentGroup(), true);
|
||||||
|
}
|
||||||
|
|
||||||
LearnSpecializationSpells();
|
LearnSpecializationSpells();
|
||||||
|
|
||||||
if (CanUseMastery())
|
if (CanUseMastery())
|
||||||
@@ -498,7 +537,7 @@ namespace Game.Entities
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
var talents = GetTalentMap(i);
|
var talents = GetTalentMap(i);
|
||||||
|
var pvpTalents = GetPvpTalentMap(i);
|
||||||
|
|
||||||
UpdateTalentData.TalentGroupInfo groupInfoPkt = new UpdateTalentData.TalentGroupInfo();
|
UpdateTalentData.TalentGroupInfo groupInfoPkt = new UpdateTalentData.TalentGroupInfo();
|
||||||
groupInfoPkt.SpecID = spec.Id;
|
groupInfoPkt.SpecID = spec.Id;
|
||||||
@@ -528,6 +567,31 @@ namespace Game.Entities
|
|||||||
groupInfoPkt.TalentIDs.Add((ushort)pair.Key);
|
groupInfoPkt.TalentIDs.Add((ushort)pair.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var pair in pvpTalents)
|
||||||
|
{
|
||||||
|
if (pair.Value == PlayerSpellState.Removed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PvpTalentRecord talentInfo = CliDB.PvpTalentStorage.LookupByKey(pair.Key);
|
||||||
|
if (talentInfo == null)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Player, $"Player.SendTalentsInfoData: Player '{GetName()}' ({GetGUID().ToString()}) has unknown pvp talent id: {pair.Key}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (talentInfo.ClassID != 0 && talentInfo.ClassID != (int)GetClass())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID);
|
||||||
|
if (spellEntry == null)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Player, $"Player.SendTalentsInfoData: Player '{GetName()}' ({GetGUID().ToString()}) has unknown pvp talent spell: {talentInfo.SpellID}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
groupInfoPkt.PvPTalentIDs.Add((ushort)pair.Key);
|
||||||
|
}
|
||||||
|
|
||||||
packet.Info.TalentGroups.Add(groupInfoPkt);
|
packet.Info.TalentGroups.Add(groupInfoPkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -494,6 +494,14 @@ namespace Game.Entities
|
|||||||
|
|
||||||
UpdateAfkReport(now);
|
UpdateAfkReport(now);
|
||||||
|
|
||||||
|
if (GetCombatTimer() != 0) // Only set when in pvp combat
|
||||||
|
{
|
||||||
|
Aura aura = GetAura(PlayerConst.SpellPvpRulesEnabled);
|
||||||
|
if (aura != null)
|
||||||
|
if (!aura.IsPermanent())
|
||||||
|
aura.SetDuration(aura.GetSpellInfo().GetMaxDuration());
|
||||||
|
}
|
||||||
|
|
||||||
if (IsAIEnabled && GetAI() != null)
|
if (IsAIEnabled && GetAI() != null)
|
||||||
GetAI().UpdateAI(diff);
|
GetAI().UpdateAI(diff);
|
||||||
else if (NeedChangeAI)
|
else if (NeedChangeAI)
|
||||||
@@ -5307,6 +5315,9 @@ namespace Game.Entities
|
|||||||
InitTalentForLevel();
|
InitTalentForLevel();
|
||||||
InitTaxiNodesForLevel();
|
InitTaxiNodesForLevel();
|
||||||
|
|
||||||
|
if (level < PlayerConst.LevelMinHonor)
|
||||||
|
ResetPvpTalents();
|
||||||
|
|
||||||
UpdateAllStats();
|
UpdateAllStats();
|
||||||
|
|
||||||
if (WorldConfig.GetBoolValue(WorldCfg.AlwaysMaxskill)) // Max weapon skill when leveling up
|
if (WorldConfig.GetBoolValue(WorldCfg.AlwaysMaxskill)) // Max weapon skill when leveling up
|
||||||
|
|||||||
@@ -1279,7 +1279,12 @@ namespace Game.Entities
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (PvP)
|
if (PvP)
|
||||||
|
{
|
||||||
m_CombatTimer = 5000;
|
m_CombatTimer = 5000;
|
||||||
|
Player me = ToPlayer();
|
||||||
|
if (me)
|
||||||
|
me.EnablePvpRules(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (IsInCombat() || HasUnitState(UnitState.Evade))
|
if (IsInCombat() || HasUnitState(UnitState.Evade))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -2520,6 +2520,10 @@ namespace Game
|
|||||||
stmt.AddValue(0, lowGuid);
|
stmt.AddValue(0, lowGuid);
|
||||||
SetQuery(PlayerLoginQueryLoad.Talents, stmt);
|
SetQuery(PlayerLoginQueryLoad.Talents, stmt);
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_PVP_TALENTS);
|
||||||
|
stmt.AddValue(0, lowGuid);
|
||||||
|
SetQuery(PlayerLoginQueryLoad.PvpTalents, stmt);
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PLAYER_ACCOUNT_DATA);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PLAYER_ACCOUNT_DATA);
|
||||||
stmt.AddValue(0, lowGuid);
|
stmt.AddValue(0, lowGuid);
|
||||||
SetQuery(PlayerLoginQueryLoad.AccountData, stmt);
|
SetQuery(PlayerLoginQueryLoad.AccountData, stmt);
|
||||||
@@ -2615,6 +2619,7 @@ namespace Game
|
|||||||
BgData,
|
BgData,
|
||||||
Glyphs,
|
Glyphs,
|
||||||
Talents,
|
Talents,
|
||||||
|
PvpTalents,
|
||||||
AccountData,
|
AccountData,
|
||||||
Skills,
|
Skills,
|
||||||
WeeklyQuestStatus,
|
WeeklyQuestStatus,
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ namespace Game
|
|||||||
|
|
||||||
player.SendPacket(packet);
|
player.SendPacket(packet);
|
||||||
plTarget.SendPacket(packet);
|
plTarget.SendPacket(packet);
|
||||||
|
|
||||||
|
player.EnablePvpRules();
|
||||||
|
plTarget.EnablePvpRules();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleDuelCancelled()
|
void HandleDuelCancelled()
|
||||||
|
|||||||
@@ -52,6 +52,32 @@ namespace Game
|
|||||||
GetPlayer().SendTalentsInfoData();
|
GetPlayer().SendTalentsInfoData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[WorldPacketHandler(ClientOpcodes.LearnPvpTalents)]
|
||||||
|
void HandleLearnPvpTalentsOpcode(LearnPvpTalents packet)
|
||||||
|
{
|
||||||
|
LearnPvpTalentsFailed learnPvpTalentsFailed = new LearnPvpTalentsFailed();
|
||||||
|
bool anythingLearned = false;
|
||||||
|
foreach (ushort talentId in packet.Talents)
|
||||||
|
{
|
||||||
|
TalentLearnResult result = _player.LearnPvpTalent(talentId, ref learnPvpTalentsFailed.SpellID);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
if (learnPvpTalentsFailed.Reason == 0)
|
||||||
|
learnPvpTalentsFailed.Reason = (uint)result;
|
||||||
|
|
||||||
|
learnPvpTalentsFailed.Talents.Add(talentId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
anythingLearned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (learnPvpTalentsFailed.Reason != 0)
|
||||||
|
SendPacket(learnPvpTalentsFailed);
|
||||||
|
|
||||||
|
if (anythingLearned)
|
||||||
|
_player.SendTalentsInfoData();
|
||||||
|
}
|
||||||
|
|
||||||
[WorldPacketHandler(ClientOpcodes.ConfirmRespecWipe)]
|
[WorldPacketHandler(ClientOpcodes.ConfirmRespecWipe)]
|
||||||
void HandleConfirmRespecWipe(ConfirmRespecWipe confirmRespecWipe)
|
void HandleConfirmRespecWipe(ConfirmRespecWipe confirmRespecWipe)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Game.Entities;
|
using Game.Entities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Framework.Collections;
|
||||||
|
using Framework.Dynamic;
|
||||||
|
|
||||||
namespace Game.Network.Packets
|
namespace Game.Network.Packets
|
||||||
{
|
{
|
||||||
@@ -144,6 +146,39 @@ namespace Game.Network.Packets
|
|||||||
public bool IsFullUpdate;
|
public bool IsFullUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LearnPvpTalents : ClientPacket
|
||||||
|
{
|
||||||
|
public LearnPvpTalents(WorldPacket packet) : base(packet) { }
|
||||||
|
|
||||||
|
public override void Read()
|
||||||
|
{
|
||||||
|
int size = _worldPacket.ReadBits<int>(6);
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
Talents[i] = _worldPacket.ReadUInt16();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<ushort> Talents = new Array<ushort>(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LearnPvpTalentsFailed : ServerPacket
|
||||||
|
{
|
||||||
|
public LearnPvpTalentsFailed() : base(ServerOpcodes.LearnPvpTalentsFailed) { }
|
||||||
|
|
||||||
|
public override void Write()
|
||||||
|
{
|
||||||
|
_worldPacket.WriteBits(Reason, 4);
|
||||||
|
_worldPacket.WriteUInt32(SpellID);
|
||||||
|
_worldPacket.WriteUInt32(Talents.Count);
|
||||||
|
|
||||||
|
foreach (var id in Talents)
|
||||||
|
_worldPacket.WriteUInt16(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Reason;
|
||||||
|
public uint SpellID;
|
||||||
|
public List<ushort> Talents = new List<ushort>();
|
||||||
|
}
|
||||||
|
|
||||||
//Structs
|
//Structs
|
||||||
struct GlyphBinding
|
struct GlyphBinding
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5953,6 +5953,22 @@ namespace Game.Spells
|
|||||||
caster.RemoveAreaTrigger(this);
|
caster.RemoveAreaTrigger(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AuraEffectHandler(AuraType.PvpTalents)]
|
||||||
|
void HandleAuraPvpTalents(AuraApplication auraApp, AuraEffectHandleModes mode, bool apply)
|
||||||
|
{
|
||||||
|
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Player target = auraApp.GetTarget().ToPlayer();
|
||||||
|
if (target)
|
||||||
|
{
|
||||||
|
if (apply)
|
||||||
|
target.TogglePvpTalents(true);
|
||||||
|
else if (!target.HasAuraType(AuraType.PvpTalents))
|
||||||
|
target.TogglePvpTalents(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1086,6 +1086,30 @@ LOCK TABLES `character_pet_declinedname` WRITE;
|
|||||||
/*!40000 ALTER TABLE `character_pet_declinedname` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `character_pet_declinedname` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `character_pvp_talent`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `character_pvp_talent`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8 */;
|
||||||
|
CREATE TABLE `character_pvp_talent` (
|
||||||
|
`guid` bigint(20) unsigned NOT NULL,
|
||||||
|
`talentId` mediumint(8) unsigned NOT NULL,
|
||||||
|
`talentGroup` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`guid`,`talentId`,`talentGroup`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `character_pvp_talent`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `character_pvp_talent` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `character_pvp_talent` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `character_pvp_talent` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `character_queststatus`
|
-- Table structure for table `character_queststatus`
|
||||||
--
|
--
|
||||||
@@ -3537,7 +3561,8 @@ INSERT INTO `updates` VALUES
|
|||||||
('2017_10_29_00_characters.sql','8CFC473E7E87E58C317A72016BF69E9050D3BC83','ARCHIVED','2017-04-19 00:07:40',25),
|
('2017_10_29_00_characters.sql','8CFC473E7E87E58C317A72016BF69E9050D3BC83','ARCHIVED','2017-04-19 00:07:40',25),
|
||||||
('2018_02_03_00_characters.sql','73E9BFD848D7A22F2A7DD89CF64E30E3A8689512','ARCHIVED','2018-02-03 23:52:42',0),
|
('2018_02_03_00_characters.sql','73E9BFD848D7A22F2A7DD89CF64E30E3A8689512','ARCHIVED','2018-02-03 23:52:42',0),
|
||||||
('2018_02_08_00_characters.sql','75FA162A9B85D678B26F972371265F1EC2C75187','ARCHIVED','2018-02-08 22:23:28',0),
|
('2018_02_08_00_characters.sql','75FA162A9B85D678B26F972371265F1EC2C75187','ARCHIVED','2018-02-08 22:23:28',0),
|
||||||
('2018_02_19_00_characters.sql','75A0FFAFD0633921708DB0F72F9CC9796ACB960B','RELEASED','2018-02-19 22:33:32',117);
|
('2018_02_19_00_characters.sql','75A0FFAFD0633921708DB0F72F9CC9796ACB960B','RELEASED','2018-02-19 22:33:32',117),
|
||||||
|
('2018_03_04_00_characters.sql','2A4CD2EE2547E718490706FADC78BF36F0DED8D6','RELEASED','2018-03-04 18:15:24',0);
|
||||||
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
--
|
||||||
|
-- Table structure for table `character_pvp_talent`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `character_pvp_talent`;
|
||||||
|
CREATE TABLE `character_pvp_talent` (
|
||||||
|
`guid` bigint(20) unsigned NOT NULL,
|
||||||
|
`talentId` mediumint(8) unsigned NOT NULL,
|
||||||
|
`talentGroup` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`guid`,`talentId`,`talentGroup`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
--
|
||||||
|
-- Table structure for table `pvp_talent`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `pvp_talent`;
|
||||||
|
CREATE TABLE `pvp_talent` (
|
||||||
|
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`Description` text,
|
||||||
|
`SpellID` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`OverridesSpellID` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`ExtraSpellID` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`TierID` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`ColumnIndex` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`Flags` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`ClassID` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`SpecID` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`Role` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`ID`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `pvp_talent_locale`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `pvp_talent_locale`;
|
||||||
|
CREATE TABLE `pvp_talent_locale` (
|
||||||
|
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`locale` varchar(4) NOT NULL,
|
||||||
|
`Description_lang` text,
|
||||||
|
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`ID`,`locale`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `pvp_talent_unlock`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `pvp_talent_unlock`;
|
||||||
|
CREATE TABLE `pvp_talent_unlock` (
|
||||||
|
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`TierID` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`ColumnIndex` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`HonorLevel` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`ID`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
--
|
||||||
|
-- Table structure for table `pvp_item`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `pvp_item`;
|
||||||
|
CREATE TABLE `pvp_item` (
|
||||||
|
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`ItemID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`ItemLevelBonus` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`ID`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
Reference in New Issue
Block a user