diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 06d549e77..34bcd6336 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -69,7 +69,8 @@ body: attributes: label: Operating system description: | - Operating System, i.e. Windows 10 x64, Debian 10 x64, etc + The Operating System the Server is running on. + i.e. Windows 11 x64, Debian 10 x64, macOS 12, Ubuntu 20.04 validations: required: true - type: textarea diff --git a/data/sql/updates/db_world/2023_04_02_00.sql b/data/sql/updates/db_world/2023_04_02_00.sql new file mode 100644 index 000000000..d141681de --- /dev/null +++ b/data/sql/updates/db_world/2023_04_02_00.sql @@ -0,0 +1,6 @@ +-- DB update 2023_04_01_02 -> 2023_04_02_00 +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 2202300); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2202300, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 19, 22160, 50, 0, 0, 0, 0, 0, 0, '[DND]Spirit 1 - Actionlist - Move To Closest Creature \'Bloodmaul Taskmaster\''), +(2202300, 9, 1, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '[DND]Spirit 1 - Actionlist - Move To Invoker'), +(2202300, 9, 2, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 33, 22383, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '[DND]Spirit 1 - Actionlist - Quest Credit \'On Spirit\'s Wings\''); diff --git a/data/sql/updates/db_world/2023_04_02_01.sql b/data/sql/updates/db_world/2023_04_02_01.sql new file mode 100644 index 000000000..8135446c1 --- /dev/null +++ b/data/sql/updates/db_world/2023_04_02_01.sql @@ -0,0 +1,24 @@ +-- DB update 2023_04_02_00 -> 2023_04_02_01 +-- Mote of Shadow +DELETE FROM `creature_loot_template` WHERE `Item` = 22577; +INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(16974, 22577, 0, 20, 0, 1, 0, 1, 1, 'Rogue Voidwalker - Mote of Shadow'), +(16975, 22577, 0, 20, 0, 1, 0, 1, 1, 'Uncontrolled Voidwalker - Mote of Shadow'), +(17014, 22577, 0, 20, 0, 1, 0, 1, 2, 'Collapsing Voidwalker - Mote of Shadow'), +(17981, 22577, 0, 18.6912, 0, 1, 0, 1, 2, 'Voidspawn - Mote of Shadow'), +(18683, 22577, 0, 25, 0, 1, 0, 1, 2, 'Voidhunter Yar - Mote of Shadow'), +(18869, 22577, 0, 1.0615, 0, 1, 0, 1, 2, 'Unstable Voidwraith - Mote of Shadow'), +(18870, 22577, 0, 1.0194, 0, 1, 0, 1, 2, 'Voidshrieker - Mote of Shadow'), +(19307, 22577, 0, 17.8397, 0, 1, 0, 1, 4, 'Nexus Terror - Mote of Shadow'), +(19527, 22577, 0, 20, 0, 1, 0, 1, 2, 'Vacillating Voidcaller - Mote of Shadow'), +(19554, 22577, 0, 60, 0, 1, 0, 2, 4, 'Dimensius the All-Devouring - Mote of Shadow'), +(20554, 22577, 0, 26.6608, 0, 1, 0, 1, 2, 'Arconus the Insatiable - Mote of Shadow'), +(20873, 22577, 0, 31.15, 0, 1, 0, 2, 4, 'Negaton Warp-Master - Mote of Shadow'), +(20875, 22577, 0, 30.59, 0, 1, 0, 2, 4, 'Negaton Screamer - Mote of Shadow'), +(22295, 22577, 0, 27.0833, 0, 1, 0, 2, 4, 'Deathforge Automaton - Mote of Shadow'), +(22301, 22577, 0, 37.8378, 0, 1, 0, 1, 2, 'Throne-Guard Sentinel - Mote of Shadow'), +-- Previously missing, from TrinityCore +(19299, 22577, 0, 42.4242, 0, 1, 0, 2, 4,'Deathwhisperer - Mote of Shadow'), +(20870, 22577, 0, 15, 0, 1, 0, 2, 4, 'Zereketh the Unbound - Mote of Shadow'), +(18341, 22577, 0, 15, 0, 1, 0, 2, 4, 'Pandemonius - Mote of Shadow'), +(19354, 22577, 0, 19.0751, 0, 1, 0, 2, 4, 'Arzeth the Merciless - Mote of Shadow'); diff --git a/data/sql/updates/db_world/2023_04_02_02.sql b/data/sql/updates/db_world/2023_04_02_02.sql new file mode 100644 index 000000000..77689ee88 --- /dev/null +++ b/data/sql/updates/db_world/2023_04_02_02.sql @@ -0,0 +1,2 @@ +-- DB update 2023_04_02_01 -> 2023_04_02_02 +UPDATE `smart_scripts` SET `event_type` = 25 AND `comment` = 'Arcatraz Sentinel - On Reset - Set Health 40%' WHERE `source_type` = 0 AND `entryorguid` = 20869 AND `id` = 0; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 4548a76ea..d9ebd3c26 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -2101,34 +2101,52 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= nullptr*/) { // not need after this call if (owner->ToPlayer()->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) + { owner->ToPlayer()->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS, true); + } // reset for online if (onlinePet) + { onlinePet->resetTalents(); + } PetStable* petStable = owner->GetPetStable(); if (!petStable) + { return; + } std::unordered_set petIds; if (petStable->CurrentPet) + { petIds.insert(petStable->CurrentPet->PetNumber); + } for (Optional const& stabledPet : petStable->StabledPets) + { if (stabledPet) + { petIds.insert(stabledPet->PetNumber); + } + } for (PetStable::PetInfo const& unslottedPet : petStable->UnslottedPets) + { petIds.insert(unslottedPet.PetNumber); + } // now need only reset for offline pets (all pets except online case) if (onlinePet) + { petIds.erase(onlinePet->GetCharmInfo()->GetPetNumber()); + } // no offline pets - if (!petIds.empty()) + if (petIds.empty()) + { return; + } bool need_comma = false; std::ostringstream ss; @@ -2137,7 +2155,9 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= nullptr*/) for (uint32 id : petIds) { if (need_comma) + { ss << ','; + } ss << id; @@ -2150,7 +2170,9 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= nullptr*/) for (uint32 spell : sPetTalentSpells) { if (need_comma) + { ss << ','; + } ss << spell; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 042081b8b..7f239d321 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -6498,11 +6498,12 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType } //victim may be nullptr -bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc /*= nullptr*/) +bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, ProcEventInfo const& eventInfo) { SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo(); uint32 effIndex = triggeredByAura->GetEffIndex(); int32 triggerAmount = triggeredByAura->GetAmount(); + Spell const* spellProc = eventInfo.GetProcSpell(); Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : nullptr; @@ -7864,12 +7865,22 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (!procSpell || !procSpell->IsPositive()) return false; - // heal amount - basepoints0 = int32(CalculatePct(std::min(damage, GetMaxHealth() - GetHealth()), triggerAmount)); - target = this; + HealInfo const* healInfo = eventInfo.GetHealInfo(); + if (!healInfo) + { + return false; + } - if (basepoints0) - triggered_spell_id = 31786; + uint32 effectiveHeal = healInfo->GetEffectiveHeal(); + if (effectiveHeal) + { + // heal amount + basepoints0 = int32(CalculatePct(effectiveHeal, triggerAmount)); + target = this; + + if (basepoints0) + triggered_spell_id = 31786; + } break; } // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal) @@ -11202,16 +11213,18 @@ void Unit::UnsummonAllTotems(bool onDeath /*= false*/) } } -void Unit::SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical) +void Unit::SendHealSpellLog(HealInfo const& healInfo, bool critical) { + uint32 overheal = healInfo.GetHeal() - healInfo.GetEffectiveHeal(); + // we guess size WorldPacket data(SMSG_SPELLHEALLOG, (8 + 8 + 4 + 4 + 4 + 4 + 1 + 1)); - data << victim->GetPackGUID(); + data << healInfo.GetTarget()->GetPackGUID(); data << GetPackGUID(); - data << uint32(SpellID); - data << uint32(Damage); - data << uint32(OverHeal); - data << uint32(Absorb); // Absorb amount + data << uint32(healInfo.GetSpellInfo()->Id); + data << uint32(healInfo.GetHeal()); + data << uint32(overheal); + data << uint32(healInfo.GetAbsorb()); // Absorb amount data << uint8(critical ? 1 : 0); data << uint8(0); // unused SendMessageToSet(&data, true); @@ -11227,7 +11240,9 @@ int32 Unit::HealBySpell(HealInfo& healInfo, bool critical) CalcHealAbsorb(healInfo); int32 gain = Unit::DealHeal(healInfo.GetHealer(), healInfo.GetTarget(), healInfo.GetHeal()); - SendHealSpellLog(healInfo.GetTarget(), healInfo.GetSpellInfo()->Id, healInfo.GetHeal(), uint32(healInfo.GetHeal() - gain), healInfo.GetAbsorb(), critical); + healInfo.SetEffectiveHeal(gain); + + SendHealSpellLog(healInfo, critical); return gain; } @@ -16555,7 +16570,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u case SPELL_AURA_DUMMY: { LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} dummy aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); - if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procSpell)) + if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, eventInfo)) takeCharges = true; break; } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index ae8eae814..2081b013f 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -806,6 +806,7 @@ private: Unit* const m_healer; Unit* const m_target; uint32 m_heal; + uint32 m_effectiveHeal; uint32 m_absorb; SpellInfo const* const m_spellInfo; SpellSchoolMask const m_schoolMask; @@ -814,12 +815,17 @@ public: : m_healer(_healer), m_target(_target), m_heal(_heal), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask) { m_absorb = 0; + m_effectiveHeal = 0; } + void AbsorbHeal(uint32 amount) { amount = std::min(amount, GetHeal()); m_absorb += amount; m_heal -= amount; + + amount = std::min(amount, GetEffectiveHeal()); + m_effectiveHeal -= amount; } void SetHeal(uint32 amount) @@ -827,9 +833,15 @@ public: m_heal = amount; } + void SetEffectiveHeal(uint32 amount) + { + m_effectiveHeal = amount; + } + [[nodiscard]] Unit* GetHealer() const { return m_healer; } [[nodiscard]] Unit* GetTarget() const { return m_target; } [[nodiscard]] uint32 GetHeal() const { return m_heal; } + [[nodiscard]] uint32 GetEffectiveHeal() const { return m_effectiveHeal; } [[nodiscard]] uint32 GetAbsorb() const { return m_absorb; } [[nodiscard]] SpellInfo const* GetSpellInfo() const { return m_spellInfo; }; [[nodiscard]] SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }; @@ -1724,7 +1736,7 @@ public: [[nodiscard]] virtual bool IsUnderWater() const; bool isInAccessiblePlaceFor(Creature const* c) const; - void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false); + void SendHealSpellLog(HealInfo const& healInfo, bool critical = false); int32 HealBySpell(HealInfo& healInfo, bool critical = false); void SendEnergizeSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); void EnergizeBySpell(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); @@ -2551,7 +2563,7 @@ protected: private: bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo); - bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc = nullptr); + bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, ProcEventInfo const& eventInfo); bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled); bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo); bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 197a17fe8..a9d12efde 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -6626,8 +6626,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const HealInfo healInfo(caster, target, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); Unit::CalcHealAbsorb(healInfo); int32 gain = Unit::DealHeal(caster, target, healInfo.GetHeal()); + healInfo.SetEffectiveHeal(gain); - SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - gain, healInfo.GetAbsorb(), 0, 0.0f, crit); + SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit); target->SendPeriodicAuraLog(&pInfo); if (caster) diff --git a/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_talon_king_ikiss.cpp b/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_talon_king_ikiss.cpp index 521854100..f09f4262a 100644 --- a/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_talon_king_ikiss.cpp +++ b/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_talon_king_ikiss.cpp @@ -43,7 +43,7 @@ enum Spells struct boss_talon_king_ikiss : public BossAI { - boss_talon_king_ikiss(Creature* creature) : BossAI(creature, DATA_IKISS), _spoken(false), _manaShield(false) + boss_talon_king_ikiss(Creature* creature) : BossAI(creature, DATA_IKISS), _spoken(false) { scheduler.SetValidator([this] { @@ -55,8 +55,44 @@ struct boss_talon_king_ikiss : public BossAI { _Reset(); _spoken = false; - _manaShield = false; - _comboHealthStages.fill(false); + + ScheduleHealthCheckEvent(80, [&] { + TeleportAndCastExplosion(); + }); + + ScheduleHealthCheckEvent(50, [&] { + TeleportAndCastExplosion(); + }); + + ScheduleHealthCheckEvent(25, [&] { + TeleportAndCastExplosion(); + }); + + ScheduleHealthCheckEvent(20, [&] { + DoCast(me, SPELL_MANA_SHIELD); + }); + } + + /// @todo: remove this once pets stop going through doors. + bool CanAIAttack(Unit const* /*victim*/) const override + { + return _spoken; + } + + void TeleportAndCastExplosion() + { + me->InterruptNonMeleeSpells(false); + DoCastSelf(SPELL_ARCANE_BUBBLE, true); + DoCastAOE(SPELL_BLINK); + Talk(EMOTE_ARCANE_EXP); + + scheduler.Schedule(1s, [this](TaskContext) + { + DoCastAOE(SPELL_ARCANE_EXPLOSION); + }).Schedule(6500ms, [this](TaskContext /*context*/) + { + me->GetThreatMgr().ResetAllThreat(); + }); } void MoveInLineOfSight(Unit* who) override @@ -106,69 +142,6 @@ struct boss_talon_king_ikiss : public BossAI } } - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override - { - if (!_comboHealthStages[0] && me->HealthBelowPctDamaged(80, damage)) - { - _comboHealthStages[0] = true; - - me->InterruptNonMeleeSpells(false); - DoCastSelf(SPELL_ARCANE_BUBBLE, true); - DoCastAOE(SPELL_BLINK); - Talk(EMOTE_ARCANE_EXP); - - scheduler.Schedule(1s, [this](TaskContext) - { - DoCastAOE(SPELL_ARCANE_EXPLOSION); - }).Schedule(6500ms, [this](TaskContext /*context*/) - { - me->GetThreatMgr().ResetAllThreat(); - }); - } - - if (!_comboHealthStages[1] && me->HealthBelowPctDamaged(50, damage)) - { - _comboHealthStages[1] = true; - - me->InterruptNonMeleeSpells(false); - DoCastSelf(SPELL_ARCANE_BUBBLE, true); - DoCastAOE(SPELL_BLINK); - Talk(EMOTE_ARCANE_EXP); - - scheduler.Schedule(1s, [this](TaskContext) - { - DoCastAOE(SPELL_ARCANE_EXPLOSION); - }).Schedule(6500ms, [this](TaskContext /*context*/) - { - me->GetThreatMgr().ResetAllThreat(); - }); - } - - if (!_comboHealthStages[2] && me->HealthBelowPctDamaged(25, damage)) - { - _comboHealthStages[2] = true; - - me->InterruptNonMeleeSpells(false); - DoCastSelf(SPELL_ARCANE_BUBBLE, true); - DoCastAOE(SPELL_BLINK); - Talk(EMOTE_ARCANE_EXP); - - scheduler.Schedule(1s, [this](TaskContext) - { - DoCastAOE(SPELL_ARCANE_EXPLOSION); - }).Schedule(6500ms, [this](TaskContext /*context*/) - { - me->GetThreatMgr().ResetAllThreat(); - }); - } - - if (!_manaShield && me->HealthBelowPctDamaged(20, damage)) - { - DoCast(me, SPELL_MANA_SHIELD); - _manaShield = true; - } - } - void KilledUnit(Unit* /*victim*/) override { if (urand(0, 1)) @@ -177,8 +150,6 @@ struct boss_talon_king_ikiss : public BossAI private: bool _spoken; - bool _manaShield; - std::array _comboHealthStages; }; // 38194 - Blink