public uint ExtractSpellIdFromLink(StringArguments args) { // number or [name] Shift-click form |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r // number or [name] Shift-click form |color|Hglyph:glyph_slot_id:glyph_prop_id|h[value]|h|r // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r // number or [name] Shift-click form |color|Htalent:talent_id, rank|h[name]|h|r // number or [name] Shift-click form |color|Htrade:spell_id, skill_id, max_value, cur_value|h[name]|h|r string idS = ExtractKeyFromLink(args, spellKeys, out int type, out string param1Str); if (string.IsNullOrEmpty(idS)) { return(0); } if (!uint.TryParse(idS, out uint id)) { return(0); } switch (type) { case 0: return(id); case 1: { // talent TalentRecord talentEntry = CliDB.TalentStorage.LookupByKey(id); if (talentEntry == null) { return(0); } return(talentEntry.SpellID); } case 2: case 3: return(id); case 4: { if (!uint.TryParse(param1Str, out uint glyph_prop_id)) { glyph_prop_id = 0; } GlyphPropertiesRecord glyphPropEntry = CliDB.GlyphPropertiesStorage.LookupByKey(glyph_prop_id); if (glyphPropEntry == null) { return(0); } return(glyphPropEntry.SpellID); } } // unknown type? return(0); }
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 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); }
static bool TalentCheck(uint talent_id) { TalentRecord talentInfo = CliDB.TalentStorage.LookupByKey(talent_id); if (talentInfo == null) { return(false); } return(CliDB.ChrSpecializationStorage.ContainsKey(talentInfo.SpecID)); }
public bool StoreTo(out TalentRecord val, string arg) { val = default; HyperlinkDataTokenizer t = new(arg); if (!(t.TryConsumeTo(out uint talentId) && t.IsEmpty())) { return(false); } val = CliDB.TalentStorage.LookupByKey(talentId); return(val != null); }
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 SendTalentsInfoData() { UpdateTalentData packet = new UpdateTalentData(); packet.Info.PrimarySpecialization = GetPrimarySpecialization(); for (byte i = 0; i < PlayerConst.MaxSpecializations; ++i) { ChrSpecializationRecord spec = Global.DB2Mgr.GetChrSpecializationByIndex(GetClass(), i); if (spec == null) { continue; } var talents = GetTalentMap(i); var pvpTalents = GetPvpTalentMap(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; } SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID, Difficulty.None); if (spellEntry == null) { Log.outError(LogFilter.Player, "Player {0} has unknown talent spell: {1}", GetName(), talentInfo.SpellID); continue; } groupInfoPkt.TalentIDs.Add((ushort)pair.Key); } for (byte slot = 0; slot < PlayerConst.MaxPvpTalentSlots; ++slot) { if (pvpTalents[slot] == 0) { continue; } PvpTalentRecord talentInfo = CliDB.PvpTalentStorage.LookupByKey(pvpTalents[slot]); if (talentInfo == null) { Log.outError(LogFilter.Player, $"Player.SendTalentsInfoData: Player '{GetName()}' ({GetGUID()}) has unknown pvp talent id: {pvpTalents[slot]}"); continue; } SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID, Difficulty.None); if (spellEntry == null) { Log.outError(LogFilter.Player, $"Player.SendTalentsInfoData: Player '{GetName()}' ({GetGUID()}) has unknown pvp talent spell: {talentInfo.SpellID}"); continue; } PvPTalent pvpTalent = new PvPTalent(); pvpTalent.PvPTalentID = (ushort)pvpTalents[slot]; pvpTalent.Slot = slot; groupInfoPkt.PvPTalents.Add(pvpTalent); } if (i == GetActiveTalentGroup()) { packet.Info.ActiveGroup = (byte)packet.Info.TalentGroups.Count; } if (!groupInfoPkt.TalentIDs.Empty() || !groupInfoPkt.PvPTalents.Empty() || i == GetActiveTalentGroup()) { packet.Info.TalentGroups.Add(groupInfoPkt); } } SendPacket(packet); }