BFA Update (still lots of testing to do tho)
This commit is contained in:
@@ -141,6 +141,10 @@ namespace Game.Entities
|
||||
if (setSpawnTime)
|
||||
m_respawnTime = Time.UnixTime + respawnDelay;
|
||||
|
||||
// if corpse was removed during falling, the falling will continue and override relocation to respawn position
|
||||
if (IsFalling())
|
||||
StopMoving();
|
||||
|
||||
float x, y, z, o;
|
||||
GetRespawnPosition(out x, out y, out z, out o);
|
||||
SetHomePosition(x, y, z, o);
|
||||
@@ -193,22 +197,22 @@ namespace Game.Entities
|
||||
SetByteValue(UnitFields.Bytes0, 1, (byte)cinfo.UnitClass);
|
||||
|
||||
// Cancel load if no model defined
|
||||
if (cinfo.GetFirstValidModelId() == 0)
|
||||
if (cinfo.GetFirstValidModel() == null)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has no model defined in table `creature_template`, can't load. ", entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint displayID = ObjectManager.ChooseDisplayId(GetCreatureTemplate(), data);
|
||||
CreatureModelInfo minfo = Global.ObjectMgr.GetCreatureModelRandomGender(ref displayID);
|
||||
CreatureModel model = ObjectManager.ChooseDisplayId(cinfo, data);
|
||||
CreatureModelInfo minfo = Global.ObjectMgr.GetCreatureModelRandomGender(ref model, cinfo);
|
||||
if (minfo == null) // Cancel load if no model defined
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has no model defined in table `creature_template`, can't load. ", entry);
|
||||
Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has invalid model {1} defined in table `creature_template`, can't load.", entry, model.CreatureDisplayID);
|
||||
return false;
|
||||
}
|
||||
|
||||
SetDisplayId(displayID);
|
||||
SetNativeDisplayId(displayID);
|
||||
SetDisplayId(model.CreatureDisplayID, model.DisplayScale);
|
||||
SetNativeDisplayId(model.CreatureDisplayID, model.DisplayScale);
|
||||
SetByteValue(UnitFields.Bytes0, 3, (byte)minfo.gender);
|
||||
|
||||
// Load creature equipment
|
||||
@@ -279,6 +283,8 @@ namespace Game.Entities
|
||||
|
||||
SetUInt32Value(ObjectFields.DynamicFlags, dynamicFlags);
|
||||
|
||||
SetUInt32Value(UnitFields.StateAnimId, (uint)CliDB.AnimationDataStorage.Count);
|
||||
|
||||
RemoveFlag(UnitFields.Flags, UnitFlags.InCombat);
|
||||
|
||||
SetBaseAttackTime(WeaponAttackType.BaseAttack, cInfo.BaseAttackTime);
|
||||
@@ -768,7 +774,8 @@ namespace Game.Entities
|
||||
if (!CreateFromProto(guidlow, entry, data, vehId))
|
||||
return false;
|
||||
|
||||
switch (GetCreatureTemplate().Rank)
|
||||
cinfo = GetCreatureTemplate(); // might be different than initially requested
|
||||
switch (cinfo.Rank)
|
||||
{
|
||||
case CreatureEliteType.Rare:
|
||||
m_corpseDelay = WorldConfig.GetUIntValue(WorldCfg.CorpseDecayRare);
|
||||
@@ -797,12 +804,12 @@ namespace Game.Entities
|
||||
Relocate(x, y, z, ang);
|
||||
}
|
||||
|
||||
uint displayID = GetNativeDisplayId();
|
||||
CreatureModelInfo minfo = Global.ObjectMgr.GetCreatureModelRandomGender(ref displayID);
|
||||
CreatureModel display = new CreatureModel(GetNativeDisplayId(), GetNativeDisplayScale(), 1.0f);
|
||||
CreatureModelInfo minfo = Global.ObjectMgr.GetCreatureModelRandomGender(ref display, cinfo);
|
||||
if (minfo != null && !IsTotem()) // Cancel load if no model defined or if totem
|
||||
{
|
||||
SetDisplayId(displayID);
|
||||
SetNativeDisplayId(displayID);
|
||||
SetDisplayId(display.CreatureDisplayID, display.DisplayScale);
|
||||
SetNativeDisplayId(display.CreatureDisplayID, display.DisplayScale);
|
||||
SetByteValue(UnitFields.Bytes0, 3, (byte)minfo.gender);
|
||||
}
|
||||
|
||||
@@ -815,10 +822,10 @@ namespace Game.Entities
|
||||
m_serverSideVisibilityDetect.SetValue(ServerSideVisibilityType.Ghost, GhostVisibilityType.Ghost);
|
||||
}
|
||||
|
||||
if (GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.IgnorePathfinding))
|
||||
if (cinfo.FlagsExtra.HasAnyFlag(CreatureFlagsExtra.IgnorePathfinding))
|
||||
AddUnitState(UnitState.IgnorePathfinding);
|
||||
|
||||
if (GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.ImmunityKnockback))
|
||||
if (cinfo.FlagsExtra.HasAnyFlag(CreatureFlagsExtra.ImmunityKnockback))
|
||||
{
|
||||
ApplySpellImmune(0, SpellImmunity.Effect, SpellEffectName.KnockBack, true);
|
||||
ApplySpellImmune(0, SpellImmunity.Effect, SpellEffectName.KnockBackDest, true);
|
||||
@@ -1014,9 +1021,9 @@ namespace Game.Entities
|
||||
CreatureTemplate cinfo = GetCreatureTemplate();
|
||||
if (cinfo != null)
|
||||
{
|
||||
if (displayId == cinfo.ModelId1 || displayId == cinfo.ModelId2 ||
|
||||
displayId == cinfo.ModelId3 || displayId == cinfo.ModelId4)
|
||||
displayId = 0;
|
||||
foreach (CreatureModel model in cinfo.Models)
|
||||
if (displayId != 0 && displayId == model.CreatureDisplayID)
|
||||
displayId = 0;
|
||||
|
||||
if (npcflag == (uint)cinfo.Npcflag)
|
||||
npcflag = 0;
|
||||
@@ -1620,12 +1627,12 @@ namespace Game.Entities
|
||||
|
||||
setDeathState(DeathState.JustRespawned);
|
||||
|
||||
uint displayID = GetNativeDisplayId();
|
||||
CreatureModelInfo minfo = Global.ObjectMgr.GetCreatureModelRandomGender(ref displayID);
|
||||
CreatureModel display = new CreatureModel(GetNativeDisplayId(), GetNativeDisplayScale(), 1.0f);
|
||||
CreatureModelInfo minfo = Global.ObjectMgr.GetCreatureModelRandomGender(ref display, GetCreatureTemplate());
|
||||
if (minfo != null) // Cancel load if no model defined
|
||||
{
|
||||
SetDisplayId(displayID);
|
||||
SetNativeDisplayId(displayID);
|
||||
SetDisplayId(display.CreatureDisplayID, display.DisplayScale);
|
||||
SetNativeDisplayId(display.CreatureDisplayID, display.DisplayScale);
|
||||
SetByteValue(UnitFields.Bytes0, 3, (byte)minfo.gender);
|
||||
}
|
||||
|
||||
@@ -2372,7 +2379,7 @@ namespace Game.Entities
|
||||
int targetLevelWithDelta = ((int)unitTarget.getLevel() + GetInt32Value(UnitFields.ScalingLevelDelta));
|
||||
|
||||
if (target.IsPlayer())
|
||||
targetLevelWithDelta += target.GetInt32Value(PlayerFields.ScalingLevelDelta);
|
||||
targetLevelWithDelta += target.GetInt32Value(ActivePlayerFields.ScalingPlayerLevelDelta);
|
||||
|
||||
return (uint)MathFunctions.RoundToInterval(ref targetLevelWithDelta, GetInt32Value(UnitFields.ScalingLevelMin), GetInt32Value(UnitFields.ScalingLevelMax));
|
||||
}
|
||||
@@ -2622,6 +2629,10 @@ namespace Game.Entities
|
||||
if (m_playerMovingMe != null)
|
||||
return;
|
||||
|
||||
// Creatures with CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE should control MovementFlags in your own scripts
|
||||
if (GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoMoveFlagsUpdate))
|
||||
return;
|
||||
|
||||
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
|
||||
float ground = GetMap().GetHeight(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
|
||||
|
||||
@@ -2653,23 +2664,30 @@ namespace Game.Entities
|
||||
CreatureModelInfo minfo = Global.ObjectMgr.GetCreatureModelInfo(GetDisplayId());
|
||||
if (minfo != null)
|
||||
{
|
||||
SetFloatValue(UnitFields.BoundingRadius, minfo.BoundingRadius * scale);
|
||||
SetFloatValue(UnitFields.CombatReach, minfo.CombatReach * scale);
|
||||
SetFloatValue(UnitFields.BoundingRadius, (IsPet() ? 1.0f : minfo.BoundingRadius) * scale);
|
||||
SetFloatValue(UnitFields.CombatReach, (IsPet() ? SharedConst.DefaultCombatReach : minfo.CombatReach) * scale);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetDisplayId(uint modelId)
|
||||
public override void SetDisplayId(uint modelId, float displayScale = 1f)
|
||||
{
|
||||
base.SetDisplayId(modelId);
|
||||
base.SetDisplayId(modelId, displayScale);
|
||||
|
||||
CreatureModelInfo minfo = Global.ObjectMgr.GetCreatureModelInfo(modelId);
|
||||
if (minfo != null)
|
||||
{
|
||||
SetFloatValue(UnitFields.BoundingRadius, minfo.BoundingRadius * GetObjectScale());
|
||||
SetFloatValue(UnitFields.CombatReach, minfo.CombatReach * GetObjectScale());
|
||||
SetFloatValue(UnitFields.BoundingRadius, (IsPet() ? 1.0f : minfo.BoundingRadius) * GetObjectScale());
|
||||
SetFloatValue(UnitFields.CombatReach, (IsPet() ? SharedConst.DefaultCombatReach : minfo.CombatReach) * GetObjectScale());
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDisplayFromModel(int modelIdx)
|
||||
{
|
||||
CreatureModel model = GetCreatureTemplate().GetModelByIdx(modelIdx);
|
||||
if (model != null)
|
||||
SetDisplayId(model.CreatureDisplayID, model.DisplayScale);
|
||||
}
|
||||
|
||||
public override void SetTarget(ObjectGuid guid)
|
||||
{
|
||||
if (IsFocusing(null, true))
|
||||
|
||||
@@ -28,10 +28,7 @@ namespace Game.Entities
|
||||
public uint Entry;
|
||||
public uint[] DifficultyEntry = new uint[SharedConst.MaxCreatureDifficulties];
|
||||
public uint[] KillCredit = new uint[SharedConst.MaxCreatureKillCredit];
|
||||
public uint ModelId1;
|
||||
public uint ModelId2;
|
||||
public uint ModelId3;
|
||||
public uint ModelId4;
|
||||
public List<CreatureModel> Models = new List<CreatureModel>();
|
||||
public string Name;
|
||||
public string FemaleName;
|
||||
public string SubName;
|
||||
@@ -91,75 +88,67 @@ namespace Game.Entities
|
||||
public CreatureFlagsExtra FlagsExtra;
|
||||
public uint ScriptID;
|
||||
|
||||
public uint GetRandomValidModelId()
|
||||
public CreatureModel GetModelByIdx(int idx)
|
||||
{
|
||||
byte c = 0;
|
||||
uint[] modelIDs = new uint[4];
|
||||
|
||||
if (ModelId1 != 0)
|
||||
modelIDs[c++] = ModelId1;
|
||||
if (ModelId2 != 0)
|
||||
modelIDs[c++] = ModelId2;
|
||||
if (ModelId3 != 0)
|
||||
modelIDs[c++] = ModelId3;
|
||||
if (ModelId4 != 0)
|
||||
modelIDs[c++] = ModelId4;
|
||||
|
||||
return c > 0 ? modelIDs[RandomHelper.IRand(0, c - 1)] : 0;
|
||||
}
|
||||
public uint GetFirstValidModelId()
|
||||
{
|
||||
if (ModelId1 != 0)
|
||||
return ModelId1;
|
||||
if (ModelId2 != 0)
|
||||
return ModelId2;
|
||||
if (ModelId3 != 0)
|
||||
return ModelId3;
|
||||
if (ModelId4 != 0)
|
||||
return ModelId4;
|
||||
return 0;
|
||||
return idx < Models.Count ? Models[idx] : null;
|
||||
}
|
||||
|
||||
public uint GetFirstInvisibleModel()
|
||||
public CreatureModel GetRandomValidModel()
|
||||
{
|
||||
CreatureModelInfo modelInfo = Global.ObjectMgr.GetCreatureModelInfo(ModelId1);
|
||||
if (modelInfo != null && modelInfo.IsTrigger)
|
||||
return ModelId1;
|
||||
if (Models.Empty())
|
||||
return null;
|
||||
|
||||
modelInfo = Global.ObjectMgr.GetCreatureModelInfo(ModelId2);
|
||||
if (modelInfo != null && modelInfo.IsTrigger)
|
||||
return ModelId2;
|
||||
// If only one element, ignore the Probability (even if 0)
|
||||
if (Models.Count == 1)
|
||||
return Models[0];
|
||||
|
||||
modelInfo = Global.ObjectMgr.GetCreatureModelInfo(ModelId3);
|
||||
if (modelInfo != null && modelInfo.IsTrigger)
|
||||
return ModelId3;
|
||||
var selectedItr = Models.SelectRandomElementByWeight(model =>
|
||||
{
|
||||
return model.Probability;
|
||||
});
|
||||
|
||||
modelInfo = Global.ObjectMgr.GetCreatureModelInfo(ModelId4);
|
||||
if (modelInfo != null && modelInfo.IsTrigger)
|
||||
return ModelId4;
|
||||
return selectedItr;
|
||||
}
|
||||
public CreatureModel GetFirstValidModel()
|
||||
{
|
||||
foreach (CreatureModel model in Models)
|
||||
if (model.CreatureDisplayID != 0)
|
||||
return model;
|
||||
|
||||
return 11686;
|
||||
return null;
|
||||
}
|
||||
|
||||
public uint GetFirstVisibleModel()
|
||||
public CreatureModel GetModelWithDisplayId(uint displayId)
|
||||
{
|
||||
CreatureModelInfo modelInfo = Global.ObjectMgr.GetCreatureModelInfo(ModelId1);
|
||||
if (modelInfo != null && !modelInfo.IsTrigger)
|
||||
return ModelId1;
|
||||
foreach (CreatureModel model in Models)
|
||||
if (displayId == model.CreatureDisplayID)
|
||||
return model;
|
||||
|
||||
modelInfo = Global.ObjectMgr.GetCreatureModelInfo(ModelId2);
|
||||
if (modelInfo != null && !modelInfo.IsTrigger)
|
||||
return ModelId2;
|
||||
return null;
|
||||
}
|
||||
|
||||
modelInfo = Global.ObjectMgr.GetCreatureModelInfo(ModelId3);
|
||||
if (modelInfo != null && !modelInfo.IsTrigger)
|
||||
return ModelId3;
|
||||
public CreatureModel GetFirstInvisibleModel()
|
||||
{
|
||||
foreach (CreatureModel model in Models)
|
||||
{
|
||||
CreatureModelInfo modelInfo = Global.ObjectMgr.GetCreatureModelInfo(model.CreatureDisplayID);
|
||||
if (modelInfo != null && modelInfo.IsTrigger)
|
||||
return model;
|
||||
}
|
||||
|
||||
modelInfo = Global.ObjectMgr.GetCreatureModelInfo(ModelId4);
|
||||
if (modelInfo != null && !modelInfo.IsTrigger)
|
||||
return ModelId4;
|
||||
return CreatureModel.DefaultInvisibleModel;
|
||||
}
|
||||
|
||||
return 17519;
|
||||
public CreatureModel GetFirstVisibleModel()
|
||||
{
|
||||
foreach (CreatureModel model in Models)
|
||||
{
|
||||
CreatureModelInfo modelInfo = Global.ObjectMgr.GetCreatureModelInfo(model.CreatureDisplayID);
|
||||
if (modelInfo != null && !modelInfo.IsTrigger)
|
||||
return model;
|
||||
}
|
||||
|
||||
return CreatureModel.DefaultVisibleModel;
|
||||
}
|
||||
|
||||
public SkillType GetRequiredLootSkill()
|
||||
@@ -314,6 +303,24 @@ namespace Game.Entities
|
||||
public bool IsTrigger;
|
||||
}
|
||||
|
||||
public class CreatureModel
|
||||
{
|
||||
public static CreatureModel DefaultInvisibleModel = new CreatureModel(11686, 1.0f, 1.0f);
|
||||
public static CreatureModel DefaultVisibleModel = new CreatureModel(17519, 1.0f, 1.0f);
|
||||
|
||||
public uint CreatureDisplayID;
|
||||
public float DisplayScale;
|
||||
public float Probability;
|
||||
|
||||
public CreatureModel() { }
|
||||
public CreatureModel(uint creatureDisplayID, float displayScale, float probability)
|
||||
{
|
||||
CreatureDisplayID = creatureDisplayID;
|
||||
DisplayScale = displayScale;
|
||||
Probability = probability;
|
||||
}
|
||||
}
|
||||
|
||||
public class CreatureAddon
|
||||
{
|
||||
public uint path_id;
|
||||
|
||||
@@ -316,6 +316,7 @@ namespace Game.Misc
|
||||
}
|
||||
|
||||
GossipPOI packet = new GossipPOI();
|
||||
packet.ID = pointOfInterest.ID;
|
||||
packet.Name = pointOfInterest.Name;
|
||||
|
||||
LocaleConstant locale = _session.GetSessionDbLocaleIndex();
|
||||
@@ -431,10 +432,11 @@ namespace Game.Misc
|
||||
packet.InformUnit = _session.GetPlayer().GetDivider();
|
||||
packet.QuestID = quest.Id;
|
||||
packet.PortraitGiver = quest.QuestGiverPortrait;
|
||||
packet.PortraitGiverMount = quest.QuestGiverPortraitMount;
|
||||
packet.PortraitTurnIn = quest.QuestTurnInPortrait;
|
||||
packet.AutoLaunched = autoLaunched;
|
||||
packet.DisplayPopup = displayPopup;
|
||||
packet.QuestFlags[0] = (uint)quest.Flags;
|
||||
packet.QuestFlags[0] = (uint)(quest.Flags & (WorldConfig.GetBoolValue(WorldCfg.QuestIgnoreAutoAccept) ? ~QuestFlags.AutoAccept : ~QuestFlags.None));
|
||||
packet.QuestFlags[1] = (uint)quest.FlagsEx;
|
||||
packet.SuggestedPartyMembers = quest.SuggestedPlayers;
|
||||
|
||||
@@ -501,6 +503,7 @@ namespace Game.Misc
|
||||
packet.Info.QuestID = quest.Id;
|
||||
packet.Info.QuestType = (int)quest.Type;
|
||||
packet.Info.QuestLevel = quest.Level;
|
||||
packet.Info.QuestScalingFactionGroup = quest.ScalingFactionGroup;
|
||||
packet.Info.QuestMaxScalingLevel = quest.MaxScalingLevel;
|
||||
packet.Info.QuestPackageID = quest.PackageID;
|
||||
packet.Info.QuestMinLevel = quest.MinLevel;
|
||||
@@ -532,12 +535,14 @@ namespace Game.Misc
|
||||
packet.Info.StartItem = quest.SourceItemId;
|
||||
packet.Info.Flags = (uint)quest.Flags;
|
||||
packet.Info.FlagsEx = (uint)quest.FlagsEx;
|
||||
packet.Info.FlagsEx2 = (uint)quest.FlagsEx2;
|
||||
packet.Info.RewardTitle = quest.RewardTitleId;
|
||||
packet.Info.RewardArenaPoints = quest.RewardArenaPoints;
|
||||
packet.Info.RewardSkillLineID = quest.RewardSkillId;
|
||||
packet.Info.RewardNumSkillUps = quest.RewardSkillPoints;
|
||||
packet.Info.RewardFactionFlags = quest.RewardReputationMask;
|
||||
packet.Info.PortraitGiver = quest.QuestGiverPortrait;
|
||||
packet.Info.PortraitGiverMount = quest.QuestGiverPortraitMount;
|
||||
packet.Info.PortraitTurnIn = quest.QuestTurnInPortrait;
|
||||
|
||||
for (byte i = 0; i < SharedConst.QuestItemDropCount; ++i)
|
||||
@@ -574,7 +579,7 @@ namespace Game.Misc
|
||||
packet.Info.POIPriority = quest.POIPriority;
|
||||
|
||||
packet.Info.AllowableRaces = quest.AllowableRaces;
|
||||
packet.Info.QuestRewardID = (int)quest.QuestRewardID;
|
||||
packet.Info.TreasurePickerID = (int)quest.TreasurePickerID;
|
||||
packet.Info.Expansion = quest.Expansion;
|
||||
|
||||
foreach (QuestObjective questObjective in quest.Objectives)
|
||||
@@ -654,6 +659,7 @@ namespace Game.Misc
|
||||
|
||||
packet.PortraitTurnIn = quest.QuestTurnInPortrait;
|
||||
packet.PortraitGiver = quest.QuestGiverPortrait;
|
||||
packet.PortraitGiverMount = quest.QuestGiverPortraitMount;
|
||||
packet.QuestPackageID = quest.PackageID;
|
||||
|
||||
packet.QuestData = offer;
|
||||
|
||||
@@ -15,8 +15,7 @@ namespace Game.Entities
|
||||
public Array<uint> ReqAbility = new Array<uint>(3);
|
||||
public byte ReqLevel;
|
||||
|
||||
public uint LearnedSpellId;
|
||||
public bool IsCastable() { return LearnedSpellId != SpellId; }
|
||||
public bool IsCastable() { return Global.SpellMgr.GetSpellInfo(SpellId).HasEffect(SpellEffectName.LearnSpell); }
|
||||
}
|
||||
|
||||
public class Trainer
|
||||
@@ -108,7 +107,7 @@ namespace Game.Entities
|
||||
|
||||
TrainerSpellState GetSpellState(Player player, TrainerSpell trainerSpell)
|
||||
{
|
||||
if (player.HasSpell(trainerSpell.IsCastable() ? trainerSpell.LearnedSpellId : trainerSpell.SpellId))
|
||||
if (player.HasSpell(trainerSpell.SpellId))
|
||||
return TrainerSpellState.Known;
|
||||
|
||||
// check race/class requirement
|
||||
@@ -128,10 +127,32 @@ namespace Game.Entities
|
||||
return TrainerSpellState.Unavailable;
|
||||
|
||||
// check ranks
|
||||
uint previousRankSpellId = Global.SpellMgr.GetPrevSpellInChain(trainerSpell.LearnedSpellId);
|
||||
if (previousRankSpellId != 0)
|
||||
if (!player.HasSpell(previousRankSpellId))
|
||||
return TrainerSpellState.Unavailable;
|
||||
bool hasLearnSpellEffect = false;
|
||||
bool knowsAllLearnedSpells = true;
|
||||
foreach (SpellEffectInfo spellEffect in Global.SpellMgr.GetSpellInfo(trainerSpell.SpellId).GetEffectsForDifficulty(Difficulty.None))
|
||||
{
|
||||
if (spellEffect == null || !spellEffect.IsEffect(SpellEffectName.LearnSpell))
|
||||
continue;
|
||||
|
||||
hasLearnSpellEffect = true;
|
||||
if (!player.HasSpell(spellEffect.TriggerSpell))
|
||||
knowsAllLearnedSpells = false;
|
||||
|
||||
uint previousRankSpellId = Global.SpellMgr.GetPrevSpellInChain(spellEffect.TriggerSpell);
|
||||
if (previousRankSpellId != 0)
|
||||
if (!player.HasSpell(previousRankSpellId))
|
||||
return TrainerSpellState.Unavailable;
|
||||
}
|
||||
|
||||
if (!hasLearnSpellEffect)
|
||||
{
|
||||
uint previousRankSpellId = Global.SpellMgr.GetPrevSpellInChain(trainerSpell.SpellId);
|
||||
if (previousRankSpellId != 0)
|
||||
if (!player.HasSpell(previousRankSpellId))
|
||||
return TrainerSpellState.Unavailable;
|
||||
}
|
||||
else if (knowsAllLearnedSpells)
|
||||
return TrainerSpellState.Known;
|
||||
|
||||
// check additional spell requirement
|
||||
foreach (var spellId in Global.SpellMgr.GetSpellsRequiredForSpellBounds(trainerSpell.SpellId))
|
||||
|
||||
Reference in New Issue
Block a user