mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Scripts/Botanica: Rework Warp Splinter (#27621)
(cherry picked from commit 78327500d8)
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
--
|
||||
DELETE FROM `spell_target_position` WHERE `ID` IN (34727,34730,34731,34732,34733,34734,34735,34736,34737,34739);
|
||||
INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `VerifiedBuild`) VALUES
|
||||
(34727,0,553,26,419,-25,14007),
|
||||
(34731,0,553,56,428,-25,14007),
|
||||
(34733,0,553,94,416,-27,14007),
|
||||
(34734,0,553,94,376,-27,14007),
|
||||
(34736,0,553,66,353,-26,14007),
|
||||
(34739,0,553,33,366,-25,14007);
|
||||
|
||||
UPDATE `creature_template` SET `ScriptName` = 'npc_warp_splinter_sapling' WHERE `entry` = 19949;
|
||||
|
||||
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` = 34742;
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
|
||||
(13,1,34742,0,0,31,0,3,19949,0,0,0,0,"","Group 0: Spell 'Ancestral Life' (Effect 0) targets creature 'Sapling'");
|
||||
@@ -15,237 +15,165 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Warp_Splinter
|
||||
SD%Complete: 80
|
||||
SDComment: Includes Sapling (need some better control with these).
|
||||
SDCategory: Tempest Keep, The Botanica
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "the_botanica.h"
|
||||
|
||||
enum Says
|
||||
enum Texts
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_SUMMON = 2,
|
||||
SAY_DEATH = 3
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_SUMMON = 2,
|
||||
SAY_DEATH = 3
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
WAR_STOMP = 34716,
|
||||
SUMMON_TREANTS = 34727, // DBC: 34727, 34731, 34733, 34734, 34736, 34739, 34741 (with Ancestral Life spell 34742) // won't work (guardian summon)
|
||||
ARCANE_VOLLEY = 36705,
|
||||
SPELL_HEAL_FATHER = 6262
|
||||
SPELL_STOMP = 34716,
|
||||
SPELL_ARCANE_VOLLEY = 36705,
|
||||
|
||||
SPELL_SUMMON_SAPLING_1 = 34727,
|
||||
SPELL_SUMMON_SAPLING_2 = 34731,
|
||||
SPELL_SUMMON_SAPLING_3 = 34733,
|
||||
SPELL_SUMMON_SAPLING_4 = 34734,
|
||||
SPELL_SUMMON_SAPLING_5 = 34736,
|
||||
SPELL_SUMMON_SAPLING_6 = 34739,
|
||||
SPELL_SUMMON_SAPLINGS = 34741,
|
||||
SPELL_ANCESTRAL_LIFE = 34742,
|
||||
SPELL_MOONFIRE_VISUAL = 36704
|
||||
};
|
||||
|
||||
enum Misc
|
||||
enum Events
|
||||
{
|
||||
CREATURE_TREANT = 19949,
|
||||
TREANT_SPAWN_DIST = 50 //50 yards from Warp Splinter's spawn point
|
||||
EVENT_SUMMON = 1,
|
||||
EVENT_STOMP,
|
||||
EVENT_ARCANE_VOLLEY
|
||||
};
|
||||
|
||||
float treant_pos[6][3] =
|
||||
uint32 const SummonSaplingsSpells[] =
|
||||
{
|
||||
{24.301233f, 427.221100f, -27.060635f},
|
||||
{16.795492f, 359.678802f, -27.355425f},
|
||||
{53.493484f, 345.381470f, -26.196192f},
|
||||
{61.867096f, 439.362732f, -25.921030f},
|
||||
{109.861877f, 423.201630f, -27.356019f},
|
||||
{106.780159f, 355.582581f, -27.593357f}
|
||||
SPELL_SUMMON_SAPLING_1, SPELL_SUMMON_SAPLING_2, SPELL_SUMMON_SAPLING_3,
|
||||
SPELL_SUMMON_SAPLING_4, SPELL_SUMMON_SAPLING_5, SPELL_SUMMON_SAPLING_6
|
||||
};
|
||||
|
||||
/*#####
|
||||
# npc_treant (Sapling)
|
||||
#####*/
|
||||
class npc_warp_splinter_treant : public CreatureScript
|
||||
struct boss_warp_splinter : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_warp_splinter(Creature* creature) : BossAI(creature, DATA_WARP_SPLINTER) { }
|
||||
|
||||
npc_warp_splinter_treant()
|
||||
: CreatureScript("npc_warp_splinter_treant")
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
Talk(SAY_AGGRO);
|
||||
events.ScheduleEvent(EVENT_SUMMON, 25s, 30s);
|
||||
events.ScheduleEvent(EVENT_STOMP, 10s, 15s);
|
||||
events.ScheduleEvent(EVENT_ARCANE_VOLLEY, 15s, 20s);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override
|
||||
{
|
||||
if (reason == SPELL_FINISHED_SUCCESSFUL_CAST && spell->Id == SPELL_SUMMON_SAPLINGS)
|
||||
{
|
||||
for (uint32 summonSpells : SummonSaplingsSpells)
|
||||
DoCastSelf(summonSpells, true);
|
||||
Talk(SAY_SUMMON);
|
||||
}
|
||||
struct npc_warp_splinter_treantAI : public ScriptedAI
|
||||
}
|
||||
|
||||
// Do not despawn them
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
if (me->IsEngaged())
|
||||
DoZoneInCombat(summon);
|
||||
|
||||
if (me->GetVictim())
|
||||
summon->AI()->AttackStart(me->GetVictim());
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
npc_warp_splinter_treantAI(Creature* creature) : ScriptedAI(creature)
|
||||
switch (eventId)
|
||||
{
|
||||
Initialize();
|
||||
case EVENT_SUMMON:
|
||||
// Ignore shared cooldown because otherwise both spells will be not used in too many cases
|
||||
// It looks like both spells indeed should have shared cooldown but it doesn't really blocks spell
|
||||
// cast but delays it. Maybe not in all cases. Really long sniff can tell more
|
||||
DoCastSelf(SPELL_SUMMON_SAPLINGS, TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD);
|
||||
events.Repeat(40s, 50s);
|
||||
break;
|
||||
case EVENT_STOMP:
|
||||
DoCastSelf(SPELL_STOMP, TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD);
|
||||
events.Repeat(20s, 30s);
|
||||
break;
|
||||
case EVENT_ARCANE_VOLLEY:
|
||||
DoCastSelf(SPELL_ARCANE_VOLLEY);
|
||||
events.Repeat(20s, 35s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
check_Timer = 0;
|
||||
}
|
||||
|
||||
ObjectGuid WarpGuid;
|
||||
uint32 check_Timer;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override { }
|
||||
|
||||
void MoveInLineOfSight(Unit* /*who*/) override { }
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim() || !me->GetVictim())
|
||||
{
|
||||
if (!WarpGuid.IsEmpty() && check_Timer <= diff)
|
||||
{
|
||||
if (Unit* Warp = ObjectAccessor::GetUnit(*me, WarpGuid))
|
||||
{
|
||||
if (me->IsWithinMeleeRange(Warp))
|
||||
{
|
||||
int32 CurrentHP_Treant = (int32)me->GetHealth();
|
||||
Warp->CastSpell(Warp, SPELL_HEAL_FATHER, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
|
||||
.SetOriginalCaster(me->GetGUID())
|
||||
.AddSpellBP0(CurrentHP_Treant));
|
||||
me->KillSelf();
|
||||
return;
|
||||
}
|
||||
me->GetMotionMaster()->MoveFollow(Warp, 0, 0);
|
||||
}
|
||||
check_Timer = 1000;
|
||||
}
|
||||
else
|
||||
check_Timer -= diff;
|
||||
return;
|
||||
}
|
||||
|
||||
if (me->EnsureVictim()->GetGUID() != WarpGuid)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetBotanicaAI<npc_warp_splinter_treantAI>(creature);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
/*#####
|
||||
# boss_warp_splinter
|
||||
#####*/
|
||||
class boss_warp_splinter : public CreatureScript
|
||||
struct npc_warp_splinter_sapling : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
npc_warp_splinter_sapling(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
boss_warp_splinter()
|
||||
: CreatureScript("boss_warp_splinter")
|
||||
void InitializeAI() override
|
||||
{
|
||||
me->SetCorpseDelay(2, true);
|
||||
}
|
||||
|
||||
void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
|
||||
{
|
||||
// This spell currently can miss, maybe it's fine, maybe not
|
||||
if (spellInfo->Id == SPELL_ANCESTRAL_LIFE)
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
DoCastSelf(SPELL_MOONFIRE_VISUAL);
|
||||
me->DespawnOrUnsummon(2s);
|
||||
}
|
||||
struct boss_warp_splinterAI : public BossAI
|
||||
{
|
||||
boss_warp_splinterAI(Creature* creature) : BossAI(creature, DATA_WARP_SPLINTER)
|
||||
{
|
||||
Initialize();
|
||||
Treant_Spawn_Pos_X = creature->GetPositionX();
|
||||
Treant_Spawn_Pos_Y = creature->GetPositionY();
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
War_Stomp_Timer = urand(25000, 40000);
|
||||
Summon_Treants_Timer = 45000;
|
||||
Arcane_Volley_Timer = urand(8000, 20000);
|
||||
}
|
||||
void UpdateAI(uint32 /*diff*/) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
uint32 War_Stomp_Timer;
|
||||
uint32 Summon_Treants_Timer;
|
||||
uint32 Arcane_Volley_Timer;
|
||||
|
||||
float Treant_Spawn_Pos_X;
|
||||
float Treant_Spawn_Pos_Y;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void SummonTreants()
|
||||
{
|
||||
for (uint8 i = 0; i < 6; ++i)
|
||||
{
|
||||
float angle = (float(M_PI) / 3) * i;
|
||||
|
||||
float X = Treant_Spawn_Pos_X + TREANT_SPAWN_DIST * std::cos(angle);
|
||||
float Y = Treant_Spawn_Pos_Y + TREANT_SPAWN_DIST * std::sin(angle);
|
||||
float O = - me->GetAbsoluteAngle(X, Y);
|
||||
|
||||
if (Creature* pTreant = me->SummonCreature(CREATURE_TREANT, treant_pos[i][0], treant_pos[i][1], treant_pos[i][2], O, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25s))
|
||||
ENSURE_AI(npc_warp_splinter_treant::npc_warp_splinter_treantAI, pTreant->AI())->WarpGuid = me->GetGUID();
|
||||
}
|
||||
Talk(SAY_SUMMON);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//Check for War Stomp
|
||||
if (War_Stomp_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(WAR_STOMP);
|
||||
War_Stomp_Timer = urand(25000, 40000);
|
||||
}
|
||||
else
|
||||
War_Stomp_Timer -= diff;
|
||||
|
||||
//Check for Arcane Volley
|
||||
if (Arcane_Volley_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(ARCANE_VOLLEY);
|
||||
Arcane_Volley_Timer = urand(20000, 35000);
|
||||
}
|
||||
else
|
||||
Arcane_Volley_Timer -= diff;
|
||||
|
||||
//Check for Summon Treants
|
||||
if (Summon_Treants_Timer <= diff)
|
||||
{
|
||||
SummonTreants();
|
||||
Summon_Treants_Timer = 45000;
|
||||
}
|
||||
else
|
||||
Summon_Treants_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetBotanicaAI<boss_warp_splinterAI>(creature);
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_warp_splinter()
|
||||
{
|
||||
new boss_warp_splinter();
|
||||
new npc_warp_splinter_treant();
|
||||
RegisterBotanicaCreatureAI(boss_warp_splinter);
|
||||
RegisterBotanicaCreatureAI(npc_warp_splinter_sapling);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user