From 4ba96a09a0332261c1e3cbc016612dad8e132919 Mon Sep 17 00:00:00 2001 From: Jelle Meeus Date: Sun, 28 Apr 2024 07:52:14 +0200 Subject: [PATCH] save --- .../Northrend/Naxxramas/boss_maexxna.cpp | 385 +++++++++++++----- 1 file changed, 292 insertions(+), 93 deletions(-) diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp index e31944aa4b..ac3d494486 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp @@ -27,6 +27,8 @@ enum Spells SPELL_WEB_WRAP_KILL_WEBS = 52512, + SPELL_WEB_WRAP_INIT = 28673, + SPELL_WEB_WRAP_200 = 28618, // 200 Pull speed SPELL_WEB_WRAP_300 = 28619, SPELL_WEB_WRAP_400 = 28620, @@ -71,13 +73,41 @@ enum Misc NPC_WEB_WRAP_TRIGGER = 15384 }; -const Position PosWrap[3] = + // {3546.796f, -3869.082f, 296.450f, 0.0f}, + // {3531.271f, -3847.424f, 299.450f, 0.0f}, + // {3497.067f, -3843.384f, 302.384f, 0.0f} + +const Position PosWrap[8] = { - {3546.796f, -3869.082f, 296.450f, 0.0f}, - {3531.271f, -3847.424f, 299.450f, 0.0f}, - {3497.067f, -3843.384f, 302.384f, 0.0f} + {3562.40f, -3890.35f, 314.30f, 0.0f}, + {3560.78f, -3878.10f, 316.18f, 0.0f}, + {3554.95f, -3863.24f, 314.46f, 0.0f}, + {3549.02f, -3855.07f, 311.58f, 0.0f}, + {3538.34f, -3844.68f, 314.21f, 0.0f}, + {3526.43f, -3838.73f, 317.10f, 0.0f}, + {3507.84f, -3832.71f, 319.00f, 0.0f}, + {3493.35f, -3834.06f, 318.71f, 0.0f} }; +struct WebTargetSelector +{ + WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {} + bool operator()(Unit const* target) const + { + if (target->GetTypeId() != TYPEID_PLAYER) // never web nonplayers (pets, guardians, etc.) + return false; + if (_maexxna->GetVictim() == target) // never target tank + return false; + if (target->HasAura(SPELL_WEB_WRAP_STUN)) // never target targets that are already webbed + return false; + return true; + } + + private: + Unit const* _maexxna; +}; + + class boss_maexxna : public CreatureScript { public: @@ -99,6 +129,9 @@ public: EventMap events; SummonList summons; + std::vector> wraps; + std::vector> wraps2; + bool IsInRoom() { if (me->GetExactDist(3486.6f, -3890.6f, 291.8f) > 100.0f) @@ -167,9 +200,135 @@ public: void JustDied(Unit* killer) override { BossAI::JustDied(killer); - //summons.DespawnAll(); } + bool DoCastWebWrap() + { + + std::list candidates; + SelectTargetList(candidates, RAID_MODE(1, 2), SelectTargetMethod::Random, 1, WebTargetSelector(me)); + + if (candidates.empty()) + return false; + + + for (uint i = 0; i < candidates.size() ; i++) + { + const Position &randomPos = PosWrap[urand(0,7)]; + + auto candIt = candidates.begin(); + + if (candidates.size() > 1) + std::advance(candIt, urand(0, candidates.size() - 1)); + + Unit *target = *candIt; + candIt = candidates.erase(candIt); + + float dx = target->GetPositionX() - randomPos.GetPositionX(); + float dy = target->GetPositionY() - randomPos.GetPositionY(); + float dist = sqrt((dx * dx) + (dy * dy)); + float yDist = randomPos.GetPositionZ() - target->GetPositionZ(); + + // todo: to avoid ever hitting the overhanging ceiling we would need to adjust the horizontal + // velocity based on how close we are to it. If we are close initially, reduce the travel-time + // by increasing horizontal velocity, in which case we won't need as much vertical velocity, thus + // won't hit the ceiling. + // s=ut+(0.5a*t^2) || s = vertical speed, u = initial up velocity, a = gravity factor(negative), t = time of flight + // sadly this only aproximates some parts of this formula + float horizontalSpeed = dist / 1.5f; + float verticalSpeed = 20.0f + (yDist * 0.5f); + float angle = target->GetAngle(randomPos.GetPositionX(), randomPos.GetPositionY()); + + // set immune anticheat and calculate speed + if (Player *plr = target->ToPlayer()) + { + // plr->SetLaunched(true); + // plr->SetXYSpeed(horizontalSpeed); + } + + target->KnockbackFrom(randomPos.GetPositionX(), randomPos.GetPositionY(), horizontalSpeed, verticalSpeed); + // target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20); + + wraps.push_back(std::make_pair(uint32(2000), target->GetGUID())); + + auto candIt = candidates.begin(); + + if(candidates.size() > 1) + std::advance(candIt, urand(0, candidates.size() - 1)); + + Unit* target = *candIt; + candIt = candidates.erase(candIt); + + float dx = target->GetPositionX() - PosWrap[i].GetPositionX(); + float dy = target->GetPositionY() - PosWrap[i].GetPositionY(); + float dist = sqrt((dx * dx) + (dy * dy)); + float yDist = PosWrap[i].GetPositionZ() - target->GetPositionZ(); + + // todo: to avoid ever hitting the overhanging ceiling we would need to adjust the horizontal + // velocity based on how close we are to it. If we are close initially, reduce the travel-time + // by increasing horizontal velocity, in which case we won't need as much vertical velocity, thus + // won't hit the ceiling. + //s=ut+(0.5a*t^2) || s = vertical speed, u = initial up velocity, a = gravity factor(negative), t = time of flight + // sadly this only aproximates some parts of this formula + float horizontalSpeed = dist/1.5f; + float verticalSpeed = 20.0f + (yDist*0.5f); + float angle = target->GetAngle(PosWrap[i].GetPositionX(), PosWrap[i].GetPositionY()); + + // set immune anticheat and calculate speed + if (Player* plr = target->ToPlayer()) + { + // plr->SetLaunched(true); + // plr->SetXYSpeed(horizontalSpeed); + } + + target->KnockbackFrom(PosWrap[i].GetPositionX(), PosWrap[i].GetPositionY(), horizontalSpeed, verticalSpeed); + // target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20); + + wraps.push_back(std::make_pair(uint32(2000), target->GetGUID())); + } + + return true; + } + +void UpdateWraps(uint32 uiDiff) + { + bool wdone = false; + for (auto& p : wraps2) + { + if (p.first < uiDiff) + { + if (Player* pl = ObjectAccessor::GetPlayer(*me, p.second)) + { + pl->SummonCreature(NPC_WEB_WRAP, pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 57000); + } + wdone = true; + } + else + p.first -= uiDiff; + } + + if (wdone) + wraps2.clear(); + + wdone = false; + for (auto& p : wraps) + { + if (p.first < uiDiff) + { + if (Player* pl = ObjectAccessor::GetPlayer(*me, p.second)) + { + pl->CastSpell(pl, SPELL_WEB_WRAP_STUN, true); + wraps2.push_back(std::make_pair(3000, p.second)); + } + wdone = true; + } + else + p.first -= uiDiff; + } + if (wdone) + wraps.clear(); + } + void UpdateAI(uint32 diff) override { if (!IsInRoom()) @@ -215,54 +374,8 @@ public: break; case EVENT_WEB_WRAP: Talk(EMOTE_WEB_WRAP); - //for (uint8 i = 0; i < RAID_MODE(1, 2); ++i) - for (uint8 i = 0; i < 1; ++i) - { - // TODO: this can select the same target twice - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0, true, true, -SPELL_WEB_WRAP_STUN)) - { - std::list triggers; - // TODO: This list should be saved OnAggro and range 100.0f - me->GetCreatureListWithEntryInGrid(triggers, NPC_WEB_WRAP_TRIGGER, 150.0f); - if (!triggers.empty()) - { - std::list::iterator itr = triggers.begin(); - std::advance(itr, urand(0, triggers.size() - 1)); - - Creature* triggerNPC; - triggerNPC = *itr; - - triggers.erase(std::remove(triggers.begin(), triggers.end(), triggerNPC), triggers.end()); - - - float dist = me->GetDistance(target); - uint32 spellId = SPELL_WEB_WRAP_500; - if (dist <= 20.f) - spellId = SPELL_WEB_WRAP_200; - else if (dist <= 30.f) - spellId = SPELL_WEB_WRAP_300; - else if (dist <= 40.f) - spellId = SPELL_WEB_WRAP_400; - //triggerNPC->CastCustomSpell(SPELL_WEB_WRAP_200, SPELLVALUE_AURA_DURATION, 1000, target, true); - //triggerNPC->CastSpell(target, spellId, true); - triggerNPC->CastSpell(target, spellId, true); // 4 seconds - - - //triggerNPC->AI()->SetGUID(target->GetGUID()); - - //target->RemoveAura(RAID_MODE(SPELL_WEB_SPRAY_10, SPELL_WEB_SPRAY_25)); - //uint8 pos = urand(0, 2); - //if (Creature* wrap = me->SummonCreature(NPC_WEB_WRAP, PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - //{ - // wrap->AI()->SetGUID(target->GetGUID()); - // target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20); - //} - - - } - - } - } + DoCastWebWrap(); + //me->CastSpell(me, SPELL_WEB_WRAP_INIT, true); events.Repeat(40s); break; } @@ -285,7 +398,6 @@ public: { explicit boss_maexxna_webwrap_triggerAI(Creature* c) : NullCreatureAI(c) {} - ObjectGuid victimGUID; void SetGUID(ObjectGuid guid, int32 /*param*/) override @@ -309,14 +421,11 @@ public: }; - class boss_maexxna_webwrap : public CreatureScript { public: boss_maexxna_webwrap() : CreatureScript("boss_maexxna_webwrap") { } - - CreatureAI* GetAI(Creature* pCreature) const override { return GetNaxxramasAI(pCreature); @@ -332,6 +441,24 @@ public: // me->KillSelf(10000); // } + + // void SetGUID(ObjectGuid guid, int32 /*param*/) override + // { + // victimGUID = guid; + // if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID)) + // { + // float dist = me->GetDistance(victim); + // uint32 duration = 4000; + // if (dist <= 20.f) + // duration = 1000; + // else if (dist <= 30.f) + // duration = 2000; + // else if (dist <= 40.f) + // duration = 3000; + // me->CastCustomSpell(SPELL_WEB_WRAP_200, SPELLVALUE_AURA_DURATION, duration, victim, true); + // } + // } + void IsSummonedBy(WorldObject* summoner) override { if (!summoner) @@ -348,9 +475,8 @@ public: { if (victim->IsAlive()) { - // TODO: can be SPELL_WEB_WRAP if fixed victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_STUN); - victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_SUMMON); + // victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_SUMMON); } victim->RestoreDisplayId(); } @@ -365,9 +491,6 @@ public: { if (!victim->IsAlive()) { - // TODO: can be SPELL_WEB_WRAP if fixed - // victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_STUN); - // victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_SUMMON); me->CastSpell(me, SPELL_WEB_WRAP_KILL_WEBS, true); } } @@ -378,42 +501,118 @@ public: }; -class spell_web_wrap_damage : public SpellScriptLoader -{ -public: - spell_web_wrap_damage() : SpellScriptLoader("spell_web_wrap_damage") { } - - class spell_web_wrap_damage_AuraScript : public AuraScript - { - PrepareAuraScript(spell_web_wrap_damage_AuraScript); - - void OnPeriodic(AuraEffect const* aurEff) - { - if (aurEff->GetTickNumber() == 2) - { - GetTarget()->CastSpell(GetTarget(), SPELL_WEB_WRAP_SUMMON, true); - } - - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_web_wrap_damage_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_web_wrap_damage_AuraScript(); - } -}; +//class spell_web_wrap_maexxna : public SpellScriptLoader +//{ +//public: +// spell_web_wrap_maexxna() : SpellScriptLoader("spell_web_wrap_maexxna") { } +// +// class spell_web_wrap_maexxna_SpellScript : public SpellScript +// { +// PrepareSpellScript(spell_web_wrap_maexxna_SpellScript); +// +// void HandleScriptEffect(SpellEffIndex effIndex) +// { +// PreventHitDefaultEffect(effIndex); +// for (uint8 i = 0; i < RAID_MODE(1, 2); ++i) +// { +// // TODO: this can select the same target twice +// if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0, true, true, -SPELL_WEB_WRAP_STUN)) +// { +// std::list triggers; +// // TODO: This list should be saved OnAggro and range 100.0f +// me->GetCreatureListWithEntryInGrid(triggers, NPC_WEB_WRAP_TRIGGER, 150.0f); +// if (!triggers.empty()) +// { +// std::list::iterator itr = triggers.begin(); +// std::advance(itr, urand(0, triggers.size() - 1)); +// +// Creature* triggerNPC; +// triggerNPC = *itr; +// +// triggers.erase(std::remove(triggers.begin(), triggers.end(), triggerNPC), triggers.end()); +// +// +// float dist = me->GetDistance(target); +// uint32 spellId = SPELL_WEB_WRAP_500; +// if (dist <= 20.f) +// spellId = SPELL_WEB_WRAP_200; +// else if (dist <= 30.f) +// spellId = SPELL_WEB_WRAP_300; +// else if (dist <= 40.f) +// spellId = SPELL_WEB_WRAP_400; +// //triggerNPC->CastCustomSpell(SPELL_WEB_WRAP_200, SPELLVALUE_AURA_DURATION, 1000, target, true); +// //triggerNPC->CastSpell(target, spellId, true); +// triggerNPC->CastSpell(target, spellId, true); // 4 seconds +// +// +// //triggerNPC->AI()->SetGUID(target->GetGUID()); +// +// //target->RemoveAura(RAID_MODE(SPELL_WEB_SPRAY_10, SPELL_WEB_SPRAY_25)); +// //uint8 pos = urand(0, 2); +// //if (Creature* wrap = me->SummonCreature(NPC_WEB_WRAP, PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) +// //{ +// // wrap->AI()->SetGUID(target->GetGUID()); +// // target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20); +// //} +// +// +// } +// +// } +// } +// +// } +// +// void Register() override +// { +// OnEffectHitTarget += SpellEffectFn(spell_web_wrap_maexxna_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +// } +// }; +// +// SpellScript* GetSpellScript() const override +// { +// return new spell_web_wrap_maexxna_SpellScript(); +// } +//}; +// +// +// class spell_web_wrap_damage : public SpellScriptLoader +// { +// public: + // spell_web_wrap_damage() : SpellScriptLoader("spell_web_wrap_damage") { } +// + // class spell_web_wrap_damage_AuraScript : public AuraScript + // { + // PrepareAuraScript(spell_web_wrap_damage_AuraScript); +// + // void OnPeriodic(AuraEffect const* aurEff) + // { + // if (aurEff->GetTickNumber() == 2) + // { + // GetTarget()->CastSpell(GetTarget(), SPELL_WEB_WRAP_SUMMON, true); + // } +// + // } +// + // void Register() override + // { + // OnEffectPeriodic += AuraEffectPeriodicFn(spell_web_wrap_damage_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE); + // } + // }; +// + // AuraScript* GetAuraScript() const override + // { + // return new spell_web_wrap_damage_AuraScript(); + // } +// }; void AddSC_boss_maexxna() { new boss_maexxna(); new boss_maexxna_webwrap(); - new boss_maexxna_webwrap_trigger(); - new spell_web_wrap_damage(); + //new boss_maexxna_webwrap_trigger(); + //new spell_web_wrap_damage(); + //new spell_web_wrap_maexxna(); };