fix(Scripts/Midsummer): Implement Ribbon Pole dance effects (#17417)

* fix(Scripts/Midsummer): Implement Ribbon Pole dance effects

* midsummer.cpp: remove whitespaces at end of lines

* midsummer.cpp: fix unused parameter error

* add spacing after 0.0f

* replace Milliseconds(...) by ...ms and Seconds(...) by ...s

* cleanup comments

* remove manual cleanups / despawns from DoCleanupChecks()

- rely on NPC despawn timers
- manual cleanup / removal actually is a bit excessive

* set INTERVAL_DANCING_FLAMES to 15s

* set despawn time to 1min for big dancing flames according to spell 46827

* set spawnDist to 12 for big dancing flames according so spell 46827

* use library function Acore::Containers::RandomShuffle() to shuffle _danclerList

* sql: do not set SmartAI for NPC 17066

already using ScriptName and can't have both

* combine 3 sql files into 1

* remove INTERVAL_... enum values

* remove unnecessary checks of if(_bunny)

* sql: fix smartscript comment

* rename spell define to correct spell name
This commit is contained in:
Ludwig
2023-10-18 14:22:26 +02:00
committed by GitHub
parent 54ab8dafc2
commit 630b90a633
2 changed files with 279 additions and 1 deletions

View File

@@ -0,0 +1,14 @@
-- midsummer creatureAI npc_midsummer_ribbon_pole_target
UPDATE `creature_template` SET `ScriptName` = 'npc_midsummer_ribbon_pole_target' WHERE `entry` = 17066;
-- midsummer NPC Big Dancing Flame - SmartAI - fire dance spell
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 26267;
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 26267);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(26267, 0, 0, 0, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 45418, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Big Dancing Flames - On Just Summoned - Cast Spell \'Fire Dancing\'');
-- midsummer add spell script spell_midsummer_ribbon_pole_firework
DELETE FROM `spell_script_names` WHERE `spell_id` = 46847;
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(46847, 'spell_midsummer_ribbon_pole_firework');

View File

