mirror of
https://github.com/araxiaonline/mod-mythic-plus.git
synced 2026-06-13 03:02:24 -04:00
477 lines
22 KiB
C++
477 lines
22 KiB
C++
#include "MpLogger.h"
|
|
#include "Player.h"
|
|
#include "MythicPlus.h"
|
|
#include "ScriptMgr.h"
|
|
#include "SpellAuraEffects.h"
|
|
|
|
class MythicPlus_UnitScript : public UnitScript
|
|
{
|
|
public:
|
|
MythicPlus_UnitScript() : UnitScript("MythicPlus_UnitScript", true) { }
|
|
|
|
private:
|
|
/**
|
|
* Handles damage from non-creature sources (GameObjects, Players, etc.)
|
|
* @tparam DamageType Type of damage (int32/float)
|
|
* @param target Target of the damage
|
|
* @param attacker The non-creature attacker (passed by reference and may be modified)
|
|
* @param damage Reference to damage value (will be modified)
|
|
* @param spellInfo The spell being cast
|
|
* @param eventType Type of event (spell/melee/etc)
|
|
*/
|
|
template<typename DamageType>
|
|
void HandleNonCreatureAttacker(Unit* target, Unit*& attacker, DamageType& damage,
|
|
SpellInfo const* spellInfo, MythicPlus::MP_UNIT_EVENT_TYPE eventType)
|
|
{
|
|
Map* map = target ? target->GetMap() : nullptr;
|
|
std::string attackerType = "nullptr";
|
|
std::string attackerName = "unknown";
|
|
uint32 entry = 0;
|
|
|
|
if (attacker) {
|
|
if (attacker->GetTypeId() == TYPEID_GAMEOBJECT) {
|
|
attackerType = "GameObject";
|
|
if (GameObject* go = attacker->ToGameObject()) {
|
|
entry = go->GetEntry();
|
|
if (GameObjectTemplate const* goInfo = go->GetGOInfo()) {
|
|
attackerName = goInfo->name;
|
|
}
|
|
}
|
|
} else if (attacker->GetTypeId() == TYPEID_PLAYER) {
|
|
attackerType = "Player";
|
|
attackerName = attacker->GetName();
|
|
} else if (attacker->GetTypeId() == TYPEID_UNIT) {
|
|
attackerType = "Unit (non-creature)";
|
|
attackerName = attacker->GetName();
|
|
} else {
|
|
attackerType = "Unknown Type";
|
|
}
|
|
}
|
|
|
|
// Try to find a creature attacker from target's attackers list if we have one use it for scaling
|
|
Unit::AttackerSet const& attackers = target ? target->getAttackers() : Unit::AttackerSet();
|
|
if (!attackers.empty()) {
|
|
attacker = *attackers.begin();
|
|
if (Creature* creatureAttacker = attacker->ToCreature()) {
|
|
|
|
if (MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creatureAttacker->GetGUID())) {
|
|
damage = static_cast<DamageType>(modifyIncomingDmgHeal(eventType, target, creatureAttacker,
|
|
static_cast<uint32>(damage), spellInfo)) * sMythicPlus->nonCreatureSpellReducer;
|
|
return;
|
|
}
|
|
} else {
|
|
MpLogger::debug("====== SPELL SCALING: Non-Creature attacker - Name: {}, Spell: {}({}), Damage: {}",
|
|
attackerName,
|
|
spellInfo ? spellInfo->SpellName[0] : "No Spell",
|
|
spellInfo ? spellInfo->Id : 0,
|
|
damage);
|
|
|
|
if (map) {
|
|
if (MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId())) {
|
|
damage = static_cast<DamageType>(damage * instanceData->creature.spell * sMythicPlus->nonCreatureSpellReducer);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Fallback to instance-based scaling if we can't find a nearest creature
|
|
else if (map) {
|
|
if (MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId())) {
|
|
damage = static_cast<DamageType>(damage * instanceData->creature.spell * sMythicPlus->nonCreatureSpellReducer);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// Default scaling if no specific handler applied
|
|
return;
|
|
}
|
|
|
|
// Helper function to determine if a spell scales with Attack Power
|
|
bool IsAttackPowerScalingSpell(SpellInfo const* spellInfo) {
|
|
if (!spellInfo || spellInfo->Effects.empty()) {
|
|
return false;
|
|
}
|
|
|
|
auto mainEffect = spellInfo->Effects[0];
|
|
|
|
// Check 1: Direct weapon damage effects
|
|
bool isWeaponEffect = (mainEffect.Effect == SPELL_EFFECT_WEAPON_DAMAGE ||
|
|
mainEffect.Effect == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL ||
|
|
mainEffect.Effect == SPELL_EFFECT_NORMALIZED_WEAPON_DMG ||
|
|
mainEffect.Effect == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE);
|
|
|
|
// Check 2: Damage class indicates melee/ranged (scales with AP)
|
|
bool isMeleeOrRanged = (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE ||
|
|
spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED);
|
|
|
|
// Check 3: Requires weapon equipment
|
|
bool requiresWeapon = (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON);
|
|
|
|
// Check 4: Specific spell families known to scale with AP
|
|
bool isKnownAPSpell = false;
|
|
if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) {
|
|
// Rogue poisons and weapon-based abilities
|
|
isKnownAPSpell = (spellInfo->SpellFamilyFlags[0] & 0x10000) || // Deadly Poison flag
|
|
(spellInfo->SpellFamilyFlags[1] & 0x80000); // Other poison flags
|
|
}
|
|
|
|
// Return true if any indicator suggests AP scaling
|
|
return (isWeaponEffect || isMeleeOrRanged || requiresWeapon || isKnownAPSpell);
|
|
}
|
|
|
|
/**
|
|
* @brief This functions processes spell damage for DOTs and Direct Damage Spells it
|
|
* handles special cases for Melee scaling spells and AP scaling spells also so they
|
|
* are not scaled up twice and murder all my friends
|
|
*
|
|
* @tparam DamageType
|
|
* @param target
|
|
* @param attacker
|
|
* @param damage
|
|
* @param spellInfo
|
|
* @param eventType
|
|
* @param logPrefix
|
|
*/
|
|
|
|
template<typename DamageType>
|
|
void ProcessSpellDamage(Unit* target, Unit* attacker, DamageType& damage, SpellInfo const* spellInfo, MythicPlus::MP_UNIT_EVENT_TYPE eventType, const std::string& logPrefix) {
|
|
if(damage == 0) {
|
|
return;
|
|
}
|
|
|
|
// If this is a special case where the attacker is not a creature
|
|
if (!attacker || !attacker->ToCreature()) {
|
|
return HandleNonCreatureAttacker(target, attacker, damage, spellInfo, eventType);
|
|
}
|
|
|
|
Creature* creatureCaster = attacker->ToCreature();
|
|
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creatureCaster->GetGUID());
|
|
|
|
if (!creatureCaster) {
|
|
MpLogger::error("Creature caster is null in map {}", attacker ? attacker->GetMap()->GetId() : 0);
|
|
return;
|
|
}
|
|
if (!creatureData) {
|
|
MpLogger::error("Failed to get creature data for {} in map {}", creatureCaster->GetName(), attacker ? attacker->GetMap()->GetId() : 0);
|
|
return;
|
|
}
|
|
|
|
// Check if this spell scales with Attack Power
|
|
if (IsAttackPowerScalingSpell(spellInfo)) {
|
|
|
|
// need another special case here to determine if a spell was not scaled up by AP meaning the incoming damage is close to the
|
|
// original effect of the spell and therefore should instead use spell effect scaling it should be no more than 15% of the original effect
|
|
bool notScaledByAP = false;
|
|
if (spellInfo && !spellInfo->Effects.empty()) {
|
|
int32 baseEffect = spellInfo->Effects[0].CalcValue(attacker, nullptr, nullptr);
|
|
if (damage <= (baseEffect * 1.15f)) {
|
|
// MpLogger::debug(">>>> MELEE SPELL SCALING: Spell {} (ID: {}) is not scaled by AP damage: {} vs originalEffect: {}",
|
|
// spellInfo->SpellName[0], spellInfo->Id, damage, baseEffect);
|
|
notScaledByAP = true;
|
|
}
|
|
} else {
|
|
// If we can't determine the base effect, default to treating it as not AP-scaled
|
|
notScaledByAP = true;
|
|
// MpLogger::debug(">>>> MELEE SPELL SCALING: Could not determine base effect for spell, defaulting to spell scaling");
|
|
}
|
|
|
|
// if the effect type of the spell is not physical (aka not mitigated by armor/defense) then it needs to instead have the typical
|
|
// spell damage multiplier applied instead of melee damage scaling
|
|
if (! notScaledByAP && (spellInfo->SchoolMask == SPELL_SCHOOL_NORMAL || spellInfo->SchoolMask == SPELL_SCHOOL_MASK_NORMAL)) {
|
|
uint32 meleeDamage = static_cast<uint32>(std::max(0, static_cast<int32>(damage)));
|
|
|
|
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_MELEE, target, attacker, meleeDamage);
|
|
|
|
// MpLogger::debug(">>MELEE SPELL SCALING: {} hits with spell: {} ID: {} meleeDamage: {} damage: {}", attacker->GetName(), spellInfo->SpellName[0], spellInfo->Id, meleeDamage, damage);
|
|
} else {
|
|
|
|
// get the creatures original attack power
|
|
SpellEffectInfo const& effect = spellInfo->Effects[0];
|
|
uint32 spellDmg = static_cast<uint32>(effect.CalcValue(attacker, nullptr, nullptr) * effect.CalcDamageMultiplier(attacker, nullptr));
|
|
|
|
// now take the original attack power * 0.08 and add it to the spell damage
|
|
uint32 apDmg = static_cast<uint32>(creatureData->originalStats->AttackPower * 0.10f);
|
|
uint32 finalDmg = spellDmg + apDmg;
|
|
|
|
// MpLogger::debug(">> AP BASED DAMAGE Scaledown: origDamage: {} | spellDmg: {} | apDmg: {} | finalDmg: {}", static_cast<int32>(damage), spellDmg, apDmg, finalDmg);
|
|
|
|
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_SPELL, target, attacker, finalDmg, spellInfo);
|
|
|
|
// need to take into consideration if this is a stacking spell and multiply the final damage by the number of stacks
|
|
if(spellInfo->AttributesEx3 & SPELL_ATTR3_DOT_STACKING_RULE) {
|
|
|
|
Aura* aura = target->GetAura(spellInfo->Id, attacker->GetGUID());
|
|
uint32 stacks = aura ? aura->GetStackAmount() : 1;
|
|
if(aura) {
|
|
damage *= stacks;
|
|
}
|
|
}
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Reverse the CalcValue scaling to get original base damage
|
|
int32 originalDamage = static_cast<int32>(damage);
|
|
|
|
if (creatureCaster && creatureData && creatureData->originalLevel < 70) {
|
|
CreatureTemplate const* cInfo = creatureCaster->GetCreatureTemplate();
|
|
|
|
// Get the scaling factors used in CalcValue
|
|
CreatureBaseStats const* pCBS = sObjectMgr->GetCreatureBaseStats(creatureCaster->GetLevel(), creatureCaster->getClass());
|
|
float CBSPowerCreature = pCBS->BaseDamage[cInfo->expansion];
|
|
|
|
uint32 tempLevel = spellInfo->SpellLevel;
|
|
if(tempLevel == 0) {
|
|
tempLevel = creatureData->originalLevel;
|
|
}
|
|
|
|
CreatureBaseStats const* spellCBS = sObjectMgr->GetCreatureBaseStats(tempLevel, creatureCaster->getClass());
|
|
float CBSPowerSpell = spellCBS->BaseDamage[cInfo->expansion];
|
|
|
|
// MpLogger::debug("SPELL SCALING: Creature Lvl {} -> {} | Spell Lvl {} | tempLevel: {} | CBSPowerCreature: {} CBSPowerSpell: {}",
|
|
// creatureData->originalLevel, creatureCaster->GetLevel(), tempLevel, CBSPowerCreature, CBSPowerSpell);
|
|
|
|
// Reverse the CalcValue scaling: originalDamage = scaledDamage / (CBSPowerCreature / CBSPowerSpell)
|
|
if (CBSPowerCreature > 0.0f) {
|
|
originalDamage = static_cast<int32>(static_cast<int32>(damage) * (CBSPowerSpell / CBSPowerCreature));
|
|
// MpLogger::debug("SPELL SCALING: Reversed CalcValue scaling - Scaled: {} -> Original: {} (Factor: {:.2f})",
|
|
// damage, originalDamage, CBSPowerSpell / CBSPowerCreature);
|
|
}
|
|
}
|
|
|
|
// Apply Mythic+ scaling to the original base damage
|
|
damage = static_cast<DamageType>(modifyIncomingDmgHeal(eventType, target, attacker, static_cast<uint32>(originalDamage), spellInfo));
|
|
}
|
|
|
|
public:
|
|
|
|
void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage, SpellInfo const* spellInfo) override {
|
|
if (!target && !attacker) {
|
|
return;
|
|
}
|
|
|
|
Map *map = target->GetMap();
|
|
if(!sMythicPlus->IsMapEligible(map)) {
|
|
return;
|
|
}
|
|
|
|
auto effects = spellInfo->Effects;
|
|
bool isHot = false;
|
|
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) {
|
|
switch(effects[i].Effect) {
|
|
case SPELL_EFFECT_HEAL:
|
|
case SPELL_EFFECT_HEAL_MAX_HEALTH:
|
|
case SPELL_EFFECT_HEAL_MECHANICAL:
|
|
case SPELL_EFFECT_HEAL_PCT:
|
|
case SPELL_EFFECT_SPIRIT_HEAL:
|
|
isHot = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(isHot) {
|
|
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_HOT, target, attacker, damage, spellInfo);
|
|
} else {
|
|
ProcessSpellDamage(target, attacker, damage, spellInfo, MythicPlus::UNIT_EVENT_DOT, "DOT DAMAGE");
|
|
}
|
|
}
|
|
|
|
void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage, SpellInfo const* spellInfo) override {
|
|
if (!target && !attacker) {
|
|
|
|
if(spellInfo) {
|
|
// MpLogger::info("ModifySpellDamageTaken: Target and attacker are null for spell: {} ID: {}", spellInfo->SpellName[0], spellInfo->Id);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Map *map = target->GetMap();
|
|
if(!sMythicPlus->IsMapEligible(map)) {
|
|
return;
|
|
}
|
|
|
|
if(!sMythicPlus->EligibleDamageTarget(target)) {
|
|
if(spellInfo) {
|
|
// MpLogger::info("ModifySpellDamageTaken: Target is not eligible for spell: {} ID: {}", spellInfo->SpellName[0], spellInfo->Id);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// MpLogger::debug("ModifySpellDamageTaken: {} hits {} with spell: {} ID: {}", attacker ? attacker->GetName() : "[null]", target ? target->GetName() : "[null]", spellInfo ? spellInfo->SpellName[0] : "[no spell]", spellInfo ? spellInfo->Id : 0);
|
|
|
|
// Use the generic ProcessSpellDamage function
|
|
ProcessSpellDamage(target, attacker, damage, spellInfo, MythicPlus::UNIT_EVENT_SPELL, "SPELL DAMAGE");
|
|
}
|
|
|
|
/**
|
|
* Directly Modify the melee damage characters and allied creatures will
|
|
* receive from mythic+ scaled enemies.
|
|
*/
|
|
void ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage) override {
|
|
if (!target && !attacker) {
|
|
return;
|
|
}
|
|
|
|
Map *map = target->GetMap();
|
|
if(!sMythicPlus->IsMapEligible(map)) {
|
|
return;
|
|
}
|
|
|
|
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_MELEE, target, attacker, damage);
|
|
}
|
|
|
|
// When a healing spell hits a mythic+ enemy modify based on the modifiers for the difficulty
|
|
void ModifyHealReceived(Unit* target, Unit* healer, uint32& healing, SpellInfo const* spellInfo) override {
|
|
if (!target && !healer) {
|
|
return;
|
|
}
|
|
|
|
Map *map = target->GetMap();
|
|
if(!sMythicPlus->IsMapEligible(map)) {
|
|
return;
|
|
}
|
|
|
|
healing = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_HEAL, target, healer, healing, spellInfo);
|
|
}
|
|
|
|
uint32 modifyIncomingDmgHeal(MythicPlus::MP_UNIT_EVENT_TYPE eventType,Unit* target, Unit* attacker, uint32 damageOrHeal, SpellInfo const* spellInfo = nullptr) {
|
|
if (!target && !attacker) {
|
|
// MpLogger::info("modifyIncomingDmgHeal: Target and attacker are null for event {}", eventType);
|
|
return damageOrHeal;
|
|
}
|
|
|
|
int32 alteredDmgHeal = 0;
|
|
|
|
Map *map = target->GetMap();
|
|
if(!sMythicPlus->IsMapEligible(map)) {
|
|
return damageOrHeal;
|
|
}
|
|
|
|
if(attacker && attacker->IsPlayer()) {
|
|
return damageOrHeal;
|
|
}
|
|
|
|
#if defined(MOD_PRESENT_NPCBOTS)
|
|
if (attacker && attacker->IsNPCBotOrPet()) {
|
|
return damageOrHeal;
|
|
}
|
|
#endif
|
|
|
|
Creature* creature = attacker ? attacker->ToCreature() : nullptr;
|
|
if (!creature) {
|
|
MpLogger::debug("Attacker was considered not a creature");
|
|
return damageOrHeal;
|
|
}
|
|
|
|
MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId());
|
|
if(!instanceData) {
|
|
return damageOrHeal;
|
|
}
|
|
|
|
std::string eventName = "";
|
|
switch (eventType) {
|
|
case MythicPlus::UNIT_EVENT_MELEE:
|
|
eventName = "Melee";
|
|
break;
|
|
case MythicPlus::UNIT_EVENT_HEAL:
|
|
eventName = "Heal";
|
|
break;
|
|
case MythicPlus::UNIT_EVENT_DOT:
|
|
eventName = "DOT";
|
|
break;
|
|
case MythicPlus::UNIT_EVENT_SPELL:
|
|
eventName = "Spell";
|
|
break;
|
|
case MythicPlus::UNIT_EVENT_HOT:
|
|
eventName = "HOT";
|
|
break;
|
|
}
|
|
|
|
// If the target is the enemy then increase the amount of healing by the instance data modifier for spell output.
|
|
if(sMythicPlus->EligibleDamageTarget(target)) {
|
|
/**
|
|
* @TODO: Allow more granular control over the scaling of DOT, HOT, and other spell effects
|
|
* in the future if needed
|
|
*/
|
|
switch (eventType) {
|
|
case MythicPlus::UNIT_EVENT_MELEE:
|
|
|
|
// Damage that is not mitigated by armor needs to be debuffed as it hits too hard and without resists
|
|
// it hits too hard give everyone a benefit of 30% armor reduction
|
|
MpLogger::debug(">>> Modify Melee Damage: Creature Name: {} alteredDmgHeal: {} School Mask: {}", creature->GetName(), alteredDmgHeal, creature->GetMeleeDamageSchoolMask());
|
|
if(creature->GetMeleeDamageSchoolMask() != SPELL_SCHOOL_MASK_NORMAL && creature->GetMeleeDamageSchoolMask() != SPELL_SCHOOL_MASK_NONE) {
|
|
damageOrHeal = damageOrHeal * 0.50f;
|
|
}
|
|
if(creature->IsDungeonBoss() || creature->isWorldBoss() || creature->GetEntry() == 23682) {
|
|
alteredDmgHeal = damageOrHeal * instanceData->boss.melee;
|
|
} else {
|
|
alteredDmgHeal = damageOrHeal * instanceData->creature.melee;
|
|
}
|
|
|
|
// MpLogger::debug(">>>>>>>>>>>> Incoming Melee New Damage: {}({}) {} hits {}", alteredDmgHeal, damageOrHeal, attacker->GetName(), target->GetName());
|
|
|
|
break;
|
|
case MythicPlus::UNIT_EVENT_DOT:
|
|
case MythicPlus::UNIT_EVENT_SPELL:
|
|
if(creature->IsDungeonBoss() || creature->isWorldBoss() || creature->GetEntry() == 23682) {
|
|
if(spellInfo) {
|
|
// MpLogger::debug("Scaling spell {} using ScaleDamageSpell() Original Damage: {} New Damage: {}", spellInfo->SpellName[0], damageOrHeal, alteredDmgHeal);
|
|
alteredDmgHeal = sMythicPlus->ScaleDamageSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, target, instanceData->boss.spell);
|
|
} else {
|
|
alteredDmgHeal = damageOrHeal * instanceData->boss.spell;
|
|
// MpLogger::debug("Scaling spell {} using flat modifier Original Damage: {} New Damage: {}", spellInfo->SpellName[0], damageOrHeal, alteredDmgHeal);
|
|
}
|
|
} else {
|
|
if(spellInfo) {
|
|
// MpLogger::debug("Scaling spell {} using ScaleDamageSpell() Original Damage: {} New Damage: {}", spellInfo->SpellName[0], damageOrHeal, alteredDmgHeal);
|
|
alteredDmgHeal = sMythicPlus->ScaleDamageSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, target, instanceData->creature.spell);
|
|
} else {
|
|
// MpLogger::debug("Scaling spell {} using flat modifier Original Damage: {} New Damage: {}", spellInfo->SpellName[0], damageOrHeal, alteredDmgHeal);
|
|
alteredDmgHeal = damageOrHeal * instanceData->creature.spell;
|
|
}
|
|
}
|
|
|
|
break;
|
|
case MythicPlus::UNIT_EVENT_HEAL:
|
|
case MythicPlus::UNIT_EVENT_HOT:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @TODO: Add more granular control over the scaling of healing spells
|
|
*/
|
|
if(sMythicPlus->EligibleHealTarget(target) && (eventType == MythicPlus::UNIT_EVENT_HEAL || eventType == MythicPlus::UNIT_EVENT_HOT)) {
|
|
if(creature->IsDungeonBoss()) {
|
|
if(spellInfo) {
|
|
alteredDmgHeal = sMythicPlus->ScaleHealSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, attacker->ToCreature(), instanceData->boss.spell * 0.7f);
|
|
} else {
|
|
alteredDmgHeal = damageOrHeal * instanceData->boss.spell * 0.7f;
|
|
}
|
|
} else {
|
|
if(spellInfo) {
|
|
alteredDmgHeal = sMythicPlus->ScaleHealSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, attacker->ToCreature(), instanceData->creature.spell * 0.7f);
|
|
} else {
|
|
alteredDmgHeal = damageOrHeal * instanceData->creature.spell * 0.70f;
|
|
}
|
|
}
|
|
MpLogger::debug("Incoming heal: {}({}) {} hits {}",
|
|
alteredDmgHeal,
|
|
damageOrHeal,
|
|
attacker ? attacker->GetName() : "[null]",
|
|
target ? target->GetName() : "[null]");
|
|
}
|
|
|
|
return alteredDmgHeal > 0 ? alteredDmgHeal : damageOrHeal;
|
|
}
|
|
|
|
};
|
|
|
|
void Add_MP_UnitScripts()
|
|
{
|
|
new MythicPlus_UnitScript();
|
|
}
|