Skip to content

Commit

Permalink
Fixes for Spirit of Redemption.
Browse files Browse the repository at this point in the history
Closes #889

Closes #2665
  • Loading branch information
ratkosrb committed Jun 24, 2024
1 parent f78194e commit 47b4f67
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 69 deletions.
32 changes: 32 additions & 0 deletions sql/migrations/20240623222319_world.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
DROP PROCEDURE IF EXISTS add_migration;
DELIMITER ??
CREATE PROCEDURE `add_migration`()
BEGIN
DECLARE v INT DEFAULT 1;
SET v = (SELECT COUNT(*) FROM `migrations` WHERE `id`='20240623222319');
IF v = 0 THEN
INSERT INTO `migrations` VALUES ('20240623222319');
-- Add your query below.


-- Events list for Spirit Of Redemption
DELETE FROM `creature_ai_events` WHERE `creature_id`=12904;
INSERT INTO `creature_ai_events` (`id`, `creature_id`, `condition_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_script`, `action2_script`, `action3_script`, `comment`) VALUES
(1290401, 12904, 0, 1, 0, 100, 0, 0, 0, 0, 0, 1290401, 0, 0, 'Spirit of Redemption - Cast Dummy Visuals after Spawn'),
(1290402, 12904, 0, 6, 0, 100, 0, 0, 0, 0, 0, 1290402, 0, 0, 'Spirit of Redemption - Despawn on Death');
DELETE FROM `creature_ai_scripts` WHERE `id`=1290401;
INSERT INTO `creature_ai_scripts` (`id`, `delay`, `priority`, `command`, `datalong`, `datalong2`, `datalong3`, `datalong4`, `target_param1`, `target_param2`, `target_type`, `data_flags`, `dataint`, `dataint2`, `dataint3`, `dataint4`, `x`, `y`, `z`, `o`, `condition_id`, `comments`) VALUES
(1290401, 0, 0, 15, 20723, 2, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Spirit of Redemption - Cast Dummy Visual Spell'),
(1290401, 0, 1, 15, 20721, 2, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Spirit of Redemption - Cast Dummy Animation Spell');
DELETE FROM `creature_ai_scripts` WHERE `id`=1290402;
INSERT INTO `creature_ai_scripts` (`id`, `delay`, `priority`, `command`, `datalong`, `datalong2`, `datalong3`, `datalong4`, `target_param1`, `target_param2`, `target_type`, `data_flags`, `dataint`, `dataint2`, `dataint3`, `dataint4`, `x`, `y`, `z`, `o`, `condition_id`, `comments`) VALUES
(1290402, 0, 0, 18, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Spirit of Redemption - Despawn');
UPDATE `creature_template` SET `ai_name`='EventAI' WHERE `entry`=12904;


-- End of migration.
END IF;
END??
DELIMITER ;
CALL add_migration();
DROP PROCEDURE IF EXISTS add_migration;
106 changes: 41 additions & 65 deletions src/game/Objects/Unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,8 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
if (health <= damage && pVictim->GetInvincibilityHpThreshold() == 0)
{
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage: victim just died");
Kill(pVictim, spellProto, durabilityLoss); // Function too long, we cut
Kill(pVictim, spellProto, durabilityLoss);

// last damage from non duel opponent or opponent controlled creature
if (duel_hasEnded)
{
Expand Down Expand Up @@ -1053,38 +1054,53 @@ void Unit::Kill(Unit* pVictim, SpellEntry const* spellProto, bool durabilityLoss

DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageAttackStop");

bool damageFromSpiritOfRedemtionTalent = (spellProto && spellProto->Id == 27795);
bool const damageFromSpiritOfRedemptionTalent = (spellProto && spellProto->Id == 27965);
bool const spiritOfRedemptionTalentImmune = pVictim->GetClass() == CLASS_PRIEST && !damageFromSpiritOfRedemptionTalent && pVictim->HasAura(20711);

// if talent known but not triggered (check priest class for speedup check)
bool spiritOfRedemtionTalentImmune = false;
if (pPlayerVictim && pVictim->GetClass() == CLASS_PRIEST)
// handle spirit of redemption talent
if (spiritOfRedemptionTalentImmune)
#if SUPPORTED_CLIENT_BUILD > CLIENT_BUILD_1_9_4
{
if (!damageFromSpiritOfRedemtionTalent) // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
{
AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
for (const auto& itr : vDummyAuras)
{
if (itr->GetSpellProto()->SpellIconID == 1654)
{
spiritOfRedemtionTalentImmune = true;
break;
}
}
}
pVictim->InterruptNonMeleeSpells(false);

// Already applied spirit of redemption. Fix stuck in ANGEL form.
if (!spiritOfRedemtionTalentImmune && HasAura(27827))
return;
}
// save value before aura remove
uint32 ressSpellId = 0;
#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1
ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
if (!ressSpellId)
ressSpellId = ((Player*)pVictim)->SelectResurrectionSpellId();
#else
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT))
ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId();
#endif

if (!spiritOfRedemtionTalentImmune)
pVictim->RemoveAllAurasOnDeath();

// restore for use at real death
#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1
pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId);
#else
pPlayerVictim->SetResurrectionSpellId(ressSpellId);
if (ressSpellId)
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT);
#endif

pVictim->CastCustomSpell(pVictim, 27827, pVictim->GetMaxHealth(), {}, {}, true);
}
else
#else
{
pVictim->CastSpell(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ(), 20713, true);
}
// no else
#endif
{
pVictim->SetHealth(0);
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "SET JUST_DIED");
pVictim->SetDeathState(JUST_DIED);

// World of Warcraft Client Patch 1.6.0 (2005-07-12)
// - Self-resurrection spells show their name on the button in the release spirit dialog.
// World of Warcraft Client Patch 1.6.0 (2005-07-12)
// - Self-resurrection spells show their name on the button in the release spirit dialog.
#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1
if (pPlayerVictim && pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL))
pVictim->DirectSendPublicValueUpdate(PLAYER_SELF_RES_SPELL);
Expand All @@ -1095,14 +1111,6 @@ void Unit::Kill(Unit* pVictim, SpellEntry const* spellProto, bool durabilityLoss
// Nostalrius: Instantly send values update for health
pVictim->DirectSendPublicValueUpdate(UNIT_FIELD_HEALTH);
}
else
{
// Before the stop of combat, the auras of type MC are removed. We must be able to redirect the mobs to the caster.
pVictim->RemoveCharmAuras(AURA_REMOVE_BY_DEATH);

// stop combat
pVictim->CombatStop();
}

