void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recv_data) { ObjectGuid guid; uint32 spellId = 0, trainerId = 0; recv_data >> guid >> trainerId >> spellId; DEBUG_LOG("WORLD: Received opcode CMSG_TRAINER_BUY_SPELL Trainer: %s, learn spell id is: %u", guid.GetString().c_str(), spellId); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); if (!unit) { DEBUG_LOG("WORLD: HandleTrainerBuySpellOpcode - %s not found or you can't interact with him.", guid.GetString().c_str()); return; } WorldPacket sendData(SMSG_TRAINER_SERVICE, 16); uint32 trainState = 2; if (!unit->IsTrainerOf(_player, true)) trainState = 1; // check present spell in trainer spell list TrainerSpellData const* cSpells = unit->GetTrainerSpells(); TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells(); if (!cSpells && !tSpells) trainState = 1; // Try find spell in npc_trainer TrainerSpell const* trainer_spell = cSpells ? cSpells->Find(spellId) : nullptr; // Not found, try find in npc_trainer_template if (!trainer_spell && tSpells) trainer_spell = tSpells->Find(spellId); // Not found anywhere, cheating? if (!trainer_spell) trainState = 1; // can't be learn, cheat? Or double learn with lags... uint32 reqLevel = 0; if (!_player->IsSpellFitByClassAndRace(trainer_spell->learnedSpell, &reqLevel)) trainState = 1; reqLevel = trainer_spell->isProvidedReqLevel ? trainer_spell->reqLevel : std::max(reqLevel, trainer_spell->reqLevel); if (_player->GetTrainerSpellState(trainer_spell, reqLevel) != TRAINER_SPELL_GREEN) trainState = 1; // apply reputation discount uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit))); // check money requirement if (_player->GetMoney() < nSpellCost && trainState > 1) trainState = 0; if (trainState != 2) { sendData << ObjectGuid(guid); sendData << uint32(spellId); sendData << uint32(trainState); SendPacket(&sendData); } else { _player->ModifyMoney(-int64(nSpellCost)); // visual effect on trainer WorldPacket data; unit->BuildSendPlayVisualPacket(&data, 0xB3, false); SendPacket(&data); // visual effect on player _player->BuildSendPlayVisualPacket(&data, 0x016A, true); SendPacket(&data); // learn explicitly or cast explicitly // TODO - Are these spells really cast correctly this way? if (trainer_spell->IsCastable()) _player->CastSpell(_player, trainer_spell->spell, true); else _player->learnSpell(spellId, false); sendData << ObjectGuid(guid); sendData << uint32(spellId); // should be same as in packet from client sendData << uint32(trainState); SendPacket(&sendData); } }
void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recv_data) { ObjectGuid guid; uint32 spellId = 0, trainerId = 0; recv_data >> guid >> trainerId >> spellId; DEBUG_LOG("WORLD: Received CMSG_TRAINER_BUY_SPELL Trainer: %s, learn spell id is: %u", guid.GetString().c_str(), spellId); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); if (!unit) { DEBUG_LOG("WORLD: HandleTrainerBuySpellOpcode - %s not found or you can't interact with him.", guid.GetString().c_str()); return; } // remove fake death if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if (!unit->IsTrainerOf(_player, true)) return; // check present spell in trainer spell list TrainerSpellData const* cSpells = unit->GetTrainerSpells(); TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells(); if (!cSpells && !tSpells) return; // Try find spell in npc_trainer TrainerSpell const* trainer_spell = cSpells ? cSpells->Find(spellId) : NULL; // Not found, try find in npc_trainer_template if (!trainer_spell && tSpells) trainer_spell = tSpells->Find(spellId); // Not found anywhere, cheating? if (!trainer_spell) return; // can't be learn, cheat? Or double learn with lags... uint32 reqLevel = 0; if (!_player->IsSpellFitByClassAndRace(trainer_spell->learnedSpell, &reqLevel)) return; reqLevel = trainer_spell->isProvidedReqLevel ? trainer_spell->reqLevel : std::max(reqLevel, trainer_spell->reqLevel); if (_player->GetTrainerSpellState(trainer_spell, reqLevel) != TRAINER_SPELL_GREEN) return; // apply reputation discount uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit))); // check money requirement if (_player->GetMoney() < nSpellCost) return; _player->ModifyMoney(-int32(nSpellCost)); // visual effect on trainer WorldPacket data; unit->BuildSendPlayVisualPacket(&data, 0xB3, false); SendPacket(&data); // visual effect on player _player->BuildSendPlayVisualPacket(&data, 0x016A, true); SendPacket(&data); // learn explicitly or cast explicitly if (trainer_spell->IsCastable()) _player->CastSpell(_player, trainer_spell->spell, true); else _player->learnSpell(spellId, false); data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12); data << ObjectGuid(guid); data << uint32(spellId); // should be same as in packet from client SendPacket(&data); }