Ported .Net Core commits:
hondacrx: - Initial commit: Switch to .Net Core 2.0 - Fix build and removed not needed files Fabi: - Updated solution platforms. - Changed folder structure. - Change library target framework to netstandard2.0. - Updated solution platforms again... - Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
@@ -0,0 +1,555 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.DataStorage;
|
||||
using Game.Network.Packets;
|
||||
using Game.Spells;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Entities
|
||||
{
|
||||
public partial class Player
|
||||
{
|
||||
public void InitTalentForLevel()
|
||||
{
|
||||
uint level = getLevel();
|
||||
// talents base at level diff (talents = level - 9 but some can be used already)
|
||||
if (level < PlayerConst.MinSpecializationLevel)
|
||||
ResetTalentSpecialization();
|
||||
|
||||
uint talentTiers = CalculateTalentsTiers();
|
||||
if (level < 15)
|
||||
{
|
||||
// Remove all talent points
|
||||
ResetTalents(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!GetSession().HasPermission(RBACPermissions.SkipCheckMoreTalentsThanAllowed))
|
||||
{
|
||||
for (uint t = talentTiers; t < PlayerConst.MaxTalentTiers; ++t)
|
||||
for (uint c = 0; c < PlayerConst.MaxTalentColumns; ++c)
|
||||
foreach (TalentRecord talent in Global.DB2Mgr.GetTalentsByPosition(GetClass(), t, c))
|
||||
RemoveTalent(talent);
|
||||
}
|
||||
}
|
||||
|
||||
SetUInt32Value(PlayerFields.MaxTalentTiers, talentTiers);
|
||||
|
||||
if (!GetSession().PlayerLoading())
|
||||
SendTalentsInfoData(); // update at client
|
||||
}
|
||||
|
||||
public bool AddTalent(TalentRecord talent, byte spec, bool learning)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID);
|
||||
if (spellInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Spells, "Player.AddTalent: Spell (ID: {0}) does not exist.", talent.SpellID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Global.SpellMgr.IsSpellValid(spellInfo, this, false))
|
||||
{
|
||||
Log.outError(LogFilter.Spells, "Player.AddTalent: Spell (ID: {0}) is invalid", talent.SpellID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (talent.OverridesSpellID != 0)
|
||||
AddOverrideSpell(talent.OverridesSpellID, talent.SpellID);
|
||||
|
||||
if (GetTalentMap(spec).ContainsKey(talent.Id))
|
||||
GetTalentMap(spec)[talent.Id] = PlayerSpellState.Unchanged;
|
||||
else
|
||||
GetTalentMap(spec)[talent.Id] = learning ? PlayerSpellState.New : PlayerSpellState.Unchanged;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveTalent(TalentRecord talent)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID);
|
||||
if (spellInfo == null)
|
||||
return;
|
||||
|
||||
RemoveSpell(talent.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 (talent.OverridesSpellID != 0)
|
||||
RemoveOverrideSpell(talent.OverridesSpellID, talent.SpellID);
|
||||
|
||||
var talentMap = GetTalentMap(GetActiveTalentGroup());
|
||||
// if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
|
||||
if (talentMap.ContainsKey(talent.Id))
|
||||
talentMap[talent.Id] = PlayerSpellState.Removed;
|
||||
}
|
||||
|
||||
public TalentLearnResult LearnTalent(uint talentId, ref int spellOnCooldown)
|
||||
{
|
||||
if (IsInCombat())
|
||||
return TalentLearnResult.FailedAffectingCombat;
|
||||
|
||||
if (IsDead() || GetMap().IsBattlegroundOrArena())
|
||||
return TalentLearnResult.FailedCantDoThatRightNow;
|
||||
|
||||
if (GetUInt32Value(PlayerFields.CurrentSpecId) == 0)
|
||||
return TalentLearnResult.FailedNoPrimaryTreeSelected;
|
||||
|
||||
TalentRecord talentInfo = CliDB.TalentStorage.LookupByKey(talentId);
|
||||
if (talentInfo == null)
|
||||
return TalentLearnResult.FailedUnknown;
|
||||
|
||||
if (talentInfo.SpecID != 0 && talentInfo.SpecID != GetUInt32Value(PlayerFields.CurrentSpecId))
|
||||
return TalentLearnResult.FailedUnknown;
|
||||
|
||||
// prevent learn talent for different class (cheating)
|
||||
if (talentInfo.ClassID != (byte)GetClass())
|
||||
return TalentLearnResult.FailedUnknown;
|
||||
|
||||
// check if we have enough talent points
|
||||
if (talentInfo.TierID >= GetUInt32Value(PlayerFields.MaxTalentTiers))
|
||||
return TalentLearnResult.FailedUnknown;
|
||||
|
||||
// TODO: prevent changing talents that are on cooldown
|
||||
|
||||
// Check if there is a different talent for us to learn in selected slot
|
||||
// Example situation:
|
||||
// Warrior talent row 2 slot 0
|
||||
// Talent.dbc has an entry for each specialization
|
||||
// but only 2 out of 3 have SpecID != 0
|
||||
// We need to make sure that if player is in one of these defined specs he will not learn the other choice
|
||||
TalentRecord bestSlotMatch = null;
|
||||
foreach (TalentRecord talent in Global.DB2Mgr.GetTalentsByPosition(GetClass(), talentInfo.TierID, talentInfo.ColumnIndex))
|
||||
{
|
||||
if (talent.SpecID == 0)
|
||||
bestSlotMatch = talent;
|
||||
else if (talent.SpecID == GetUInt32Value(PlayerFields.CurrentSpecId))
|
||||
{
|
||||
bestSlotMatch = talent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (talentInfo != bestSlotMatch)
|
||||
return TalentLearnResult.FailedUnknown;
|
||||
|
||||
// Check if player doesn't have any talent in current tier
|
||||
for (uint c = 0; c < PlayerConst.MaxTalentColumns; ++c)
|
||||
{
|
||||
foreach (TalentRecord talent in Global.DB2Mgr.GetTalentsByPosition(GetClass(), talentInfo.TierID, c))
|
||||
{
|
||||
//Todo test me
|
||||
if (talent.SpecID != GetUInt32Value(PlayerFields.CurrentSpecId))
|
||||
continue;
|
||||
|
||||
if (HasTalent(talent.Id, GetActiveTalentGroup()) && !HasFlag(PlayerFields.Flags, PlayerFlags.Resting) && HasFlag(UnitFields.Flags, UnitFlags.ImmuneToNpc))
|
||||
return TalentLearnResult.FailedRestArea;
|
||||
|
||||
if (GetSpellHistory().HasCooldown(talent.SpellID))
|
||||
{
|
||||
spellOnCooldown = (int)talent.SpellID;
|
||||
return TalentLearnResult.FailedCantRemoveTalent;
|
||||
}
|
||||
|
||||
RemoveTalent(talent);
|
||||
}
|
||||
}
|
||||
|
||||
// spell not set in talent.dbc
|
||||
uint spellid = talentInfo.SpellID;
|
||||
if (spellid == 0)
|
||||
{
|
||||
Log.outError(LogFilter.Player, "Player.LearnTalent: Talent.dbc has no spellInfo for talent: {0} (spell id = 0)", talentId);
|
||||
return TalentLearnResult.FailedUnknown;
|
||||
}
|
||||
|
||||
// already known
|
||||
if (HasTalent(talentId, GetActiveTalentGroup()) || HasSpell(spellid))
|
||||
return TalentLearnResult.FailedUnknown;
|
||||
|
||||
if (!AddTalent(talentInfo, GetActiveTalentGroup(), true))
|
||||
return TalentLearnResult.FailedUnknown;
|
||||
|
||||
LearnSpell(spellid, false);
|
||||
|
||||
Log.outDebug(LogFilter.Misc, "Player.LearnTalent: TalentID: {0} Spell: {1} Group: {2}", talentId, spellid, GetActiveTalentGroup());
|
||||
|
||||
return TalentLearnResult.LearnOk;
|
||||
}
|
||||
|
||||
public void ResetTalentSpecialization()
|
||||
{
|
||||
// Reset only talents that have different spells for each spec
|
||||
Class class_ = GetClass();
|
||||
for (uint t = 0; t < PlayerConst.MaxTalentTiers; ++t)
|
||||
{
|
||||
for (uint c = 0; c < PlayerConst.MaxTalentColumns; ++c)
|
||||
{
|
||||
if (Global.DB2Mgr.GetTalentsByPosition(class_, t, c).Count > 1)
|
||||
{
|
||||
foreach (TalentRecord talent in Global.DB2Mgr.GetTalentsByPosition(class_, t, c))
|
||||
RemoveTalent(talent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RemoveSpecializationSpells();
|
||||
|
||||
ChrSpecializationRecord defaultSpec = Global.DB2Mgr.GetDefaultChrSpecializationForClass(GetClass());
|
||||
SetPrimarySpecialization(defaultSpec.Id);
|
||||
SetActiveTalentGroup(defaultSpec.OrderIndex);
|
||||
SetUInt32Value(PlayerFields.CurrentSpecId, defaultSpec.Id);
|
||||
|
||||
LearnSpecializationSpells();
|
||||
|
||||
SendTalentsInfoData();
|
||||
UpdateItemSetAuras(false);
|
||||
}
|
||||
|
||||
bool HasTalent(uint talnetId, byte group)
|
||||
{
|
||||
return GetTalentMap(group).ContainsKey(talnetId) && GetTalentMap(group)[talnetId] != PlayerSpellState.Removed;
|
||||
}
|
||||
|
||||
uint GetTalentResetCost() { return _specializationInfo.ResetTalentsCost; }
|
||||
void SetTalentResetCost(uint cost) { _specializationInfo.ResetTalentsCost = cost; }
|
||||
long GetTalentResetTime() { return _specializationInfo.ResetTalentsTime; }
|
||||
void SetTalentResetTime(long time_) { _specializationInfo.ResetTalentsTime = time_; }
|
||||
uint GetPrimarySpecialization() { return _specializationInfo.PrimarySpecialization; }
|
||||
void SetPrimarySpecialization(uint spec) { _specializationInfo.PrimarySpecialization = spec; }
|
||||
public byte GetActiveTalentGroup() { return _specializationInfo.ActiveGroup; }
|
||||
void SetActiveTalentGroup(byte group) { _specializationInfo.ActiveGroup = group; }
|
||||
|
||||
// Loot Spec
|
||||
public void SetLootSpecId(uint id) { SetUInt32Value(PlayerFields.LootSpecId, id); }
|
||||
uint GetLootSpecId() { return GetUInt32Value(PlayerFields.LootSpecId); }
|
||||
|
||||
public uint GetDefaultSpecId()
|
||||
{
|
||||
return Global.DB2Mgr.GetDefaultChrSpecializationForClass(GetClass()).Id;
|
||||
}
|
||||
|
||||
public void ActivateTalentGroup(ChrSpecializationRecord spec)
|
||||
{
|
||||
if (GetActiveTalentGroup() == spec.OrderIndex)
|
||||
return;
|
||||
|
||||
if (IsNonMeleeSpellCast(false))
|
||||
InterruptNonMeleeSpells(false);
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
_SaveActions(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
// TO-DO: We need more research to know what happens with warlock's reagent
|
||||
Pet pet = GetPet();
|
||||
if (pet)
|
||||
RemovePet(pet, PetSaveMode.NotInSlot);
|
||||
|
||||
ClearAllReactives();
|
||||
UnsummonAllTotems();
|
||||
ExitVehicle();
|
||||
RemoveAllControlled();
|
||||
|
||||
// Let client clear his current Actions
|
||||
SendActionButtons(2);
|
||||
foreach (var talentInfo in CliDB.TalentStorage.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 != (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
|
||||
RemoveSpecializationSpells();
|
||||
|
||||
foreach (uint glyphId in GetGlyphs(GetActiveTalentGroup()))
|
||||
RemoveAurasDueToSpell(CliDB.GlyphPropertiesStorage.LookupByKey(glyphId).SpellID);
|
||||
|
||||
SetActiveTalentGroup(spec.OrderIndex);
|
||||
SetUInt32Value(PlayerFields.CurrentSpecId, spec.Id);
|
||||
if (GetPrimarySpecialization() == 0)
|
||||
SetPrimarySpecialization(spec.Id);
|
||||
|
||||
foreach (var talentInfo in CliDB.TalentStorage.Values)
|
||||
{
|
||||
// learn only talents for character class
|
||||
if (talentInfo.ClassID != (int)GetClass())
|
||||
continue;
|
||||
|
||||
if (talentInfo.SpellID == 0)
|
||||
continue;
|
||||
|
||||
if (HasTalent(talentInfo.SpellID, GetActiveTalentGroup()))
|
||||
{
|
||||
LearnSpell(talentInfo.SpellID, false); // add the talent to the PlayerSpellMap
|
||||
if (talentInfo.OverridesSpellID != 0)
|
||||
AddOverrideSpell(talentInfo.OverridesSpellID, talentInfo.SpellID);
|
||||
}
|
||||
}
|
||||
|
||||
LearnSpecializationSpells();
|
||||
|
||||
if (CanUseMastery())
|
||||
{
|
||||
for (uint i = 0; i < PlayerConst.MaxMasterySpells; ++i)
|
||||
{
|
||||
uint mastery = spec.MasterySpellID[i];
|
||||
if (mastery != 0)
|
||||
LearnSpell(mastery, false);
|
||||
}
|
||||
}
|
||||
|
||||
InitTalentForLevel();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_ACTIONS_SPEC);
|
||||
stmt.AddValue(0, GetGUID().GetCounter());
|
||||
stmt.AddValue(1, GetActiveTalentGroup());
|
||||
_LoadActions(DB.Characters.Query(stmt));
|
||||
|
||||
SendActionButtons(1);
|
||||
|
||||
UpdateDisplayPower();
|
||||
PowerType pw = getPowerType();
|
||||
if (pw != PowerType.Mana)
|
||||
SetPower(PowerType.Mana, 0); // Mana must be 0 even if it isn't the active power type.
|
||||
|
||||
SetPower(pw, 0);
|
||||
UpdateItemSetAuras(false);
|
||||
|
||||
// update visible transmog
|
||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
{
|
||||
Item equippedItem = GetItemByPos(InventorySlots.Bag0, i);
|
||||
if (equippedItem)
|
||||
SetVisibleItemSlot(i, equippedItem);
|
||||
}
|
||||
|
||||
foreach (uint glyphId in GetGlyphs(spec.OrderIndex))
|
||||
CastSpell(this, CliDB.GlyphPropertiesStorage.LookupByKey(glyphId).SpellID, true);
|
||||
|
||||
ActiveGlyphs activeGlyphs = new ActiveGlyphs();
|
||||
foreach (uint glyphId in GetGlyphs(spec.OrderIndex))
|
||||
{
|
||||
List<uint> bindableSpells = Global.DB2Mgr.GetGlyphBindableSpells(glyphId);
|
||||
foreach (uint bindableSpell in bindableSpells)
|
||||
if (HasSpell(bindableSpell) && !m_overrideSpells.ContainsKey(bindableSpell))
|
||||
activeGlyphs.Glyphs.Add(new GlyphBinding(bindableSpell, (ushort)glyphId));
|
||||
}
|
||||
|
||||
activeGlyphs.IsFullUpdate = true;
|
||||
SendPacket(activeGlyphs);
|
||||
}
|
||||
|
||||
public Dictionary<uint, PlayerSpellState> GetTalentMap(uint spec) { return _specializationInfo.Talents[spec]; }
|
||||
public List<uint> GetGlyphs(byte spec) { return _specializationInfo.Glyphs[spec]; }
|
||||
|
||||
public uint GetNextResetTalentsCost()
|
||||
{
|
||||
// The first time reset costs 1 gold
|
||||
if (GetTalentResetCost() < 1 * MoneyConstants.Gold)
|
||||
return 1 * MoneyConstants.Gold;
|
||||
// then 5 gold
|
||||
else if (GetTalentResetCost() < 5 * MoneyConstants.Gold)
|
||||
return 5 * MoneyConstants.Gold;
|
||||
// After that it increases in increments of 5 gold
|
||||
else if (GetTalentResetCost() < 10 * MoneyConstants.Gold)
|
||||
return 10 * MoneyConstants.Gold;
|
||||
else
|
||||
{
|
||||
ulong months = (ulong)(Global.WorldMgr.GetGameTime() - GetTalentResetTime()) / Time.Month;
|
||||
if (months > 0)
|
||||
{
|
||||
// This cost will be reduced by a rate of 5 gold per month
|
||||
uint new_cost = (uint)(GetTalentResetCost() - 5 * MoneyConstants.Gold * months);
|
||||
// to a minimum of 10 gold.
|
||||
return new_cost < 10 * MoneyConstants.Gold ? 10 * MoneyConstants.Gold : new_cost;
|
||||
}
|
||||
else
|
||||
{
|
||||
// After that it increases in increments of 5 gold
|
||||
uint new_cost = GetTalentResetCost() + 5 * MoneyConstants.Gold;
|
||||
// until it hits a cap of 50 gold.
|
||||
if (new_cost > 50 * MoneyConstants.Gold)
|
||||
new_cost = 50 * MoneyConstants.Gold;
|
||||
return new_cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ResetTalents(bool noCost = false)
|
||||
{
|
||||
Global.ScriptMgr.OnPlayerTalentsReset(this, noCost);
|
||||
|
||||
// not need after this call
|
||||
if (HasAtLoginFlag(AtLoginFlags.ResetTalents))
|
||||
RemoveAtLoginFlag(AtLoginFlags.ResetTalents, true);
|
||||
|
||||
uint cost = 0;
|
||||
if (!noCost && !WorldConfig.GetBoolValue(WorldCfg.NoResetTalentCost))
|
||||
{
|
||||
cost = GetNextResetTalentsCost();
|
||||
|
||||
if (!HasEnoughMoney(cost))
|
||||
{
|
||||
SendBuyError(BuyResult.NotEnoughtMoney, null, 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RemovePet(null, PetSaveMode.NotInSlot, true);
|
||||
|
||||
foreach (var talentInfo in CliDB.TalentStorage.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 != (uint)GetClass())
|
||||
continue;
|
||||
|
||||
// skip non-existant talent ranks
|
||||
if (talentInfo.SpellID == 0)
|
||||
continue;
|
||||
|
||||
RemoveTalent(talentInfo);
|
||||
}
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
_SaveTalents(trans);
|
||||
_SaveSpells(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
if (!noCost)
|
||||
{
|
||||
ModifyMoney(-cost);
|
||||
UpdateCriteria(CriteriaTypes.GoldSpentForTalents, cost);
|
||||
UpdateCriteria(CriteriaTypes.NumberOfTalentResets, 1);
|
||||
|
||||
SetTalentResetCost(cost);
|
||||
SetTalentResetTime(Time.UnixTime);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SendTalentsInfoData()
|
||||
{
|
||||
UpdateTalentData packet = new UpdateTalentData();
|
||||
packet.Info.PrimarySpecialization = GetPrimarySpecialization();
|
||||
packet.Info.ActiveGroup = GetActiveTalentGroup();
|
||||
|
||||
for (byte i = 0; i < PlayerConst.MaxSpecializations; ++i)
|
||||
{
|
||||
ChrSpecializationRecord spec = Global.DB2Mgr.GetChrSpecializationByIndex(GetClass(), i);
|
||||
if (spec == null)
|
||||
continue;
|
||||
|
||||
var talents = GetTalentMap(i);
|
||||
|
||||
|
||||
UpdateTalentData.TalentGroupInfo groupInfoPkt = new UpdateTalentData.TalentGroupInfo();
|
||||
groupInfoPkt.SpecID = spec.Id;
|
||||
|
||||
foreach (var pair in talents)
|
||||
{
|
||||
if (pair.Value == PlayerSpellState.Removed)
|
||||
continue;
|
||||
|
||||
TalentRecord talentInfo = CliDB.TalentStorage.LookupByKey(pair.Key);
|
||||
if (talentInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Player, "Player {0} has unknown talent id: {1}", GetName(), pair.Key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (talentInfo.ClassID != (uint)GetClass())
|
||||
continue;
|
||||
|
||||
SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID);
|
||||
if (spellEntry == null)
|
||||
{
|
||||
Log.outError(LogFilter.Player, "Player {0} has unknown talent spell: {1}", GetName(), talentInfo.SpellID);
|
||||
continue;
|
||||
}
|
||||
|
||||
groupInfoPkt.TalentIDs.Add((ushort)pair.Key);
|
||||
}
|
||||
|
||||
packet.Info.TalentGroups.Add(groupInfoPkt);
|
||||
}
|
||||
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
public void SendRespecWipeConfirm(ObjectGuid guid, uint cost)
|
||||
{
|
||||
RespecWipeConfirm respecWipeConfirm = new RespecWipeConfirm();
|
||||
respecWipeConfirm.RespecMaster = guid;
|
||||
respecWipeConfirm.Cost = cost;
|
||||
respecWipeConfirm.RespecType = SpecResetType.Talents;
|
||||
SendPacket(respecWipeConfirm);
|
||||
}
|
||||
|
||||
uint CalculateTalentsTiers()
|
||||
{
|
||||
uint[] rowLevels = new uint[0];
|
||||
switch (GetClass())
|
||||
{
|
||||
case Class.Deathknight:
|
||||
rowLevels = new uint[] { 57, 58, 59, 60, 75, 90, 100 };
|
||||
break;
|
||||
case Class.DemonHunter:
|
||||
rowLevels = new uint[] { 99, 100, 102, 104, 106, 108, 110 };
|
||||
break;
|
||||
default:
|
||||
rowLevels = new uint[] { 15, 30, 45, 60, 75, 90, 100 };
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint i = PlayerConst.MaxTalentTiers; i != 0; --i)
|
||||
if (getLevel() >= rowLevels[i - 1])
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user