mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/Handlers: actually check allowed trainer classes and races to avoid spoofing
Closes #14586
This commit is contained in:
@@ -14010,8 +14010,11 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
|
||||
break;
|
||||
case GOSSIP_OPTION_TRAINER:
|
||||
if (getClass() != creature->GetCreatureTemplate()->trainer_class && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "GOSSIP_OPTION_TRAINER:: Player %s (GUID: %u) requested wrong gossip menu: %u with wrong class: %u at Creature: %s (Entry: %u, Trainer Class: %u)",
|
||||
GetName().c_str(), GetGUID().GetCounter(), menu->GetGossipMenu().GetMenuId(), getClass(), creature->GetName().c_str(), creature->GetEntry(), creature->GetCreatureTemplate()->trainer_class);
|
||||
GetName().c_str(), GetGUID().GetCounter(), menu->GetGossipMenu().GetMenuId(), getClass(), creature->GetName().c_str(), creature->GetEntry(), creature->GetCreatureTemplate()->trainer_class);
|
||||
canTalk = false;
|
||||
}
|
||||
// no break;
|
||||
case GOSSIP_OPTION_GOSSIP:
|
||||
case GOSSIP_OPTION_SPIRITGUIDE:
|
||||
|
||||
@@ -236,8 +236,8 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData)
|
||||
recvData >> guid >> spellId;
|
||||
TC_LOG_DEBUG("network", "WORLD: Received CMSG_TRAINER_BUY_SPELL %s, learn spell id is: %u", guid.ToString().c_str(), spellId);
|
||||
|
||||
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
|
||||
if (!unit)
|
||||
Creature* trainer = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
|
||||
if (!trainer)
|
||||
{
|
||||
TC_LOG_DEBUG("network", "WORLD: HandleTrainerBuySpellOpcode - %s not found or you can not interact with him.", guid.ToString().c_str());
|
||||
return;
|
||||
@@ -247,8 +247,20 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData)
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
// check race for mount trainers
|
||||
if (trainer->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_MOUNTS)
|
||||
{
|
||||
if (uint32 trainerRace = trainer->GetCreatureTemplate()->trainer_race)
|
||||
if (_player->getRace() != trainerRace)
|
||||
return;
|
||||
}
|
||||
|
||||
// check class for class trainers
|
||||
if (_player->getClass() != trainer->GetCreatureTemplate()->trainer_class && trainer->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS)
|
||||
return;
|
||||
|
||||
// check present spell in trainer spell list
|
||||
TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
|
||||
TrainerSpellData const* trainer_spells = trainer->GetTrainerSpells();
|
||||
if (!trainer_spells)
|
||||
return;
|
||||
|
||||
@@ -262,7 +274,7 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
|
||||
// apply reputation discount
|
||||
uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
|
||||
uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(trainer)));
|
||||
|
||||
// check money requirement
|
||||
if (!_player->HasEnoughMoney(nSpellCost))
|
||||
@@ -270,8 +282,8 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData)
|
||||
|
||||
_player->ModifyMoney(-int32(nSpellCost));
|
||||
|
||||
unit->SendPlaySpellVisual(179); // 53 SpellCastDirected
|
||||
unit->SendPlaySpellImpact(_player->GetGUID(), 362); // 113 EmoteSalute
|
||||
trainer->SendPlaySpellVisual(179); // 53 SpellCastDirected
|
||||
trainer->SendPlaySpellImpact(_player->GetGUID(), 362); // 113 EmoteSalute
|
||||
|
||||
// learn explicitly or cast explicitly
|
||||
if (trainer_spell->IsCastable())
|
||||
|
||||
Reference in New Issue
Block a user