TrinityCore
Loading...
Searching...
No Matches
zone_wintergrasp.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 "ScriptMgr.h"
19#include "Battlefield.h"
20#include "BattlefieldMgr.h"
22#include "DB2Stores.h"
23#include "GameObject.h"
24#include "GameObjectAI.h"
25#include "GameTime.h"
26#include "ObjectMgr.h"
27#include "Player.h"
28#include "ScriptedCreature.h"
29#include "ScriptedGossip.h"
30#include "ScriptSystem.h"
31#include "SpellAuras.h"
32#include "SpellAuraEffects.h"
33#include "SpellScript.h"
34#include "Vehicle.h"
35#include "WorldSession.h"
36
37#define GOSSIP_HELLO_DEMO1 "Build catapult."
38#define GOSSIP_HELLO_DEMO2 "Build demolisher."
39#define GOSSIP_HELLO_DEMO3 "Build siege engine."
40#define GOSSIP_HELLO_DEMO4 "I cannot build more!"
41
52
65
75
106
108
116
118{
120
143
144 bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
145 {
146 uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId);
147 CloseGossipMenuFor(player);
148
149 if (CanBuild())
150 {
151 switch (action - GOSSIP_ACTION_INFO_DEF)
152 {
153 case 0:
154 DoCast(player, SPELL_BUILD_CATAPULT_FORCE, true);
155 break;
156 case 1:
158 break;
159 case 2:
161 break;
162 }
163 if (Creature* controlArms = me->FindNearestCreature(NPC_WINTERGRASP_CONTROL_ARMS, 30.0f, true))
164 DoCast(controlArms, SPELL_ACTIVATE_CONTROL_ARMS, true);
165 }
166 return true;
167 }
168
169private:
170 bool CanBuild() const
171 {
172 Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(me->GetMap(), BATTLEFIELD_BATTLEID_WG);
173 if (!wintergrasp)
174 return false;
175
176 switch (me->GetEntry())
177 {
182 default:
183 return false;
184 }
185 }
186};
187
189{
190 npc_wg_spirit_guide(Creature* creature) : ScriptedAI(creature) { }
191
192 bool OnGossipHello(Player* player) override
193 {
194 if (me->IsQuestGiver())
195 player->PrepareQuestMenu(me->GetGUID());
196
197 Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(me->GetMap(), BATTLEFIELD_BATTLEID_WG);
198 if (!wintergrasp)
199 return true;
200
201 GraveyardVect const& graveyard = wintergrasp->GetGraveyardVector();
202 for (uint8 i = 0; i < graveyard.size(); i++)
203 if (graveyard[i]->GetControlTeamId() == player->GetTeamId())
205
206 SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID());
207 return true;
208 }
209
210 bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
211 {
212 uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId);
213 CloseGossipMenuFor(player);
214
215 Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(me->GetMap(), BATTLEFIELD_BATTLEID_WG);
216 if (wintergrasp)
217 {
218 GraveyardVect const& gy = wintergrasp->GetGraveyardVector();
219 for (uint8 i = 0; i < gy.size(); i++)
220 if (action - GOSSIP_ACTION_INFO_DEF == i && gy[i]->GetControlTeamId() == player->GetTeamId())
221 if (WorldSafeLocsEntry const* safeLoc = sObjectMgr->GetWorldSafeLoc(gy[i]->GetGraveyardId()))
222 player->TeleportTo(safeLoc->Loc);
223 }
224 return true;
225 }
226};
227
229{
230 SPELL_FROST_ARMOR = 12544
232
234{
235 npc_wg_queue(Creature* creature) : ScriptedAI(creature)
236 {
238 }
239
241
242 void Reset() override
243 {
245 }
246
247 void JustEngagedWith(Unit* /*who*/) override { }
248
249 void UpdateAI(uint32 diff) override
250 {
251 if (FrostArmor_Timer <= diff)
252 {
254 FrostArmor_Timer = 180000;
255 }
256 else FrostArmor_Timer -= diff;
257 }
258
259 bool OnGossipHello(Player* player) override
260 {
261 if (me->IsQuestGiver())
262 player->PrepareQuestMenu(me->GetGUID());
263
264 Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(me->GetMap(), BATTLEFIELD_BATTLEID_WG);
265 if (!wintergrasp)
266 return true;
267
268 if (wintergrasp->IsWarTime())
269 {
272 }
273 else
274 {
275 uint32 timer = wintergrasp->GetTimer() / 1000;
276 player->SendUpdateWorldState(4354, GameTime::GetGameTime() + timer);
277 if (timer < 15 * MINUTE)
278 {
281 }
282 else
284 }
285 return true;
286 }
287
288 bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
289 {
290 CloseGossipMenuFor(player);
291
292 Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(me->GetMap(), BATTLEFIELD_BATTLEID_WG);
293 if (!wintergrasp)
294 return true;
295
296 if (wintergrasp->IsWarTime())
297 wintergrasp->InvitePlayerToWar(player);
298 else
299 {
300 uint32 timer = wintergrasp->GetTimer() / 1000;
301 if (timer < 15 * MINUTE)
302 wintergrasp->InvitePlayerToQueue(player);
303 }
304 return true;
305 }
306};
307
309{
311
312 bool IsFriendly(Unit* passenger)
313 {
314 return ((me->GetFaction() == FACTION_HORDE_GENERIC_WG && passenger->GetFaction() == HORDE) ||
315 (me->GetFaction() == FACTION_ALLIANCE_GENERIC_WG && passenger->GetFaction() == ALLIANCE));
316 }
317
319 {
321 if (Vehicle* vehicle = cVeh->GetVehicleKit())
322 if (Unit* passenger = vehicle->GetPassenger(0))
323 if (IsFriendly(passenger))
324 if (Creature* teleportTrigger = passenger->SummonTrigger(me->GetPositionX()-60.0f, me->GetPositionY(), me->GetPositionZ()+1.0f, cVeh->GetOrientation(), 1s))
325 return teleportTrigger;
326
327 return nullptr;
328 }
329
330 void UpdateAI(uint32 diff) override
331 {
332 _checkTimer += diff;
333 if (_checkTimer >= 1000)
334 {
335 for (uint8 i = 0; i < MAX_WINTERGRASP_VEHICLES; i++)
336 if (Creature* vehicleCreature = me->FindNearestCreature(vehiclesList[i], 3.0f, true))
337 if (Creature* teleportTrigger = GetValidVehicle(vehicleCreature))
338 teleportTrigger->CastSpell(vehicleCreature, SPELL_VEHICLE_TELEPORT, true);
339
340 _checkTimer = 0;
341 }
342 }
343
344private:
346};
347
348/* 49899 - Activate Robotic Arms
349 56659 - Build Demolisher (Force)
350 56662 - Build Siege Vehicle (Force)
351 56664 - Build Catapult (Force)
352 61409 - Build Siege Vehicle (Force) */
377
378// 61178 - Grab Passenger
380{
381 void HandleScript(SpellEffIndex /*effIndex*/)
382 {
383 if (Player* target = GetHitPlayer())
384 target->CastSpell(GetCaster(), SPELL_RIDE_WG_VEHICLE, false);
385 }
386
391};
392
394{
395public:
396 achievement_wg_didnt_stand_a_chance() : AchievementCriteriaScript("achievement_wg_didnt_stand_a_chance") { }
397
398 bool OnCheck(Player* source, Unit* target) override
399 {
400 if (!target)
401 return false;
402
403 if (Player* victim = target->ToPlayer())
404 {
405 if (!victim->IsMounted())
406 return false;
407
408 if (Vehicle* vehicle = source->GetVehicle())
409 if (vehicle->GetVehicleInfo()->ID == 244) // Wintergrasp Tower Cannon
410 return true;
411 }
412
413 return false;
414 }
415};
416
421
422// 54640 - Teleport
424{
426 {
427 if (Player* target = GetExplTargetUnit()->ToPlayer())
428 if (Battlefield* wg = sBattlefieldMgr->GetBattlefieldByBattleId(target->GetMap(), BATTLEFIELD_BATTLEID_WG))
429 // check if we are in Wintergrasp at all, SotA uses same teleport spells
430 if ((target->GetZoneId() == AREA_WINTERGRASP && target->GetTeamId() != wg->GetDefenderTeam()) || target->HasAura(SPELL_WINTERGRASP_TELEPORT_TRIGGER))
432 return SPELL_CAST_OK;
433 }
434
439};
440
441// 54643 - Teleport
443{
444 void HandleDummy(SpellEffIndex /*effindex*/)
445 {
446 if (Unit* target = GetHitUnit())
447 {
448 WorldLocation loc = target->GetWorldLocation();
450 }
451 }
452
457
458};
459
460// 58549 - Tenacity
461// 59911 - Tenacity
463{
464 bool Validate(SpellInfo const* spellInfo) override
465 {
466 if (!ValidateSpellEffect({ { spellInfo->Id, EFFECT_2 } }))
467 return false;
468 uint32 triggeredSpellId = spellInfo->GetEffect(EFFECT_2).CalcValueAsInt();
469 return !triggeredSpellId || ValidateSpellInfo({ triggeredSpellId });
470 }
471
472 void Refresh(AuraEffect const* aurEff)
473 {
475
476 if (uint32 triggeredSpellId = aurEff->GetSpellEffectInfo().CalcValueAsInt())
477 {
478 SpellEffectValue bp = 0;
479 if (AuraEffect const* healEffect = GetEffect(EFFECT_0))
480 bp = healEffect->GetAmount();
481
482 CastSpellExtraArgs args(aurEff);
483 args
486 GetTarget()->CastSpell(nullptr, triggeredSpellId, args);
487 }
488
490 }
491
492 void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
493 {
494 if (uint32 triggeredSpellId = aurEff->GetSpellEffectInfo().CalcValueAsInt())
495 GetTarget()->RemoveAurasDueToSpell(triggeredSpellId);
496 }
497
503};
504
506{
507public:
508 condition_is_wintergrasp_horde() : ConditionScript("condition_is_wintergrasp_horde") { }
509
510 bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& sourceInfo)
511 {
512 if (!sourceInfo.mConditionMap)
513 return false;
514 Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(sourceInfo.mConditionMap, BATTLEFIELD_BATTLEID_WG);
515 if (wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_HORDE)
516 return true;
517 return false;
518 }
519};
520
522{
523public:
524 condition_is_wintergrasp_alliance() : ConditionScript("condition_is_wintergrasp_alliance") { }
525
526 bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& sourceInfo)
527 {
528 if (!sourceInfo.mConditionMap)
529 return false;
530 Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(sourceInfo.mConditionMap, BATTLEFIELD_BATTLEID_WG);
531 if (wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_ALLIANCE)
532 return true;
533 return false;
534 }
535};
536
#define sBattlefieldMgr
@ NPC_WINTERGRASP_SIEGE_ENGINE_HORDE
@ NPC_WINTERGRASP_CATAPULT
@ NPC_WINTERGRASP_DEMOLISHER
@ NPC_WINTERGRASP_SIEGE_ENGINE_ALLIANCE
@ SPELL_CORPORAL
@ SPELL_LIEUTENANT
@ BATTLEFIELD_WG_DATA_VEHICLE_A
@ BATTLEFIELD_WG_DATA_MAX_VEHICLE_A
@ BATTLEFIELD_WG_DATA_VEHICLE_H
@ BATTLEFIELD_WG_DATA_MAX_VEHICLE_H
std::vector< BfGraveyard * > GraveyardVect
Definition Battlefield.h:93
@ BATTLEFIELD_BATTLEID_WG
Definition Battlefield.h:36
@ MINUTE
Definition Common.h:32
uint8_t uint8
Definition Define.h:156
uint32_t uint32
Definition Define.h:154
#define sObjectMgr
Definition ObjectMgr.h:1885
Spells
Definition PlayerAI.cpp:32
#define RegisterCreatureAI(ai_name)
Definition ScriptMgr.h:1392
#define RegisterGameObjectAI(ai_name)
Definition ScriptMgr.h:1410
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1383
void AddGossipItemFor(Player *player, GossipOptionNpc optionNpc, std::string text, uint32 sender, uint32 action)
void SendGossipMenuFor(Player *player, uint32 npcTextID, ObjectGuid const &guid)
void CloseGossipMenuFor(Player *player)
@ GOSSIP_SENDER_MAIN
@ GOSSIP_ACTION_INFO_DEF
SpellEffIndex
@ EFFECT_0
@ EFFECT_2
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_SCRIPT_EFFECT
@ ALLIANCE
@ HORDE
SpellCastResult
@ SPELL_FAILED_BAD_TARGETS
@ SPELL_CAST_OK
@ FACTION_ALLIANCE_GENERIC_WG
@ FACTION_HORDE_GENERIC_WG
@ AREA_WINTERGRASP
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
@ SPELL_AURA_PERIODIC_DUMMY
double SpellEffectValue
This is a double instead of float to be able to store full range of int32.
@ SPELLVALUE_BASE_POINT1
@ SPELLVALUE_BASE_POINT0
#define SpellCheckCastFn(F)
#define SpellEffectFn(F, I, N)
#define AuraEffectPeriodicFn(F, I, N)
#define AuraEffectRemoveFn(F, I, N, M)
SpellEffectInfo const & GetSpellEffectInfo() const
void PreventDefaultAction()
HookList< EffectApplyHandler > AfterEffectRemove
HookList< EffectPeriodicHandler > OnEffectPeriodic
AuraEffect * GetEffect(uint8 effIndex) const
Unit * GetTarget() const
void RefreshDuration()
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
bool IsWarTime() const
Return true if battle is start, false if battle is not started.
GraveyardVect const & GetGraveyardVector() const
void InvitePlayerToQueue(Player *player)
void InvitePlayerToWar(Player *player)
TeamId GetDefenderTeam() const
uint32 GetTimer() const
virtual uint32 GetData(uint32 dataId) const override
bool IsEnabled() const
Return if battlefield is enable.
Creature *const me
Definition CreatureAI.h:63
GameObject *const me
uint32 GetFaction() const override
Definition GameObject.h:397
Player * ToPlayer()
Definition Object.h:126
uint32 GetEntry() const
Definition Object.h:89
WorldSession * GetSession() const
Definition Player.h:2272
TeamId GetTeamId() const
Definition Player.h:2424
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 PrepareQuestMenu(ObjectGuid guid)
Definition Player.cpp:14376
void SendUpdateWorldState(uint32 variable, uint32 value, bool hidden=false) const
Definition Player.cpp:9222
uint32 GetGossipTextId(uint32 menuId, WorldObject *source)
Definition Player.cpp:14269
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition Player.h:2570
int32 CalcValueAsInt(WorldObject const *caster=nullptr, SpellEffectValue const *basePoints=nullptr, Unit const *target=nullptr, float *variance=nullptr, uint32 castItemId=0, int32 itemLevel=-1) const
uint32 const Id
Definition SpellInfo.h:328
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:588
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
static bool ValidateSpellEffect(std::initializer_list< std::pair< uint32, SpellEffIndex > > effects)
HookList< CheckCastHandler > OnCheckCast
Player * GetHitPlayer() const
Unit * GetCaster() const
int32 GetEffectValueAsInt() const
void PreventHitDefaultEffect(SpellEffIndex effIndex)
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
void SetExplTargetDest(WorldLocation const &loc)
Unit * GetExplTargetUnit() const
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:89
Definition Unit.h:635
Vehicle * GetVehicle() const
Definition Unit.h:1784
bool IsQuestGiver() const
Definition Unit.h:1009
uint32 GetFaction() const override
Definition Unit.h:871
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4804
Vehicle * GetVehicleKit() const
Definition Unit.h:1782
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3974
constexpr WorldLocation GetWorldLocation() const
Definition Position.h:211
Map * GetMap() const
Definition Object.h:411
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
Creature * SummonTrigger(float x, float y, float z, float ang, Milliseconds despawnTime, CreatureAI *(*GetAI)(Creature *)=nullptr)
Definition Object.cpp:1482
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:1517
char const * GetTrinityString(uint32 entry) const
bool OnCheck(Player *source, Unit *target) override
bool OnConditionCheck(Condition const *, ConditionSourceInfo &sourceInfo)
bool OnConditionCheck(Condition const *, ConditionSourceInfo &sourceInfo)
void HandleScript(SpellEffIndex effIndex)
bool Validate(SpellInfo const *) override
void OnRemove(AuraEffect const *aurEff, AuraEffectHandleModes)
bool Validate(SpellInfo const *spellInfo) override
void Refresh(AuraEffect const *aurEff)
time_t GetGameTime()
Definition GameTime.cpp:52
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
Map const * mConditionMap
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetPositionY() const
Definition Position.h:88
constexpr float GetOrientation() const
Definition Position.h:90
constexpr float GetPositionZ() const
Definition Position.h:89
go_wg_vehicle_teleporter(GameObject *gameObject)
Creature * GetValidVehicle(Creature *cVeh)
bool IsFriendly(Unit *passenger)
void UpdateAI(uint32 diff) override
bool OnGossipHello(Player *player) override
npc_wg_demolisher_engineer(Creature *creature)
bool OnGossipSelect(Player *player, uint32, uint32 gossipListId) override
bool OnGossipSelect(Player *player, uint32, uint32) override
npc_wg_queue(Creature *creature)
void UpdateAI(uint32 diff) override
void Reset() override
bool OnGossipHello(Player *player) override
void JustEngagedWith(Unit *) override
bool OnGossipSelect(Player *player, uint32, uint32 gossipListId) override
bool OnGossipHello(Player *player) override
npc_wg_spirit_guide(Creature *creature)
uint32 const vehiclesList[MAX_WINTERGRASP_VEHICLES]
#define GOSSIP_HELLO_DEMO4
#define GOSSIP_HELLO_DEMO2
@ SPELL_WINTERGRASP_TELEPORT_TRIGGER
WGqueuenpctext
@ WG_NPCQUEUE_TEXT_H_WAR
@ WG_NPCQUEUE_TEXTOPTION_JOIN
@ WG_NPCQUEUE_TEXT_H_NOWAR
@ WG_NPCQUEUE_TEXT_A_WAR
@ WG_NPCQUEUE_TEXT_A_QUEUE
@ WG_NPCQUEUE_TEXT_H_QUEUE
@ WG_NPCQUEUE_TEXT_A_NOWAR
@ SPELL_BUILD_DEMOLISHER_FORCE
@ SPELL_VEHICLE_TELEPORT
@ SPELL_RIDE_WG_VEHICLE
@ SPELL_ACTIVATE_CONTROL_ARMS
@ SPELL_BUILD_SIEGE_VEHICLE_FORCE_ALLIANCE
@ SPELL_BUILD_SIEGE_VEHICLE_FORCE_HORDE
@ SPELL_BUILD_CATAPULT_FORCE
uint8 const MAX_WINTERGRASP_VEHICLES
@ QUEST_HEALING_WITH_ROSES_HORDE_DEF
@ QUEST_DEFEND_THE_SIEGE_HORDE_ATT
@ QUEST_SHOUTHERN_SABOTAGE_ALLIANCE_DEF
@ QUEST_SLAY_THEM_ALL_HORDE_DEF
@ QUEST_FUELING_THE_DEMOLISHERS_HORDE_DEF
@ QUEST_A_RARE_HERB_ALLIANCE_DEF
@ QUEST_FUELING_THE_DEMOLISHERS_HORDE_ATT
@ QUEST_SLAY_THEM_ALL_HORDE_ATT
@ QUEST_STOP_THE_SIEGE_HORDE_DEF
@ QUEST_WARDING_THE_WALLS_HORDE_DEF
@ QUEST_BONES_AND_ARROWS_ALLIANCE_DEF
@ QUEST_A_RARE_HERB_ALLIANCE_ATT
@ QUEST_HEALING_WITH_ROSES_HORDE_ATT
@ QUEST_BONES_AND_ARROWS_ALLIANCE_ATT
@ QUEST_NO_MERCY_FOR_THE_MERCILESS_ALLIANCE_ATT
@ QUEST_STOP_THE_SIEGE_ALLIANCE_DEF
@ QUEST_NO_MERCY_FOR_THE_MERCILESS_ALLIANCE_DEF
@ QUEST_WARDING_THE_WARRIORS_ALLIANCE_ATT
@ QUEST_TOPPLING_THE_TOWERS_HORDE_DEF
@ QUEST_BONES_AND_ARROWS_HORDE_DEF
@ QUEST_WARDING_THE_WARRIORS_ALLIANCE_DEF
@ QUEST_BONES_AND_ARROWS_HORDE_ATT
@ QUEST_DEFEND_THE_SIEGE_ALLIANCE_ATT
@ QUEST_JINXING_THE_WALLS_HORDE_ATT
@ NPC_GOBLIN_MECHANIC
@ NPC_WINTERGRASP_CONTROL_ARMS
@ NPC_WORLD_TRIGGER_LARGE_AOI_NOT_IMMUNE_PC_NPC
@ NPC_GNOMISH_ENGINEER
void AddSC_wintergrasp()
#define GOSSIP_HELLO_DEMO3
@ SPELL_FROST_ARMOR
#define GOSSIP_HELLO_DEMO1