TrinityCore
NPCHandler.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WorldSession.h"
19#include "Battleground.h"
20#include "Common.h"
21#include "Creature.h"
22#include "CreatureAI.h"
23#include "DatabaseEnv.h"
24#include "DB2Stores.h"
25#include "GameObject.h"
26#include "GameObjectAI.h"
27#include "GossipDef.h"
28#include "Item.h"
29#include "ItemPackets.h"
30#include "Log.h"
31#include "Map.h"
32#include "NPCPackets.h"
33#include "ObjectMgr.h"
34#include "Pet.h"
35#include "PetPackets.h"
36#include "Player.h"
37#include "ReputationMgr.h"
38#include "SpellInfo.h"
39#include "Trainer.h"
40#include "WorldPacket.h"
41
43{
44 Guild = 0,
45 Personal = 1,
46};
47
49{
51 if (!unit)
52 {
53 TC_LOG_DEBUG("network", "WORLD: HandleTabardVendorActivateOpcode - {} not found or you can not interact with him.", tabardVendorActivate.Vendor.ToString());
54 return;
55 }
56
57 TabardVendorType type = TabardVendorType(tabardVendorActivate.Type);
59 return;
60
61 // remove fake death
62 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
64
65 SendTabardVendorActivate(tabardVendorActivate.Vendor, TabardVendorType(tabardVendorActivate.Type));
66}
67
69{
71 npcInteraction.Npc = guid;
72 npcInteraction.InteractionType = [&]
73 {
74 switch (type)
75 {
80 default:
81 ABORT_MSG("Unsupported tabard vendor type %d", AsUnderlyingType(type));
82 }
83 }();
84 npcInteraction.Success = true;
85 SendPacket(npcInteraction.Write());
86}
87
89{
91 npcInteraction.Npc = guid;
93 npcInteraction.Success = true;
94 SendPacket(npcInteraction.Write());
95}
96
98{
100 if (!npc)
101 {
102 TC_LOG_DEBUG("network", "WorldSession::SendTrainerList - {} not found or you can not interact with him.", packet.Unit.ToString());
103 return;
104 }
105
106 if (uint32 trainerId = npc->GetTrainerId())
107 SendTrainerList(npc, trainerId);
108 else
109 TC_LOG_DEBUG("network", "WorldSession::SendTrainerList - Creature id {} has no trainer data.", npc->GetEntry());
110}
111
113{
114 // remove fake death
115 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
117
118 Trainer::Trainer const* trainer = sObjectMgr->GetTrainer(trainerId);
119 if (!trainer)
120 {
121 TC_LOG_DEBUG("network", "WorldSession::SendTrainerList - trainer spells not found for trainer {} id {}", npc->GetGUID().ToString(), trainerId);
122 return;
123 }
124
125 _player->PlayerTalkClass->GetInteractionData().Reset();
126 _player->PlayerTalkClass->GetInteractionData().SourceGuid = npc->GetGUID();
127 _player->PlayerTalkClass->GetInteractionData().TrainerId = trainerId;
129}
130
132{
133 TC_LOG_DEBUG("network", "WORLD: Received CMSG_TRAINER_BUY_SPELL {}, learn spell id is: {}", packet.TrainerGUID.ToString(), packet.SpellID);
134
136 if (!npc)
137 {
138 TC_LOG_DEBUG("network", "WORLD: HandleTrainerBuySpellOpcode - {} not found or you can not interact with him.", packet.TrainerGUID.ToString());
139 return;
140 }
141
142 // remove fake death
143 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
145
146 if (_player->PlayerTalkClass->GetInteractionData().SourceGuid != packet.TrainerGUID)
147 return;
148
149 if (_player->PlayerTalkClass->GetInteractionData().TrainerId != uint32(packet.TrainerID))
150 return;
151
152 Trainer::Trainer const* trainer = sObjectMgr->GetTrainer(packet.TrainerID);
153 if (!trainer)
154 return;
155
156 trainer->TeachSpell(npc, _player, packet.SpellID);
157}
158
160{
162 if (!unit)
163 {
164 TC_LOG_DEBUG("network", "WORLD: HandleGossipHelloOpcode - {} not found or you can not interact with him.", packet.Unit.ToString());
165 return;
166 }
167
168 // set faction visible if needed
169 if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->GetFaction()))
170 _player->GetReputationMgr().SetVisible(factionTemplateEntry);
171
173
174 // Stop the npc if moving
176 unit->PauseMovement(pause);
177 unit->SetHomePosition(unit->GetPosition());
178
179 if (unit->IsAreaSpiritHealer())
180 {
183 }
184
185 _player->PlayerTalkClass->ClearMenus();
186 if (!unit->AI()->OnGossipHello(_player))
187 {
188// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID());
191 }
192}
193
195{
196 GossipMenuItem const* gossipMenuItem = _player->PlayerTalkClass->GetGossipMenu().GetItem(packet.GossipOptionID);
197 if (!gossipMenuItem)
198 return;
199
200 // Prevent cheating on C++ scripted menus
201 if (_player->PlayerTalkClass->GetInteractionData().SourceGuid != packet.GossipUnit)
202 return;
203
204 Creature* unit = nullptr;
205 GameObject* go = nullptr;
206 if (packet.GossipUnit.IsCreatureOrVehicle())
207 {
209 if (!unit)
210 {
211 TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - {} not found or you can't interact with him.", packet.GossipUnit.ToString());
212 return;
213 }
214 }
215 else if (packet.GossipUnit.IsGameObject())
216 {
218 if (!go)
219 {
220 TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - {} not found or you can't interact with it.", packet.GossipUnit.ToString());
221 return;
222 }
223 }
224 else
225 {
226
227 TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - unsupported {}.", packet.GossipUnit.ToString());
228 return;
229 }
230
231 // remove fake death
232 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
234
235 if ((unit && unit->GetScriptId() != unit->LastUsedScriptID) || (go && go->GetScriptId() != go->LastUsedScriptID))
236 {
237 TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - Script reloaded while in use, ignoring and set new scipt id");
238 if (unit)
239 unit->LastUsedScriptID = unit->GetScriptId();
240
241 if (go)
242 go->LastUsedScriptID = go->GetScriptId();
243 _player->PlayerTalkClass->SendCloseGossip();
244 return;
245 }
246
247 if (!packet.PromotionCode.empty())
248 {
249 if (unit)
250 {
251 if (!unit->AI()->OnGossipSelectCode(_player, packet.GossipID, gossipMenuItem->OrderIndex, packet.PromotionCode.c_str()))
252 _player->OnGossipSelect(unit, packet.GossipOptionID, packet.GossipID);
253 }
254 else
255 {
256 if (!go->AI()->OnGossipSelectCode(_player, packet.GossipID, gossipMenuItem->OrderIndex, packet.PromotionCode.c_str()))
257 _player->OnGossipSelect(go, packet.GossipOptionID, packet.GossipID);
258 }
259 }
260 else
261 {
262 if (unit)
263 {
264 if (!unit->AI()->OnGossipSelect(_player, packet.GossipID, gossipMenuItem->OrderIndex))
265 _player->OnGossipSelect(unit, packet.GossipOptionID, packet.GossipID);
266 }
267 else
268 {
269 if (!go->AI()->OnGossipSelect(_player, packet.GossipID, gossipMenuItem->OrderIndex))
270 _player->OnGossipSelect(go, packet.GossipOptionID, packet.GossipID);
271 }
272 }
273}
274
276{
278 if (!unit)
279 {
280 TC_LOG_DEBUG("network", "WORLD: HandleSpiritHealerActivateOpcode - {} not found or you can not interact with him.", packet.Healer.ToString());
281 return;
282 }
283
284 // remove fake death
285 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
287
289}
290
292{
293 _player->ResurrectPlayer(0.5f, true);
294 _player->DurabilityLossAll(0.25f, true);
295
296 // get corpse nearest graveyard
297 WorldSafeLocsEntry const* corpseGrave = nullptr;
298 WorldLocation corpseLocation = _player->GetCorpseLocation();
299 if (_player->HasCorpse())
300 {
301 corpseGrave = sObjectMgr->GetClosestGraveyard(corpseLocation, _player->GetTeam(), _player);
302 }
303
304 // now can spawn bones
306
307 // teleport to nearest from corpse graveyard, if different from nearest to player ghost
308 if (corpseGrave)
309 {
310 WorldSafeLocsEntry const* ghostGrave = sObjectMgr->GetClosestGraveyard(*_player, _player->GetTeam(), _player);
311
312 if (corpseGrave != ghostGrave)
313 _player->TeleportTo(corpseGrave->Loc);
314 }
315}
316
318{
319 if (!GetPlayer()->IsInWorld() || !GetPlayer()->IsAlive())
320 return;
321
323 if (!unit)
324 {
325 TC_LOG_DEBUG("network", "WORLD: HandleBinderActivateOpcode - {} not found or you can not interact with him.", packet.Unit.ToString());
326 return;
327 }
328
329 // remove fake death
330 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
332
333 SendBindPoint(unit);
334}
335
337{
338 // prevent set homebind to instances in any case
339 if (GetPlayer()->GetMap()->Instanceable())
340 return;
341
342 uint32 bindspell = 3286;
343
344 // send spell for homebinding (3286)
345 npc->CastSpell(_player, bindspell, true);
346
347 _player->PlayerTalkClass->SendCloseGossip();
348}
349
351{
352 if (!CheckStableMaster(packet.StableMaster))
353 return;
354
355 // remove fake death
356 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
358
359 // remove mounts this fix bug where getting pet from stable while mounted deletes pet.
360 if (GetPlayer()->IsMounted())
362
364}
365
367{
369 petStableResult.Result = AsUnderlyingType(result);
370 SendPacket(petStableResult.Write());
371}
372
374{
375 if (!CheckStableMaster(setPetSlot.StableMaster) || setPetSlot.DestSlot >= PET_SAVE_LAST_STABLE_SLOT)
376 {
378 return;
379 }
380
381 _player->SetPetSlot(setPetSlot.PetNumber, PetSaveMode(setPetSlot.DestSlot));
382}
383
385{
386 TC_LOG_DEBUG("network", "WORLD: CMSG_REPAIR_ITEM: Npc {}, Item {}, UseGuildBank: {}",
387 packet.NpcGUID.ToString(), packet.ItemGUID.ToString(), packet.UseGuildBank);
388
390 if (!unit)
391 {
392 TC_LOG_DEBUG("network", "WORLD: HandleRepairItemOpcode - {} not found or you can not interact with him.", packet.NpcGUID.ToString());
393 return;
394 }
395
396 // remove fake death
397 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
399
400 // reputation discount
401 float discountMod = _player->GetReputationPriceDiscount(unit);
402
403 if (!packet.ItemGUID.IsEmpty())
404 {
405 TC_LOG_DEBUG("network", "ITEM: Repair {}, at {}", packet.ItemGUID.ToString(), packet.NpcGUID.ToString());
406
407 Item* item = _player->GetItemByGuid(packet.ItemGUID);
408 if (item)
409 _player->DurabilityRepair(item->GetPos(), true, discountMod);
410 }
411 else
412 {
413 TC_LOG_DEBUG("network", "ITEM: Repair all items at {}", packet.NpcGUID.ToString());
414 _player->DurabilityRepairAll(true, discountMod, packet.UseGuildBank);
415 }
416}
DB2Storage< FactionTemplateEntry > sFactionTemplateStore("FactionTemplate.db2", &FactionTemplateLoadInfo::Instance)
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
#define ABORT_MSG
Definition: Errors.h:75
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
TabardVendorType
Definition: NPCHandler.cpp:43
#define sObjectMgr
Definition: ObjectMgr.h:1946
StableResult
Definition: PetDefines.h:120
PetSaveMode
Definition: PetDefines.h:41
@ PET_SAVE_LAST_STABLE_SLOT
Definition: PetDefines.h:47
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_FEIGN_DEATH
@ UNIT_NPC_FLAG_TABARDDESIGNER
Definition: UnitDefines.h:316
@ UNIT_NPC_FLAG_SPIRIT_HEALER
Definition: UnitDefines.h:311
@ UNIT_NPC_FLAG_GOSSIP
Definition: UnitDefines.h:297
@ UNIT_NPC_FLAG_INNKEEPER
Definition: UnitDefines.h:313
@ UNIT_NPC_FLAG_REPAIR
Definition: UnitDefines.h:309
@ UNIT_NPC_FLAG_TRAINER
Definition: UnitDefines.h:301
@ UNIT_NPC_FLAG_2_NONE
Definition: UnitDefines.h:336
@ UNIT_STATE_DIED
Definition: Unit.h:255
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
virtual bool OnGossipHello(Player *)
Definition: CreatureAI.h:198
virtual bool OnGossipSelectCode(Player *, uint32, uint32, char const *)
Definition: CreatureAI.h:204
virtual bool OnGossipSelect(Player *, uint32, uint32)
Definition: CreatureAI.h:201
void SetHomePosition(float x, float y, float z, float o)
Definition: Creature.h:371
uint32 GetTrainerId() const
Definition: Creature.cpp:3695
uint32 GetScriptId() const
Definition: Creature.cpp:3156
CreatureMovementData const & GetMovementTemplate() const
Definition: Creature.cpp:2939
CreatureAI * AI() const
Definition: Creature.h:214
virtual bool OnGossipSelect(Player *, uint32, uint32)
Definition: GameObjectAI.h:79
virtual bool OnGossipSelectCode(Player *, uint32, uint32, char const *)
Definition: GameObjectAI.h:82
GameObjectAI * AI() const
Definition: GameObject.h:378
uint32 GetScriptId() const
Definition: Guild.h:329
Definition: Item.h:170
uint16 GetPos() const
Definition: Item.h:284
bool IsEmpty() const
Definition: ObjectGuid.h:319
std::string ToString() const
Definition: ObjectGuid.cpp:554
bool IsGameObject() const
Definition: ObjectGuid.h:329
bool IsCreatureOrVehicle() const
Definition: ObjectGuid.h:324
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void OnGossipSelect(WorldObject *source, int32 gossipOptionId, uint32 menuId)
Definition: Player.cpp:14162
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition: Player.cpp:1947
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={})
Definition: Player.cpp:1250
GameObject * GetGameObjectIfCanInteractWith(ObjectGuid const &guid) const
Definition: Player.cpp:2004
void DurabilityLossAll(double percent, bool inventory)
Definition: Player.cpp:4611
void DurabilityRepair(uint16 pos, bool takeCost, float discountMod)
Definition: Player.cpp:4802
void SpawnCorpseBones(bool triggerSave=true)
Definition: Player.cpp:4598
void SendPreparedGossip(WorldObject *source)
Definition: Player.cpp:14137
float GetReputationPriceDiscount(Creature const *creature) const
Definition: Player.cpp:25133
bool HasCorpse() const
Definition: Player.h:2163
void DurabilityRepairAll(bool takeCost, float discountMod, bool guildBank)
Definition: Player.cpp:4718
void SetStableMaster(ObjectGuid stableMaster)
Definition: Player.cpp:28842
void SendAreaSpiritHealerTime(Unit *spiritHealer) const
Definition: Player.cpp:30146
WorldLocation GetCorpseLocation() const
Definition: Player.h:2164
void SetAreaSpiritHealer(Creature *creature)
Definition: Player.cpp:30130
void PrepareGossipMenu(WorldObject *source, uint32 menuId, bool showQuests=false)
Definition: Player.cpp:14036
Item * GetItemByGuid(ObjectGuid guid) const
Definition: Player.cpp:9566
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition: Player.h:2380
ReputationMgr & GetReputationMgr()
Definition: Player.h:2251
void SetPetSlot(uint32 petNumber, PetSaveMode dstPetSlot)
Definition: Player.cpp:28675
Team GetTeam() const
Definition: Player.h:2235
uint32 GetGossipMenuForSource(WorldObject const *source) const
Definition: Player.cpp:14389
void ResurrectPlayer(float restore_percent, bool applySickness=false)
Definition: Player.cpp:4408
void SetVisible(FactionTemplateEntry const *factionTemplateEntry)
void SendSpells(Creature const *npc, Player *player, LocaleConstant locale) const
Definition: Trainer.cpp:41
void TeachSpell(Creature const *npc, Player *player, uint32 spellId) const
Definition: Trainer.cpp:76
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3812
bool IsAreaSpiritHealer() const
Definition: Unit.h:1002
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition: Unit.cpp:10064
uint32 GetFaction() const override
Definition: Unit.h:858
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition: Unit.cpp:4101
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
uint32 LastUsedScriptID
Definition: Object.h:747
WorldPacket const * Write() override
Definition: NPCPackets.cpp:94
WorldPacket const * Write() override
Definition: PetPackets.cpp:56
bool CheckStableMaster(ObjectGuid guid)
Definition: PetHandler.cpp:440
void HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelectOption &packet)
Definition: NPCHandler.cpp:194
LocaleConstant GetSessionDbLocaleIndex() const
void HandleRequestStabledPets(WorldPackets::NPC::RequestStabledPets &packet)
Definition: NPCHandler.cpp:350
void HandleTrainerListOpcode(WorldPackets::NPC::Hello &packet)
Definition: NPCHandler.cpp:97
void HandleTrainerBuySpellOpcode(WorldPackets::NPC::TrainerBuySpell &packet)
Definition: NPCHandler.cpp:131
void SendPetStableResult(StableResult result)
Definition: NPCHandler.cpp:366
void HandleGossipHelloOpcode(WorldPackets::NPC::Hello &packet)
Definition: NPCHandler.cpp:159
Player * GetPlayer() const
void SendBindPoint(Creature *npc)
Definition: NPCHandler.cpp:336
void SendSpiritResurrect()
Definition: NPCHandler.cpp:291
void SendTabardVendorActivate(ObjectGuid guid, TabardVendorType type)
Definition: NPCHandler.cpp:68
void HandleRepairItemOpcode(WorldPackets::Item::RepairItem &packet)
Definition: NPCHandler.cpp:384
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
void HandleSetPetSlot(WorldPackets::NPC::SetPetSlot &setPetSlot)
Definition: NPCHandler.cpp:373
void SendShowMailBox(ObjectGuid guid)
Definition: NPCHandler.cpp:88
Player * _player
void SendTrainerList(Creature *npc, uint32 trainerId)
Definition: NPCHandler.cpp:112
void HandleBinderActivateOpcode(WorldPackets::NPC::Hello &packet)
Definition: NPCHandler.cpp:317
void HandleSpiritHealerActivate(WorldPackets::NPC::SpiritHealerActivate &packet)
Definition: NPCHandler.cpp:275
void HandleTabardVendorActivateOpcode(WorldPackets::NPC::TabardVendorActivate const &tabardVendorActivate)
Definition: NPCHandler.cpp:48
uint32 GetInteractionPauseTimer() const
Definition: CreatureData.h:407
uint32 OrderIndex
Definition: GossipDef.h:118
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
WorldLocation Loc
Definition: ObjectMgr.h:835