fix(Scripts/ZulGurub): Renataki - improvements: (#11967)
Added missing spells and events. Removed invalid spells Corrected event timers Fixes #11620 Fixes #11621
This commit is contained in:
@@ -196,6 +196,7 @@ public:
|
|||||||
virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; }
|
virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; }
|
||||||
|
|
||||||
virtual bool CanBeSeen(Player const* /*seer*/) { return true; }
|
virtual bool CanBeSeen(Player const* /*seer*/) { return true; }
|
||||||
|
virtual bool CanAlwaysBeDetectable(WorldObject const* /*seer*/) { return false; }
|
||||||
|
|
||||||
virtual void PetStopAttack() { }
|
virtual void PetStopAttack() { }
|
||||||
|
|
||||||
|
|||||||
@@ -1809,6 +1809,21 @@ bool Creature::CanAlwaysSee(WorldObject const* obj) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Creature::IsAlwaysDetectableFor(WorldObject const* seer) const
|
||||||
|
{
|
||||||
|
if (Unit::IsAlwaysDetectableFor(seer))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsAIEnabled && AI()->CanAlwaysBeDetectable(seer))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Creature::CanStartAttack(Unit const* who) const
|
bool Creature::CanStartAttack(Unit const* who) const
|
||||||
{
|
{
|
||||||
if (IsCivilian())
|
if (IsCivilian())
|
||||||
|
|||||||
@@ -444,6 +444,7 @@ protected:
|
|||||||
|
|
||||||
[[nodiscard]] bool IsInvisibleDueToDespawn() const override;
|
[[nodiscard]] bool IsInvisibleDueToDespawn() const override;
|
||||||
bool CanAlwaysSee(WorldObject const* obj) const override;
|
bool CanAlwaysSee(WorldObject const* obj) const override;
|
||||||
|
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ForcedDespawn(uint32 timeMSToDespawn = 0, Seconds forcedRespawnTimer = 0s);
|
void ForcedDespawn(uint32 timeMSToDespawn = 0, Seconds forcedRespawnTimer = 0s);
|
||||||
|
|||||||
@@ -28,13 +28,20 @@ EndScriptData */
|
|||||||
|
|
||||||
enum Spells
|
enum Spells
|
||||||
{
|
{
|
||||||
SPELL_AMBUSH = 34794,
|
SPELL_VANISH = 24699,
|
||||||
SPELL_THOUSANDBLADES = 34799
|
SPELL_AMBUSH = 24337,
|
||||||
|
SPELL_GOUGE = 24698,
|
||||||
|
SPELL_THOUSAND_BLADES = 24649,
|
||||||
|
SPELL_THRASH = 3417,
|
||||||
|
SPELL_ENRAGE = 8269
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Misc
|
enum Events
|
||||||
{
|
{
|
||||||
EQUIP_ID_MAIN_HAND = 0 //was item display id 31818, but this id does not exist
|
EVENT_VANISH = 1,
|
||||||
|
EVENT_AMBUSH = 2,
|
||||||
|
EVENT_GOUGE = 3,
|
||||||
|
EVENT_THOUSAND_BLADES = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
class boss_renataki : public CreatureScript
|
class boss_renataki : public CreatureScript
|
||||||
@@ -46,36 +53,67 @@ public:
|
|||||||
{
|
{
|
||||||
boss_renatakiAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { }
|
boss_renatakiAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { }
|
||||||
|
|
||||||
uint32 Invisible_Timer;
|
|
||||||
uint32 Ambush_Timer;
|
|
||||||
uint32 Visible_Timer;
|
|
||||||
uint32 Aggro_Timer;
|
|
||||||
uint32 ThousandBlades_Timer;
|
|
||||||
|
|
||||||
bool Invisible;
|
|
||||||
bool Ambushed;
|
|
||||||
|
|
||||||
void Reset() override
|
void Reset() override
|
||||||
{
|
{
|
||||||
_Reset();
|
_Reset();
|
||||||
Invisible_Timer = urand(8000, 18000);
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
Ambush_Timer = 3000;
|
_enraged = false;
|
||||||
Visible_Timer = 4000;
|
_thousandBladesCount = urand(2, 5);
|
||||||
Aggro_Timer = urand(15000, 25000);
|
_thousandBladesTargets.clear();
|
||||||
ThousandBlades_Timer = urand(4000, 8000);
|
_dynamicFlags = me->GetDynamicFlags();
|
||||||
|
|
||||||
Invisible = false;
|
|
||||||
Ambushed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JustDied(Unit* /*killer*/) override
|
|
||||||
{
|
|
||||||
_JustDied();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnterCombat(Unit* /*who*/) override
|
void EnterCombat(Unit* /*who*/) override
|
||||||
{
|
{
|
||||||
_EnterCombat();
|
_EnterCombat();
|
||||||
|
events.ScheduleEvent(EVENT_VANISH, 23s, 25s);
|
||||||
|
events.ScheduleEvent(EVENT_GOUGE, 5s, 10s);
|
||||||
|
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 15s, 20s);
|
||||||
|
|
||||||
|
DoCastSelf(SPELL_THRASH, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||||
|
{
|
||||||
|
if (!_enraged && HealthBelowPct(30))
|
||||||
|
{
|
||||||
|
me->TextEmote("%s becomes enraged", me, false);
|
||||||
|
DoCast(me, SPELL_ENRAGE);
|
||||||
|
_enraged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanAIAttack(Unit const* target) const override
|
||||||
|
{
|
||||||
|
if (me->GetThreatMgr().getThreatList().size() > 1 && me->GetThreatMgr().getOnlineContainer().getMostHated()->getTarget() == target)
|
||||||
|
return !target->HasAura(SPELL_GOUGE);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanBeSeen(Player const* /*player*/) override
|
||||||
|
{
|
||||||
|
return me->GetReactState() == REACT_AGGRESSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanSeeAlways(WorldObject const* obj) override
|
||||||
|
{
|
||||||
|
if (me->GetReactState() == REACT_PASSIVE)
|
||||||
|
{
|
||||||
|
return obj->ToCreature() && obj->ToCreature()->IsPet();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanAlwaysBeDetectable(WorldObject const* seer) override
|
||||||
|
{
|
||||||
|
if (me->GetReactState() == REACT_PASSIVE)
|
||||||
|
{
|
||||||
|
return seer->ToCreature() && seer->ToCreature()->IsPet();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateAI(uint32 diff) override
|
void UpdateAI(uint32 diff) override
|
||||||
@@ -83,86 +121,122 @@ public:
|
|||||||
if (!UpdateVictim())
|
if (!UpdateVictim())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Invisible_Timer
|
events.Update(diff);
|
||||||
if (Invisible_Timer <= diff)
|
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (uint32 eventId = events.ExecuteEvent())
|
||||||
{
|
{
|
||||||
me->InterruptSpell(CURRENT_GENERIC_SPELL);
|
switch (eventId)
|
||||||
|
|
||||||
SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE);
|
|
||||||
me->SetDisplayId(11686);
|
|
||||||
|
|
||||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
|
||||||
Invisible = true;
|
|
||||||
|
|
||||||
Invisible_Timer = urand(15000, 30000);
|
|
||||||
}
|
|
||||||
else Invisible_Timer -= diff;
|
|
||||||
|
|
||||||
if (Invisible)
|
|
||||||
{
|
{
|
||||||
if (Ambush_Timer <= diff)
|
case EVENT_VANISH:
|
||||||
{
|
me->SetReactState(REACT_PASSIVE);
|
||||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
|
_dynamicFlags = me->GetDynamicFlags();
|
||||||
if (target)
|
me->RemoveDynamicFlag(UNIT_DYNFLAG_TRACK_UNIT);
|
||||||
|
DoCastSelf(SPELL_VANISH);
|
||||||
|
events.DelayEvents(5s);
|
||||||
|
events.ScheduleEvent(EVENT_AMBUSH, 5s);
|
||||||
|
events.ScheduleEvent(EVENT_VANISH, 38s, 45s);
|
||||||
|
return;
|
||||||
|
case EVENT_AMBUSH:
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
|
||||||
{
|
{
|
||||||
me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation());
|
me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation());
|
||||||
DoCast(target, SPELL_AMBUSH);
|
DoCast(target, SPELL_AMBUSH, true);
|
||||||
}
|
}
|
||||||
|
me->SetDynamicFlag(_dynamicFlags);
|
||||||
Ambushed = true;
|
me->RemoveAurasDueToSpell(SPELL_VANISH);
|
||||||
Ambush_Timer = 3000;
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
}
|
break;
|
||||||
else Ambush_Timer -= diff;
|
case EVENT_GOUGE:
|
||||||
}
|
DoCastAOE(SPELL_GOUGE);
|
||||||
|
events.ScheduleEvent(EVENT_GOUGE, 10s, 15s);
|
||||||
if (Ambushed)
|
return;
|
||||||
|
case EVENT_THOUSAND_BLADES:
|
||||||
{
|
{
|
||||||
if (Visible_Timer <= diff)
|
if (_thousandBladesTargets.empty())
|
||||||
{
|
{
|
||||||
me->InterruptSpell(CURRENT_GENERIC_SPELL);
|
std::vector<Unit*> targetList;
|
||||||
|
ThreatContainer::StorageType const& threatlist = me->GetThreatMgr().getThreatList();
|
||||||
me->SetDisplayId(15268);
|
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
|
||||||
SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE);
|
|
||||||
|
|
||||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
|
||||||
Invisible = false;
|
|
||||||
|
|
||||||
Visible_Timer = 4000;
|
|
||||||
}
|
|
||||||
else Visible_Timer -= diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Resetting some aggro so he attacks other gamers
|
|
||||||
if (!Invisible)
|
|
||||||
{
|
{
|
||||||
if (Aggro_Timer <= diff)
|
if (Unit* target = (*itr)->getTarget())
|
||||||
{
|
{
|
||||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
|
if (target->IsAlive() && target->IsWithinDist2d(me, 100.f))
|
||||||
|
|
||||||
if (DoGetThreat(me->GetVictim()))
|
|
||||||
{
|
{
|
||||||
DoModifyThreatPercent(me->GetVictim(), -50);
|
targetList.push_back(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target)
|
if (!targetList.empty())
|
||||||
{
|
{
|
||||||
AttackStart(target);
|
Acore::Containers::RandomShuffle(targetList);
|
||||||
}
|
|
||||||
|
|
||||||
Aggro_Timer = urand(7000, 20000);
|
// First get ranged targets
|
||||||
}
|
for (Unit* target : targetList)
|
||||||
else Aggro_Timer -= diff;
|
|
||||||
|
|
||||||
if (ThousandBlades_Timer <= diff)
|
|
||||||
{
|
{
|
||||||
DoCastVictim(SPELL_THOUSANDBLADES);
|
if (!target->IsWithinMeleeRange(me))
|
||||||
ThousandBlades_Timer = urand(7000, 12000);
|
{
|
||||||
|
_thousandBladesTargets.push_back(target);
|
||||||
}
|
}
|
||||||
else ThousandBlades_Timer -= diff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_thousandBladesTargets.size() < _thousandBladesCount)
|
||||||
|
{
|
||||||
|
// if still not enough, get melee targets
|
||||||
|
for (Unit* target : targetList)
|
||||||
|
{
|
||||||
|
if (target->IsWithinMeleeRange(me))
|
||||||
|
{
|
||||||
|
_thousandBladesTargets.push_back(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_thousandBladesTargets.empty())
|
||||||
|
{
|
||||||
|
Acore::Containers::RandomResize(_thousandBladesTargets, _thousandBladesCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_thousandBladesTargets.empty())
|
||||||
|
{
|
||||||
|
std::vector<Unit*>::iterator itr = _thousandBladesTargets.begin();
|
||||||
|
std::advance(itr, urand(0, _thousandBladesTargets.size() - 1));
|
||||||
|
|
||||||
|
if (Unit* target = *itr)
|
||||||
|
{
|
||||||
|
DoCast(target, SPELL_THOUSAND_BLADES, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_thousandBladesTargets.erase(itr);
|
||||||
|
|
||||||
|
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 500ms);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_thousandBladesCount = urand(2, 5);
|
||||||
|
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 15s, 22s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me->GetReactState() == REACT_AGGRESSIVE)
|
||||||
DoMeleeAttackIfReady();
|
DoMeleeAttackIfReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _enraged;
|
||||||
|
uint32 _dynamicFlags;
|
||||||
|
uint8 _thousandBladesCount;
|
||||||
|
std::vector<Unit*> _thousandBladesTargets;
|
||||||
};
|
};
|
||||||
|
|
||||||
CreatureAI* GetAI(Creature* creature) const override
|
CreatureAI* GetAI(Creature* creature) const override
|
||||||
|
|||||||
Reference in New Issue
Block a user