TrinityCore
Loading...
Searching...
No Matches
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().StartInteraction(npc->GetGUID(), PlayerInteractionType::Trainer);
126 _player->PlayerTalkClass->GetInteractionData().GetTrainer()->Id = trainerId;
128}
129
131{
132 TC_LOG_DEBUG("network", "WORLD: Received CMSG_TRAINER_BUY_SPELL {}, learn spell id is: {}", packet.TrainerGUID.ToString(), packet.SpellID);
133
135 if (!npc)
136 {
137 TC_LOG_DEBUG("network", "WORLD: HandleTrainerBuySpellOpcode - {} not found or you can not interact with him.", packet.TrainerGUID.ToString());
138 return;
139 }
140
141 // remove fake death
142 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
144
145 if (!_player->PlayerTalkClass->GetInteractionData().IsInteractingWith(packet.TrainerGUID, PlayerInteractionType::Trainer))
146 return;
147
148 if (_player->PlayerTalkClass->GetInteractionData().GetTrainer()->Id != uint32(packet.TrainerID))
149 return;
150
151 Trainer::Trainer const* trainer = sObjectMgr->GetTrainer(packet.TrainerID);
152 if (!trainer)
153 return;
154
155 trainer->TeachSpell(npc, _player, packet.SpellID);
156}
157
159{
161 if (!unit)
162 {
163 TC_LOG_DEBUG("network", "WORLD: HandleGossipHelloOpcode - {} not found or you can not interact with him.", packet.Unit.ToString());
164 return;
165 }
166
167 // set faction visible if needed
168 if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->GetFaction()))
169 _player->GetReputationMgr().SetVisible(factionTemplateEntry);
170
172
173 // Stop the npc if moving
175 unit->PauseMovement(pause);
176 unit->SetHomePosition(unit->GetPosition());
177
178 if (unit->IsAreaSpiritHealer())
179 {
182 }
183
184 _player->PlayerTalkClass->ClearMenus();
185 if (!unit->AI()->OnGossipHello(_player))
186 {
187// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID());
190 }
191}
192
194{
195 GossipMenuItem const* gossipMenuItem = _player->PlayerTalkClass->GetGossipMenu().GetItem(packet.GossipOptionID);
196 if (!gossipMenuItem)
197 return;
198
199 // Prevent cheating on C++ scripted menus
200 if (!_player->PlayerTalkClass->GetInteractionData().IsInteractingWith(packet.GossipUnit, PlayerInteractionType::Gossip))
201 return;
202
203 Creature* unit = nullptr;
204 GameObject* go = nullptr;
205 if (packet.GossipUnit.IsCreatureOrVehicle())
206 {
208 if (!unit)
209 {
210 TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - {} not found or you can't interact with him.", packet.GossipUnit.ToString());
211 return;
212 }
213 }
214 else if (packet.GossipUnit.IsGameObject())
215 {
217 if (!go)
218 {
219 TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - {} not found or you can't interact with it.", packet.GossipUnit.ToString());
220 return;
221 }
222 }
223 else
224 {
225
226 TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - unsupported {}.", packet.GossipUnit.ToString());
227 return;
228 }
229
230 // remove fake death
231 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
233
234 if ((unit && unit->GetScriptId() != unit->LastUsedScriptID) || (go && go->GetScriptId() != go->LastUsedScriptID))
235 {
236 TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - Script reloaded while in use, ignoring and set new scipt id");
237 if (unit)
238 unit->LastUsedScriptID = unit->GetScriptId();
239
240 if (go)
241 go->LastUsedScriptID = go->GetScriptId();
242 _player->PlayerTalkClass->SendCloseGossip();
243 return;
244 }
245
246 if (!packet.PromotionCode.empty())
247 {
248 if (unit)
249 {
250 if (!unit->AI()->OnGossipSelectCode(_player, packet.GossipID, gossipMenuItem->OrderIndex, packet.PromotionCode.c_str()))
251 _player->OnGossipSelect(unit, packet.GossipOptionID, packet.GossipID);
252 }
253 else
254 {
255 if (!go->AI()->OnGossipSelectCode(_player, packet.GossipID, gossipMenuItem->OrderIndex, packet.PromotionCode.c_str()))
256 _player->OnGossipSelect(go, packet.GossipOptionID, packet.GossipID);
257 }
258 }
259 else
260 {
261 if (unit)
262 {
263 if (!unit->AI()->OnGossipSelect(_player, packet.GossipID, gossipMenuItem->OrderIndex))
264 _player->OnGossipSelect(unit, packet.GossipOptionID, packet.GossipID);
265 }
266 else
267 {
268 if (!go->AI()->OnGossipSelect(_player, packet.GossipID, gossipMenuItem->OrderIndex))
269 _player->OnGossipSelect(go, packet.GossipOptionID, packet.GossipID);
270 }
271 }
272}
273
275{
277 if (!unit)
278 {
279 TC_LOG_DEBUG("network", "WORLD: HandleSpiritHealerActivateOpcode - {} not found or you can not interact with him.", packet.Healer.ToString());
280 return;
281 }
282
283 // remove fake death
284 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
286
288}
289
291{
292 _player->ResurrectPlayer(0.5f, true);
293 _player->DurabilityLossAll(0.25f, true);
294
295 // get corpse nearest graveyard
296 WorldSafeLocsEntry const* corpseGrave = nullptr;
297 WorldLocation corpseLocation = _player->GetCorpseLocation();
298 if (_player->HasCorpse())
299 {
300 corpseGrave = sObjectMgr->GetClosestGraveyard(corpseLocation, _player->GetTeam(), _player);
301 }
302
303 // now can spawn bones
305
306 // teleport to nearest from corpse graveyard, if different from nearest to player ghost
307 if (corpseGrave)
308 {
309 WorldSafeLocsEntry const* ghostGrave = sObjectMgr->GetClosestGraveyard(*_player, _player->GetTeam(), _player);
310
311 if (corpseGrave != ghostGrave)
312 _player->TeleportTo(corpseGrave->Loc);
313 }
314}
315
317{
318 if (!GetPlayer()->IsInWorld() || !GetPlayer()->IsAlive())
319 return;
320
322 if (!unit)
323 {
324 TC_LOG_DEBUG("network", "WORLD: HandleBinderActivateOpcode - {} not found or you can not interact with him.", packet.Unit.ToString());
325 return;
326 }
327
328 // remove fake death
329 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
331
332 SendBindPoint(unit);
333}
334
336{
337 // prevent set homebind to instances in any case
338 if (GetPlayer()->GetMap()->Instanceable())
339 return;
340
341 uint32 bindspell = 3286;
342
343 // send spell for homebinding (3286)
344 npc->CastSpell(_player, bindspell, true);
345
346 _player->PlayerTalkClass->SendCloseGossip();
347}
348
350{
351 if (!CheckStableMaster(packet.StableMaster))
352 return;
353
354 // remove fake death
355 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
357
358 // remove mounts this fix bug where getting pet from stable while mounted deletes pet.
359 if (GetPlayer()->IsMounted())
361
363}
364
366{
368 petStableResult.Result = AsUnderlyingType(result);
369 SendPacket(petStableResult.Write());
370}
371
373{
374 if (!CheckStableMaster(setPetSlot.StableMaster))
375 {
377 return;
378 }
379
380 if (setPetSlot.DestSlot >= PET_SAVE_LAST_STABLE_SLOT)
381 {
383 return;
384 }
385
386 _player->SetPetSlot(setPetSlot.PetNumber, PetSaveMode(setPetSlot.DestSlot));
387}
388
390{
391 TC_LOG_DEBUG("network", "WORLD: CMSG_REPAIR_ITEM: Npc {}, Item {}, UseGuildBank: {}",
392 packet.NpcGUID.ToString(), packet.ItemGUID.ToString(), packet.UseGuildBank);
393
395 if (!unit)
396 {
397 TC_LOG_DEBUG("network", "WORLD: HandleRepairItemOpcode - {} not found or you can not interact with him.", packet.NpcGUID.ToString());
398 return;
399 }
400
401 // remove fake death
402 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
404
405 // reputation discount
406 float discountMod = _player->GetReputationPriceDiscount(unit);
407
408 if (!packet.ItemGUID.IsEmpty())
409 {
410 TC_LOG_DEBUG("network", "ITEM: Repair {}, at {}", packet.ItemGUID.ToString(), packet.NpcGUID.ToString());
411
412 Item* item = _player->GetItemByGuid(packet.ItemGUID);
413 if (item)
414 _player->DurabilityRepair(item->GetPos(), true, discountMod);
415 }
416 else
417 {
418 TC_LOG_DEBUG("network", "ITEM: Repair all items at {}", packet.NpcGUID.ToString());
419 _player->DurabilityRepairAll(true, discountMod, packet.UseGuildBank);
420 }
421}
DB2Storage< FactionTemplateEntry > sFactionTemplateStore("FactionTemplate.db2", &FactionTemplateLoadInfo::Instance)
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
#define ABORT_MSG
Definition Errors.h:88
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
TabardVendorType
#define sObjectMgr
Definition ObjectMgr.h:1885
StableResult
Definition PetDefines.h:121
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
@ UNIT_NPC_FLAG_SPIRIT_HEALER
@ UNIT_NPC_FLAG_GOSSIP
@ UNIT_NPC_FLAG_INNKEEPER
@ UNIT_NPC_FLAG_REPAIR
@ UNIT_NPC_FLAG_TRAINER
@ UNIT_NPC_FLAG_2_NONE
@ UNIT_STATE_DIED
Definition Unit.h:261
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
virtual bool OnGossipHello(Player *)
Definition CreatureAI.h:206
virtual bool OnGossipSelectCode(Player *, uint32, uint32, char const *)
Definition CreatureAI.h:212
virtual bool OnGossipSelect(Player *, uint32, uint32)
Definition CreatureAI.h:209
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:386
uint32 GetTrainerId() const
uint32 GetScriptId() const
CreatureMovementData const & GetMovementTemplate() const
CreatureAI * AI() const
Definition Creature.h:228
virtual bool OnGossipSelect(Player *, uint32, uint32)
virtual bool OnGossipSelectCode(Player *, uint32, uint32, char const *)
GameObjectAI * AI() const
Definition GameObject.h:384
uint32 GetScriptId() const
Definition Guild.h:329
Definition Item.h:179
uint16 GetPos() const
Definition Item.h:294
bool IsEmpty() const
Definition ObjectGuid.h:362
std::string ToString() const
bool IsGameObject() const
Definition ObjectGuid.h:372
bool IsCreatureOrVehicle() const
Definition ObjectGuid.h:367
uint32 GetEntry() const
Definition Object.h:89
WorldLocation const & GetCorpseLocation() const
Definition Player.h:2338
void OnGossipSelect(WorldObject *source, int32 gossipOptionId, uint32 menuId)
Definition Player.cpp:14054
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition Player.cpp:1903
GameObject * GetGameObjectIfCanInteractWith(ObjectGuid const &guid) const
Definition Player.cpp:1960
void DurabilityLossAll(double percent, bool inventory)
Definition Player.cpp:4567
void DurabilityRepair(uint16 pos, bool takeCost, float discountMod)
Definition Player.cpp:4758
void SpawnCorpseBones(bool triggerSave=true)
Definition Player.cpp:4554
void SendPreparedGossip(WorldObject *source)
Definition Player.cpp:14028
float GetReputationPriceDiscount(Creature const *creature) const
Definition Player.cpp:25877
bool HasCorpse() const
Definition Player.h:2337
void DurabilityRepairAll(bool takeCost, float discountMod, bool guildBank)
Definition Player.cpp:4674
void SetStableMaster(ObjectGuid stableMaster)
Definition Player.cpp:29855
void SendAreaSpiritHealerTime(Unit *spiritHealer) const
Definition Player.cpp:31485
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={}, uint32 teleportSpellId=0)
Definition Player.cpp:1226
void SetAreaSpiritHealer(Creature *creature)
Definition Player.cpp:31469
void PrepareGossipMenu(WorldObject *source, uint32 menuId, bool showQuests=false)
Definition Player.cpp:13927
Item * GetItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9614
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition Player.h:2570
ReputationMgr & GetReputationMgr()
Definition Player.h:2439
void SetPetSlot(uint32 petNumber, PetSaveMode dstPetSlot)
Definition Player.cpp:29658
Team GetTeam() const
Definition Player.h:2423
uint32 GetGossipMenuForSource(WorldObject const *source) const
Definition Player.cpp:14291
void ResurrectPlayer(float restore_percent, bool applySickness=false)
Definition Player.cpp:4379
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:3955
bool IsAreaSpiritHealer() const
Definition Unit.h:1017
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition Unit.cpp:10695
uint32 GetFaction() const override
Definition Unit.h:871
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition Unit.cpp:4241
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
uint32 LastUsedScriptID
Definition Object.h:534
WorldPacket const * Write() override
WorldPacket const * Write() override
bool CheckStableMaster(ObjectGuid guid)
void HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelectOption &packet)
LocaleConstant GetSessionDbLocaleIndex() const
void HandleRequestStabledPets(WorldPackets::NPC::RequestStabledPets &packet)
void HandleTrainerListOpcode(WorldPackets::NPC::Hello &packet)
void HandleTrainerBuySpellOpcode(WorldPackets::NPC::TrainerBuySpell &packet)
void SendPetStableResult(StableResult result)
void HandleGossipHelloOpcode(WorldPackets::NPC::Hello &packet)
Player * GetPlayer() const
void SendBindPoint(Creature *npc)
void SendSpiritResurrect()
void SendTabardVendorActivate(ObjectGuid guid, TabardVendorType type)
void HandleRepairItemOpcode(WorldPackets::Item::RepairItem &packet)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
void HandleSetPetSlot(WorldPackets::NPC::SetPetSlot &setPetSlot)
void SendShowMailBox(ObjectGuid guid)
Player * _player
void SendTrainerList(Creature *npc, uint32 trainerId)
void HandleBinderActivateOpcode(WorldPackets::NPC::Hello &packet)
void HandleSpiritHealerActivate(WorldPackets::NPC::SpiritHealerActivate &packet)
void HandleTabardVendorActivateOpcode(WorldPackets::NPC::TabardVendorActivate const &tabardVendorActivate)
uint32 GetInteractionPauseTimer() const
uint32 OrderIndex
Definition GossipDef.h:135
constexpr void GetPosition(float &x, float &y) const
Definition Position.h:92
WorldLocation Loc
Definition ObjectMgr.h:836