@@ -23,6 +23,7 @@
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellScript.h"
#include <random>
enum eBonfire
{
@@ -210,15 +211,276 @@ class spell_gen_crab_disguise : public AuraScript
enum RibbonPole
{
GO_RIBBON_POLE = 181605,
SPELL_RIBBON_POLE_CHANNEL_VISUAL = 29172,
SPELL_RIBBON_POLE_CHANNEL_VISUAL_2 = 29531,
SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE = 29705,
SPELL_TEST_RIBBON_POLE_CHANNEL_RED = 29726,
SPELL_TEST_RIBBON_POLE_CHANNEL_PINK = 29727,
// player spinning/rorating around himself
SPELL_RIBBON_POLE_PERIODIC_VISUAL = 45406,
// spew lava trails
SPELL_RIBBON_POLE_FIRE_SPIRAL_VISUAL= 45421,
// blue fire ring, duration 5s
SPELL_FLAME_RING = 46842,
// red fire ring, duration 5s
SPELL_FLAME_PATCH = 46836,
// single firework explosion
SPELL_RIBBON_POLE_FIREWORK = 46847,
SPELL_RIBBON_POLE_GROUND_FLOWER = 46969,
SPELL_RIBBON_POLE_XP = 29175,
SPELL_RIBBON_POLE_FIREWORKS = 46971,
NPC_RIBBON_POLE_DEBUG_TARGET = 17066,
NPC_GROUND_FLOWER = 25518,
NPC_BIG_DANCING_FLAMES = 26267,
NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY = 25303,
// dancing players count
THRESHOLD_FLAME_CIRCLE = 1,
THRESHOLD_FIREWORK = 2,
THRESHOLD_FIREWORK_3 = 3,
THRESHOLD_FIREWORK_5 = 5,
THRESHOLD_GROUND_FLOWERS = 3,
THRESHOLD_SPEW_LAVA = 6,
THRESHOLD_DANCING_FLAMES = 7,
MAX_COUNT_GROUND_FLOWERS = 3,
MAX_COUNT_SPEW_LAVA_TARGETS = 2,
MAX_COUNT_DANCING_FLAMES = 4,
};
struct npc_midsummer_ribbon_pole_target : public ScriptedAI
{
npc_midsummer_ribbon_pole_target(Creature* creature) : ScriptedAI(creature)
{
// ribbonPole trap also spawns this NPC (currently unwanted)
if (me->ToTempSummon())
me->DespawnOrUnsummon();
_ribbonPole = nullptr;
_bunny = nullptr;
_dancerList.clear();
LocateRibbonPole();
SpawnFireSpiralBunny();
_scheduler.Schedule(1s, [this](TaskContext context)
{
DoCleanupChecks();
context.Repeat();
})
.Schedule(5s, [this](TaskContext context)
{
DoFlameCircleChecks();
context.Repeat();
})
.Schedule(15s, [this](TaskContext context)
{
DoFireworkChecks();
context.Repeat();
})
.Schedule(10s, [this](TaskContext context)
{
DoGroundFlowerChecks();
context.Repeat();
})
.Schedule(10s, [this](TaskContext context)
{
DoSpewLavaChecks();
context.Repeat();
})
.Schedule(15s, [this](TaskContext context)
{
DoDancingFLameChecks();
context.Repeat();
});
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
Player* dancer = caster->ToPlayer();
if (!dancer)
return;
switch (spell->Id)
{
case SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE:
case SPELL_TEST_RIBBON_POLE_CHANNEL_RED:
case SPELL_TEST_RIBBON_POLE_CHANNEL_PINK:
break;
default:
return;
}
// prevent duplicates
if (std::find(_dancerList.begin(), _dancerList.end(), dancer) != _dancerList.end())
return;
_dancerList.push_back(dancer);
}
void LocateRibbonPole()
{
_scheduler.Schedule(420ms, [this](TaskContext context)
{
_ribbonPole = me->FindNearestGameObject(GO_RIBBON_POLE, 10.0f);
if (!_ribbonPole)
context.Repeat(420ms);
});
}
void SpawnFireSpiralBunny()
{
_bunny = me->FindNearestCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, 10.0f);
if (!_bunny)
_bunny = DoSpawnCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, 0, 0, 0, 0, TEMPSUMMON_MANUAL_DESPAWN, 0);
}
void DoCleanupChecks()
{
if (_dancerList.empty())
return;
// remove non-dancing players from list
std::erase_if(_dancerList, [](Player* dancer)
{
return !dancer->HasAura(SPELL_RIBBON_POLE_PERIODIC_VISUAL);
});
}
void DoFlameCircleChecks()
{
if (!_ribbonPole)
return;
if (_dancerList.size() >= THRESHOLD_FLAME_CIRCLE)
{
// random blue / red circle
if (urand(0, 1))
_ribbonPole->CastSpell(me, SPELL_FLAME_RING);
else
_ribbonPole->CastSpell(me, SPELL_FLAME_PATCH);
}
}
void DoFireworkChecks()
{
if (!_bunny)
return;
if (_dancerList.size() >= THRESHOLD_FIREWORK)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
}
if (_dancerList.size() >= THRESHOLD_FIREWORK_3)
{
_scheduler.Schedule(500ms, [this](TaskContext /*context*/)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
})
.Schedule(1s, [this](TaskContext /*context*/)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
});
}
if (_dancerList.size() >= THRESHOLD_FIREWORK_5)
{
_scheduler.Schedule(1500ms, [this](TaskContext /*context*/)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
})
.Schedule(2s, [this](TaskContext /*context*/)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
});
}
}
void DoGroundFlowerChecks()
{
if (!_bunny)
return;
if (_dancerList.size() >= THRESHOLD_GROUND_FLOWERS)
{
std::list<Creature*> crList;
me->GetCreaturesWithEntryInRange(crList, 20.0f, NPC_GROUND_FLOWER);
if (crList.size() < MAX_COUNT_GROUND_FLOWERS)
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_GROUND_FLOWER);
}
}
void DoSpewLavaChecks()
{
if (!_bunny)
return;
if (_dancerList.size() >= THRESHOLD_SPEW_LAVA)
{
if (!_dancerList.empty())
{
Acore::Containers::RandomShuffle(_dancerList);
for (uint8 i = 0; (i < MAX_COUNT_SPEW_LAVA_TARGETS) && (i < _dancerList.size()); i++)
{
Player* dancerTarget = _dancerList[i];
if (dancerTarget)
{
Creature* fireSpiralBunny = dancerTarget->SummonCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, dancerTarget->GetPositionX(), dancerTarget->GetPositionY(), dancerTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
if (fireSpiralBunny)
fireSpiralBunny->CastSpell(_bunny, SPELL_RIBBON_POLE_FIRE_SPIRAL_VISUAL, true);
}
}
}
}
}
void DoDancingFLameChecks()
{
if (_dancerList.size() >= THRESHOLD_DANCING_FLAMES)
{
std::list<Creature*> crList;
me->GetCreaturesWithEntryInRange(crList, 20.0f, NPC_BIG_DANCING_FLAMES);
if (crList.size() < MAX_COUNT_DANCING_FLAMES)
{
float spawnDist = 12.0f;
float angle = rand_norm() * 2 * M_PI;
DoSpawnCreature(NPC_BIG_DANCING_FLAMES, spawnDist * cos(angle), spawnDist * std::sin(angle), 0, angle + M_PI, TEMPSUMMON_TIMED_DESPAWN, 60000);
}
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
std::vector<Player*> _dancerList;
GameObject* _ribbonPole;
Creature* _bunny;
};
class spell_midsummer_ribbon_pole_firework : public SpellScript
{
PrepareSpellScript(spell_midsummer_ribbon_pole_firework)
void ModDestHeight(SpellDestination& dest)
{
Position const offset = { 0.0f, 0.0f, 20.0f , 0.0f };
dest.RelocateOffset(offset);
}
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_midsummer_ribbon_pole_firework::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_RANDOM);
}
};
class spell_midsummer_ribbon_pole : public AuraScript
@@ -617,9 +879,11 @@ void AddSC_event_midsummer_scripts()
// NPCs
new go_midsummer_bonfire();
RegisterCreatureAI(npc_midsummer_torch_target);
RegisterCreatureAI(npc_midsummer_ribbon_pole_target);
// Spells
RegisterSpellScript(spell_gen_crab_disguise);
RegisterSpellScript(spell_midsummer_ribbon_pole_firework);
RegisterSpellScript(spell_midsummer_ribbon_pole);
RegisterSpellScript(spell_midsummer_ribbon_pole_visual);
RegisterSpellScript(spell_midsummer_torch_quest);