From c7de7b04e60894ab6240017f62c6a31edba485da Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Mon, 8 Jul 2019 22:35:16 +0200 Subject: [PATCH] Scripts/GB: implement Battered Red Drake bombardment event --- .../custom/custom_2019_07_08_02_world.sql | 73 +++++++++ .../EasternKingdoms/GrimBatol/grim_batol.cpp | 151 ++++++++++++++++++ .../GrimBatol/instance_grim_batol.cpp | 128 ++++++++++++++- src/server/scripts/Spells/spell_generic.cpp | 134 ++++++++++------ 4 files changed, 430 insertions(+), 56 deletions(-) create mode 100644 sql/updates/world/custom/custom_2019_07_08_02_world.sql diff --git a/sql/updates/world/custom/custom_2019_07_08_02_world.sql b/sql/updates/world/custom/custom_2019_07_08_02_world.sql new file mode 100644 index 0000000000..fd2170626d --- /dev/null +++ b/sql/updates/world/custom/custom_2019_07_08_02_world.sql @@ -0,0 +1,73 @@ +UPDATE `creature_template` SET `unit_flags`= 0, `IconName`= 'vehichleCursor', `ScriptName`= 'npc_grim_batol_battered_red_drake' WHERE `entry`= 39294; + +DELETE FROM `npc_spellclick_spells` WHERE `npc_entry`= 39294; +INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES +(39294, 80343, 1, 1); + +DELETE FROM `creature` WHERE `guid` IN (339899, 340384, 340108, 339892, 339905); +DELETE FROM `creature_addon` WHERE `guid` IN (339899, 340384, 340108, 339892, 339905); + +-- Summon Groups +DELETE FROM `creature_summon_groups` WHERE `summonerId`= 670 AND `summonerType`= 2; +INSERT INTO `creature_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `summonType`, `summonTime`) VALUES +(670, 2, 0, 39294, -440.7257, -335.5625, 268.8163, 3.124139, 8, 0), +(670, 2, 0, 39294, -443.1285, -350.7656, 267.6065, 2.583087, 8, 0), +(670, 2, 0, 39294, -436.0382, -371.0208, 269.048, 2.600541, 8, 0), +(670, 2, 0, 39294, -450.401, -387.3906, 268.959, 1.151917, 8, 0), +(670, 2, 0, 39294, -435.717, -387.1146, 267.7955, 1.937315, 8, 0); + +DELETE FROM `creature_text` WHERE `CreatureID`= 39294; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `comment`) VALUES +(39294, 0, 0, 'Welcome, friend. Let\'s ride through Grim Batol and strike a blow against Deathwing that he won\'t soon forget!', 15, 0, 100, 0, 0, 0, 39638, 'Battered Red Drake'), +(39294, 1, 0, '|TInterface\\Icons\\ability_mage_firestarter.blp:20|tUse |cFFFF0000|Hspell:74040|h[Engulfing Flames]|h|r to destroy the Twilight\'s Hammer!', 42, 0, 100, 0, 0, 0, 49153, 'Battered Red Drake'); + +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`= 39294; +INSERT INTO `script_spline_chain_waypoints` (`entry`, `chainId`, `splineId`, `wpId`, `x`, `y`, `z`) VALUES +-- 1 +(39294, 1, 0, 0, -440.7257, -335.5625, 268.7344), +(39294, 1, 0, 1, -442.3385, -345.099, 277.725), +(39294, 1, 0, 2, -470.4236, -328.9063, 297.9019), +(39294, 1, 0, 3, -534.6597, -322.5816, 301.79), +(39294, 1, 0, 4, -626.283, -381.1163, 288.429), +(39294, 1, 0, 5, -674.8021, -396.4879, 322.5092), +(39294, 1, 0, 6, -722.1858, -463.8368, 306.454), +(39294, 1, 0, 7, -714.2639, -588.7604, 331.7317), +(39294, 1, 0, 8, -684.1719, -676.0486, 301.2165), +(39294, 1, 0, 9, -635.1007, -714.7153, 302.4538), +(39294, 1, 0, 10, -533.9254, -731.7726, 291.2872), +(39294, 1, 0, 11, -462.1371, -724.3055, 288.4538), +(39294, 1, 0, 12, -399.845, -697.885, 292.704), +(39294, 1, 0, 13, -389.738, -662.714, 301.537), +(39294, 1, 0, 14, -441.842, -673.3004, 293.8704), +(39294, 1, 0, 15, -533.5643, -720.9549, 297.9536), +(39294, 1, 0, 16, -626.3611, -689.4618, 311.9816), +(39294, 1, 0, 17, -678.4479, -646.75, 322.6483), +(39294, 1, 0, 18, -699.4375, -607.6424, 314.0928), +(39294, 1, 0, 19, -723.5938, -524.5643, 308.8705), +(39294, 1, 0, 20, -687.9358, -424.9115, 291.3428), +(39294, 1, 0, 21, -538.7361, -318.3976, 292.5929), +(39294, 1, 0, 22, -452.2274, -357.5938, 276.204), +-- 2 +(39294, 2, 0, 0, -452.2274, -357.5938, 276.204), +(39294, 2, 0, 1, -443.7083, -350.4722, 285.9457), +(39294, 2, 0, 2, -477.875, -344.184, 318.846), +(39294, 2, 0, 3, -532.6545, -296.8021, 356.0412), +(39294, 2, 0, 4, -534.6094, -281.1754, 356.0412); + + +DELETE FROM `script_spline_chain_meta` WHERE `entry`= 39294; +INSERT INTo `script_spline_chain_meta` (`entry`, `chainId`, `splineId`, `expectedDuration`, `msUntilNext`, `velocity`) VALUES +(39294, 1, 0, 89126, 0, 13.0), +(39294, 2, 0, 5328, 0, 13.0); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN +('spell_grim_batol_engulfing_flames', +'spell_gen_vehicle_scaling_trigger'); + +DELETE FROM `spell_script_names` WHERE `ScriptName`= 'spell_gen_vehicle_scaling' AND `spell_id` IN (91401, 91405); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(74040, 'spell_grim_batol_engulfing_flames'), +(90904, 'spell_grim_batol_engulfing_flames'), +(73917, 'spell_gen_vehicle_scaling_trigger'), +(91401, 'spell_gen_vehicle_scaling'), +(91405, 'spell_gen_vehicle_scaling'); diff --git a/src/server/scripts/EasternKingdoms/GrimBatol/grim_batol.cpp b/src/server/scripts/EasternKingdoms/GrimBatol/grim_batol.cpp index 49cee00cbf..a32c5c6435 100644 --- a/src/server/scripts/EasternKingdoms/GrimBatol/grim_batol.cpp +++ b/src/server/scripts/EasternKingdoms/GrimBatol/grim_batol.cpp @@ -20,6 +20,7 @@ #include "ScriptedCreature.h" #include "SpellScript.h" #include "SpellAuraEffects.h" +#include "CombatAI.h" #include "grim_batol.h" enum TwilightBeguiler @@ -135,7 +136,157 @@ private: EventMap _events; }; +enum BatteredRedDrake +{ + SPELL_NET = 79377, + SPELL_NET_SCRIPT = 79374, + SPELL_BOMBING_RUN_PROTECTION_TRIGGER = 80364, + SPELL_GEAR_SCALING_TRIGGER = 73917, + SPELL_EJECT_ALL_PASSENGERS = 68576, + + ANIM_KIT_ID_LIFTOFF = 1009, + + EVENT_SET_HOVERING = 1, + EVENT_PREPARE_BOMBARDMENT, + EVENT_FLY_BOMBARDMENT, + EVENT_FLY_AWAY, + + SAY_WHISPER_BOMBARDMENT = 0, + SAY_ANNOUNCE_BOMBARDMENT = 1, + + SPLINE_CHAIN_BOMBARDMENT = 1, + SPLINE_CHAIN_ESCAPE_BOMBARDMENT = 2, + + POINT_EJECT_PLAYER = 1 +}; + +struct npc_grim_batol_battered_red_drake: public VehicleAI +{ + npc_grim_batol_battered_red_drake(Creature* creature) : VehicleAI(creature), _instance(me->GetInstanceScript()) { } + + void JustAppeared() override + { + if (_instance->GetData(DATA_BATTERED_RED_DRAKE_STATE) != DONE) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCastSelf(SPELL_NET); + } + } + + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + if (summon->GetEntry() == NPC_NET) + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->RemoveAurasDueToSpell(SPELL_NET); + DoCastSelf(SPELL_BOMBING_RUN_PROTECTION_TRIGGER); + summon->CastSpell(summon, SPELL_NET_SCRIPT); + summon->DespawnOrUnsummon(3s); + } + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != SPLINE_CHAIN_MOTION_TYPE) + return; + + switch (pointId) + { + case POINT_EJECT_PLAYER: + DoCastSelf(SPELL_EJECT_ALL_PASSENGERS); + _events.ScheduleEvent(EVENT_FLY_AWAY, 2s + 500ms); + break; + default: + break; + } + } + + void PassengerBoarded(Unit* passenger, int8 /*seat*/, bool apply) override + { + Player* player = passenger->ToPlayer(); + if (!player) + return; + + if (apply) + { + _instance->SetData(DATA_START_BATTERED_RED_DRAKE_DESPAWN_EVENT, IN_PROGRESS); + me->SetControlled(true, UNIT_STATE_ROOT); + me->PlayOneShotAnimKitId(ANIM_KIT_ID_LIFTOFF); + player->SetMover(me); + _playerGuid = player->GetGUID(); + + _events.ScheduleEvent(EVENT_SET_HOVERING, 2s); + _events.ScheduleEvent(EVENT_PREPARE_BOMBARDMENT, 1s); + } + else + player->SetMover(player); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SET_HOVERING: + if (Player* player = ObjectAccessor::FindConnectedPlayer(_playerGuid)) + DoCast(player, SPELL_GEAR_SCALING_TRIGGER, true); + me->SendSetPlayHoverAnim(true); + me->AddUnitMovementFlag(MOVEMENTFLAG_HOVER); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + break; + case EVENT_PREPARE_BOMBARDMENT: + if (Player* player = ObjectAccessor::FindConnectedPlayer(_playerGuid)) + { + Talk(SAY_WHISPER_BOMBARDMENT, player); + Talk(SAY_ANNOUNCE_BOMBARDMENT, player); + _events.ScheduleEvent(EVENT_FLY_BOMBARDMENT, 2s); + } + break; + case EVENT_FLY_BOMBARDMENT: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_EJECT_PLAYER, SPLINE_CHAIN_BOMBARDMENT, false); + break; + case EVENT_FLY_AWAY: + me->GetMotionMaster()->MoveAlongSplineChain(0, SPLINE_CHAIN_ESCAPE_BOMBARDMENT, false); + me->DespawnOrUnsummon(6s + 700ms); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + +private: + EventMap _events; + InstanceScript* _instance; + ObjectGuid _playerGuid; +}; + +class spell_grim_batol_engulfing_flames : public SpellScript +{ + PrepareSpellScript(spell_grim_batol_engulfing_flames); + + void HandleEffect(SpellEffIndex /*effIndex*/) + { + if (Creature* creature = GetHitCreature()) + creature->setRegeneratingHealth(false); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_grim_batol_engulfing_flames::HandleEffect, EFFECT_1, SPELL_EFFECT_DUMMY); + } +}; + void AddSC_grim_batol() { RegisterGrimBatolCreatureAI(npc_grim_batol_twilight_beguiler); + RegisterGrimBatolCreatureAI(npc_grim_batol_battered_red_drake); + RegisterSpellScript(spell_grim_batol_engulfing_flames); } diff --git a/src/server/scripts/EasternKingdoms/GrimBatol/instance_grim_batol.cpp b/src/server/scripts/EasternKingdoms/GrimBatol/instance_grim_batol.cpp index fa2eea15d4..1842834790 100644 --- a/src/server/scripts/EasternKingdoms/GrimBatol/instance_grim_batol.cpp +++ b/src/server/scripts/EasternKingdoms/GrimBatol/instance_grim_batol.cpp @@ -34,6 +34,18 @@ ObjectData const creatureData[] = { 0, 0 } // End }; +enum Events +{ + EVENT_DESPAWN_BATTERED_RED_DRAKES = 1 +}; + +enum BatteredDrakeStates +{ + STATE_EMPRISONED = 0, + STATE_FREED = 1, + STATE_DESPAWNED = 2 +}; + class instance_grim_batol : public InstanceMapScript { public: @@ -46,6 +58,25 @@ class instance_grim_batol : public InstanceMapScript SetHeaders(DataHeader); SetBossNumber(EncounterCount); LoadObjectData(creatureData, nullptr); + Initialize(); + } + + void Initialize() + { + _initialized = false; + _destroyedNets = 0; + _batteredRedDrakeState = STATE_EMPRISONED; + } + + void OnPlayerEnter(Player* /*player*/) + { + if (_initialized) + return; + + if (_batteredRedDrakeState != STATE_DESPAWNED) + instance->SummonCreatureGroup(SUMMON_GROUP_BATTERED_DRAKES); + + _initialized = true; } void OnCreatureCreate(Creature* creature) override @@ -86,7 +117,10 @@ class instance_grim_batol : public InstanceMapScript case NPC_ALEXSTRASZAS_EGG: creature->SetCorpseDelay(DAY); creature->SetHealth(creature->GetMaxHealth()); - alexstraszasEggGuidList.insert(creature->GetGUID()); + _alexstraszasEggGuidSet.insert(creature->GetGUID()); + break; + case NPC_BATTERED_RED_DRAKE_BOMBARDMENT: + _batteredRedDrakeGuidSet.insert(creature->GetGUID()); break; default: break; @@ -110,14 +144,14 @@ class instance_grim_batol : public InstanceMapScript } if (state == FAIL) { - for (ObjectGuid guid : alexstraszasEggGuidList) + for (ObjectGuid guid : _alexstraszasEggGuidSet) if (Creature* egg = instance->GetCreature(guid)) egg->DespawnOrUnsummon(0, 30s); - alexstraszasEggGuidList.clear(); + _alexstraszasEggGuidSet.clear(); } else if (state == DONE) - for (ObjectGuid guid : alexstraszasEggGuidList) + for (ObjectGuid guid : _alexstraszasEggGuidSet) if (Creature* egg = instance->GetCreature(guid)) egg->DespawnOrUnsummon(); break; @@ -127,8 +161,92 @@ class instance_grim_batol : public InstanceMapScript return true; } + void OnUnitDeath(Unit* victim) override + { + if (victim->GetTypeId() != TYPEID_UNIT) + return; + + switch (victim->GetEntry()) + { + case NPC_NET: + _destroyedNets++; + if (_destroyedNets == 5) + { + _batteredRedDrakeState = STATE_FREED; + SaveToDB(); + } + break; + default: + break; + } + } + + uint32 GetData(uint32 type) const override + { + switch (type) + { + case DATA_BATTERED_RED_DRAKE_STATE: + return _batteredRedDrakeState; + } + return 0; + } + + void SetData(uint32 type, uint32 /*data*/) override + { + switch (type) + { + case DATA_START_BATTERED_RED_DRAKE_DESPAWN_EVENT: + _batteredRedDrakeState = STATE_DESPAWNED; + SaveToDB(); + if (!_events.GetTimeUntilEvent(EVENT_DESPAWN_BATTERED_RED_DRAKES)) + _events.ScheduleEvent(EVENT_DESPAWN_BATTERED_RED_DRAKES, 3min); + break; + default: + break; + } + } + + void Update(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DESPAWN_BATTERED_RED_DRAKES: + { + for (ObjectGuid guid : _batteredRedDrakeGuidSet) + { + if (Creature* drake = instance->GetCreature(guid)) + if (!drake->GetCharmerOrOwnerPlayerOrPlayerItself()) + drake->DespawnOrUnsummon(); + } + break; + } + default: + break; + } + } + } + + void WriteSaveDataMore(std::ostringstream& data) + { + data << _batteredRedDrakeState; + } + + void ReadSaveDataMore(std::istringstream& data) + { + data >> _batteredRedDrakeState; + } + private: - GuidSet alexstraszasEggGuidList; + GuidSet _alexstraszasEggGuidSet; + GuidSet _batteredRedDrakeGuidSet; + uint8 _batteredRedDrakeState; + uint8 _destroyedNets; + bool _initialized; + EventMap _events; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 5bbb5c59e5..b7b238b1c8 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -3613,63 +3613,94 @@ class spell_gen_vampiric_touch : public SpellScriptLoader } }; -enum VehicleScaling +class spell_gen_vehicle_scaling_trigger : public SpellScript { - SPELL_GEAR_SCALING = 66668 + PrepareSpellScript(spell_gen_vehicle_scaling_trigger); + + bool Validate(SpellInfo const* spellInfo) override + { + return ValidateSpellInfo({ uint32(spellInfo->Effects[EFFECT_0].BasePoints) }); + } + + void HandleEffect(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + GetHitUnit()->CastSpell(caster, GetSpellInfo()->Effects[effIndex].BasePoints, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gen_vehicle_scaling_trigger::HandleEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } }; -class spell_gen_vehicle_scaling : public SpellScriptLoader +enum VehicleScaling { - public: - spell_gen_vehicle_scaling() : SpellScriptLoader("spell_gen_vehicle_scaling") { } + SPELL_GEAR_SCALING_1 = 66668, + SPELL_GEAR_SCALING_CATA_N = 91401, + SPELL_GEAR_SCALING_CATA_HC = 91405 - class spell_gen_vehicle_scaling_AuraScript : public AuraScript +}; + +class spell_gen_vehicle_scaling : public AuraScript +{ + PrepareAuraScript(spell_gen_vehicle_scaling); + + bool Load() override + { + return GetCaster() && GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + Unit* caster = GetCaster(); + float factor = 0.0f; + uint16 baseItemLevel = 0; + + /// @todo Reserach coeffs for different vehicles + switch (GetId()) { - PrepareAuraScript(spell_gen_vehicle_scaling_AuraScript); - - bool Load() override - { - return GetCaster() && GetCaster()->GetTypeId() == TYPEID_PLAYER; - } - - void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) - { - Unit* caster = GetCaster(); - float factor; - uint16 baseItemLevel; - - /// @todo Reserach coeffs for different vehicles - switch (GetId()) - { - case SPELL_GEAR_SCALING: - factor = 1.0f; - baseItemLevel = 205; - break; - default: - factor = 1.0f; - baseItemLevel = 170; - break; - } - - float avgILvl = caster->ToPlayer()->GetAverageItemLevel(); - if (avgILvl < baseItemLevel) - return; /// @todo Research possibility of scaling down - - amount = uint16((avgILvl - baseItemLevel) * factor); - } - - void Register() override - { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_gen_vehicle_scaling_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_HEALING_PCT); - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_gen_vehicle_scaling_AuraScript::CalculateAmount, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_gen_vehicle_scaling_AuraScript::CalculateAmount, EFFECT_2, SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_gen_vehicle_scaling_AuraScript(); + case SPELL_GEAR_SCALING_1: + factor = 1.0f; + baseItemLevel = 205; + break; + case SPELL_GEAR_SCALING_CATA_N: + factor = 1.0f; + baseItemLevel = 305; + break; + case SPELL_GEAR_SCALING_CATA_HC: + factor = 1.0f; + baseItemLevel = 329; + break; + default: + factor = 1.0f; + baseItemLevel = 170; + break; } + + float avgILvl = caster->ToPlayer()->GetAverageItemLevel(); + if (avgILvl < baseItemLevel) + return; /// @todo Research possibility of scaling down + + amount = uint16((avgILvl - baseItemLevel) * factor); + } + + void Register() override + { + switch (m_scriptSpellId) + { + case SPELL_GEAR_SCALING_CATA_N: + case SPELL_GEAR_SCALING_CATA_HC: + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_gen_vehicle_scaling::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_HEALING_DONE_PERCENT); + break; + default: + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_gen_vehicle_scaling::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_HEALING_PCT); + break; + } + + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_gen_vehicle_scaling::CalculateAmount, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_gen_vehicle_scaling::CalculateAmount, EFFECT_2, SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); + } }; enum VendorBarkTrigger @@ -5087,7 +5118,8 @@ void AddSC_generic_spell_scripts() new spell_gen_turkey_marker(); new spell_gen_upper_deck_create_foam_sword(); new spell_gen_vampiric_touch(); - new spell_gen_vehicle_scaling(); + RegisterSpellScript(spell_gen_vehicle_scaling_trigger); + RegisterAuraScript(spell_gen_vehicle_scaling); new spell_gen_vendor_bark_trigger(); new spell_gen_wg_water(); new spell_gen_whisper_gulch_yogg_saron_whisper();