pVictim->GetHostileRefManager().deleteReferences();

Expand All @@ -1115,39 +1123,7 @@ void Unit::Kill(Unit* pVictim, SpellEntry const* spellProto, bool durabilityLoss

DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageHealth1");

if (spiritOfRedemtionTalentImmune)
{
// save value before aura remove
uint32 ressSpellId = 0;
#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1
ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
if (!ressSpellId)
ressSpellId = ((Player*)pVictim)->SelectResurrectionSpellId();
#else
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT))
ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId();
#endif

//Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
pVictim->RemoveAllAurasOnDeath();

// restore for use at real death
#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1
pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId);
#else
pPlayerVictim->SetResurrectionSpellId(ressSpellId);
if (ressSpellId)
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT);
#endif

// FORM_SPIRITOFREDEMPTION and related auras
pVictim->AddAura(27827, ADD_AURA_NO_OPTION, pVictim);
pVictim->InterruptNonMeleeSpells(false);
}

// remember victim PvP death for corpse type and corpse reclaim delay
// at original death (not at SpiritOfRedemtionTalent timeout)
if (pPlayerVictim && !damageFromSpiritOfRedemtionTalent)
if (pPlayerVictim && !damageFromSpiritOfRedemptionTalent)
pPlayerVictim->SetPvPDeath(pPlayerTap != nullptr);

// Call KilledUnit for creatures
Expand Down
6 changes: 5 additions & 1 deletion src/game/Spells/Spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,11 @@ void Spell::AddUnitTarget(Unit* pTarget, SpellEffectIndex effIndex)
if (m_spellInfo->Effect[effIndex] == 0)
return;

