Rewrite trainer handling to properly support multiple trainers on the same creature
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Framework.Constants;
|
||||
using Game.Network.Packets;
|
||||
using Game.Spells;
|
||||
|
||||
namespace Game.Entities
|
||||
{
|
||||
public class TrainerSpell
|
||||
{
|
||||
public uint SpellId;
|
||||
public uint MoneyCost;
|
||||
public uint ReqSkillLine;
|
||||
public uint ReqSkillRank;
|
||||
public Array<uint> ReqAbility = new Array<uint>(3);
|
||||
public byte ReqLevel;
|
||||
|
||||
public uint CastSpellId;
|
||||
}
|
||||
|
||||
public class Trainer
|
||||
{
|
||||
public Trainer(uint id, TrainerType type, string greeting, List<TrainerSpell> spells)
|
||||
{
|
||||
_id = id;
|
||||
_type = type;
|
||||
_spells = spells;
|
||||
|
||||
_greeting[(int)LocaleConstant.enUS] = greeting;
|
||||
}
|
||||
|
||||
public void SendSpells(Creature npc, Player player, LocaleConstant locale)
|
||||
{
|
||||
float reputationDiscount = player.GetReputationPriceDiscount(npc);
|
||||
|
||||
TrainerList trainerList = new TrainerList();
|
||||
trainerList.TrainerGUID = npc.GetGUID();
|
||||
trainerList.TrainerType = (int)_type;
|
||||
trainerList.TrainerID = (int)_id;
|
||||
trainerList.Greeting = GetGreeting(locale);
|
||||
|
||||
foreach (TrainerSpell trainerSpell in _spells)
|
||||
{
|
||||
if (!player.IsSpellFitByClassAndRace(trainerSpell.SpellId))
|
||||
continue;
|
||||
|
||||
TrainerListSpell trainerListSpell = new TrainerListSpell();
|
||||
trainerListSpell.SpellID = trainerSpell.SpellId;
|
||||
trainerListSpell.MoneyCost = (uint)(trainerSpell.MoneyCost * reputationDiscount);
|
||||
trainerListSpell.ReqSkillLine = trainerSpell.ReqSkillLine;
|
||||
trainerListSpell.ReqSkillRank = trainerSpell.ReqSkillRank;
|
||||
trainerListSpell.ReqAbility = trainerSpell.ReqAbility.ToArray();
|
||||
trainerListSpell.Usable = GetSpellState(player, trainerSpell);
|
||||
trainerListSpell.ReqLevel = trainerSpell.ReqLevel;
|
||||
trainerList.Spells.Add(trainerListSpell);
|
||||
}
|
||||
|
||||
player.SendPacket(trainerList);
|
||||
}
|
||||
|
||||
public void TeachSpell(Creature npc, Player player, uint spellId)
|
||||
{
|
||||
TrainerSpell trainerSpell = GetSpell(spellId);
|
||||
if (trainerSpell == null || !CanTeachSpell(player, trainerSpell))
|
||||
{
|
||||
SendTeachFailure(npc, player, spellId, TrainerFailReason.Unavailable);
|
||||
return;
|
||||
}
|
||||
|
||||
float reputationDiscount = player.GetReputationPriceDiscount(npc);
|
||||
long moneyCost = (long)(trainerSpell.MoneyCost * reputationDiscount);
|
||||
if (!player.HasEnoughMoney(moneyCost))
|
||||
{
|
||||
SendTeachFailure(npc, player, spellId, TrainerFailReason.NotEnoughMoney);
|
||||
return;
|
||||
}
|
||||
|
||||
player.ModifyMoney(-moneyCost);
|
||||
|
||||
npc.SendPlaySpellVisualKit(179, 0, 0); // 53 SpellCastDirected
|
||||
player.SendPlaySpellVisualKit(362, 1, 0); // 113 EmoteSalute
|
||||
|
||||
// learn explicitly or cast explicitly
|
||||
if (trainerSpell.CastSpellId != 0)
|
||||
player.CastSpell(player, trainerSpell.CastSpellId, true);
|
||||
else
|
||||
player.LearnSpell(trainerSpell.SpellId, false);
|
||||
}
|
||||
|
||||
TrainerSpell GetSpell(uint spellId)
|
||||
{
|
||||
return _spells.Find(trainerSpell => trainerSpell.SpellId == spellId);
|
||||
}
|
||||
|
||||
bool CanTeachSpell(Player player, TrainerSpell trainerSpell)
|
||||
{
|
||||
TrainerSpellState state = GetSpellState(player, trainerSpell);
|
||||
if (state != TrainerSpellState.Available)
|
||||
return false;
|
||||
|
||||
SpellInfo trainerSpellInfo = Global.SpellMgr.GetSpellInfo(trainerSpell.SpellId);
|
||||
if (trainerSpellInfo.IsPrimaryProfessionFirstRank() && player.GetFreePrimaryProfessionPoints() == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TrainerSpellState GetSpellState(Player player, TrainerSpell trainerSpell)
|
||||
{
|
||||
if (player.HasSpell(trainerSpell.SpellId))
|
||||
return TrainerSpellState.Known;
|
||||
|
||||
// check race/class requirement
|
||||
if (!player.IsSpellFitByClassAndRace(trainerSpell.SpellId))
|
||||
return TrainerSpellState.Unavailable;
|
||||
|
||||
// check skill requirement
|
||||
if (trainerSpell.ReqSkillLine != 0 && player.GetBaseSkillValue((SkillType)trainerSpell.ReqSkillLine) < trainerSpell.ReqSkillRank)
|
||||
return TrainerSpellState.Unavailable;
|
||||
|
||||
foreach (uint reqAbility in trainerSpell.ReqAbility)
|
||||
if (reqAbility != 0 && !player.HasSpell(reqAbility))
|
||||
return TrainerSpellState.Unavailable;
|
||||
|
||||
// check level requirement
|
||||
if (player.getLevel() < trainerSpell.ReqLevel)
|
||||
return TrainerSpellState.Unavailable;
|
||||
|
||||
// check additional spell requirement
|
||||
foreach (var spellId in Global.SpellMgr.GetSpellsRequiredForSpellBounds(trainerSpell.SpellId))
|
||||
if (!player.HasSpell(spellId))
|
||||
return TrainerSpellState.Unavailable;
|
||||
|
||||
return TrainerSpellState.Available;
|
||||
}
|
||||
|
||||
void SendTeachFailure(Creature npc, Player player, uint spellId, TrainerFailReason reason)
|
||||
{
|
||||
TrainerBuyFailed trainerBuyFailed = new TrainerBuyFailed();
|
||||
trainerBuyFailed.TrainerGUID = npc.GetGUID();
|
||||
trainerBuyFailed.SpellID = spellId;
|
||||
trainerBuyFailed.TrainerFailedReason = reason;
|
||||
player.SendPacket(trainerBuyFailed);
|
||||
}
|
||||
|
||||
string GetGreeting(LocaleConstant locale)
|
||||
{
|
||||
if (_greeting[(int)locale].IsEmpty())
|
||||
return _greeting[(int)LocaleConstant.enUS];
|
||||
|
||||
return _greeting[(int)locale];
|
||||
}
|
||||
|
||||
public void AddGreetingLocale(LocaleConstant locale, string greeting)
|
||||
{
|
||||
_greeting[(int)locale] = greeting;
|
||||
}
|
||||
|
||||
uint _id;
|
||||
TrainerType _type;
|
||||
List<TrainerSpell> _spells;
|
||||
Array<string> _greeting = new Array<string>((int)LocaleConstant.Total);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user