Files
CypherCore/Source/Game/Handlers/TraitHandler.cs
T

248 lines
12 KiB
C#

// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Networking;
using Game.Networking.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.TraitsCommitConfig)]
void HandleTraitsCommitConfig(TraitsCommitConfig traitsCommitConfig)
{
int configId = (int)(uint)traitsCommitConfig.Config.ID;
TraitConfig existingConfig = _player.GetTraitConfig(configId);
if (existingConfig == null)
{
SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown));
return;
}
if (_player.IsInCombat())
{
SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedAffectingCombat));
return;
}
if (_player.GetBattleground() != null && _player.GetBattleground().GetStatus() == BattlegroundStatus.InProgress)
{
SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.InPvpMatch));
return;
}
bool hasRemovedEntries = false;
TraitConfigPacket newConfigState = new(existingConfig);
foreach (TraitEntryPacket newEntry in traitsCommitConfig.Config.Entries)
{
TraitEntryPacket traitEntry = newConfigState.Entries.Find(traitEntry => traitEntry.TraitNodeID == newEntry.TraitNodeID && traitEntry.TraitNodeEntryID == newEntry.TraitNodeEntryID);
if (traitEntry != null && traitEntry.Rank > newEntry.Rank)
{
TraitNodeRecord traitNode = CliDB.TraitNodeStorage.LookupByKey(newEntry.TraitNodeID);
if (traitNode == null)
{
SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown));
return;
}
TraitTreeRecord traitTree = CliDB.TraitTreeStorage.LookupByKey(traitNode.TraitTreeID);
if (traitTree == null)
{
SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown));
return;
}
if (traitTree.HasFlag(TraitTreeFlag.CannotRefund))
{
SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedCantRemoveTalent));
return;
}
TraitNodeEntryRecord traitNodeEntry = CliDB.TraitNodeEntryStorage.LookupByKey(newEntry.TraitNodeEntryID);
if (traitNodeEntry == null)
{
SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown));
return;
}
if (traitNodeEntry.TraitDefinitionID != 0)
{
TraitDefinitionRecord traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(traitNodeEntry.TraitDefinitionID);
if (traitDefinition == null)
{
SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown));
return;
}
if (traitDefinition.SpellID != 0 && _player.GetSpellHistory().HasCooldown(traitDefinition.SpellID))
{
SendPacket(new TraitConfigCommitFailed(configId, traitDefinition.SpellID, (int)TalentLearnResult.FailedCantRemoveTalent));
return;
}
if (traitDefinition.VisibleSpellID != 0 && _player.GetSpellHistory().HasCooldown((uint)traitDefinition.VisibleSpellID))
{
SendPacket(new TraitConfigCommitFailed(configId, traitDefinition.VisibleSpellID, (int)TalentLearnResult.FailedCantRemoveTalent));
return;
}
}
hasRemovedEntries = true;
}
if (traitEntry != null)
{
if (newEntry.Rank != 0)
traitEntry.Rank = newEntry.Rank;
else
newConfigState.Entries.RemoveAll(traitEntry => traitEntry.TraitNodeID == newEntry.TraitNodeID && traitEntry.TraitNodeEntryID == newEntry.TraitNodeEntryID);
}
else
newConfigState.Entries.Add(newEntry);
}
TalentLearnResult validationResult = TraitMgr.ValidateConfig(newConfigState, _player, true);
if (validationResult != TalentLearnResult.LearnOk)
{
SendPacket(new TraitConfigCommitFailed(configId, 0, (int)validationResult));
return;
}
bool needsCastTime = newConfigState.Type == TraitConfigType.Combat && hasRemovedEntries;
if (traitsCommitConfig.SavedLocalIdentifier != 0)
newConfigState.LocalIdentifier = traitsCommitConfig.SavedLocalIdentifier;
else
{
TraitConfig savedConfig = _player.GetTraitConfig(traitsCommitConfig.SavedLocalIdentifier);
if (savedConfig != null)
newConfigState.LocalIdentifier = savedConfig.LocalIdentifier;
}
_player.UpdateTraitConfig(newConfigState, traitsCommitConfig.SavedConfigID, needsCastTime);
}
[WorldPacketHandler(ClientOpcodes.ClassTalentsRequestNewConfig)]
void HandleClassTalentsRequestNewConfig(ClassTalentsRequestNewConfig classTalentsRequestNewConfig)
{
if (classTalentsRequestNewConfig.Config.Type != TraitConfigType.Combat)
return;
if ((classTalentsRequestNewConfig.Config.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) != (int)TraitCombatConfigFlags.None)
return;
long configCount = _player.m_activePlayerData.TraitConfigs.GetValues().Count(traitConfig =>
{
return (TraitConfigType)(int)traitConfig.Item1.Type == TraitConfigType.Combat
&& ((TraitCombatConfigFlags)(int)traitConfig.Item1.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) == TraitCombatConfigFlags.None;
});
if (configCount >= TraitMgr.MAX_COMBAT_TRAIT_CONFIGS)
return;
int findFreeLocalIdentifier()
{
int index = 1;
while (_player.m_activePlayerData.TraitConfigs.FindIf(traitConfig =>
{
return (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat
&& traitConfig.ChrSpecializationID == (int)_player.GetPrimarySpecialization()
&& traitConfig.LocalIdentifier == index;
}).Item1 != 0)
++index;
return index;
}
classTalentsRequestNewConfig.Config.ChrSpecializationID = (int)_player.GetPrimarySpecialization();
classTalentsRequestNewConfig.Config.LocalIdentifier = findFreeLocalIdentifier();
foreach (TraitEntry grantedEntry in TraitMgr.GetGrantedTraitEntriesForConfig(classTalentsRequestNewConfig.Config, _player))
{
var newEntry = classTalentsRequestNewConfig.Config.Entries.Find(entry => { return entry.TraitNodeID == grantedEntry.TraitNodeID && entry.TraitNodeEntryID == grantedEntry.TraitNodeEntryID; });
if (newEntry == null)
{
newEntry = new();
classTalentsRequestNewConfig.Config.Entries.Add(newEntry);
}
newEntry.TraitNodeID = grantedEntry.TraitNodeID;
newEntry.TraitNodeEntryID = grantedEntry.TraitNodeEntryID;
newEntry.Rank = grantedEntry.Rank;
newEntry.GrantedRanks = grantedEntry.GrantedRanks;
TraitNodeEntryRecord traitNodeEntry = CliDB.TraitNodeEntryStorage.LookupByKey(grantedEntry.TraitNodeEntryID);
if (traitNodeEntry != null)
if (newEntry.Rank + newEntry.GrantedRanks > traitNodeEntry.MaxRanks)
newEntry.Rank = Math.Max(0, traitNodeEntry.MaxRanks - newEntry.GrantedRanks);
}
TalentLearnResult validationResult = TraitMgr.ValidateConfig(classTalentsRequestNewConfig.Config, _player);
if (validationResult != TalentLearnResult.LearnOk)
return;
_player.CreateTraitConfig(classTalentsRequestNewConfig.Config);
}
[WorldPacketHandler(ClientOpcodes.ClassTalentsRenameConfig)]
void HandleClassTalentsRenameConfig(ClassTalentsRenameConfig classTalentsRenameConfig)
{
_player.RenameTraitConfig(classTalentsRenameConfig.ConfigID, classTalentsRenameConfig.Name);
}
[WorldPacketHandler(ClientOpcodes.ClassTalentsDeleteConfig)]
void HandleClassTalentsDeleteConfig(ClassTalentsDeleteConfig classTalentsDeleteConfig)
{
_player.DeleteTraitConfig(classTalentsDeleteConfig.ConfigID);
}
[WorldPacketHandler(ClientOpcodes.ClassTalentsSetStarterBuildActive)]
void HandleClassTalentsSetStarterBuildActive(ClassTalentsSetStarterBuildActive classTalentsSetStarterBuildActive)
{
TraitConfig traitConfig = _player.GetTraitConfig(classTalentsSetStarterBuildActive.ConfigID);
if (traitConfig == null)
return;
if ((TraitConfigType)(int)traitConfig.Type != TraitConfigType.Combat)
return;
if (!((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags).HasFlag(TraitCombatConfigFlags.ActiveForSpec))
return;
if (classTalentsSetStarterBuildActive.Active)
{
TraitConfigPacket newConfigState = new(traitConfig);
int freeLocalIdentifier = 1;
while (_player.m_activePlayerData.TraitConfigs.FindIf(traitConfig =>
{
return (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat
&& traitConfig.ChrSpecializationID == (int)_player.GetPrimarySpecialization()
&& traitConfig.LocalIdentifier == freeLocalIdentifier;
}).Item1 != 0)
++freeLocalIdentifier;
TraitMgr.InitializeStarterBuildTraitConfig(newConfigState, _player);
newConfigState.CombatConfigFlags |= TraitCombatConfigFlags.StarterBuild;
newConfigState.LocalIdentifier = freeLocalIdentifier;
_player.UpdateTraitConfig(newConfigState, 0, true);
}
else
_player.SetTraitConfigUseStarterBuild(classTalentsSetStarterBuildActive.ConfigID, false);
}
[WorldPacketHandler(ClientOpcodes.ClassTalentsSetUsesSharedActionBars)]
void HandleClassTalentsSetUsesSharedActionBars(ClassTalentsSetUsesSharedActionBars classTalentsSetUsesSharedActionBars)
{
_player.SetTraitConfigUseSharedActionBars(classTalentsSetUsesSharedActionBars.ConfigID, classTalentsSetUsesSharedActionBars.UsesShared,
classTalentsSetUsesSharedActionBars.IsLastSelectedSavedConfig);
}
}
}