if ((m_spellInfo->AttributesEx & SPELL_ATTR_EX_EXCLUDE_CASTER) && (m_spellInfo->EffectImplicitTargetA[effIndex] != TARGET_UNIT_CASTER) && (m_spellInfo->EffectImplicitTargetB[effIndex] != TARGET_UNIT_CASTER) && (pTarget->GetObjectGuid() == m_originalCasterGUID))
if (m_spellInfo->HasAttribute(SPELL_ATTR_EX_EXCLUDE_CASTER) &&
(pTarget->GetObjectGuid() == m_originalCasterGUID) &&
(m_spellInfo->EffectImplicitTargetA[effIndex] != TARGET_UNIT_CASTER) &&
(m_spellInfo->EffectImplicitTargetB[effIndex] != TARGET_UNIT_CASTER) &&
!IsSummonEffect(m_spellInfo->Effect[effIndex])) // summon effects need to have unit target to work, fixes 20713
return;

// Check for effect immune skip if immuned
Expand Down
20 changes: 18 additions & 2 deletions src/game/Spells/SpellAuras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5944,11 +5944,27 @@ void Aura::HandleSpiritOfRedemption(bool apply, bool Real)
target->SetStandState(UNIT_STAND_STATE_STAND);
}

target->SetHealth(1);
// set health and mana to maximum
target->SetPower(POWER_MANA, target->GetMaxPower(POWER_MANA));
target->SetInvincibilityHpThreshold(target->GetMaxHealth());

// cast visual on next tick
target->m_Events.AddLambdaEventAtOffset([target]()
{
target->CastSpell(target, 25100, true);
}, BATCHING_INTERVAL);
}
// die at aura end
else
target->DealDamage(target, target->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, GetSpellProto(), false);
{
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
target->m_Events.AddLambdaEventAtOffset([target]()
{
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
target->SetInvincibilityHpThreshold(0);
target->CastSpell(target, 27965, true);
}, BATCHING_INTERVAL);
}
}

void Aura::HandleAuraAoeCharm(bool apply, bool real)
Expand Down
2 changes: 1 addition & 1 deletion src/game/Spells/SpellEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ void Spell::EffectInstaKill(SpellEffectIndex /*effIdx*/)
m_caster->SendMessageToSet(&data, true);
#endif

m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, m_spellInfo, false, this);
}

void Spell::EffectEnvironmentalDMG(SpellEffectIndex effIdx)
Expand Down
29 changes: 29 additions & 0 deletions src/game/Spells/SpellEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,35 @@ namespace Spells

return false;
}

inline bool IsSummonEffect(uint32 effectName)
{
switch (effectName)
{
case SPELL_EFFECT_SUMMON:
case SPELL_EFFECT_SUMMON_WILD:
case SPELL_EFFECT_SUMMON_GUARDIAN:
case SPELL_EFFECT_SUMMON_PET:
case SPELL_EFFECT_SUMMON_POSSESSED:
case SPELL_EFFECT_SUMMON_TOTEM:
case SPELL_EFFECT_SUMMON_OBJECT_WILD:
case SPELL_EFFECT_SUMMON_TOTEM_SLOT1:
case SPELL_EFFECT_SUMMON_TOTEM_SLOT2:
case SPELL_EFFECT_SUMMON_TOTEM_SLOT3:
case SPELL_EFFECT_SUMMON_TOTEM_SLOT4:
case SPELL_EFFECT_SUMMON_PHANTASM:
case SPELL_EFFECT_SUMMON_CRITTER:
case SPELL_EFFECT_SUMMON_OBJECT_SLOT1:
case SPELL_EFFECT_SUMMON_OBJECT_SLOT2:
case SPELL_EFFECT_SUMMON_OBJECT_SLOT3:
case SPELL_EFFECT_SUMMON_OBJECT_SLOT4:
case SPELL_EFFECT_SUMMON_DEAD_PET:
case SPELL_EFFECT_SUMMON_DEMON:
return true;
}

return false;
}
}

class SpellEntry
Expand Down

0 comments on commit 47b4f67

Please sign in to comment.