fix(Scripts/Karazhan): Fix Julliane awarding no loot (#17334)

* fix(Scripts/Karazhan): Fix Julliene awarding no loot

* Update bosses_opera.cpp
This commit is contained in:
Skjalf
2023-09-25 06:38:01 -03:00
committed by GitHub
parent ebe887c5ba
commit 84d4d60cfc
4 changed files with 107 additions and 199 deletions

View File

@@ -366,6 +366,7 @@ public:
// Handling caster facing during spellcast // Handling caster facing during spellcast
void SetTarget(ObjectGuid guid = ObjectGuid::Empty) override; void SetTarget(ObjectGuid guid = ObjectGuid::Empty) override;
void ClearTarget() { SetTarget(); };
void FocusTarget(Spell const* focusSpell, WorldObject const* target); void FocusTarget(Spell const* focusSpell, WorldObject const* target);
void ReleaseFocus(Spell const* focusSpell); void ReleaseFocus(Spell const* focusSpell);
[[nodiscard]] bool IsMovementPreventedByCasting() const override; [[nodiscard]] bool IsMovementPreventedByCasting() const override;

View File

@@ -947,7 +947,7 @@ enum JulianneRomulo
SAY_ROMULO_AGGRO = 0, SAY_ROMULO_AGGRO = 0,
SAY_ROMULO_DEATH = 1, SAY_ROMULO_DEATH = 1,
SAY_ROMULO_ENTER = 2, SAY_ROMULO_DEATH2 = 2,
SAY_ROMULO_RESURRECT = 3, SAY_ROMULO_RESURRECT = 3,
SAY_ROMULO_SLAY = 4, SAY_ROMULO_SLAY = 4,
@@ -985,12 +985,10 @@ enum RAJGroups
enum RAJActions enum RAJActions
{ {
ACTION_DIED_ANNOUNCE = 0,
ACTION_PHASE_SET = 1,
ACTION_FAKING_DEATH = 2, ACTION_FAKING_DEATH = 2,
ACTION_COMBAT_SCHEDULE = 3, ACTION_COMBAT_SCHEDULE = 3,
ACTION_DO_RESURRECT = 4, //ACTION_DO_RESURRECT = 4,
ACTION_EARLY_REVIVE = 5, //ACTION_RESS_ROMULO = 5,
ACTION_CANCEL_COMBAT = 6 ACTION_CANCEL_COMBAT = 6
}; };
@@ -999,7 +997,6 @@ void PretendToDie(Creature* creature)
creature->AI()->DoAction(ACTION_CANCEL_COMBAT); creature->AI()->DoAction(ACTION_CANCEL_COMBAT);
creature->InterruptNonMeleeSpells(true); creature->InterruptNonMeleeSpells(true);
creature->RemoveAllAuras(); creature->RemoveAllAuras();
creature->SetHealth(0);
creature->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); creature->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
creature->SetReactState(REACT_PASSIVE); creature->SetReactState(REACT_PASSIVE);
creature->GetMotionMaster()->MovementExpired(false); creature->GetMotionMaster()->MovementExpired(false);
@@ -1032,14 +1029,6 @@ struct boss_julianne : public ScriptedAI
isFakingDeath = false; isFakingDeath = false;
} }
InstanceScript* instance;
uint32 phase;
bool isFakingDeath;
bool summonedRomulo;
bool romuloDied;
void Reset() override void Reset() override
{ {
phase = PHASE_JULIANNE; phase = PHASE_JULIANNE;
@@ -1051,10 +1040,8 @@ struct boss_julianne : public ScriptedAI
} }
summonedRomulo = false; summonedRomulo = false;
romuloDied = false;
me->SetImmuneToPC(true); me->SetImmuneToPC(true);
//intro sequence
_scheduler.Schedule(1s, [this](TaskContext) _scheduler.Schedule(1s, [this](TaskContext)
{ {
Talk(SAY_JULIANNE_ENTER); Talk(SAY_JULIANNE_ENTER);
@@ -1071,38 +1058,29 @@ struct boss_julianne : public ScriptedAI
{ {
switch(action) switch(action)
{ {
case ACTION_DIED_ANNOUNCE:
romuloDied = true;
break;
case ACTION_EARLY_REVIVE:
romuloDied = true;
_resurrectScheduler.Schedule(10s, [this](TaskContext)
{
Talk(SAY_JULIANNE_RESURRECT);
romuloDied = false;
});
break;
case ACTION_PHASE_SET:
phase = PHASE_BOTH;
isFakingDeath = false;
break;
case ACTION_FAKING_DEATH: case ACTION_FAKING_DEATH:
isFakingDeath = false; isFakingDeath = false;
break; break;
case ACTION_COMBAT_SCHEDULE: case ACTION_COMBAT_SCHEDULE:
ScheduleCombat(); ScheduleCombat();
break; break;
case ACTION_DO_RESURRECT: case ACTION_RESS_ROMULO:
_resurrectScheduler.Schedule(1s, [this](TaskContext) me->m_Events.AddEventAtOffset([this]
{ {
if (Creature* Romulo = instance->GetCreature(DATA_ROMULO)) if (Creature* romulo = instance->GetCreature(DATA_ROMULO))
{ {
Talk(SAY_JULIANNE_RESURRECT); Talk(SAY_JULIANNE_RESURRECT);
Resurrect(Romulo); Resurrect(romulo);
Romulo->AI()->DoAction(ACTION_FAKING_DEATH); romulo->AI()->DoAction(ACTION_FAKING_DEATH);
romuloDied = false; romulo->AI()->Talk(SAY_ROMULO_RESURRECT);
} }
}); }, 1s);
break;
case ACTION_DO_RESURRECT:
phase = PHASE_BOTH;
isFakingDeath = false;
Resurrect(me);
me->ResumeChasingVictim();
break; break;
case ACTION_CANCEL_COMBAT: case ACTION_CANCEL_COMBAT:
_scheduler.CancelGroup(GROUP_COMBAT); _scheduler.CancelGroup(GROUP_COMBAT);
@@ -1128,11 +1106,11 @@ struct boss_julianne : public ScriptedAI
{ {
if (urand(0, 1) && summonedRomulo) if (urand(0, 1) && summonedRomulo)
{ {
if (Creature* Romulo = instance->GetCreature(DATA_ROMULO)) if (Creature* romulo = instance->GetCreature(DATA_ROMULO))
{ {
if (Romulo->IsAlive() && !romuloDied) if (!romulo->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
{ {
DoCast(Romulo, SPELL_ETERNAL_AFFECTION); DoCast(romulo, SPELL_ETERNAL_AFFECTION);
} }
} }
} }
@@ -1149,22 +1127,6 @@ struct boss_julianne : public ScriptedAI
ScheduleCombat(); ScheduleCombat();
} }
void AttackStart(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::AttackStart(who);
}
void MoveInLineOfSight(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::MoveInLineOfSight(who);
}
void JustReachedHome() override void JustReachedHome() override
{ {
me->DespawnOrUnsummon(); me->DespawnOrUnsummon();
@@ -1183,10 +1145,9 @@ struct boss_julianne : public ScriptedAI
phase = PHASE_ROMULO; phase = PHASE_ROMULO;
_scheduler.Schedule(10s, GROUP_RP, [this](TaskContext) _scheduler.Schedule(10s, GROUP_RP, [this](TaskContext)
{ {
if (Creature* pRomulo = me->SummonCreature(CREATURE_ROMULO, ROMULO_X, ROMULO_Y, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR * 2 * IN_MILLISECONDS)) if (Creature* romulo = me->SummonCreature(CREATURE_ROMULO, ROMULO_X, ROMULO_Y, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR * 2 * IN_MILLISECONDS))
{ {
pRomulo->AI()->DoAction(ACTION_PHASE_SET); romulo->SetInCombatWithZone();
pRomulo->SetInCombatWithZone();
} }
summonedRomulo = true; summonedRomulo = true;
}); });
@@ -1201,13 +1162,12 @@ struct boss_julianne : public ScriptedAI
return; return;
} }
//anything below only used if incoming damage will kill damage = me->GetHealth() - 1;
if (phase == PHASE_JULIANNE) if (phase == PHASE_JULIANNE)
{ {
damage = 0; me->ClearTarget();
//this means already drinking, so return
if (isFakingDeath) if (isFakingDeath)
{ {
return; return;
@@ -1222,50 +1182,12 @@ struct boss_julianne : public ScriptedAI
return; return;
} }
if (phase == PHASE_ROMULO) if (phase == PHASE_BOTH && !isFakingDeath)
{ {
//LOG_ERROR("scripts", "boss_julianneAI: cannot take damage in PHASE_ROMULO, why was i here?"); PretendToDie(me);
damage = 0; isFakingDeath = true;
return; instance->DoAction(ACTION_SCHEDULE_RAJ_CHECK);
} }
if (phase == PHASE_BOTH)
{
//if this is true then we have to kill romulo too
if (romuloDied)
{
if (Creature* Romulo = instance->GetCreature(DATA_ROMULO))
{
_scheduler.CancelAll();
_resurrectScheduler.CancelAll();
Romulo->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
Romulo->GetMotionMaster()->Clear();
Romulo->setDeathState(JUST_DIED);
Romulo->CombatStop(true);
Romulo->GetThreatMgr().ClearAllThreat();
Romulo->ReplaceAllDynamicFlags(UNIT_DYNFLAG_LOOTABLE);
//this does not seem to really work - the lootable dynamic flags
}
return;
}
//if not already returned, then romulo is alive and we can pretend die
if (Creature* Romulo = instance->GetCreature(DATA_ROMULO))
{
PretendToDie(me);
isFakingDeath = true;
Romulo->AI()->DoAction(ACTION_EARLY_REVIVE);
_scheduler.Schedule(10050ms, [this](TaskContext)
{
Resurrect(me);
isFakingDeath = false;
});
damage = 0;
return;
}
}
//LOG_ERROR("scripts", "boss_julianneAI: DamageTaken reach end of code, that should not happen.");
} }
void EnterEvadeMode(EvadeReason reason) override void EnterEvadeMode(EvadeReason reason) override
@@ -1286,15 +1208,17 @@ struct boss_julianne : public ScriptedAI
instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE);
} }
void KilledUnit(Unit* /*victim*/) override void KilledUnit(Unit* victim) override
{ {
Talk(SAY_JULIANNE_SLAY); if (victim != me)
{
Talk(SAY_JULIANNE_SLAY);
}
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
_scheduler.Update(diff); _scheduler.Update(diff);
_resurrectScheduler.Update(diff);
if (!UpdateVictim()) if (!UpdateVictim())
{ {
@@ -1307,50 +1231,30 @@ struct boss_julianne : public ScriptedAI
} }
} }
private: private:
InstanceScript* instance;
uint32 phase;
bool isFakingDeath;
bool summonedRomulo;
TaskScheduler _scheduler; TaskScheduler _scheduler;
TaskScheduler _resurrectScheduler;
}; };
struct boss_romulo : public ScriptedAI struct boss_romulo : public ScriptedAI
{ {
boss_romulo(Creature* creature) : ScriptedAI(creature) boss_romulo(Creature* creature) : ScriptedAI(creature)
{ {
instance = creature->GetInstanceScript(); //not necessary instance = creature->GetInstanceScript();
} }
InstanceScript* instance;
uint32 phase;
bool isFakingDeath;
bool julianneDead;
void Reset() override void Reset() override
{ {
phase = PHASE_ROMULO; phase = PHASE_ROMULO;
isFakingDeath = false; isFakingDeath = false;
julianneDead = false;
} }
void DoAction(int32 action) override void DoAction(int32 action) override
{ {
switch(action) switch(action)
{ {
case ACTION_DIED_ANNOUNCE:
julianneDead = true;
break;
case ACTION_EARLY_REVIVE:
julianneDead = true;
_resurrectScheduler.Schedule(10s, [this](TaskContext)
{
Talk(SAY_ROMULO_RESURRECT);
julianneDead = false;
});
break;
case ACTION_PHASE_SET:
phase = PHASE_ROMULO;
break;
case ACTION_FAKING_DEATH: case ACTION_FAKING_DEATH:
isFakingDeath = false; isFakingDeath = false;
break; break;
@@ -1375,9 +1279,11 @@ struct boss_romulo : public ScriptedAI
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{ {
if (damage < me->GetHealth()) if (damage < me->GetHealth())
{
return; return;
}
//anything below only used if incoming damage will kill damage = me->GetHealth() - 1;
if (phase == PHASE_ROMULO) if (phase == PHASE_ROMULO)
{ {
@@ -1386,63 +1292,24 @@ struct boss_romulo : public ScriptedAI
isFakingDeath = true; isFakingDeath = true;
phase = PHASE_BOTH; phase = PHASE_BOTH;
if (Creature* Julianne = instance->GetCreature(DATA_JULIANNE)) me->m_Events.AddEventAtOffset([this]
{ {
Julianne->AI()->DoAction(ACTION_DIED_ANNOUNCE); Resurrect(me);
//resurrect julianne isFakingDeath = false;
_scheduler.Schedule(10s, GROUP_RP, [this](TaskContext) if (Creature* julliane = instance->GetCreature(DATA_JULIANNE))
{ {
if (Creature* Julianne = instance->GetCreature(DATA_JULIANNE)) julliane->AI()->DoAction(ACTION_DO_RESURRECT);
{
Resurrect(Julianne);
Julianne->AI()->DoAction(ACTION_PHASE_SET);
Julianne->AI()->DoAction(ACTION_DO_RESURRECT);
if (Julianne->GetVictim())
{
AttackStart(Julianne->GetVictim());
}
}
});
}
damage = 0;
return;
}
if (phase == PHASE_BOTH)
{
if (julianneDead)
{
if (Creature* Julianne = instance->GetCreature(DATA_JULIANNE))
{
_scheduler.CancelAll();
_resurrectScheduler.CancelAll();
Julianne->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
Julianne->GetMotionMaster()->Clear();
Julianne->setDeathState(JUST_DIED);
Julianne->CombatStop(true);
Julianne->GetThreatMgr().ClearAllThreat();
Julianne->ReplaceAllDynamicFlags(UNIT_DYNFLAG_LOOTABLE);
//this does not seem to really work
} }
return; }, 3s);
} }
if (Creature* Julianne = instance->GetCreature(DATA_JULIANNE)) if (phase == PHASE_BOTH && !isFakingDeath)
{ {
PretendToDie(me); Talk(SAY_ROMULO_DEATH2);
isFakingDeath = true; PretendToDie(me);
Julianne->AI()->DoAction(ACTION_EARLY_REVIVE); instance->DoAction(ACTION_SCHEDULE_RAJ_CHECK);
_scheduler.Schedule(10050ms, [this](TaskContext) isFakingDeath = true;
{
Resurrect(me);
isFakingDeath = false;
});
damage = 0;
return;
}
} }
//LOG_ERROR("scripts", "boss_romuloAI: DamageTaken reach end of code, that should not happen.");
} }
void ScheduleCombat() void ScheduleCombat()
@@ -1488,14 +1355,6 @@ struct boss_romulo : public ScriptedAI
ScheduleCombat(); ScheduleCombat();
} }
void MoveInLineOfSight(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::MoveInLineOfSight(who);
}
void EnterEvadeMode(EvadeReason reason) override void EnterEvadeMode(EvadeReason reason) override
{ {
ScriptedAI::EnterEvadeMode(reason); ScriptedAI::EnterEvadeMode(reason);
@@ -1510,15 +1369,17 @@ struct boss_romulo : public ScriptedAI
instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE);
} }
void KilledUnit(Unit* /*victim*/) override void KilledUnit(Unit* victim) override
{ {
Talk(SAY_ROMULO_SLAY); if (victim != me)
{
Talk(SAY_ROMULO_SLAY);
}
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
_scheduler.Update(diff); _scheduler.Update(diff);
_resurrectScheduler.Update(diff);
if (!UpdateVictim()) if (!UpdateVictim())
{ {
@@ -1531,8 +1392,10 @@ struct boss_romulo : public ScriptedAI
} }
} }
private: private:
InstanceScript* instance;
uint32 phase;
bool isFakingDeath;
TaskScheduler _scheduler; TaskScheduler _scheduler;
TaskScheduler _resurrectScheduler;
}; };
void AddSC_bosses_opera() void AddSC_bosses_opera()

View File

@@ -421,6 +421,42 @@ public:
return 0; return 0;
} }
void DoAction(int32 actionId) override
{
if (actionId == ACTION_SCHEDULE_RAJ_CHECK)
{
scheduler.Schedule(10s, [this](TaskContext)
{
Creature* julliane = GetCreature(DATA_JULIANNE);
Creature* romulo = GetCreature(DATA_ROMULO);
if (julliane && romulo)
{
if (julliane->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)
&& romulo->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
{
julliane->KillSelf();
julliane->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
romulo->KillSelf();
romulo->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
else
{
if (romulo->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
{
julliane->AI()->DoAction(ACTION_RESS_ROMULO);
}
if (julliane->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
{
julliane->AI()->DoAction(ACTION_DO_RESURRECT);
}
}
}
});
}
}
ObjectGuid GetGuidData(uint32 data) const override ObjectGuid GetGuidData(uint32 data) const override
{ {
switch (data) switch (data)

View File

@@ -204,6 +204,14 @@ enum KarazhanChessGameFactions
CHESS_FACTION_BOTH = 536 CHESS_FACTION_BOTH = 536
}; };
enum InstanceActions
{
ACTION_SCHEDULE_RAJ_CHECK,
ACTION_DO_RESURRECT = 4,
ACTION_RESS_ROMULO = 5,
};
template <class AI, class T> template <class AI, class T>
inline AI* GetKarazhanAI(T* obj) inline AI* GetKarazhanAI(T* obj)
{ {