aboutsummaryrefslogtreecommitdiff
path: root/src/server/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/scripts')
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp7
-rw-r--r--src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp5
-rw-r--r--src/server/scripts/EasternKingdoms/zone_undercity.cpp54
-rw-r--r--src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp53
-rw-r--r--src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp14
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp1
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp3
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp3
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp5
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp43
-rw-r--r--src/server/scripts/Spells/spell_item.cpp39
-rw-r--r--src/server/scripts/World/duel_reset.cpp43
-rw-r--r--src/server/scripts/World/go_scripts.cpp44
-rw-r--r--src/server/scripts/World/npc_professions.cpp106
-rw-r--r--src/server/scripts/World/npcs_special.cpp251
16 files changed, 556 insertions, 117 deletions
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index daf4fe5866a..fbd199b99db 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -43,7 +43,7 @@ struct EnumName
#define CREATE_NAMED_ENUM(VALUE) { VALUE, STRINGIZE(VALUE) }
#define NPCFLAG_COUNT 24
-#define FLAGS_EXTRA_COUNT 16
+#define FLAGS_EXTRA_COUNT 19
EnumName<NPCFlags, int32> const npcFlagTexts[NPCFLAG_COUNT] =
{
@@ -162,7 +162,10 @@ EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] =
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_SKILLGAIN),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TAUNT_DIMINISH),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_ALL_DIMINISH),
- CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS)
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK)
};
class npc_commandscript : public CommandScript
diff --git a/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp b/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp
index 80391ab2873..6714b243765 100644
--- a/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp
+++ b/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp
@@ -61,6 +61,8 @@ class instance_deadmines : public InstanceMapScript
SetHeaders(DataHeader);
State = CANNON_NOT_USED;
+ CannonBlast_Timer = 0;
+ PiratesDelay_Timer = 0;
}
ObjectGuid FactoryDoorGUID;
diff --git a/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp b/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp
index 622c8f0de01..447dbcd67f9 100644
--- a/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp
+++ b/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp
@@ -132,7 +132,10 @@ public:
## at_map_chamber
######*/
-#define QUEST_HIDDEN_CHAMBER 2240
+enum MapChamber
+{
+ QUEST_HIDDEN_CHAMBER = 2240
+};
class AreaTrigger_at_map_chamber : public AreaTriggerScript
{
diff --git a/src/server/scripts/EasternKingdoms/zone_undercity.cpp b/src/server/scripts/EasternKingdoms/zone_undercity.cpp
index 43143748661..c0b4e06cfff 100644
--- a/src/server/scripts/EasternKingdoms/zone_undercity.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_undercity.cpp
@@ -317,59 +317,6 @@ public:
};
/*######
-## npc_parqual_fintallas
-######*/
-
-enum ParqualFintallas
-{
- SPELL_MARK_OF_SHAME = 6767
-};
-
-#define GOSSIP_HPF1 "Gul'dan"
-#define GOSSIP_HPF2 "Kel'Thuzad"
-#define GOSSIP_HPF3 "Ner'zhul"
-
-class npc_parqual_fintallas : public CreatureScript
-{
-public:
- npc_parqual_fintallas() : CreatureScript("npc_parqual_fintallas") { }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- if (action == GOSSIP_ACTION_INFO_DEF+1)
- {
- player->CLOSE_GOSSIP_MENU();
- creature->CastSpell(player, SPELL_MARK_OF_SHAME, false);
- }
- if (action == GOSSIP_ACTION_INFO_DEF+2)
- {
- player->CLOSE_GOSSIP_MENU();
- player->AreaExploredOrEventHappens(6628);
- }
- return true;
- }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- if (player->GetQuestStatus(6628) == QUEST_STATUS_INCOMPLETE && !player->HasAura(SPELL_MARK_OF_SHAME))
- {
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HPF1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HPF2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HPF3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
- player->SEND_GOSSIP_MENU(5822, creature->GetGUID());
- }
- else
- player->SEND_GOSSIP_MENU(5821, creature->GetGUID());
-
- return true;
- }
-};
-
-/*######
## AddSC
######*/
@@ -377,5 +324,4 @@ void AddSC_undercity()
{
new npc_lady_sylvanas_windrunner();
new npc_highborne_lamenter();
- new npc_parqual_fintallas();
}
diff --git a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp
index 6cf86c3069f..b1a00f35bb5 100644
--- a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp
@@ -41,12 +41,23 @@ EndContentData */
## npcs_dithers_and_arbington
######*/
-#define GOSSIP_HDA1 "What does the Felstone Field Cauldron need?"
-#define GOSSIP_HDA2 "What does the Dalson's Tears Cauldron need?"
-#define GOSSIP_HDA3 "What does the Writhing Haunt Cauldron need?"
-#define GOSSIP_HDA4 "What does the Gahrron's Withering Cauldron need?"
-
-#define GOSSIP_SDA1 "Thanks, i need a Vitreous Focuser"
+enum DithersAndArbington
+{
+ GOSSIP_ITEM_ID_FELSTONE_FIELD = 0,
+ GOSSIP_ITEM_ID_DALSON_S_TEARS = 1,
+ GOSSIP_ITEM_ID_WRITHING_HAUNT = 2,
+ GOSSIP_ITEM_ID_GAHRRON_S_WITH = 3,
+ GOSSIP_MENU_ID_LETS_GET_TO_WORK = 3223,
+ GOSSIP_MENU_ID_VITREOUS_FOCUSER = 3229,
+ NPC_TEXT_OSSEOUS_AGITATORS = 3980,
+ NPC_TEXT_SOMATIC_INTENSIFIERS_1 = 3981,
+ NPC_TEXT_SOMATIC_INTENSIFIERS_2 = 3982,
+ NPC_TEXT_ECTOPLASMIC_RESONATORS = 3983,
+ NPC_TEXT_LET_S_GET_TO_WORK = 3985,
+ QUEST_MISSION_ACCOMPLISHED_H = 5237,
+ QUEST_MISSION_ACCOMPLISHED_A = 5238,
+ CREATE_ITEM_VITREOUS_FOCUSER = 17529
+};
class npcs_dithers_and_arbington : public CreatureScript
{
@@ -62,24 +73,24 @@ public:
player->GetSession()->SendListInventory(creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+1:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
- player->SEND_GOSSIP_MENU(3980, creature->GetGUID());
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_VITREOUS_FOCUSER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
+ player->SEND_GOSSIP_MENU(NPC_TEXT_OSSEOUS_AGITATORS, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+2:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
- player->SEND_GOSSIP_MENU(3981, creature->GetGUID());
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_VITREOUS_FOCUSER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
+ player->SEND_GOSSIP_MENU(NPC_TEXT_SOMATIC_INTENSIFIERS_1, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+3:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
- player->SEND_GOSSIP_MENU(3982, creature->GetGUID());
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_VITREOUS_FOCUSER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
+ player->SEND_GOSSIP_MENU(NPC_TEXT_SOMATIC_INTENSIFIERS_2, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+4:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
- player->SEND_GOSSIP_MENU(3983, creature->GetGUID());
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_VITREOUS_FOCUSER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
+ player->SEND_GOSSIP_MENU(NPC_TEXT_ECTOPLASMIC_RESONATORS, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+5:
player->CLOSE_GOSSIP_MENU();
- creature->CastSpell(player, 17529, false);
+ creature->CastSpell(player, CREATE_ITEM_VITREOUS_FOCUSER, false);
break;
}
return true;
@@ -93,13 +104,13 @@ public:
if (creature->IsVendor())
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
- if (player->GetQuestRewardStatus(5237) || player->GetQuestRewardStatus(5238))
+ if (player->GetQuestRewardStatus(QUEST_MISSION_ACCOMPLISHED_H) || player->GetQuestRewardStatus(QUEST_MISSION_ACCOMPLISHED_A))
{
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HDA2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HDA3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HDA4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4);
- player->SEND_GOSSIP_MENU(3985, creature->GetGUID());
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_LETS_GET_TO_WORK, GOSSIP_ITEM_ID_FELSTONE_FIELD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_LETS_GET_TO_WORK, GOSSIP_ITEM_ID_DALSON_S_TEARS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_LETS_GET_TO_WORK, GOSSIP_ITEM_ID_WRITHING_HAUNT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3);
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_LETS_GET_TO_WORK, GOSSIP_ITEM_ID_GAHRRON_S_WITH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4);
+ player->SEND_GOSSIP_MENU(NPC_TEXT_LET_S_GET_TO_WORK, creature->GetGUID());
}
else
player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
diff --git a/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp b/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp
index 63c56e29414..29a754d5895 100644
--- a/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp
+++ b/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp
@@ -58,6 +58,10 @@ enum Enums
SAY_FAREWELL = 5,
SAY_ATTACKED = 11,
+ GOSSIP_OPTION_LET_EVENT_BEGIN = 201,
+ NPC_TEXT_NARALEX_SLEEPS_AGAIN = 698,
+ NPC_TEXT_FANGLORDS_ARE_DEAD = 699,
+
SPELL_MARK_OF_THE_WILD_RANK_2 = 5232,
SPELL_SERPENTINE_CLEANSING = 6270,
SPELL_NARALEXS_AWAKENING = 6271,
@@ -70,10 +74,6 @@ enum Enums
NPC_MUTANUS_THE_DEVOURER = 3654,
};
-#define GOSSIP_ID_START_1 698 //Naralex sleeps again!
-#define GOSSIP_ID_START_2 699 //The fanglords are dead!
-#define GOSSIP_ITEM_NARALEX "Let the event begin!"
-
class npc_disciple_of_naralex : public CreatureScript
{
public:
@@ -116,8 +116,8 @@ public:
if ((instance->GetData(TYPE_LORD_COBRAHN) == DONE) && (instance->GetData(TYPE_LORD_PYTHAS) == DONE) &&
(instance->GetData(TYPE_LADY_ANACONDRA) == DONE) && (instance->GetData(TYPE_LORD_SERPENTIS) == DONE))
{
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NARALEX, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
- player->SEND_GOSSIP_MENU(GOSSIP_ID_START_2, creature->GetGUID());
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_OPTION_LET_EVENT_BEGIN, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
+ player->SEND_GOSSIP_MENU(NPC_TEXT_FANGLORDS_ARE_DEAD, creature->GetGUID());
if (!instance->GetData(TYPE_NARALEX_YELLED))
{
@@ -127,7 +127,7 @@ public:
}
else
{
- player->SEND_GOSSIP_MENU(GOSSIP_ID_START_1, creature->GetGUID());
+ player->SEND_GOSSIP_MENU(NPC_TEXT_NARALEX_SLEEPS_AGAIN, creature->GetGUID());
}
}
return true;
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
index f59701b9c25..b8e7dcc91d5 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
@@ -1222,6 +1222,7 @@ class npc_kinetic_bomb : public CreatureScript
_x = 0.f;
_y = 0.f;
_groundZ = 0.f;
+ me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);
}
void Reset() override
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
index dbb00fa252e..fd945db4604 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
@@ -979,6 +979,9 @@ class go_celestial_planetarium_access : public GameObjectScript
bool GossipHello(Player* player) override
{
+ if (go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE))
+ return false;
+
bool hasKey = true;
if (LockEntry const* lock = sLockStore.LookupEntry(go->GetGOInfo()->goober.lockId))
{
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
index c77f5b2bce3..01c4704592f 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
@@ -1186,6 +1186,7 @@ class npc_brann_bronzebeard_ulduar_intro : public CreatureScript
{
if (menuId == GOSSIP_MENU_BRANN_BRONZEBEARD && gossipListId == GOSSIP_OPTION_BRANN_BRONZEBEARD)
{
+ me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
player->PlayerTalkClass->SendCloseGossip();
if (Creature* loreKeeper = _instance->GetCreature(DATA_LORE_KEEPER_OF_NORGANNON))
loreKeeper->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
@@ -1238,6 +1239,7 @@ class npc_lorekeeper : public CreatureScript
{
if (menuId == GOSSIP_MENU_LORE_KEEPER && gossipListId == GOSSIP_OPTION_LORE_KEEPER)
{
+ me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
player->PlayerTalkClass->SendCloseGossip();
_instance->instance->LoadGrid(364, -16); // make sure leviathan is loaded
@@ -1250,6 +1252,7 @@ class npc_lorekeeper : public CreatureScript
{
if (Creature* brann = _instance->GetCreature(DATA_BRANN_BRONZEBEARD_INTRO))
{
+ brann->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
delorah->GetMotionMaster()->MovePoint(0, brann->GetPositionX() - 4, brann->GetPositionY(), brann->GetPositionZ());
/// @todo delorah->AI()->Talk(xxxx, brann->GetGUID()); when reached at branz
}
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
index 820332791c8..4d6aa046d10 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
@@ -1634,8 +1634,11 @@ class go_mimiron_hardmode_button : public GameObjectScript
public:
go_mimiron_hardmode_button() : GameObjectScript("go_mimiron_hardmode_button") { }
- bool OnGossipHello(Player* /*player*/, GameObject* go)
+ bool OnGossipHello(Player* /*player*/, GameObject* go) override
{
+ if (go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE))
+ return false;
+
InstanceScript* instance = go->GetInstanceScript();
if (!instance)
return false;
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
index b72bcbecdac..86a4a9caf3a 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
@@ -110,30 +110,24 @@ class boss_ingvar_the_plunderer : public CreatureScript
{
if (me->GetEntry() != NPC_INGVAR)
me->UpdateEntry(NPC_INGVAR);
-
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE);
_Reset();
- events.SetPhase(PHASE_HUMAN);
-
- events.ScheduleEvent(EVENT_CLEAVE, urand(6, 12)*IN_MILLISECONDS, 0, PHASE_HUMAN);
- events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18, 21)*IN_MILLISECONDS, 0, PHASE_HUMAN);
- events.ScheduleEvent(EVENT_ENRAGE, urand(7, 14)*IN_MILLISECONDS, 0, PHASE_HUMAN);
- events.ScheduleEvent(EVENT_SMASH, urand(12, 17)*IN_MILLISECONDS, 0, PHASE_HUMAN);
}
void DamageTaken(Unit* /*doneBy*/, uint32& damage) override
{
if (damage >= me->GetHealth() && events.IsInPhase(PHASE_HUMAN))
{
+ events.SetPhase(PHASE_EVENT);
+ events.ScheduleEvent(EVENT_SUMMON_BANSHEE, 3 * IN_MILLISECONDS, 0, PHASE_EVENT);
+
me->RemoveAllAuras();
+ me->StopMoving();
DoCast(me, SPELL_INGVAR_FEIGN_DEATH, true);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE);
- events.SetPhase(PHASE_EVENT);
- events.ScheduleEvent(EVENT_SUMMON_BANSHEE, 3 * IN_MILLISECONDS, 0, PHASE_EVENT);
-
Talk(SAY_DEATH);
}
@@ -152,13 +146,28 @@ class boss_ingvar_the_plunderer : public CreatureScript
me->RemoveAura(SPELL_INGVAR_FEIGN_DEATH);
DoCast(me, SPELL_INGVAR_TRANSFORM, true);
me->UpdateEntry(NPC_INGVAR_UNDEAD);
- events.ScheduleEvent(EVENT_JUST_TRANSFORMED, 2 * IN_MILLISECONDS, 0, PHASE_EVENT);
+ events.ScheduleEvent(EVENT_JUST_TRANSFORMED, IN_MILLISECONDS / 2, 0, PHASE_EVENT);
}
void EnterCombat(Unit* /*who*/) override
{
+ if (events.IsInPhase(PHASE_EVENT) || events.IsInPhase(PHASE_UNDEAD)) // ingvar gets multiple EnterCombat calls
+ return;
_EnterCombat();
+
Talk(SAY_AGGRO);
+ events.SetPhase(PHASE_HUMAN);
+ events.ScheduleEvent(EVENT_CLEAVE, urand(6, 12)*IN_MILLISECONDS, 0, PHASE_HUMAN);
+ events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18, 21)*IN_MILLISECONDS, 0, PHASE_HUMAN);
+ events.ScheduleEvent(EVENT_ENRAGE, urand(7, 14)*IN_MILLISECONDS, 0, PHASE_HUMAN);
+ events.ScheduleEvent(EVENT_SMASH, urand(12, 17)*IN_MILLISECONDS, 0, PHASE_HUMAN);
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ if (events.IsInPhase(PHASE_EVENT)) // prevent ingvar from beginning to attack/chase during transition
+ return;
+ BossAI::AttackStart(who);
}
void JustDied(Unit* /*killer*/) override
@@ -171,7 +180,7 @@ class boss_ingvar_the_plunderer : public CreatureScript
{
events.SetPhase(PHASE_UNDEAD);
events.ScheduleEvent(EVENT_DARK_SMASH, urand(14, 18)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
- events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18, 22)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
+ events.ScheduleEvent(EVENT_DREADFUL_ROAR, 0, 0, PHASE_UNDEAD);
events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10, 14)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
events.ScheduleEvent(EVENT_SHADOW_AXE, 30*IN_MILLISECONDS, 0, PHASE_UNDEAD);
}
@@ -214,9 +223,17 @@ class boss_ingvar_the_plunderer : public CreatureScript
events.ScheduleEvent(EVENT_SMASH, urand(12, 16)*IN_MILLISECONDS, 0, PHASE_HUMAN);
break;
case EVENT_JUST_TRANSFORMED:
+ ScheduleSecondPhase();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE);
+ if (Unit* target = me->getThreatManager().getHostilTarget())
+ AttackStart(target);
+ else
+ {
+ EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
+ return;
+ }
+ Talk(SAY_AGGRO);
DoZoneInCombat();
- ScheduleSecondPhase();
return;
case EVENT_SUMMON_BANSHEE:
DoCast(me, SPELL_SUMMON_BANSHEE);
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index 9475da91a77..0abff255e4b 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -29,6 +29,7 @@
#include "SpellAuraEffects.h"
#include "SkillDiscovery.h"
#include "Battleground.h"
+#include "DBCStores.h"
// Generic script for handling item dummy effects which trigger another spell.
class spell_item_trigger_spell : public SpellScriptLoader
@@ -2630,6 +2631,43 @@ public:
}
};
+class spell_item_toy_train_set_pulse : public SpellScriptLoader
+{
+public:
+ spell_item_toy_train_set_pulse() : SpellScriptLoader("spell_item_toy_train_set_pulse") { }
+
+ class spell_item_toy_train_set_pulse_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_item_toy_train_set_pulse_SpellScript);
+
+ void HandleDummy(SpellEffIndex /*index*/)
+ {
+ if (Player* target = GetHitUnit()->ToPlayer())
+ {
+ target->HandleEmoteCommand(EMOTE_ONESHOT_TRAIN);
+ if (EmotesTextSoundEntry const* soundEntry = FindTextSoundEmoteFor(TEXT_EMOTE_TRAIN, target->getRace(), target->getGender()))
+ target->PlayDistanceSound(soundEntry->SoundId);
+ }
+ }
+
+ void HandleTargets(std::list<WorldObject*>& targetList)
+ {
+ targetList.remove_if([](WorldObject const* obj) { return obj->GetTypeId() != TYPEID_PLAYER; });
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_item_toy_train_set_pulse_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_item_toy_train_set_pulse_SpellScript::HandleTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ALLY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_item_toy_train_set_pulse_SpellScript();
+ }
+};
+
void AddSC_item_spell_scripts()
{
// 23074 Arcanite Dragonling
@@ -2698,4 +2736,5 @@ void AddSC_item_spell_scripts()
new spell_item_chicken_cover();
new spell_item_muisek_vessel();
new spell_item_greatmothers_soulcatcher();
+ new spell_item_toy_train_set_pulse();
}
diff --git a/src/server/scripts/World/duel_reset.cpp b/src/server/scripts/World/duel_reset.cpp
index c5b53368bc8..3c46255a1bf 100644
--- a/src/server/scripts/World/duel_reset.cpp
+++ b/src/server/scripts/World/duel_reset.cpp
@@ -34,9 +34,8 @@ class DuelResetScript : public PlayerScript
player1->GetSpellHistory()->SaveCooldownStateBeforeDuel();
player2->GetSpellHistory()->SaveCooldownStateBeforeDuel();
-
- ResetSpellCooldowns(player1);
- ResetSpellCooldowns(player2);
+ ResetSpellCooldowns(player1, true);
+ ResetSpellCooldowns(player2, true);
}
// Health and mana reset
@@ -73,9 +72,8 @@ class DuelResetScript : public PlayerScript
// Cooldown restore
if (sWorld->getBoolConfig(CONFIG_RESET_DUEL_COOLDOWNS))
{
-
- ResetSpellCooldowns(winner);
- ResetSpellCooldowns(loser);
+ ResetSpellCooldowns(winner, false);
+ ResetSpellCooldowns(loser, false);
winner->GetSpellHistory()->RestoreCooldownStateAfterDuel();
loser->GetSpellHistory()->RestoreCooldownStateAfterDuel();
@@ -98,14 +96,35 @@ class DuelResetScript : public PlayerScript
}
}
- static void ResetSpellCooldowns(Player* player)
+ static void ResetSpellCooldowns(Player* player, bool onStartDuel)
{
- // remove cooldowns on spells that have < 10 min CD and has no onHold
- player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ if (onStartDuel)
{
- SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
- return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS && !itr->second.OnHold;
- }, true);
+ // remove cooldowns on spells that have < 10 min CD > 30 sec and has no onHold
+ player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellHistory::Clock::time_point now = SpellHistory::Clock::now();
+ uint32 cooldownDuration = itr->second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(itr->second.CooldownEnd - now).count() : 0;
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
+ return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS
+ && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS
+ && !itr->second.OnHold
+ && cooldownDuration > 0
+ && ( spellInfo->RecoveryTime - cooldownDuration ) > (MINUTE / 2) * IN_MILLISECONDS
+ && ( spellInfo->CategoryRecoveryTime - cooldownDuration ) > (MINUTE / 2) * IN_MILLISECONDS;
+ }, true);
+ }
+ else
+ {
+ // remove cooldowns on spells that have < 10 min CD and has no onHold
+ player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
+ return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS
+ && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS
+ && !itr->second.OnHold;
+ }, true);
+ }
// pet cooldowns
if (Pet* pet = player->GetPet())
diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp
index ef4a2b0e32f..b90839f50c5 100644
--- a/src/server/scripts/World/go_scripts.cpp
+++ b/src/server/scripts/World/go_scripts.cpp
@@ -41,6 +41,7 @@ go_tadpole_cage
go_amberpine_outhouse
go_hive_pod
go_veil_skith_cage
+go_toy_train_set
EndContentData */
#include "ScriptMgr.h"
@@ -1196,6 +1197,48 @@ public:
}
};
+
+enum ToyTrainSpells
+{
+ SPELL_TOY_TRAIN_PULSE = 61551,
+};
+
+class go_toy_train_set : public GameObjectScript
+{
+ public:
+ go_toy_train_set() : GameObjectScript("go_toy_train_set") { }
+
+ struct go_toy_train_setAI : public GameObjectAI
+ {
+ go_toy_train_setAI(GameObject* go) : GameObjectAI(go), _pulseTimer(3 * IN_MILLISECONDS) { }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (diff < _pulseTimer)
+ _pulseTimer -= diff;
+ else
+ {
+ go->CastSpell(nullptr, SPELL_TOY_TRAIN_PULSE, true);
+ _pulseTimer = 6 * IN_MILLISECONDS;
+ }
+ }
+
+ // triggered on wrecker'd
+ void DoAction(int32 /*action*/) override
+ {
+ go->Delete();
+ }
+
+ private:
+ uint32 _pulseTimer;
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const override
+ {
+ return new go_toy_train_setAI(go);
+ }
+};
+
void AddSC_go_scripts()
{
new go_cat_figurine();
@@ -1231,4 +1274,5 @@ void AddSC_go_scripts()
new go_veil_skith_cage();
new go_frostblade_shrine();
new go_midsummer_bonfire();
+ new go_toy_train_set();
}
diff --git a/src/server/scripts/World/npc_professions.cpp b/src/server/scripts/World/npc_professions.cpp
index 4dca55d562d..867ebafe32b 100644
--- a/src/server/scripts/World/npc_professions.cpp
+++ b/src/server/scripts/World/npc_professions.cpp
@@ -18,27 +18,26 @@
/* ScriptData
SDName: Npc_Professions
-SD%Complete: 80
-SDComment: Provides learn/unlearn/relearn-options for professions. Not supported: Unlearn engineering, re-learn engineering, re-learn leatherworking.
-SDCategory: NPCs
+SD%Complete: 100
+SDComment: Provides learn/unlearn/relearn-options for professions.
+SDCategory: NPCs/GOBs
EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
+#include "GameObjectAI.h"
#include "Player.h"
#include "SpellInfo.h"
#include "WorldSession.h"
/*
A few notes for future developement:
-- A full implementation of gossip for GO's is required. They must have the same scripting capabilities as creatures. Basically,
-there is no difference here (except that default text is chosen with `gameobject_template`.`data3` (for GO type2, different dataN for a few others)
- It's possible blacksmithing still require some tweaks and adjustments due to the way we _have_ to use reputation.
*/
/*###
-# to be removed from here (->ncp_text). This is data for database projects.
+# to be removed from here (->npc_text). This is data for database projects.
###*/
#define TALK_MUST_UNLEARN_WEAPON "You must forget your weapon type specialty before I can help you. Go to Everlook in Winterspring and seek help there."
@@ -153,6 +152,9 @@ enum ProfessionSpells
S_LEARN_GOBLIN = 20221,
S_LEARN_GNOMISH = 20220,
+ S_UNLEARN_GOBLIN = 68334,
+ S_UNLEARN_GNOMISH = 68333,
+
S_SPELLFIRE = 26797,
S_MOONCLOTH = 26798,
S_SHADOWEAVE = 26801,
@@ -376,6 +378,27 @@ void ProfessionUnlearnSpells(Player* player, uint32 type)
player->RemoveSpell(36075); // Wildfeather Leggings
player->RemoveSpell(36078); // Living Crystal Breastplate
break;
+ case S_UNLEARN_GOBLIN: // S_UNLEARN_GOBLIN
+ player->RemoveSpell(30565); // Foreman's Enchanted Helmet
+ player->RemoveSpell(30566); // Foreman's Reinforced Helmet
+ player->RemoveSpell(30563); // Goblin Rocket Launcher
+ player->RemoveSpell(56514); // Global Thermal Sapper Charge
+ player->RemoveSpell(36954); // Dimensional Ripper - Area 52
+ player->RemoveSpell(23486); // Dimensional Ripper - Everlook
+ player->RemoveSpell(23078); // Goblin Jumper Cables XL
+ player->RemoveSpell(72952); // Shatter Rounds
+ break;
+ case S_UNLEARN_GNOMISH: // S_UNLEARN_GNOMISH
+ player->RemoveSpell(30575); // Gnomish Battle Goggles
+ player->RemoveSpell(30574); // Gnomish Power Goggles
+ player->RemoveSpell(56473); // Gnomish X-Ray Specs
+ player->RemoveSpell(30569); // Gnomish Poultryizer
+ player->RemoveSpell(30563); // Ultrasafe Transporter - Toshley's Station
+ player->RemoveSpell(23489); // Ultrasafe Transporter - Gadgetzan
+ player->RemoveSpell(23129); // World Enlarger
+ player->RemoveSpell(23096); // Gnomish Alarm-o-Bot
+ player->RemoveSpell(72953); // Iceblade Arrow
+ break;
case S_UNLEARN_SPELLFIRE: // S_UNLEARN_SPELLFIRE
player->RemoveSpell(26752); // Spellfire Belt
player->RemoveSpell(26753); // Spellfire Gloves
@@ -923,6 +946,76 @@ public:
}
};
+// Object ID - 177226
+// Book "Soothsaying for dummies"
+enum SoothsayingForDummies
+{
+ GOSSIP_ID = 7058,
+
+ // Engineering
+ OPTION_UNLEARN_GNOMISH = 0,
+ OPTION_UNLEARN_GOBLIN = 1,
+ OPTION_LEARN_GNOMISH = 2,
+ OPTION_LEARN_GOBLIN = 3,
+
+ // Leatherworking
+ OPTION_LEARN_DRAGONSCALE = 4,
+ OPTION_LEARN_ELEMENTAL = 5,
+ OPTION_LEARN_TRIBAL = 6
+};
+
+class go_soothsaying_for_dummies : public GameObjectScript
+{
+ public:
+ go_soothsaying_for_dummies() : GameObjectScript("go_soothsaying_for_dummies") { }
+
+ struct go_soothsaying_for_dummiesAI : public GameObjectAI
+ {
+ go_soothsaying_for_dummiesAI(GameObject* go) : GameObjectAI(go) { }
+
+ bool GossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override
+ {
+ if (menuId != GOSSIP_ID)
+ return false;
+
+ switch (gossipListId)
+ {
+ case OPTION_UNLEARN_GNOMISH:
+ ProcessUnlearnAction(player, nullptr, S_UNLEARN_GNOMISH, 0, 0); // cost is handled by gossip code
+ break;
+ case OPTION_UNLEARN_GOBLIN:
+ ProcessUnlearnAction(player, nullptr, S_UNLEARN_GOBLIN, 0, 0);
+ break;
+ case OPTION_LEARN_GNOMISH:
+ player->CastSpell(player, S_LEARN_GNOMISH, true);
+ break;
+ case OPTION_LEARN_GOBLIN:
+ player->CastSpell(player, S_LEARN_GOBLIN, true);
+ break;
+ case OPTION_LEARN_DRAGONSCALE:
+ player->CastSpell(player, S_LEARN_DRAGON, true);
+ break;
+ case OPTION_LEARN_ELEMENTAL:
+ player->CastSpell(player, S_LEARN_ELEMENTAL, true);
+ break;
+ case OPTION_LEARN_TRIBAL:
+ player->CastSpell(player, S_LEARN_TRIBAL, true);
+ break;
+ default:
+ return false;
+ }
+
+ player->CLOSE_GOSSIP_MENU();
+ return true; // prevent further processing
+ }
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const override
+ {
+ return new go_soothsaying_for_dummiesAI(go);
+ }
+};
+
/*###
# start menues leatherworking
###*/
@@ -1212,6 +1305,7 @@ void AddSC_npc_professions()
new npc_prof_alchemy();
new npc_prof_blacksmith();
new npc_engineering_tele_trinket();
+ new go_soothsaying_for_dummies();
new npc_prof_leather();
new npc_prof_tailor();
}
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index 16b95e555bb..40f9e63f4f6 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -38,6 +38,7 @@ npc_snake_trap_serpents 80% AI for snakes that summoned by Snake Trap
npc_shadowfiend 100% restore 5% of owner's mana when shadowfiend die from damage
npc_locksmith 75% list of keys needs to be confirmed
npc_firework 100% NPC's summoned by rockets and rocket clusters, for making them cast visual
+npc_train_wrecker 100% Wind-Up Train Wrecker that kills train set
EndContentData */
#include "ScriptMgr.h"
@@ -56,6 +57,7 @@ EndContentData */
#include "SpellHistory.h"
#include "SpellAuras.h"
#include "Pet.h"
+#include "PetAI.h"
#include "CreatureTextMgr.h"
#include "SmartAI.h"
@@ -519,6 +521,67 @@ public:
};
/*######
+## npc_torch_tossing_target_bunny_controller
+######*/
+
+enum TorchTossingTarget
+{
+ NPC_TORCH_TOSSING_TARGET_BUNNY = 25535,
+ SPELL_TARGET_INDICATOR = 45723
+};
+
+class npc_torch_tossing_target_bunny_controller : public CreatureScript
+{
+public:
+ npc_torch_tossing_target_bunny_controller() : CreatureScript("npc_torch_tossing_target_bunny_controller") { }
+
+ struct npc_torch_tossing_target_bunny_controllerAI : public ScriptedAI
+ {
+ npc_torch_tossing_target_bunny_controllerAI(Creature* creature) : ScriptedAI(creature)
+ {
+ _targetTimer = 3000;
+ }
+
+ ObjectGuid DoSearchForTargets(ObjectGuid lastTargetGUID)
+ {
+ std::list<Creature*> targets;
+ me->GetCreatureListWithEntryInGrid(targets, NPC_TORCH_TOSSING_TARGET_BUNNY, 60.0f);
+ targets.remove_if([lastTargetGUID](Creature* creature) { return creature->GetGUID() == lastTargetGUID; });
+
+ if (!targets.empty())
+ {
+ _lastTargetGUID = Trinity::Containers::SelectRandomContainerElement(targets)->GetGUID();
+
+ return _lastTargetGUID;
+ }
+ return ObjectGuid::Empty;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_targetTimer < diff)
+ {
+ if (Unit* target = ObjectAccessor::GetUnit(*me, DoSearchForTargets(_lastTargetGUID)))
+ target->CastSpell(target, SPELL_TARGET_INDICATOR, true);
+
+ _targetTimer = 3000;
+ }
+ else
+ _targetTimer -= diff;
+ }
+
+ private:
+ uint32 _targetTimer;
+ ObjectGuid _lastTargetGUID;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_torch_tossing_target_bunny_controllerAI(creature);
+ }
+};
+
+/*######
## Triage quest
######*/
@@ -2387,12 +2450,198 @@ class npc_stable_master : public CreatureScript
}
};
+enum TrainWrecker
+{
+ GO_TOY_TRAIN = 193963,
+ SPELL_TOY_TRAIN_PULSE = 61551,
+ SPELL_WRECK_TRAIN = 62943,
+ ACTION_WRECKED = 1,
+ EVENT_DO_JUMP = 1,
+ EVENT_DO_FACING = 2,
+ EVENT_DO_WRECK = 3,
+ EVENT_DO_DANCE = 4,
+ MOVEID_CHASE = 1,
+ MOVEID_JUMP = 2
+};
+class npc_train_wrecker : public CreatureScript
+{
+ public:
+ npc_train_wrecker() : CreatureScript("npc_train_wrecker") { }
+
+ struct npc_train_wreckerAI : public NullCreatureAI
+ {
+ npc_train_wreckerAI(Creature* creature) : NullCreatureAI(creature), _isSearching(true), _nextAction(0), _timer(1 * IN_MILLISECONDS) { }
+
+ GameObject* VerifyTarget() const
+ {
+ if (GameObject* target = ObjectAccessor::GetGameObject(*me, _target))
+ return target;
+ me->HandleEmoteCommand(EMOTE_ONESHOT_RUDE);
+ me->DespawnOrUnsummon(3 * IN_MILLISECONDS);
+ return nullptr;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_isSearching)
+ {
+ if (diff < _timer)
+ _timer -= diff;
+ else
+ {
+ if (GameObject* target = me->FindNearestGameObject(GO_TOY_TRAIN, 15.0f))
+ {
+ _isSearching = false;
+ _target = target->GetGUID();
+ me->SetWalk(true);
+ me->GetMotionMaster()->MovePoint(MOVEID_CHASE, target->GetNearPosition(3.0f, target->GetAngle(me)));
+ }
+ else
+ _timer = 3 * IN_MILLISECONDS;
+ }
+ }
+ else
+ {
+ switch (_nextAction)
+ {
+ case EVENT_DO_JUMP:
+ if (GameObject* target = VerifyTarget())
+ me->GetMotionMaster()->MoveJump(*target, 5.0, 10.0, MOVEID_JUMP);
+ _nextAction = 0;
+ break;
+ case EVENT_DO_FACING:
+ if (GameObject* target = VerifyTarget())
+ {
+ me->SetFacingTo(target->GetOrientation());
+ me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK1H);
+ _timer = 1.5 * IN_MILLISECONDS;
+ _nextAction = EVENT_DO_WRECK;
+ }
+ else
+ _nextAction = 0;
+ break;
+ case EVENT_DO_WRECK:
+ if (diff < _timer)
+ {
+ _timer -= diff;
+ break;
+ }
+ if (GameObject* target = VerifyTarget())
+ {
+ me->CastSpell(target, SPELL_WRECK_TRAIN, false);
+ target->AI()->DoAction(ACTION_WRECKED);
+ _timer = 2 * IN_MILLISECONDS;
+ _nextAction = EVENT_DO_DANCE;
+ }
+ else
+ _nextAction = 0;
+ break;
+ case EVENT_DO_DANCE:
+ if (diff < _timer)
+ {
+ _timer -= diff;
+ break;
+ }
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_DANCE);
+ me->DespawnOrUnsummon(5 * IN_MILLISECONDS);
+ _nextAction = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ void MovementInform(uint32 /*type*/, uint32 id) override
+ {
+ if (id == MOVEID_CHASE)
+ _nextAction = EVENT_DO_JUMP;
+ else if (id == MOVEID_JUMP)
+ _nextAction = EVENT_DO_FACING;
+ }
+
+ private:
+ bool _isSearching;
+ uint8 _nextAction;
+ uint32 _timer;
+ ObjectGuid _target;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_train_wreckerAI(creature);
+ }
+};
+
+enum EgbertMisc
+{
+ EVENT_MOVE_POS = 1,
+ EVENT_RETURN = 2
+};
+
+class npc_egbert : public CreatureScript
+{
+public:
+ npc_egbert() : CreatureScript("npc_egbert") {}
+
+ struct npc_egbertAI : public PetAI
+ {
+ npc_egbertAI(Creature* creature) : PetAI(creature)
+ {
+ if (Unit* owner = me->GetCharmerOrOwner())
+ if (owner->GetMap()->GetEntry()->addon > 1)
+ me->SetCanFly(true);
+ }
+
+ void Reset() override
+ {
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_MOVE_POS, urandms(1, 20));
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_MOVE_POS:
+ if (Unit* owner = me->GetCharmerOrOwner())
+ {
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MovePoint(0, owner->GetPositionX() + frand(-30.0f, 30.0f), owner->GetPositionY() + frand(-30.0f, 30.0f), owner->GetPositionZ());
+ }
+ _events.ScheduleEvent(EVENT_RETURN, urandms(3, 4));
+ break;
+ case EVENT_RETURN:
+ if (Unit* owner = me->GetCharmerOrOwner())
+ me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle());
+ _events.ScheduleEvent(EVENT_MOVE_POS, urandms(1, 20));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ private:
+ EventMap _events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_egbertAI(creature);
+ }
+};
+
void AddSC_npcs_special()
{
new npc_air_force_bots();
new npc_lunaclaw_spirit();
new npc_chicken_cluck();
new npc_dancing_flames();
+ new npc_torch_tossing_target_bunny_controller();
new npc_doctor();
new npc_injured_patient();
new npc_garments_of_quests();
@@ -2410,4 +2659,6 @@ void AddSC_npcs_special()
new npc_spring_rabbit();
new npc_imp_in_a_ball();
new npc_stable_master();
+ new npc_train_wrecker();
+ new npc_egbert();
}