aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOvahlord <dreadkiller@gmx.de>2023-11-06 11:51:37 +0100
committerGitHub <noreply@github.com>2023-11-06 11:51:37 +0100
commit24dab9326df00f981ddb7f8d8077c079c2ac0c16 (patch)
tree143e769c715453e51bd5dbdbf332e46da84a96db
parent0e2f04172864e3cff2b5559ac89ded23ade5f92e (diff)
Scripts/LCT: implement General Husam encounter (#29414)
-rw-r--r--sql/updates/world/master/2023_11_06_00_world.sql72
-rw-r--r--src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_general_husam.cpp548
-rw-r--r--src/server/scripts/Kalimdor/LostCityOfTheTolvir/instance_lost_city_of_the_tolvir.cpp65
-rw-r--r--src/server/scripts/Kalimdor/LostCityOfTheTolvir/lost_city_of_the_tolvir.h66
-rw-r--r--src/server/scripts/Kalimdor/kalimdor_script_loader.cpp6
5 files changed, 757 insertions, 0 deletions
diff --git a/sql/updates/world/master/2023_11_06_00_world.sql b/sql/updates/world/master/2023_11_06_00_world.sql
new file mode 100644
index 00000000000..69ab13ce5d9
--- /dev/null
+++ b/sql/updates/world/master/2023_11_06_00_world.sql
@@ -0,0 +1,72 @@
+DELETE FROM `instance_template` WHERE `map`= 755;
+INSERT INTO `instance_template` (`map`, `parent`, `script`) VALUES
+(755, 1, 'instance_lost_city_of_the_tolvir');
+
+-- General Husam
+UPDATE `creature_template` SET `mechanic_immune_mask`= 667893759, `ScriptName`= 'boss_general_husam' WHERE `entry`= 44577;
+-- Shockwave Stalker
+UPDATE `creature_template` SET `faction`= 35, `unit_flags`= 33554432, `flags_extra`= 128, `speed_run`= 1.14286 WHERE `entry`= 44711;
+-- Shockwave Visual
+UPDATE `creature_template` SET `faction`= 14, `unit_flags`= 33554432, `flags_extra`= 128 WHERE `entry`= 44712;
+-- Tol'Vir Land Mine
+UPDATE `creature_template` SET `faction`= 14, `unit_flags`= 33554432, `flags_extra`= 0, `ScriptName`= 'npc_husam_tolvir_land_mine' WHERE `entry`= 44840;
+-- Tol'Vir Land Mine Vehicle
+UPDATE `creature_template` SET `faction`= 14, `unit_flags`= 33554432, `flags_extra`= 0, `VehicleId`= 1050, `ScriptName`= 'npc_husam_tolvir_land_mine' WHERE `entry`= 44798;
+-- Tol'Vir Land Mine 2
+UPDATE `creature_template` SET `faction`= 14, `unit_flags`= 33554432, `flags_extra`= 0, `ScriptName`= 'npc_husam_tolvir_land_mine' WHERE `entry`= 44796;
+-- Bad Intentions Target
+UPDATE `creature_template` SET `flags_extra`= 128 WHERE `entry`= 44586;
+
+DELETE FROM `creature_template_movement` WHERE `CreatureId` IN (44711, 44712, 44840, 44798, 44796, 44586);
+INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`) VALUES
+(44711, 0, 0, 1, 0),
+(44712, 0, 0, 1, 1),
+(44840, 0, 0, 1, 1),
+(44798, 0, 0, 1, 1),
+(44796, 0, 0, 1, 0),
+(44586, 0, 0, 1, 0);
+
+DELETE FROM `npc_spellclick_spells` WHERE `npc_entry`= 44798;
+DELETE FROM `vehicle_template_accessory` WHERE `entry`= 44798;
+
+UPDATE `creature_template` SET `ScriptName`= 'npc_husam_bad_intentions_target', `AIName`='' WHERE `entry`= 44586;
+UPDATE `creature_template` SET `ScriptName`= 'npc_husam_shockwave_visual', `AIName`='' WHERE `entry`= 44712;
+
+DELETE FROM `creature_text` WHERE `CreatureID`= 44577;
+INSERT INTO `creature_text` (`CreatureID`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `comment`) VALUES
+(44577, 0, 0, 'Invaders, you shall go no further!', 14, 0, 100, 0, 0, 0, 49310, 'General Husam - Aggro'),
+(44577, 1, 0, 'Insolent rat!', 14, 0, 100, 0, 0, 0, 49311, 'General Husam - Slay'),
+(44577, 2, 0, 'Murkash!', 14, 0, 100, 0, 0, 0, 49313, 'General Husam - Shockwave'),
+(44577, 3, 0, '|TInterface\\Icons\\spell_nature_earthquake.blp:20|t%s begins to cast |cFFFF0000|Hspell:83445|h[Shockwave]!|h|r', 41, 0, 100, 0, 0, 0, 44921, 'General Husam - Announce Shockwave'),
+(44577, 4, 0, 'Tread Lightly.', 14, 0, 100, 0, 0, 0, 49314, 'General Husam - Detonate Mines'),
+(44577, 5, 0, 'Siamat must not be freed! Turn back before it is too late!', 14, 0, 100, 0, 0, 0, 49312, 'General Husam - Death');
+
+DELETE FROM `spell_script_names` WHERE `ScriptName` IN
+('spell_husam_hammer_fist',
+'spell_husam_shockwave_summon_search',
+'spell_husam_shockwave',
+'spell_husam_detonate_traps',
+'spell_husam_bad_intentions',
+'spell_husam_hurl',
+'spell_husam_hurl_vehicle',
+'spell_husam_land_mine_player_search_effect');
+
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(83654, 'spell_husam_hammer_fist'),
+(83466, 'spell_husam_shockwave_summon_search'),
+(83445, 'spell_husam_shockwave'),
+(91263, 'spell_husam_detonate_traps'),
+(83113, 'spell_husam_bad_intentions'),
+(83236, 'spell_husam_hurl'),
+(83235, 'spell_husam_hurl_vehicle'),
+(83112, 'spell_husam_land_mine_player_search_effect');
+
+DELETE FROM `creature_template_addon` WHERE `entry` IN (44712, 44840, 44798, 44796);
+INSERT INTO `creature_template_addon` (`entry`, `SheathState`, `Auras`) VALUES
+(44712, 1, '83127');
+
+DELETE FROM conditions WHERE `SourceTypeOrReferenceId`= 13 AND `SourceEntry` IN (83466, 83445, 91263);
+INSERT INTO conditions (SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, ConditionValue1, ConditionValue2, ConditionValue3, NegativeCondition, ErrorType, ScriptName, Comment) VALUES
+(13, 0x1, 83466, 0, 0, 51, 0, 5, 44712, 0, 0, 0, '', 'Shockwave Summon Search - Target Shockwave Visual'),
+(13, 0x1, 83445, 0, 0, 51, 0, 5, 44711, 0, 0, 0, '', 'Shockwave - Target Shockwave Stalker'),
+(13, 0x1, 91263, 0, 0, 51, 0, 5, 44796, 0, 0, 0, '', 'Detonate Traps - Target Tolvir Land Mine');
diff --git a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_general_husam.cpp b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_general_husam.cpp
new file mode 100644
index 00000000000..6da8fefc1a1
--- /dev/null
+++ b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_general_husam.cpp
@@ -0,0 +1,548 @@
+/*
+* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ScriptMgr.h"
+#include "Containers.h"
+#include "InstanceScript.h"
+#include "lost_city_of_the_tolvir.h"
+#include "MoveSplineInit.h"
+#include "MotionMaster.h"
+#include "PassiveAI.h"
+#include "ScriptedCreature.h"
+#include "SpellInfo.h"
+#include "SpellScript.h"
+#include "TemporarySummon.h"
+#include "Vehicle.h"
+
+enum Spells
+{
+ // General Husam
+ SPELL_HAMMER_FIST = 83654,
+ SPELL_SHOCKWAVE = 83445,
+ SPELL_SHOCKWAVE_VISUAL = 83130,
+ SPELL_SUMMON_SHOCKWAVE_TARGET_N = 83131,
+ SPELL_SUMMON_SHOCKWAVE_TARGET_S = 83132,
+ SPELL_SUMMON_SHOCKWAVE_TARGET_E = 83133,
+ SPELL_SUMMON_SHOCKWAVE_TARGET_W = 83134,
+ SPELL_MYSTIC_TRAP = 83644,
+ SPELL_THROW_LAND_MINES = 83122,
+ SPELL_DETONATE_TRAPS = 91263,
+ SPELL_BAD_INTENTIONS = 83113,
+ SPELL_HURL = 83236,
+ SPELL_THROW_VISUAL = 83371,
+
+ // Shockwave Stalker
+ SPELL_SHOCKWAVE_SUMMON_EFFECT = 83128,
+ SPELL_SHOCKWAVE_VISUAL_PERIODIC_SUMMON_TRIGGER = 83129,
+
+ // Shockwave Visual
+ SPELL_SHOCKWAVE_DAMAGE = 83454,
+
+ // Tol'Vir Land Mine
+ SPELL_TOLVIR_LAND_MINE_VISUAL = 83110,
+ SPELL_LAND_MINE_PLAYER_SEARCH_TRIGGER = 83111,
+ SPELL_LAND_MINE_PLAYER_SEARCH_EFFECT = 83112,
+ SPELL_LAND_MINE_PERIODIC = 85523,
+ SPELL_MYSTIC_TRAP_DAMAGE = 83171,
+
+ // Bad Intentions Target
+ SPELL_HARD_IMPACT = 83339,
+ SPELL_EJECT_ALL_PASSENGERS = 50630
+};
+
+enum Events
+{
+ // General Husam
+ EVENT_HAMMER_FIST = 1,
+ EVENT_MYSTIC_TRAP,
+ EVENT_BAD_INTENTIONS,
+ EVENT_THROW_PLAYER,
+ EVENT_SHOCKWAVE,
+ EVENT_DETONATE_TRAPS,
+
+ // Tol'Vir Land Mine
+ EVENT_READY_MINE,
+ EVENT_START_COUNTDOWN,
+ EVENT_CLEAR_AURAS
+};
+
+enum Actions
+{
+ // General Husam
+ ACTION_SAY_DETONATE_TRAPS = 0,
+
+ // Tol'vir Land Mine
+ ACTION_INITIATE_COUNTDOWN = 0,
+ ACTION_DETONATE = 1
+};
+
+enum Texts
+{
+ // General Husam
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_SHOCKWAVE = 2,
+ SAY_ANNOUNCE_SHOCKWAVE = 3,
+ SAY_DETONATE_MINES = 4,
+ SAY_DEATH = 5
+};
+
+enum Misc
+{
+ SEAT_PLAYER = 0
+};
+
+struct boss_general_husam : public BossAI
+{
+ boss_general_husam(Creature* creature) : BossAI(creature, BOSS_GENERAL_HUSAM), _shockwaveStalkerCount(0) { }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
+ Talk(SAY_AGGRO);
+
+ events.ScheduleEvent(EVENT_HAMMER_FIST, 7s, 10s);
+ events.ScheduleEvent(EVENT_MYSTIC_TRAP, 7s, 10s);
+ events.ScheduleEvent(EVENT_BAD_INTENTIONS, 12s, 13s);
+ events.ScheduleEvent(EVENT_SHOCKWAVE, IsHeroic() ? 15s : 18s);
+ if (IsHeroic())
+ events.ScheduleEvent(EVENT_DETONATE_TRAPS, 22s);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->IsPlayer())
+ Talk(SAY_SLAY);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ summons.DespawnAll();
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ Talk(SAY_DEATH);
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ _EnterEvadeMode();
+ summons.DespawnAll();
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ _DespawnAtEvade();
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ summons.Summon(summon);
+
+ switch (summon->GetEntry())
+ {
+ case NPC_SHOCKWAVE_STALKER:
+ {
+ ++_shockwaveStalkerCount;
+ float orientation = summon->GetAbsoluteAngle(me) + float(M_PI);
+ Position dest = summon->GetPosition();
+ dest.m_positionX += std::cos(orientation) * 40.f;
+ dest.m_positionY += std::sin(orientation) * 40.f;
+
+ std::function<void(Movement::MoveSplineInit&)> initializer = [dest](Movement::MoveSplineInit& init)
+ {
+ init.MoveTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), false);
+ init.SetVelocity(8.f);
+ };
+ summon->GetMotionMaster()->LaunchMoveSpline(std::move(initializer));
+ summon->CastSpell(nullptr, SPELL_SHOCKWAVE_VISUAL_PERIODIC_SUMMON_TRIGGER);
+
+ if (_shockwaveStalkerCount == 4)
+ {
+ DoCastSelf(SPELL_SHOCKWAVE);
+ _shockwaveStalkerCount = 0;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ void PassengerBoarded(Unit* /*passenger*/, int8 /*seatId*/, bool apply) override
+ {
+ if (apply)
+ events.ScheduleEvent(EVENT_THROW_PLAYER, 1s);
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_SAY_DETONATE_TRAPS)
+ Talk(SAY_DETONATE_MINES);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_HAMMER_FIST:
+ DoCastSelf(SPELL_HAMMER_FIST);
+ events.Repeat(21s);
+ break;
+ case EVENT_MYSTIC_TRAP:
+ DoCastAOE(SPELL_MYSTIC_TRAP, CastSpellExtraArgs().AddSpellMod(SPELLVALUE_MAX_TARGETS, 3));
+ events.Repeat(11s, 12s);
+ break;
+ case EVENT_BAD_INTENTIONS:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, NonTankTargetSelector(me)))
+ DoCast(target, SPELL_BAD_INTENTIONS);
+ break;
+ case EVENT_SHOCKWAVE:
+ Talk(SAY_ANNOUNCE_SHOCKWAVE);
+ Talk(SAY_SHOCKWAVE);
+ DoCastSelf(SPELL_SUMMON_SHOCKWAVE_TARGET_N);
+ DoCastSelf(SPELL_SUMMON_SHOCKWAVE_TARGET_S);
+ DoCastSelf(SPELL_SUMMON_SHOCKWAVE_TARGET_E);
+ DoCastSelf(SPELL_SUMMON_SHOCKWAVE_TARGET_W);
+
+ events.RescheduleEvent(EVENT_MYSTIC_TRAP, 8s, 10s);
+ events.RescheduleEvent(EVENT_HAMMER_FIST, 10s, 12s);
+ events.RescheduleEvent(EVENT_BAD_INTENTIONS, 17s);
+ events.Repeat(39s);
+ break;
+ case EVENT_DETONATE_TRAPS:
+ DoCastSelf(SPELL_DETONATE_TRAPS);
+ events.DelayEvents(2s);
+ events.Repeat(32s);
+ break;
+ case EVENT_THROW_PLAYER:
+ DoCastSelf(SPELL_HURL);
+ DoCastSelf(SPELL_THROW_VISUAL);
+ me->SetReactState(REACT_AGGRESSIVE);
+ break;
+ default:
+ break;
+ }
+ }
+ DoMeleeAttackIfReady();
+ }
+
+private:
+ uint8 _shockwaveStalkerCount;
+};
+
+struct npc_husam_tolvir_land_mine : public NullCreatureAI
+{
+ npc_husam_tolvir_land_mine(Creature* creature) : NullCreatureAI(creature), _instance(nullptr) { }
+
+ void InitializeAI() override
+ {
+ _instance = me->GetInstanceScript();
+ }
+
+ void JustAppeared() override
+ {
+ if (!_instance)
+ return;
+
+ switch (me->GetEntry())
+ {
+ case NPC_TOLVIR_LAND_MINE_TARGET:
+ if (Creature* husam = _instance->GetCreature(BOSS_GENERAL_HUSAM))
+ husam->CastSpell(me, SPELL_THROW_LAND_MINES);
+ me->DespawnOrUnsummon(6s);
+ break;
+ case NPC_TOLVIR_LAND_MINE_VEHICLE:
+ if (Creature* husam = _instance->GetCreature(BOSS_GENERAL_HUSAM))
+ {
+ if (CreatureAI* ai = husam->AI())
+ {
+ ai->JustSummoned(me);
+ if (Creature* landMine = DoSummon(NPC_TOLVIR_LAND_MINE_CASTER, me->GetPosition(), 0s, TEMPSUMMON_MANUAL_DESPAWN))
+ ai->JustSummoned(landMine);
+ }
+ }
+ break;
+ case NPC_TOLVIR_LAND_MINE_CASTER:
+ if (me->IsSummon())
+ if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit())
+ me->EnterVehicle(summoner);
+ _events.ScheduleEvent(EVENT_READY_MINE, 2s);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void PassengerBoarded(Unit* /*passenger*/, int8 /*seatId*/, bool apply) override
+ {
+ // If our casting land mine has despawned, we also despawn alongside it.
+ if (me->GetEntry() == NPC_TOLVIR_LAND_MINE_VEHICLE && !apply)
+ me->DespawnOrUnsummon();
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_INITIATE_COUNTDOWN:
+ _events.RescheduleEvent(EVENT_START_COUNTDOWN, 1ms);
+ break;
+ case ACTION_DETONATE:
+ _events.Reset();
+ DoCastSelf(SPELL_MYSTIC_TRAP_DAMAGE);
+ me->RemoveAurasDueToSpell(SPELL_LAND_MINE_PLAYER_SEARCH_TRIGGER);
+ me->RemoveAurasDueToSpell(SPELL_TOLVIR_LAND_MINE_VISUAL);
+ me->RemoveAurasDueToSpell(SPELL_LAND_MINE_PERIODIC);
+ me->DespawnOrUnsummon(6s);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_READY_MINE:
+ DoCastSelf(SPELL_TOLVIR_LAND_MINE_VISUAL);
+ DoCastSelf(SPELL_LAND_MINE_PLAYER_SEARCH_TRIGGER);
+ _events.ScheduleEvent(EVENT_START_COUNTDOWN, 20s);
+ break;
+ case EVENT_START_COUNTDOWN:
+ DoCastSelf(SPELL_LAND_MINE_PERIODIC);
+ _events.ScheduleEvent(EVENT_CLEAR_AURAS, 5s);
+ break;
+ case EVENT_CLEAR_AURAS:
+ me->RemoveAurasDueToSpell(SPELL_TOLVIR_LAND_MINE_VISUAL);
+ me->RemoveAurasDueToSpell(SPELL_LAND_MINE_PLAYER_SEARCH_TRIGGER);
+ me->DespawnOrUnsummon(6s);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+private:
+ EventMap _events;
+ InstanceScript* _instance;
+};
+
+struct npc_husam_bad_intentions_target : public NullCreatureAI
+{
+ npc_husam_bad_intentions_target(Creature* creature) : NullCreatureAI(creature) { }
+
+ void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) override
+ {
+ if (apply)
+ {
+ me->m_Events.AddEventAtOffset([&, passenger]()
+ {
+ if (passenger)
+ {
+ DoCast(passenger, SPELL_HARD_IMPACT);
+ DoCastSelf(SPELL_EJECT_ALL_PASSENGERS);
+ }
+ }, 400ms);
+ }
+ }
+};
+
+struct npc_husam_shockwave_visual : public NullCreatureAI
+{
+ npc_husam_shockwave_visual(Creature* creature) : NullCreatureAI(creature) { }
+
+ void JustAppeared() override
+ {
+ me->m_Events.AddEventAtOffset([&]() { DoCastSelf(SPELL_SHOCKWAVE_DAMAGE); }, 4s + 600ms);
+ me->m_Events.AddEventAtOffset([&]() { me->RemoveAllAuras(); }, 7s);
+ me->DespawnOrUnsummon(12s);
+ }
+};
+
+class spell_husam_hammer_fist : public AuraScript
+{
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ return ValidateSpellEffect({ { spellInfo->Id, EFFECT_0 } }) && ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell });
+ }
+
+ void HandleTick(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(GetCaster()->GetVictim(), GetSpellInfo()->GetEffect(EFFECT_0).TriggerSpell, true);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_husam_hammer_fist::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+};
+
+class spell_husam_shockwave : public SpellScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_SHOCKWAVE_VISUAL });
+ }
+
+ void EffectScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_SHOCKWAVE_VISUAL, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_husam_shockwave::EffectScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+class spell_husam_shockwave_summon_search : public SpellScript
+{
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_SHOCKWAVE_SUMMON_EFFECT });
+ }
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ if (targets.empty())
+ GetCaster()->CastSpell(GetCaster(), SPELL_SHOCKWAVE_SUMMON_EFFECT, true);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_husam_shockwave_summon_search::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ }
+};
+
+class spell_husam_detonate_traps : public SpellScript
+{
+ void HandlePostCastText()
+ {
+ if (Creature* caster = GetCaster()->ToCreature())
+ if (CreatureAI* ai = caster->AI())
+ ai->DoAction(ACTION_SAY_DETONATE_TRAPS);
+ }
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Creature* target = GetHitCreature())
+ if (CreatureAI* ai = target->AI())
+ ai->DoAction(ACTION_INITIATE_COUNTDOWN);
+ }
+
+ void Register() override
+ {
+ AfterCast += SpellCastFn(spell_husam_detonate_traps::HandlePostCastText);
+ OnEffectHitTarget += SpellEffectFn(spell_husam_detonate_traps::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+class spell_husam_bad_intentions : public SpellScript
+{
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ return ValidateSpellEffect({ { spellInfo->Id, EFFECT_0 } }) && ValidateSpellInfo({ static_cast<uint32>(spellInfo->GetEffect(EFFECT_0).BasePoints) });
+ }
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ Unit* target = GetHitUnit();
+ target->CastStop();
+ target->CastSpell(caster, GetSpellInfo()->GetEffect(EFFECT_1).BasePoints, true);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_husam_bad_intentions::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+class spell_husam_hurl : public SpellScript
+{
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ return ValidateSpellEffect({ { spellInfo->Id, EFFECT_0 } }) && ValidateSpellInfo({ static_cast<uint32>(spellInfo->GetEffect(EFFECT_0).BasePoints) });
+ }
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Vehicle* vehicle = GetCaster()->GetVehicleKit())
+ {
+ if (Unit* passenger = vehicle->GetPassenger(SEAT_PLAYER))
+ {
+ if (Creature* intentionsTarget = GetCaster()->FindNearestCreature(NPC_BAD_INTENTIONS_TARGET, 100.0f))
+ passenger->CastSpell(intentionsTarget, static_cast<uint32>(GetSpellInfo()->GetEffect(EFFECT_0).BasePoints), true);
+ else
+ passenger->ExitVehicle(); // Safety case to avoid players getting stuck in Husam's hand
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_husam_hurl::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+class spell_husam_land_mine_player_search_effect : public SpellScript
+{
+ void HandleDummyEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (Creature* creature = caster->ToCreature())
+ if (creature->IsAIEnabled())
+ creature->AI()->DoAction(ACTION_DETONATE);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_husam_land_mine_player_search_effect::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+};
+
+void AddSC_boss_general_husam()
+{
+ RegisterLostCityOfTheTolvirAI(boss_general_husam);
+ RegisterLostCityOfTheTolvirAI(npc_husam_tolvir_land_mine);
+ RegisterLostCityOfTheTolvirAI(npc_husam_bad_intentions_target);
+ RegisterLostCityOfTheTolvirAI(npc_husam_shockwave_visual);
+ RegisterSpellScript(spell_husam_hammer_fist);
+ RegisterSpellScript(spell_husam_shockwave);
+ RegisterSpellScript(spell_husam_shockwave_summon_search);
+ RegisterSpellScript(spell_husam_detonate_traps);
+ RegisterSpellScript(spell_husam_bad_intentions);
+ RegisterSpellScript(spell_husam_hurl);
+ RegisterSpellScript(spell_husam_land_mine_player_search_effect);
+}
diff --git a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/instance_lost_city_of_the_tolvir.cpp b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/instance_lost_city_of_the_tolvir.cpp
new file mode 100644
index 00000000000..7a01516ad20
--- /dev/null
+++ b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/instance_lost_city_of_the_tolvir.cpp
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "InstanceScript.h"
+#include "lost_city_of_the_tolvir.h"
+
+static constexpr ObjectData const creatureData[] =
+{
+ { NPC_GENERAL_HUSAM, BOSS_GENERAL_HUSAM },
+ { NPC_LOCKMAW, DATA_LOCKMAW },
+ { NPC_AUGH, DATA_AUGH },
+ { NPC_HIGH_PROPHET_BARIM, BOSS_HIGH_PROPHET_BARIM },
+ { NPC_SIAMAT, BOSS_SIAMAT },
+ { 0, 0 } // End
+};
+
+static constexpr DungeonEncounterData const encounters[] =
+{
+ { BOSS_GENERAL_HUSAM, {{ 1052 }} },
+ { BOSS_LOCKMAW_AND_AUGH, {{ 1054 }} },
+ { BOSS_HIGH_PROPHET_BARIM, {{ 1053 }} },
+ { BOSS_SIAMAT, {{ 1055 }} }
+};
+
+class instance_lost_city_of_the_tolvir : public InstanceMapScript
+{
+public:
+ instance_lost_city_of_the_tolvir() : InstanceMapScript(LCTScriptName, 755) { }
+
+ struct instance_lost_city_of_the_tolvir_InstanceMapScript : public InstanceScript
+ {
+ instance_lost_city_of_the_tolvir_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
+ {
+ SetHeaders(DataHeader);
+ SetBossNumber(EncounterCount);
+ LoadDungeonEncounterData(encounters);
+ LoadObjectData(creatureData, nullptr);
+ }
+ };
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_lost_city_of_the_tolvir_InstanceMapScript(map);
+ }
+};
+
+void AddSC_instance_lost_city_of_the_tolvir()
+{
+ new instance_lost_city_of_the_tolvir();
+}
diff --git a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/lost_city_of_the_tolvir.h b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/lost_city_of_the_tolvir.h
new file mode 100644
index 00000000000..d397617ac29
--- /dev/null
+++ b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/lost_city_of_the_tolvir.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LostCityOfTheTolvir_h__
+#define LostCityOfTheTolvir_h__
+
+#include "CreatureAIImpl.h"
+
+#define DataHeader "LCT"
+#define LCTScriptName "instance_lost_city_of_the_tolvir"
+
+static constexpr uint32 EncounterCount = 4;
+
+enum LCTData
+{
+ // Encounters
+ BOSS_GENERAL_HUSAM = 0,
+ BOSS_LOCKMAW_AND_AUGH = 1,
+ BOSS_HIGH_PROPHET_BARIM = 2,
+ BOSS_SIAMAT = 3,
+
+ DATA_LOCKMAW,
+ DATA_AUGH
+};
+
+enum LCTCreatureIds
+{
+ // Bosses
+ NPC_GENERAL_HUSAM = 44577,
+ NPC_LOCKMAW = 43614,
+ NPC_AUGH = 49045,
+ NPC_HIGH_PROPHET_BARIM = 43612,
+ NPC_SIAMAT = 44819,
+
+ // Encounter related creatures
+ /*General Husam*/
+ NPC_BAD_INTENTIONS_TARGET = 44586,
+ NPC_SHOCKWAVE_STALKER = 44711,
+ NPC_TOLVIR_LAND_MINE_TARGET = 44840,
+ NPC_TOLVIR_LAND_MINE_VEHICLE = 44798,
+ NPC_TOLVIR_LAND_MINE_CASTER = 44796
+};
+
+template <class AI, class T>
+inline AI* GetLostCityOfTheTolvirAI(T* obj)
+{
+ return GetInstanceAI<AI>(obj, LCTScriptName);
+}
+
+#define RegisterLostCityOfTheTolvirAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetLostCityOfTheTolvirAI)
+
+#endif // LostCityOfTheTolvir_h__
diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
index 7f60f5e4fb0..eb5b043da2f 100644
--- a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
+++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
@@ -95,6 +95,9 @@ void AddSC_boss_twinemperors();
void AddSC_boss_ouro();
void AddSC_npc_anubisath_sentinel();
void AddSC_instance_temple_of_ahnqiraj();
+// The Lost City of the Tol'vir
+void AddSC_boss_general_husam();
+void AddSC_instance_lost_city_of_the_tolvir();
// Wailing caverns
void AddSC_wailing_caverns();
void AddSC_instance_wailing_caverns();
@@ -216,6 +219,9 @@ void AddKalimdorScripts()
AddSC_boss_ouro();
AddSC_npc_anubisath_sentinel();
AddSC_instance_temple_of_ahnqiraj();
+ // The Lost City of the Tol'vir
+ AddSC_boss_general_husam();
+ AddSC_instance_lost_city_of_the_tolvir();
// Wailing caverns
AddSC_wailing_caverns();
AddSC_instance_wailing_caverns();