From d7f11f406f4ddd573c3523a8e49f1e43050b10d0 Mon Sep 17 00:00:00 2001 From: ratkosrb Date: Sun, 12 Nov 2023 14:49:55 +0200 Subject: [PATCH] Fix Orb of Draconic Energy. Closes https://github.com/vmangos/core/issues/2282 --- src/game/Commands/UnitCommands.cpp | 6 +- src/game/Spells/Spell.cpp | 147 +++++++++++++++-------------- src/game/Spells/SpellEntry.h | 17 ++++ 3 files changed, 94 insertions(+), 76 deletions(-) diff --git a/src/game/Commands/UnitCommands.cpp b/src/game/Commands/UnitCommands.cpp index 6880d1f003e..45ae5028f77 100644 --- a/src/game/Commands/UnitCommands.cpp +++ b/src/game/Commands/UnitCommands.cpp @@ -876,13 +876,13 @@ bool ChatHandler::HandleUnfreezeCommand(char* args) bool ChatHandler::HandlePossessCommand(char *args) { - Unit* tar = GetSelectedUnit(); - if (!tar) + Unit* target = GetSelectedUnit(); + if (!target) { SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); return false; } - m_session->GetPlayer()->CastSpell(tar, 530, true); + m_session->GetPlayer()->CastCustomSpell(target, 530, 255, {}, {}, true); return true; } diff --git a/src/game/Spells/Spell.cpp b/src/game/Spells/Spell.cpp index 339718e9162..af8fa5eee71 100644 --- a/src/game/Spells/Spell.cpp +++ b/src/game/Spells/Spell.cpp @@ -6880,54 +6880,37 @@ SpellCastResult Spell::CheckCast(bool strict) if (!m_caster->IsPlayer()) return SPELL_FAILED_BAD_TARGETS; - if (!m_targets.getUnitTarget()) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - - if (m_targets.getUnitTarget() == m_casterUnit) + // no break + } + case SPELL_AURA_MOD_CHARM: + { + if (!m_casterUnit) return SPELL_FAILED_BAD_TARGETS; - if (!m_casterUnit->UnsummonOldPetBeforeNewSummon(m_targets.getUnitTarget()->GetEntry(), m_spellInfo->HasAttribute(SPELL_ATTR_EX_DISMISS_PET_FIRST))) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - - if (m_spellInfo->HasAttribute(SPELL_ATTR_EX_DISMISS_PET_FIRST)) - m_casterUnit->Uncharm(); - else if (m_casterUnit->GetCharmGuid()) - return SPELL_FAILED_ALREADY_HAVE_CHARM; - - if (m_casterUnit->GetCharmerGuid()) -#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_11_2 - return SPELL_FAILED_CHARMED; -#else - return SPELL_FAILED_FIZZLE; -#endif + if (!IsScriptTarget(m_spellInfo->EffectImplicitTargetA[i])) + { + if (!m_targets.getUnitTarget()) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - if (m_targets.getUnitTarget()->GetCharmerGuid()) + if (m_targets.getUnitTarget()->GetCharmerGuid()) #if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_11_2 - return SPELL_FAILED_CHARMED; + return SPELL_FAILED_CHARMED; #else - return SPELL_FAILED_FIZZLE; + return SPELL_FAILED_FIZZLE; #endif - if (m_spellInfo->Id != 530) // Spell for ".possess" command. if (int32(m_targets.getUnitTarget()->GetLevel()) > CalculateDamage(SpellEffectIndex(i), m_targets.getUnitTarget())) return SPELL_FAILED_HIGHLEVEL; + } - break; - } - case SPELL_AURA_MOD_CHARM: - { - if (!m_casterUnit) - return SPELL_FAILED_BAD_TARGETS; - - if (!m_targets.getUnitTarget()) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - - if (m_targets.getUnitTarget() == m_casterUnit) - return SPELL_FAILED_BAD_TARGETS; - - if (!m_casterUnit->UnsummonOldPetBeforeNewSummon(m_targets.getUnitTarget()->GetEntry(), m_spellInfo->HasAttribute(SPELL_ATTR_EX_DISMISS_PET_FIRST))) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - + if (Pet* pPet = m_casterUnit->GetPet()) + { + if (m_spellInfo->HasAttribute(SPELL_ATTR_EX_DISMISS_PET_FIRST)) + pPet->Unsummon(PET_SAVE_NOT_IN_SLOT); + else + return SPELL_FAILED_ALREADY_HAVE_SUMMON; + } + if (m_spellInfo->HasAttribute(SPELL_ATTR_EX_DISMISS_PET_FIRST)) m_casterUnit->Uncharm(); else if (m_casterUnit->GetCharmGuid()) @@ -6940,16 +6923,6 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_FIZZLE; #endif - if (m_targets.getUnitTarget()->GetCharmerGuid()) -#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_11_2 - return SPELL_FAILED_CHARMED; -#else - return SPELL_FAILED_FIZZLE; -#endif - - if (int32(m_targets.getUnitTarget()->GetLevel()) > CalculateDamage(SpellEffectIndex(i), m_targets.getUnitTarget())) - return SPELL_FAILED_HIGHLEVEL; - break; } case SPELL_AURA_MOD_POSSESS_PET: @@ -8181,17 +8154,9 @@ bool Spell::CheckTarget(Unit* target, SpellEffectIndex eff) // unselectable targets skipped in all cases except db defined script targets // in that case the target is selected by server, not by client, so no cheating if ((!m_IsTriggeredSpell || target != m_targets.getUnitTarget()) && - target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) && - m_spellInfo->EffectImplicitTargetA[eff] != TARGET_UNIT_SCRIPT_NEAR_CASTER && - m_spellInfo->EffectImplicitTargetB[eff] != TARGET_UNIT_SCRIPT_NEAR_CASTER && - m_spellInfo->EffectImplicitTargetA[eff] != TARGET_ENUM_UNITS_SCRIPT_AOE_AT_SRC_LOC && - m_spellInfo->EffectImplicitTargetB[eff] != TARGET_ENUM_UNITS_SCRIPT_AOE_AT_SRC_LOC && - m_spellInfo->EffectImplicitTargetA[eff] != TARGET_ENUM_UNITS_SCRIPT_AOE_AT_DEST_LOC && - m_spellInfo->EffectImplicitTargetB[eff] != TARGET_ENUM_UNITS_SCRIPT_AOE_AT_DEST_LOC && - m_spellInfo->EffectImplicitTargetA[eff] != TARGET_ENUM_UNITS_SCRIPT_IN_CONE_60 && - m_spellInfo->EffectImplicitTargetB[eff] != TARGET_ENUM_UNITS_SCRIPT_IN_CONE_60 && - m_spellInfo->EffectImplicitTargetA[eff] != TARGET_LOCATION_SCRIPT_NEAR_CASTER && - m_spellInfo->EffectImplicitTargetB[eff] != TARGET_LOCATION_SCRIPT_NEAR_CASTER) + target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) && + !IsScriptTarget(m_spellInfo->EffectImplicitTargetA[eff]) && + !IsScriptTarget(m_spellInfo->EffectImplicitTargetB[eff])) return false; } @@ -8205,18 +8170,63 @@ bool Spell::CheckTarget(Unit* target, SpellEffectIndex eff) return false; } + enum + { + NORMAL_LOS, + CORPSE_LOS, + NO_LOS + } checkLosType = NORMAL_LOS; + // Check targets for LOS visibility (except spells without range limitations ) switch (m_spellInfo->Effect[eff]) { case SPELL_EFFECT_SUMMON_PLAYER: // from anywhere + { + checkLosType = NO_LOS; break; + } case SPELL_EFFECT_DUMMY: - if (m_spellInfo->Id != 20577) // Cannibalize - break; - // no break. Cannibalize checks corpse target LOS. - // fall through + { + if (m_spellInfo->Id == 20577) // Cannibalize + checkLosType = CORPSE_LOS; + break; + } case SPELL_EFFECT_RESURRECT: case SPELL_EFFECT_RESURRECT_NEW: + { + checkLosType = CORPSE_LOS; + break; + } + case SPELL_AURA_MOD_POSSESS: + case SPELL_AURA_MOD_CHARM: + { + if (target == m_casterUnit) + return false; + + if (target->GetCharmerGuid()) + return false; + + if (int32(target->GetLevel()) > CalculateDamage(eff, target)) + return false; + + break; + } + } + + switch (checkLosType) + { + case NORMAL_LOS: + { + // Get GO cast coordinates if original caster -> GO + if (target != m_caster && !IsIgnoreLosTarget(m_spellInfo->EffectImplicitTargetA[eff]) && + (m_spellInfo->EffectChainTarget[eff] == 0 || target == m_targets.getUnitTarget())) + if (SpellCaster* caster = GetCastingObject()) + if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_IGNORE_LINE_OF_SIGHT) && !target->IsWithinLOSInMap(caster)) + return false; + break; + } + case CORPSE_LOS: + { // player far away, maybe his corpse near? if (target != m_caster && !(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_IGNORE_LINE_OF_SIGHT) && !target->IsWithinLOSInMap(m_caster)) { @@ -8233,17 +8243,8 @@ bool Spell::CheckTarget(Unit* target, SpellEffectIndex eff) if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_IGNORE_LINE_OF_SIGHT) && !corpse->IsWithinLOSInMap(m_caster)) return false; } - - // all ok by some way or another, skip normal check - break; - default: // normal case - // Get GO cast coordinates if original caster -> GO - if (target != m_caster && !IsIgnoreLosTarget(m_spellInfo->EffectImplicitTargetA[eff]) && - (m_spellInfo->EffectChainTarget[eff] == 0 || target == m_targets.getUnitTarget())) - if (SpellCaster* caster = GetCastingObject()) - if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_IGNORE_LINE_OF_SIGHT) && !target->IsWithinLOSInMap(caster)) - return false; break; + } } if (m_spellInfo->HasAttribute(SPELL_ATTR_EX3_NOT_ON_AOE_IMMUNE) && diff --git a/src/game/Spells/SpellEntry.h b/src/game/Spells/SpellEntry.h index e5cc7009257..7b336d8183d 100644 --- a/src/game/Spells/SpellEntry.h +++ b/src/game/Spells/SpellEntry.h @@ -342,6 +342,23 @@ namespace Spells return false; } + inline bool IsScriptTarget(uint32 target) + { + switch (target) + { + case TARGET_ENUM_UNITS_SCRIPT_AOE_AT_SRC_LOC: + case TARGET_ENUM_UNITS_SCRIPT_AOE_AT_DEST_LOC: + case TARGET_UNIT_SCRIPT_NEAR_CASTER: + case TARGET_GAMEOBJECT_SCRIPT_NEAR_CASTER: + case TARGET_LOCATION_SCRIPT_NEAR_CASTER: + case TARGET_ENUM_GAMEOBJECTS_SCRIPT_AOE_AT_SRC_LOC: + case TARGET_ENUM_GAMEOBJECTS_SCRIPT_AOE_AT_DEST_LOC: + case TARGET_ENUM_UNITS_SCRIPT_IN_CONE_60: + return true; + } + return false; + } + inline bool IsAreaEffectPossitiveTarget(SpellTarget target) { switch (target)