Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-09-18 17:01:24 -06:00
committed by GitHub
20 changed files with 1095 additions and 417 deletions
@@ -3430,8 +3430,13 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
if (me->IsInRange(me->GetVictim(), (float)e.event.minMaxRepeat.min, (float)e.event.minMaxRepeat.max))
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->GetVictim());
else // xinef: make it predictable
RecalcTimer(e, 500, 500);
else
{
if (!e.event.minMaxRepeat.controller)
RecalcTimer(e, 500, 500); // xinef: make it predictable "Malcrom: This seems to be done to standardize min, max start rather than using the range values for the timer."
else
RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); // Malcrom: if param5 value is greater than 0 first action will not happen until after repeat timer fires.
}
break;
}
case SMART_EVENT_VICTIM_CASTING:
@@ -221,6 +221,7 @@ struct SmartEvent
uint32 max;
uint32 repeatMin;
uint32 repeatMax;
uint32 controller;
} minMaxRepeat;
struct
+6 -2
View File
@@ -15517,9 +15517,13 @@ void Player::_SaveInstanceTimeRestrictions(CharacterDatabaseTransaction trans)
bool Player::IsInWhisperWhiteList(ObjectGuid guid)
{
for (WhisperListContainer::const_iterator itr = WhisperList.begin(); itr != WhisperList.end(); ++itr)
if (*itr == guid)
for (auto const& itr : WhisperList)
{
if (itr == guid)
{
return true;
}
}
return false;
}
+9 -6
View File
@@ -1762,7 +1762,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
uint32 damage = uint32(std::max(0, (*dmgShieldItr)->GetAmount())); // xinef: done calculated at amount calculation
if (Unit* caster = (*dmgShieldItr)->GetCaster())
{
damage = caster->SpellDamageBonusDone(this, i_spellProto, damage, SPELL_DIRECT_DAMAGE, (*dmgShieldItr)->GetEffIndex());
damage = this->SpellDamageBonusTaken(caster, i_spellProto, damage, SPELL_DIRECT_DAMAGE);
}
uint32 absorb = 0;
@@ -11250,7 +11253,7 @@ float Unit::SpellPctDamageModsDone(Unit* victim, SpellInfo const* spellProto, Da
return DoneTotalMod;
}
uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, float TotalMod, uint32 stack)
uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint8 effIndex, float TotalMod, uint32 stack)
{
if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
return pdamage;
@@ -11265,7 +11268,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
if (IsTotem())
{
if (Unit* owner = GetOwner())
return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, TotalMod, stack);
return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, effIndex, TotalMod, stack);
}
// Dancing Rune Weapon...
else if (GetEntry() == 27893)
@@ -11342,7 +11345,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask());
// Check for table values
float coeff = 0;
float coeff = spellProto->Effects[effIndex].BonusMultiplier;
SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id);
if (bonus)
{
@@ -12054,12 +12057,12 @@ float Unit::SpellPctHealingModsDone(Unit* victim, SpellInfo const* spellProto, D
return DoneTotalMod;
}
uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, float TotalMod, uint32 stack)
uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint8 effIndex, float TotalMod, uint32 stack)
{
// For totems get healing bonus from owner (statue isn't totem in fact)
if (GetTypeId() == TYPEID_UNIT && IsTotem())
if (Unit* owner = GetOwner())
return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, TotalMod, stack);
return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, effIndex, TotalMod, stack);
// No bonus healing for potion spells
if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
@@ -12090,7 +12093,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
// Done fixed damage bonus auras
int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask());
float coeff = 0;
float coeff = spellProto->Effects[effIndex].BonusMultiplier;
switch (spellProto->SpellFamilyName)
{
+2 -2
View File
@@ -2168,12 +2168,12 @@ public:
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask);
int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask, bool isDoT = false);
float SpellPctDamageModsDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype);
uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, float TotalMod = 0.0f, uint32 stack = 1);
uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint8 effIndex, float TotalMod = 0.0f, uint32 stack = 1);
uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1);
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask);
int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask);
float SpellPctHealingModsDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype);
uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, float TotalMod = 0.0f, uint32 stack = 1);
uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint8 effIndex, float TotalMod = 0.0f, uint32 stack = 1);
uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1);
uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = nullptr);
@@ -551,11 +551,11 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
case SPELL_AURA_PERIODIC_LEECH:
// xinef: save caster depending auras, always pass 1 as stack amount, effect will be multiplicated at the end of the function by correct value!
if (GetBase()->GetType() == UNIT_AURA_TYPE)
amount = caster->SpellDamageBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, DOT, GetPctMods(), 1);
amount = caster->SpellDamageBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, DOT, GetEffIndex(), GetPctMods(), 1);
break;
case SPELL_AURA_PERIODIC_HEAL:
if (GetBase()->GetType() == UNIT_AURA_TYPE)
amount = caster->SpellHealingBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, DOT, GetPctMods(), 1);
amount = caster->SpellHealingBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, DOT, GetEffIndex(), GetPctMods(), 1);
break;
case SPELL_AURA_DAMAGE_SHIELD:
if (GetBase()->GetType() == UNIT_AURA_TYPE)
@@ -6304,7 +6304,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
{
// xinef: leave only target depending bonuses, rest is handled in calculate amount
if (GetBase()->GetType() == DYNOBJ_AURA_TYPE && caster)
damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, 0.0f, GetBase()->GetStackAmount());
damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetEffIndex(), 0.0f, GetBase()->GetStackAmount());
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
// Calculate armor mitigation
@@ -6413,7 +6413,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage);
if (GetBase()->GetType() == DYNOBJ_AURA_TYPE)
damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, 0.0f, GetBase()->GetStackAmount());
damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetEffIndex(), 0.0f, GetBase()->GetStackAmount());
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
bool crit = false;
@@ -6483,7 +6483,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster);
uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, 0.0f, GetBase()->GetStackAmount()));
uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetEffIndex(), 0.0f, GetBase()->GetStackAmount()));
heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount()));
HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
@@ -6604,7 +6604,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
}
if (GetBase()->GetType() == DYNOBJ_AURA_TYPE)
damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, 0.0f, GetBase()->GetStackAmount());
damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetEffIndex(), 0.0f, GetBase()->GetStackAmount());
damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
}
@@ -6898,7 +6898,7 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv
}
SpellNonMeleeDamage damageInfo(target, triggerTarget, GetSpellInfo(), GetSpellInfo()->SchoolMask);
uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE);
uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE, GetEffIndex());
damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE);
target->CalculateSpellDamageTaken(&damageInfo, damage, GetSpellInfo());
Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
+1 -1
View File
@@ -2845,7 +2845,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (m_caster->IsAlive())
{
healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL);
healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL, effIndex);
healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL);
HealInfo healInfo(m_caster, m_caster, healthGain, m_spellInfo, m_spellInfo->GetSchoolMask());
+11 -11
View File
@@ -644,7 +644,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
if (damage < 0)
damage = 0;
damage = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
damage = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, effIndex);
damage = unitTarget->SpellDamageBonusTaken(m_originalCaster, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
}
@@ -1356,7 +1356,7 @@ void Spell::EffectPowerDrain(SpellEffIndex effIndex)
return;
// add spell damage bonus
damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, effIndex);
damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
@@ -1463,7 +1463,7 @@ void Spell::EffectPowerBurn(SpellEffIndex effIndex)
m_damage += newDamage;
}
void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
void Spell::EffectHeal(SpellEffIndex effIndex)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
return;
@@ -1550,12 +1550,12 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
// Death Pact - return pct of max health to caster
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000)
{
addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL);
addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL, effIndex);
addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL);
}
else if (m_spellInfo->Id != 33778) // not lifebloom
{
addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL);
addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, effIndex);
addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL);
}
@@ -1574,7 +1574,7 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
}
}
void Spell::EffectHealPct(SpellEffIndex /*effIndex*/)
void Spell::EffectHealPct(SpellEffIndex effIndex)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
return;
@@ -1586,13 +1586,13 @@ void Spell::EffectHealPct(SpellEffIndex /*effIndex*/)
if (!m_originalCaster)
return;
uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL);
uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL, effIndex);
heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL);
m_damage -= heal;
}
void Spell::EffectHealMechanical(SpellEffIndex /*effIndex*/)
void Spell::EffectHealMechanical(SpellEffIndex effIndex)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
return;
@@ -1604,12 +1604,12 @@ void Spell::EffectHealMechanical(SpellEffIndex /*effIndex*/)
if (!m_originalCaster)
return;
uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL);
uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL, effIndex);
m_damage -= unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL);
}
void Spell::EffectHealthLeech(SpellEffIndex /*effIndex*/)
void Spell::EffectHealthLeech(SpellEffIndex effIndex)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
@@ -1617,7 +1617,7 @@ void Spell::EffectHealthLeech(SpellEffIndex /*effIndex*/)
if (!unitTarget || !unitTarget->IsAlive() || damage < 0)
return;
damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, effIndex);
damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
LOG_DEBUG("spells.aura", "HealthLeech :{}", damage);
@@ -4385,6 +4385,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->ProcFlags = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS;
});
// Gift of Arthas
ApplySpellFix({ 11371 }, [](SpellInfo* spellInfo)
{
spellInfo->SpellFamilyName = SPELLFAMILY_POTION;
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];
+1 -1
View File
@@ -1965,7 +1965,7 @@ void SpellMgr::LoadSpellProcs()
LOG_INFO("server.loading", " ");
}
void SpellMgr::LoadSpellBonusess()
void SpellMgr::LoadSpellBonuses()
{
uint32 oldMSTime = getMSTime();
+2 -2
View File
@@ -381,7 +381,7 @@ struct SpellThreatEntry
float apPctMod; // Pct of AP that is added as Threat - default: 0.0f
};
typedef std::map<uint32, SpellThreatEntry> SpellThreatMap;
typedef std::unordered_map<uint32, SpellThreatEntry> SpellThreatMap;
typedef std::map<uint32, float> SpellMixologyMap;
// coordinates for spells (accessed using SpellMgr functions)
@@ -752,7 +752,7 @@ public:
void LoadSpellGroupStackRules();
void LoadSpellProcEvents();
void LoadSpellProcs();
void LoadSpellBonusess();
void LoadSpellBonuses();
void LoadSpellThreats();
void LoadSpellMixology();
void LoadSkillLineAbilityMap();
+1 -1
View File
@@ -1662,7 +1662,7 @@ void World::SetInitialWorldSettings()
sSpellMgr->LoadSpellProcs();
LOG_INFO("server.loading", "Loading Spell Bonus Data...");
sSpellMgr->LoadSpellBonusess();
sSpellMgr->LoadSpellBonuses();
LOG_INFO("server.loading", "Loading Aggro Spells Definitions...");
sSpellMgr->LoadSpellThreats();
+1 -1
View File
@@ -872,7 +872,7 @@ public:
static bool HandleReloadSpellBonusesCommand(ChatHandler* handler)
{
LOG_INFO("server.loading", "Re-Loading Spell Bonus Data...");
sSpellMgr->LoadSpellBonusess();
sSpellMgr->LoadSpellBonuses();
handler->SendGlobalGMSysMessage("DB table `spell_bonus_data` (spell damage/healing coefficients) reloaded.");
return true;
}
@@ -46,7 +46,7 @@ enum Spells
// ***** Main Phase 2 ******
//Body spells
//SPELL_CARAPACE_CTHUN = 26156 //Was removed from client dbcs
SPELL_CARAPACE_CTHUN = 26156, // Server-side
SPELL_TRANSFORM = 26232,
SPELL_PURPLE_COLORATION = 22581, //Probably not the right spell but looks similar
@@ -69,7 +69,12 @@ enum Spells
// Tentacles
SPELL_SUBMERGE_VISUAL = 26234,
SPELL_BIRTH = 26262
SPELL_BIRTH = 26262,
// Areatriggers
SPELL_SPIT_OUT = 25383,
SPELL_EXIT_STOMACH = 26221,
SPELL_RUBBLE_ROCKY = 26271
};
enum Actions
@@ -77,12 +82,24 @@ enum Actions
ACTION_FLESH_TENTACLE_KILLED = 1,
ACTION_SPAWN_EYE_TENTACLES = 1,
ACTION_START_PHASE_TWO = 1,
};
enum TaskGroups
{
GROUP_BEAM_PHASE = 1
};
enum Phases
{
PHASE_BODY = 2
};
enum Misc
{
MAX_TENTACLE_GROUPS = 5,
GROUP_BEAM_PHASE = 1
NPC_TRIGGER = 15384,
};
enum Yells
@@ -128,7 +145,7 @@ const Position KickPos = { -8545.0f, 1984.0f, -96.0f, 0.0f};
struct boss_eye_of_cthun : public BossAI
{
boss_eye_of_cthun(Creature* creature) : BossAI(creature, DATA_CTHUN), _summons(creature)
boss_eye_of_cthun(Creature* creature) : BossAI(creature, DATA_CTHUN)
{
SetCombatMovement(false);
}
@@ -143,8 +160,6 @@ struct boss_eye_of_cthun : public BossAI
_eyeTentacleCounter = 0;
//Reset flags
me->RemoveAurasDueToSpell(SPELL_RED_COLORATION);
me->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
me->SetVisible(true);
@@ -156,19 +171,23 @@ struct boss_eye_of_cthun : public BossAI
if (pPortal)
pPortal->SetReactState(REACT_PASSIVE);
_summons.DespawnAll();
_scheduler.CancelAll();
BossAI::Reset();
}
void JustDied(Unit* /*killer*/) override { }
void JustDied(Unit* /*killer*/) override
{
if (Creature* cthun = instance->GetCreature(DATA_CTHUN))
{
cthun->AI()->DoAction(ACTION_START_PHASE_TWO);
}
}
void EnterCombat(Unit* who) override
{
DoZoneInCombat();
ScheduleTasks();
instance->SetData(DATA_CTHUN_PHASE, PHASE_EYE_GREEN_BEAM);
BossAI::EnterCombat(who);
}
@@ -294,39 +313,12 @@ struct boss_eye_of_cthun : public BossAI
});
}
void JustSummoned(Creature* summon) override
{
_summons.Summon(summon);
summon->SetInCombatWithZone();
}
void UpdateAI(uint32 diff) override
{
//Check if we have a target
if (!UpdateVictim())
return;
switch (instance->GetData(DATA_CTHUN_PHASE))
{
//Transition phase
case PHASE_CTHUN_TRANSITION:
//Remove any target
me->SetTarget();
me->SetHealth(0);
me->SetVisible(false);
break;
//Dead phase
case PHASE_CTHUN_DONE:
if (Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10))
{
pPortal->DespawnOrUnsummon();
}
me->DespawnOrUnsummon();
break;
}
_scheduler.Update(diff);
}
@@ -352,15 +344,18 @@ struct boss_eye_of_cthun : public BossAI
//Remove Target field
me->SetTarget();
//Death animation/respawning;
instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_TRANSITION);
me->SetHealth(0);
damage = 0;
me->InterruptNonMeleeSpells(true);
me->RemoveAllAuras();
_scheduler.CancelAll();
if (Creature* cthun = instance->GetCreature(DATA_CTHUN))
{
cthun->AI()->DoAction(ACTION_START_PHASE_TWO);
}
break;
case PHASE_CTHUN_DONE:
@@ -382,7 +377,6 @@ private:
uint32 _eyeTentacleCounter;
TaskScheduler _scheduler;
SummonList _summons;
};
struct boss_cthun : public BossAI
@@ -392,60 +386,19 @@ struct boss_cthun : public BossAI
SetCombatMovement(false);
}
//Out of combat whisper timer
uint32 WisperTimer;
//Global variables
uint32 PhaseTimer;
//-------------------
//Phase transition
ObjectGuid HoldPlayer;
//Body Phase
uint32 EyeTentacleTimer;
uint8 FleshTentaclesKilled;
uint32 GiantClawTentacleTimer;
uint32 GiantEyeTentacleTimer;
uint32 StomachAcidTimer;
uint32 StomachEnterTimer;
uint32 StomachEnterVisTimer;
ObjectGuid StomachEnterTarget;
//Stomach map, bool = true then in stomach
std::unordered_map<ObjectGuid, bool> Stomach_Map;
void Reset() override
{
//One random wisper every 90 - 300 seconds
WisperTimer = 90000;
//Phase information
PhaseTimer = 10000; //Emerge in 10 seconds
//No hold player for transition
HoldPlayer.Clear();
//Body Phase
EyeTentacleTimer = 30000;
FleshTentaclesKilled = 0;
GiantClawTentacleTimer = 15000; //15 seconds into body phase (1 min repeat)
GiantEyeTentacleTimer = 45000; //15 seconds into body phase (1 min repeat)
StomachAcidTimer = 4000; //Every 4 seconds
StomachEnterTimer = 10000; //Every 10 seconds
StomachEnterVisTimer = 0; //Always 3.5 seconds after Stomach Enter Timer
StomachEnterTarget.Clear(); //Target to be teleported to stomach
//Clear players in stomach and outside
Stomach_Map.clear();
_fleshTentaclesKilled = 0;
//Reset flags
me->RemoveAurasDueToSpell(SPELL_TRANSFORM);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
me->SetVisible(false);
instance->SetData(DATA_CTHUN_PHASE, PHASE_NOT_STARTED);
BossAI::Reset();
_scheduler.CancelAll();
}
void EnterCombat(Unit* /*who*/) override
@@ -453,39 +406,80 @@ struct boss_cthun : public BossAI
DoZoneInCombat();
}
Unit* SelectRandomNotStomach()
void DoAction(int32 actionId) override
{
if (Stomach_Map.empty())
return nullptr;
std::unordered_map<ObjectGuid, bool>::const_iterator i = Stomach_Map.begin();
std::list<Unit*> temp;
std::list<Unit*>::const_iterator j;
//Get all players in map
while (i != Stomach_Map.end())
if (actionId == ACTION_START_PHASE_TWO)
{
//Check for valid player
Unit* unit = ObjectAccessor::GetUnit(*me, i->first);
// Animation only plays if Cthun already has this aura...
DoCastSelf(SPELL_TRANSFORM);
//Only units out of stomach
if (unit && !i->second)
temp.push_back(unit);
me->m_Events.AddEventAtOffset([this]()
{
DoCastSelf(SPELL_TRANSFORM);
DoCastSelf(SPELL_CARAPACE_CTHUN, true);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
DoZoneInCombat();
}, 500ms);
++i;
//Spawn flesh tentacle
for (uint8 i = 0; i < 2; i++)
{
me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN);
}
ScheduleTasks();
}
}
if (temp.empty())
return nullptr;
void ScheduleTasks()
{
_scheduler.Schedule(13800ms, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID))
{
target->CastSpell(target, SPELL_MOUTH_TENTACLE, true);
j = temp.begin();
target->m_Events.AddEventAtOffset([target, this]()
{
DoTeleportPlayer(target, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O);
target->RemoveAurasDueToSpell(SPELL_MIND_FLAY);
//Cast digestive acid on them
DoCast(target, SPELL_DIGESTIVE_ACID, true);
}, 3800ms);
}
//Get random but only if we have more than one unit on threat list
if (temp.size() > 1)
advance(j, rand() % (temp.size() - 1));
context.Repeat();
}).Schedule(30s, [this](TaskContext context)
{
if (Creature* eye = instance->GetCreature(DATA_EYE_OF_CTHUN))
{
eye->AI()->DoAction(ACTION_SPAWN_EYE_TENTACLES);
}
return (*j);
context.Repeat(30s);
}).Schedule(15s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID))
{
//Spawn claw tentacle on the random target
if (Creature* spawned = me->SummonCreature(NPC_GIANT_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
if (spawned->AI())
spawned->AI()->AttackStart(target);
}
context.Repeat(1min);
}).Schedule(15s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID))
{
//Spawn claw tentacle on the random target
if (Creature* spawned = me->SummonCreature(NPC_GIANT_EYE_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
if (spawned->AI())
spawned->AI()->AttackStart(target);
}
context.Repeat(1min);
});
}
void UpdateAI(uint32 diff) override
@@ -523,277 +517,16 @@ struct boss_cthun : public BossAI
me->SetTarget();
uint32 currentPhase = instance->GetData(DATA_CTHUN_PHASE);
if (currentPhase == PHASE_CTHUN_STOMACH || currentPhase == PHASE_CTHUN_WEAK)
{
// EyeTentacleTimer
if (EyeTentacleTimer <= diff)
{
if (Creature* eye = instance->GetCreature(DATA_EYE_OF_CTHUN))
{
eye->AI()->DoAction(ACTION_SPAWN_EYE_TENTACLES);
}
EyeTentacleTimer = 30000; // every 30sec in phase 2
}
else EyeTentacleTimer -= diff;
}
switch (currentPhase)
{
//Transition phase
case PHASE_CTHUN_TRANSITION:
//PhaseTimer
if (PhaseTimer <= diff)
{
//Switch
instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH);
//Switch to c'thun model
me->InterruptNonMeleeSpells(false);
DoCast(me, SPELL_TRANSFORM, false);
me->SetFullHealth();
me->SetVisible(true);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
//Emerging phase
//AttackStart(ObjectAccessor::GetUnit(*me, HoldpPlayer));
DoZoneInCombat();
//Place all units in threat list on outside of stomach
Stomach_Map.clear();
for (std::list<HostileReference*>::const_iterator i = me->GetThreatMgr().getThreatList().begin(); i != me->GetThreatMgr().getThreatList().end(); ++i)
Stomach_Map[(*i)->getUnitGuid()] = false; //Outside stomach
//Spawn 2 flesh tentacles
FleshTentaclesKilled = 0;
//Spawn flesh tentacle
for (uint8 i = 0; i < 2; i++)
{
Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN);
if (!spawned)
++FleshTentaclesKilled;
}
PhaseTimer = 0;
}
else PhaseTimer -= diff;
break;
//Body Phase
case PHASE_CTHUN_STOMACH:
//Remove Target field
me->SetTarget();
//Weaken
if (FleshTentaclesKilled > 1)
{
instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_WEAK);
Talk(EMOTE_WEAKENED);
PhaseTimer = 45000;
DoCast(me, SPELL_PURPLE_COLORATION, true);
std::unordered_map<ObjectGuid, bool>::iterator i = Stomach_Map.begin();
//Kick all players out of stomach
while (i != Stomach_Map.end())
{
//Check for valid player
Unit* unit = ObjectAccessor::GetUnit(*me, i->first);
//Only move units in stomach
if (unit && i->second)
{
//Teleport each player out
DoTeleportPlayer(unit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10, float(rand() % 6));
//Cast knockback on them
DoCast(unit, SPELL_EXIT_STOMACH_KNOCKBACK, true);
//Remove the acid debuff
unit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID);
i->second = false;
}
++i;
}
return;
}
//Stomach acid
if (StomachAcidTimer <= diff)
{
//Apply aura to all players in stomach
std::unordered_map<ObjectGuid, bool>::iterator i = Stomach_Map.begin();
while (i != Stomach_Map.end())
{
//Check for valid player
Unit* unit = ObjectAccessor::GetUnit(*me, i->first);
//Only apply to units in stomach
if (unit && i->second)
{
//Cast digestive acid on them
DoCast(unit, SPELL_DIGESTIVE_ACID, true);
//Check if player should be kicked from stomach
if (unit->IsWithinDist3d(&KickPos, 15.0f))
{
//Teleport each player out
DoTeleportPlayer(unit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10, float(rand() % 6));
//Cast knockback on them
DoCast(unit, SPELL_EXIT_STOMACH_KNOCKBACK, true);
//Remove the acid debuff
unit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID);
i->second = false;
}
}
++i;
}
StomachAcidTimer = 4000;
}
else StomachAcidTimer -= diff;
//Stomach Enter Timer
if (StomachEnterTimer <= diff)
{
if (Unit* target = SelectRandomNotStomach())
{
//Set target in stomach
Stomach_Map[target->GetGUID()] = true;
target->InterruptNonMeleeSpells(false);
target->CastSpell(target, SPELL_MOUTH_TENTACLE, true, nullptr, nullptr, me->GetGUID());
StomachEnterTarget = target->GetGUID();
StomachEnterVisTimer = 3800;
}
StomachEnterTimer = 13800;
}
else StomachEnterTimer -= diff;
if (StomachEnterVisTimer && StomachEnterTarget)
{
if (StomachEnterVisTimer <= diff)
{
//Check for valid player
Unit* unit = ObjectAccessor::GetUnit(*me, StomachEnterTarget);
if (unit)
{
DoTeleportPlayer(unit, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O);
}
StomachEnterTarget.Clear();
StomachEnterVisTimer = 0;
}
else StomachEnterVisTimer -= diff;
}
//GientClawTentacleTimer
if (GiantClawTentacleTimer <= diff)
{
if (Unit* target = SelectRandomNotStomach())
{
//Spawn claw tentacle on the random target
if (Creature* spawned = me->SummonCreature(NPC_GIANT_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
if (spawned->AI())
spawned->AI()->AttackStart(target);
}
//One giant claw tentacle every minute
GiantClawTentacleTimer = 60000;
}
else GiantClawTentacleTimer -= diff;
//GiantEyeTentacleTimer
if (GiantEyeTentacleTimer <= diff)
{
if (Unit* target = SelectRandomNotStomach())
{
//Spawn claw tentacle on the random target
if (Creature* spawned = me->SummonCreature(NPC_GIANT_EYE_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
if (spawned->AI())
spawned->AI()->AttackStart(target);
}
//One giant eye tentacle every minute
GiantEyeTentacleTimer = 60000;
}
else GiantEyeTentacleTimer -= diff;
break;
//Weakened state
case PHASE_CTHUN_WEAK:
//PhaseTimer
if (PhaseTimer <= diff)
{
//Switch
instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH);
//Remove purple coloration
me->RemoveAurasDueToSpell(SPELL_PURPLE_COLORATION);
//Spawn 2 flesh tentacles
FleshTentaclesKilled = 0;
//Spawn flesh tentacle
for (uint8 i = 0; i < 2; i++)
{
Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN);
if (!spawned)
++FleshTentaclesKilled;
}
PhaseTimer = 0;
}
else PhaseTimer -= diff;
break;
}
_scheduler.Update(diff);
}
void JustDied(Unit* killer) override
{
instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_DONE);
BossAI::JustDied(killer);
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
switch (instance->GetData(DATA_CTHUN_PHASE))
if (Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10.0f))
{
case PHASE_CTHUN_STOMACH:
//Not weakened so reduce damage by 99%
damage /= 100;
if (damage == 0)
damage = 1;
//Prevent death in non-weakened state
if (damage >= me->GetHealth())
damage = 0;
return;
case PHASE_CTHUN_WEAK:
//Weakened - takes normal damage
return;
default:
damage = 0;
break;
pPortal->DespawnOrUnsummon();
}
}
@@ -801,9 +534,42 @@ struct boss_cthun : public BossAI
{
if (creature->GetEntry() == NPC_FLESH_TENTACLE)
{
++FleshTentaclesKilled;
++_fleshTentaclesKilled;
if (_fleshTentaclesKilled > 1)
{
_scheduler.CancelAll();
_fleshTentaclesKilled = 0;
Talk(EMOTE_WEAKENED);
DoCast(me, SPELL_PURPLE_COLORATION, true);
me->RemoveAurasDueToSpell(SPELL_CARAPACE_CTHUN);
_scheduler.Schedule(45s, [this](TaskContext /*context*/)
{
ScheduleTasks();
//Remove purple coloration
me->RemoveAurasDueToSpell(SPELL_PURPLE_COLORATION);
//Spawn flesh tentacle
for (uint8 i = 0; i < 2; i++)
{
me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN);
}
});
}
}
}
private:
//Out of combat whisper timer
uint32 WisperTimer;
//Body Phase
uint8 _fleshTentaclesKilled;
TaskScheduler _scheduler;
};
struct npc_eye_tentacle : public ScriptedAI
@@ -968,6 +734,8 @@ struct npc_giant_claw_tentacle : public ScriptedAI
DoCastSelf(SPELL_THRASH);
context.Repeat(10s);
});
ScheduleMeleeCheck();
}
void ScheduleMeleeCheck()
@@ -1113,6 +881,65 @@ private:
ObjectGuid _portalGUID;
};
// 4033 - At C'thun's stomach
class at_cthun_stomach_exit : public AreaTriggerScript
{
public:
at_cthun_stomach_exit() : AreaTriggerScript("at_cthun_stomach_exit") { }
bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
{
if (Creature* cthun = instance->GetCreature(DATA_CTHUN))
{
player->CastSpell(player, SPELL_RUBBLE_ROCKY, true);
player->m_Events.AddEventAtOffset([player]()
{
if (Creature* trigger = player->FindNearestCreature(NPC_TRIGGER, 15.0f))
{
trigger->CastSpell(player, SPELL_EXIT_STOMACH, true);
}
}, 3s);
player->m_Events.AddEventAtOffset([player]()
{
player->JumpTo(0.0f, 80.0f, false);
}, 5s);
player->m_Events.AddEventAtOffset([player, cthun]()
{
if (cthun)
{
player->NearTeleportTo(cthun->GetPositionX(), cthun->GetPositionY(), cthun->GetPositionZ() + 10, float(rand32() % 6));
}
player->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID);
}, 6s);
}
}
return true;
}
};
class at_cthun_center : public AreaTriggerScript
{
public:
at_cthun_center() : AreaTriggerScript("at_cthun_center") { }
bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override
{
if (Creature* trigger = player->FindNearestCreature(NPC_TRIGGER, 15.0f))
{
trigger->CastSpell(player, SPELL_SPIT_OUT, true);
}
return true;
}
};
void AddSC_boss_cthun()
{
RegisterTempleOfAhnQirajCreatureAI(boss_eye_of_cthun);
@@ -1121,4 +948,6 @@ void AddSC_boss_cthun()
RegisterTempleOfAhnQirajCreatureAI(npc_claw_tentacle);
RegisterTempleOfAhnQirajCreatureAI(npc_giant_claw_tentacle);
RegisterTempleOfAhnQirajCreatureAI(npc_giant_eye_tentacle);
new at_cthun_stomach_exit();
new at_cthun_center();
}
@@ -23,6 +23,7 @@
ObjectData const creatureData[] =
{
{ NPC_SARTURA, DATA_SARTURA },
{ NPC_CTHUN, DATA_CTHUN },
{ NPC_EYE_OF_CTHUN, DATA_EYE_OF_CTHUN },
{ NPC_OURO_SPAWNER, DATA_OURO_SPAWNER },
{ NPC_MASTERS_EYE, DATA_MASTERS_EYE },
+2 -2
View File
@@ -569,7 +569,7 @@ class spell_dru_lifebloom : public AuraScript
if (Unit* caster = GetCaster())
{
healAmount = caster->SpellHealingBonusDone(GetTarget(), finalHeal, healAmount, HEAL, 0.0f, stack);
healAmount = caster->SpellHealingBonusDone(GetTarget(), finalHeal, healAmount, HEAL, aurEff->GetEffIndex(), 0.0f, stack);
healAmount = GetTarget()->SpellHealingBonusTaken(caster, finalHeal, healAmount, HEAL, stack);
// restore mana
int32 returnmana = (GetSpellInfo()->ManaCostPercentage * caster->GetCreateMana() / 100) * stack / 2;
@@ -590,7 +590,7 @@ class spell_dru_lifebloom : public AuraScript
if (caster)
{
// healing with bonus
healAmount = caster->SpellHealingBonusDone(target, finalHeal, healAmount, HEAL, 0.0f, dispelInfo->GetRemovedCharges());
healAmount = caster->SpellHealingBonusDone(target, finalHeal, healAmount, HEAL, EFFECT_1, 0.0f, dispelInfo->GetRemovedCharges());
healAmount = target->SpellHealingBonusTaken(caster, finalHeal, healAmount, HEAL, dispelInfo->GetRemovedCharges());
// mana amount
+4 -4
View File
@@ -525,12 +525,12 @@ class spell_sha_earth_shield : public AuraScript
return ValidateSpellInfo({ SPELL_SHAMAN_EARTH_SHIELD_HEAL, SPELL_SHAMAN_GLYPH_OF_EARTH_SHIELD });
}
void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
{
if (Unit* caster = GetCaster())
{
int32 baseAmount = amount;
amount = caster->SpellHealingBonusDone(GetUnitOwner(), GetSpellInfo(), amount, HEAL);
amount = caster->SpellHealingBonusDone(GetUnitOwner(), GetSpellInfo(), amount, HEAL, aurEff->GetEffIndex());
// xinef: taken should be calculated at every heal
//amount = GetUnitOwner()->SpellHealingBonusTaken(caster, GetSpellInfo(), amount, HEAL);
@@ -782,7 +782,7 @@ class spell_sha_healing_stream_totem : public SpellScript
return ValidateSpellInfo({ SPELL_SHAMAN_GLYPH_OF_HEALING_STREAM_TOTEM, SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL });
}
void HandleDummy(SpellEffIndex /*effIndex*/)
void HandleDummy(SpellEffIndex effIndex)
{
int32 damage = GetEffectValue();
SpellInfo const* triggeringSpell = GetTriggeringSpell();
@@ -792,7 +792,7 @@ class spell_sha_healing_stream_totem : public SpellScript
if (Unit* owner = caster->GetOwner())
{
if (triggeringSpell)
damage = int32(owner->SpellHealingBonusDone(target, triggeringSpell, damage, HEAL));
damage = int32(owner->SpellHealingBonusDone(target, triggeringSpell, damage, HEAL, effIndex));
// Restorative Totems
if (AuraEffect* dummy = owner->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, SHAMAN_ICON_ID_RESTORATIVE_TOTEMS, 1))
+2 -2
View File
@@ -456,14 +456,14 @@ class spell_warr_bloodthirst : public SpellScript
return ValidateSpellInfo({ SPELL_WARRIOR_BLOODTHIRST });
}
void HandleDamage(SpellEffIndex /*effIndex*/)
void HandleDamage(SpellEffIndex effIndex)
{
int32 damage = GetEffectValue();
ApplyPct(damage, GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK));
if (Unit* target = GetHitUnit())
{
damage = GetCaster()->SpellDamageBonusDone(target, GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE);
damage = GetCaster()->SpellDamageBonusDone(target, GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE, effIndex);
damage = target->SpellDamageBonusTaken(GetCaster(), GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE);
}
SetHitDamage(damage);