From e09a8f8f8f225cac9e1201168d306ac92a69576a Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 19 Jan 2022 22:44:17 -0500 Subject: [PATCH] [Spells] Support for bards using Disciplines while casting or /melody. (#1936) * test * complete * Update effects.cpp * Update spells.cpp * Update effects.cpp * [Spells] Support for bards using Disciplines while casting or /melody. Support for spell field 'cast not standing' not allow casting from divine aura * [Spells] Support for bards using Disciplines while casting or /melody. DA bypass logic for spells with field 'cast_not_standing' --- zone/effects.cpp | 45 ++++++++++++++++++++++++++++++++------------ zone/mob.h | 4 ++-- zone/spells.cpp | 49 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 72 insertions(+), 26 deletions(-) diff --git a/zone/effects.cpp b/zone/effects.cpp index 73d2bf434..3fedf9a24 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -727,6 +727,9 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { // Dont let client waste a reuse timer if they can't use the disc if (IsStunned() || IsFeared() || IsMezzed() || IsAmnesiad() || IsPet()) { + if (IsAmnesiad()) { + MessageString(Chat::Red, MELEE_SILENCE); + } return(false); } @@ -745,6 +748,10 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { return(false); } + if (DivineAura() && !spells[spell_id].cast_not_standing) { + return false; + } + //can we use the spell? const SPDat_Spell_Struct &spell = spells[spell_id]; uint8 level_to_use = spell.classes[GetClass() - 1]; @@ -789,8 +796,9 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { return false; } - if(spell.recast_time > 0) - { + bool instant_recast = true; + + if(spell.recast_time > 0) { uint32 reduced_recast = spell.recast_time / 1000; auto focus = GetFocusEffect(focusReduceRecastTime, spell_id); // do stupid stuff because custom servers. @@ -805,18 +813,31 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { reduced_recast -= focus; } - if (reduced_recast > 0) - CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast); - else{ - CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline); - return true; + if (reduced_recast > 0){ + instant_recast = false; + + if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) { + if (DoCastingChecks(spell_id, target)) { + SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, (uint32)DiscTimer, reduced_recast); + } + } + else { + CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast); + } + + SendDisciplineTimer(spells[spell_id].timer_id, reduced_recast); } - - SendDisciplineTimer(spells[spell_id].timer_id, reduced_recast); } - else - { - CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline); + + if (instant_recast) { + if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) { + if (DoCastingChecks(spell_id, target)) { + SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline); + } + } + else { + CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline); + } } return(true); } diff --git a/zone/mob.h b/zone/mob.h index 40665d6e6..e69802cc1 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -331,7 +331,7 @@ public: void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQ::spells::CastingSlot slot, uint16 mana_used, uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0); bool SpellFinished(uint16 spell_id, Mob *target, EQ::spells::CastingSlot slot = EQ::spells::CastingSlot::Item, uint16 mana_used = 0, - uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1); + uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0); void SendBeginCast(uint16 spell_id, uint32 casttime); virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, int reflect_effectiveness = 0, bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, int32 duration_override = 0); @@ -347,7 +347,7 @@ public: void StopCasting(); inline bool IsCasting() const { return((casting_spell_id != 0)); } uint16 CastingSpellID() const { return casting_spell_id; } - bool DoCastingChecks(); + bool DoCastingChecks(int32 spell_id = SPELL_UNKNOWN, uint16 target_id = 0); bool TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier); bool TrySpellProjectile(Mob* spell_target, uint16 spell_id, float speed = 1.5f); void ResourceTap(int32 damage, uint16 spell_id); diff --git a/zone/spells.cpp b/zone/spells.cpp index 44f1cd8e7..fbefdad0e 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -159,9 +159,9 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot, LogSpells("CastSpell called for spell [{}] ([{}]) on entity [{}], slot [{}], time [{}], mana [{}], from item slot [{}]", (IsValidSpell(spell_id))?spells[spell_id].name:"UNKNOWN SPELL", spell_id, target_id, static_cast(slot), cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot); - if(casting_spell_id == spell_id) + if (casting_spell_id == spell_id) { ZeroCastingVars(); - + } if ( !IsValidSpell(spell_id) || @@ -216,8 +216,8 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot, return(false); } - //cannot cast under divine aura - if(DivineAura()) { + //cannot cast under divine aura, unless spell has 'cast_not_standing' flag. + if(DivineAura() && !spells[spell_id].cast_not_standing) { LogSpells("Spell casting canceled: cannot cast while Divine Aura is in effect"); InterruptSpell(173, 0x121, false); if(IsClient()) { @@ -240,7 +240,6 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot, if ((item_slot != -1 && cast_time == 0) || aa_id) { can_send_spellbar_enable = false; } - if (can_send_spellbar_enable) { SendSpellBarEnable(spell_id); } @@ -620,15 +619,30 @@ void Mob::SendBeginCast(uint16 spell_id, uint32 casttime) * it's probably doing something wrong. */ -bool Mob::DoCastingChecks() +bool Mob::DoCastingChecks(int32 spell_id, uint16 target_id) { if (!IsClient() || (IsClient() && CastToClient()->GetGM())) { casting_spell_checks = true; return true; } - uint16 spell_id = casting_spell_id; - Mob *spell_target = entity_list.GetMob(casting_spell_targetid); + bool ignore_casting_spell_checks = false; + /* + If variables are passed into this function it is NOT being called from main spell process + thefore we do not want to set the 'casting_spell_checks' state keeping variable. + */ + if (spell_id != SPELL_UNKNOWN || target_id) { + ignore_casting_spell_checks = true; + } + + if (spell_id == SPELL_UNKNOWN) { + spell_id = casting_spell_id; + } + if (!target_id) { + target_id = casting_spell_targetid; + } + + Mob *spell_target = entity_list.GetMob(target_id); if (RuleB(Spells, BuffLevelRestrictions)) { // casting_spell_targetid is guaranteed to be what we went, check for ST_Self for now should work though @@ -665,7 +679,9 @@ bool Mob::DoCastingChecks() if (!CastToClient()->IsLinkedSpellReuseTimerReady(spells[spell_id].timer_id)) return false; - casting_spell_checks = true; + if (!ignore_casting_spell_checks){ + casting_spell_checks = true; + } return true; } @@ -2143,7 +2159,8 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce // we can't interrupt in this, or anything called from this! // if you need to abort the casting, return false bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, uint16 mana_used, - uint32 inventory_slot, int16 resist_adjust, bool isproc, int level_override) + uint32 inventory_slot, int16 resist_adjust, bool isproc, int level_override, + uint32 timer, uint32 timer_duration) { //EQApplicationPacket *outapp = nullptr; Mob *ae_center = nullptr; @@ -2567,6 +2584,12 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui //set our reuse timer on long ass reuse_time spells... if(IsClient() && !isproc) { + //Support for bards to get disc recast timers while singing. + if (GetClass() == BARD && spell_id != casting_spell_id && timer != 0xFFFFFFFF) { + CastToClient()->GetPTimers().Start(timer, timer_duration); + LogSpells("Spell [{}]: Setting bard custom disciple reuse timer [{}] to [{}]", spell_id, timer, timer_duration); + } + if(casting_spell_aa_id) { AA::Rank *rank = zone->GetAlternateAdvancementRank(casting_spell_aa_id); @@ -3765,8 +3788,10 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectivenes } } - // invuln mobs can't be affected by any spells, good or bad - if(spelltar->GetInvul() || spelltar->DivineAura()) { + // invuln mobs can't be affected by any spells, good or bad, except if caster is casting a spell with 'cast_not_standing' on self. + if ((spelltar->GetInvul() && !spelltar->DivineAura()) || + (spelltar != this && spelltar->DivineAura()) || + (spelltar == this && spelltar->DivineAura() && !spells[spell_id].cast_not_standing)) { LogSpells("Casting spell [{}] on [{}] aborted: they are invulnerable", spell_id, spelltar->GetName()); safe_delete(action_packet); return false;