diff --git a/zone/bot.cpp b/zone/bot.cpp index 4bdaf13bb..e0e5d99ab 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -5275,7 +5275,7 @@ int32 Bot::CalcBotAAFocus(focusType type, uint32 aa_ID, uint32 points, uint16 sp return (value * lvlModifier / 100); } -int32 Bot::GetBotFocusEffect(focusType bottype, uint16 spell_id) { +int32 Bot::GetBotFocusEffect(focusType bottype, uint16 spell_id, bool from_buff_tic) { if (IsBardSong(spell_id) && bottype != focusFcBaseEffects) return 0; @@ -5390,9 +5390,9 @@ int32 Bot::GetBotFocusEffect(focusType bottype, uint16 spell_id) { if(focusspell_tracker && rand_effectiveness && focus_max_real2 != 0) realTotal2 = CalcBotFocusEffect(bottype, focusspell_tracker, spell_id); - // For effects like gift of mana that only fire once, save the spellid into an array that consists of all available buff slots. - if(buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) - m_spellHitsLeft[buff_tracker] = focusspell_tracker; + if (!from_buff_tic && buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) { + CheckNumHitsRemaining(NumHit::MatchingSpells, buff_tracker); + } } // AA Focus diff --git a/zone/bot.h b/zone/bot.h index 5ed980fe8..e39b07c1e 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -601,7 +601,7 @@ protected: virtual void PetAIProcess(); virtual void BotMeditate(bool isSitting); virtual bool CheckBotDoubleAttack(bool Triple = false); - virtual int32 GetBotFocusEffect(focusType bottype, uint16 spell_id); + virtual int32 GetBotFocusEffect(focusType bottype, uint16 spell_id, bool from_buff_tic = false); virtual int32 CalcBotFocusEffect(focusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false); virtual int32 CalcBotAAFocus(focusType type, uint32 aa_ID, uint32 points, uint16 spell_id); virtual void PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client); diff --git a/zone/client.h b/zone/client.h index 6c48d287b..4556ed858 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1648,7 +1648,7 @@ protected: void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true); bool client_data_loaded; - int32 GetFocusEffect(focusType type, uint16 spell_id, Mob *caster = nullptr); + int32 GetFocusEffect(focusType type, uint16 spell_id, Mob *caster = nullptr, bool from_buff_tic = false); uint16 GetSympatheticFocusEffect(focusType type, uint16 spell_id); void FinishAlternateAdvancementPurchase(AA::Rank *rank, bool ignore_cost); diff --git a/zone/effects.cpp b/zone/effects.cpp index 41b8ecd62..b7aae17ca 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -192,7 +192,7 @@ int32 Mob::GetActReflectedSpellDamage(int32 spell_id, int32 value, int effective return value; } -int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { +int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target, bool from_buff_tic) { if (target == nullptr) return value; @@ -216,16 +216,16 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { int32 ratio = 200; ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease; value = base_value*ratio/100; - value += int(base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100; - value += int(base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100)*ratio/100; - value += int(base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100; - value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100)*ratio/100; - value += int(base_value*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100; - extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + - int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) + - GetFocusEffect(focusFcDamageAmt, spell_id) + - GetFocusEffect(focusFcDamageAmt2, spell_id) + - GetFocusEffect(focusFcAmplifyAmt, spell_id); + value += int(base_value*GetFocusEffect(focusImprovedDamage, spell_id, nullptr, from_buff_tic)/100)*ratio/100; + value += int(base_value*GetFocusEffect(focusImprovedDamage2, spell_id, nullptr, from_buff_tic)/100)*ratio/100; + value += int(base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id, nullptr, from_buff_tic)/100)*ratio/100; + value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id, nullptr, from_buff_tic) / 100)*ratio/100; + value += int(base_value*target->GetVulnerability(this, spell_id, 0, from_buff_tic)/100)*ratio/100; + extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id, from_buff_tic) + + int(GetFocusEffect(focusFcDamageAmtCrit, spell_id, nullptr, from_buff_tic)*ratio/100) + + GetFocusEffect(focusFcDamageAmt, spell_id, nullptr, from_buff_tic) + + GetFocusEffect(focusFcDamageAmt2, spell_id, nullptr, from_buff_tic) + + GetFocusEffect(focusFcAmplifyAmt, spell_id, nullptr, from_buff_tic); if (RuleB(Spells, DOTsScaleWithSpellDmg)) { if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) { @@ -247,16 +247,16 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { else { value = base_value; - value += base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100; - value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100; - value += base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100; - value += base_value*GetFocusEffect(focusFcAmplifyMod, spell_id)/100; - value += base_value*target->GetVulnerability(this, spell_id, 0)/100; - extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + - GetFocusEffect(focusFcDamageAmtCrit, spell_id) + - GetFocusEffect(focusFcDamageAmt, spell_id) + - GetFocusEffect(focusFcDamageAmt2, spell_id) + - GetFocusEffect(focusFcAmplifyAmt, spell_id); + value += base_value*GetFocusEffect(focusImprovedDamage, spell_id, nullptr, from_buff_tic)/100; + value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id, nullptr, from_buff_tic)/100; + value += base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id, nullptr, from_buff_tic)/100; + value += base_value*GetFocusEffect(focusFcAmplifyMod, spell_id, nullptr, from_buff_tic)/100; + value += base_value*target->GetVulnerability(this, spell_id, 0, from_buff_tic)/100; + extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id, from_buff_tic) + + GetFocusEffect(focusFcDamageAmtCrit, spell_id, nullptr, from_buff_tic) + + GetFocusEffect(focusFcDamageAmt, spell_id, nullptr, from_buff_tic) + + GetFocusEffect(focusFcDamageAmt2, spell_id, nullptr, from_buff_tic) + + GetFocusEffect(focusFcAmplifyAmt, spell_id, nullptr, from_buff_tic); if (RuleB(Spells, DOTsScaleWithSpellDmg)) { if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) { @@ -316,7 +316,7 @@ int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_s return extra_spell_amt; } -int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { +int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target, bool from_buff_tic) { if (IsNPC()) { @@ -356,8 +356,8 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { if (GetClass() == CLERIC) { value += int(base_value*RuleI(Spells, ClericInnateHealFocus) / 100); //confirmed on live parsing clerics get an innate 5 pct heal focus } - value += int(base_value*GetFocusEffect(focusImprovedHeal, spell_id) / 100); - value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100); + value += int(base_value*GetFocusEffect(focusImprovedHeal, spell_id, nullptr, from_buff_tic) / 100); + value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id, nullptr, from_buff_tic) / 100); // Instant Heals if (spells[spell_id].buff_duration < 1) { diff --git a/zone/merc.cpp b/zone/merc.cpp index 306c1aeec..daab3e407 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -2552,7 +2552,7 @@ bool Merc::CheckAENuke(Merc* caster, Mob* tar, uint16 spell_id, uint8 &numTarget return false; } -int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { +int32 Merc::GetFocusEffect(focusType type, uint16 spell_id, bool from_buff_tic) { int32 realTotal = 0; int32 realTotal2 = 0; @@ -2666,9 +2666,8 @@ int32 Merc::GetFocusEffect(focusType type, uint16 spell_id) { if(focusspell_tracker && rand_effectiveness && focus_max_real2 != 0) realTotal2 = CalcFocusEffect(type, focusspell_tracker, spell_id); - // For effects like gift of mana that only fire once, save the spellid into an array that consists of all available buff slots. - if(buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) { - m_spellHitsLeft[buff_tracker] = focusspell_tracker; + if (!from_buff_tic && buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) { + CheckNumHitsRemaining(NumHit::MatchingSpells, buff_tracker); } } diff --git a/zone/merc.h b/zone/merc.h index 44ea7dda9..e5b096612 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -272,7 +272,7 @@ protected: void AddItemBonuses(const EQ::ItemData *item, StatBonuses* newbon); int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat); - int32 GetFocusEffect(focusType type, uint16 spell_id); + int32 GetFocusEffect(focusType type, uint16 spell_id, bool from_buff_tic = false); std::vector merc_spells; std::map timers; diff --git a/zone/mob.cpp b/zone/mob.cpp index 17dba13b4..139e81a25 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -313,8 +313,6 @@ Mob::Mob( armor_tint.Slot[i].Color = in_armor_tint.Slot[i].Color; } - std::fill(std::begin(m_spellHitsLeft), std::end(m_spellHitsLeft), 0); - m_Delta = glm::vec4(); animation = 0; @@ -4567,7 +4565,7 @@ void Mob::ApplyHealthTransferDamage(Mob *caster, Mob *target, uint16 spell_id) } } -int32 Mob::GetVulnerability(Mob *caster, uint32 spell_id, uint32 ticsremaining) +int32 Mob::GetVulnerability(Mob *caster, uint32 spell_id, uint32 ticsremaining, bool from_buff_tic) { /* Modifies incoming spell damage by percent, to increase or decrease damage, can be limited to specific resists. @@ -4593,8 +4591,8 @@ int32 Mob::GetVulnerability(Mob *caster, uint32 spell_id, uint32 ticsremaining) innate_mod = Vulnerability_Mod[HIGHEST_RESIST + 1]; } - fc_spell_vulnerability_mod = GetFocusEffect(focusSpellVulnerability, spell_id, caster); - fc_spell_damage_pct_incomingPC_mod = GetFocusEffect(focusFcSpellDamagePctIncomingPC, spell_id, caster); + fc_spell_vulnerability_mod = GetFocusEffect(focusSpellVulnerability, spell_id, caster, from_buff_tic); + fc_spell_damage_pct_incomingPC_mod = GetFocusEffect(focusFcSpellDamagePctIncomingPC, spell_id, caster, from_buff_tic); total_mod = fc_spell_vulnerability_mod + fc_spell_damage_pct_incomingPC_mod; diff --git a/zone/mob.h b/zone/mob.h index ded0347a2..e88b3eded 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -317,8 +317,8 @@ public: bool NegateSpellEffect(uint16 spell_id, int effect_id); virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false); virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr); - virtual int32 GetActDoTDamage(uint16 spell_id, int32 value, Mob* target); - virtual int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr); + virtual int32 GetActDoTDamage(uint16 spell_id, int32 value, Mob* target, bool from_buff_tic = true); + virtual int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr, bool from_buff_tic = false); virtual int32 GetActSpellCost(uint16 spell_id, int32 cost){ return cost;} virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration); virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); @@ -851,8 +851,8 @@ public: void TrySympatheticProc(Mob *target, uint32 spell_id); bool TryFadeEffect(int slot); uint16 GetSpellEffectResistChance(uint16 spell_id); - int32 GetVulnerability(Mob *caster, uint32 spell_id, uint32 ticsremaining); - int32 GetFcDamageAmtIncoming(Mob *caster, int32 spell_id); + int32 GetVulnerability(Mob *caster, uint32 spell_id, uint32 ticsremaining, bool from_buff_tic = false); + int32 GetFcDamageAmtIncoming(Mob *caster, int32 spell_id, bool from_buff_tic = false); int32 GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id); //**** This can be removed when bot healing focus code is updated **** int32 GetSkillDmgTaken(const EQ::skills::SkillType skill_used, ExtraAttackOptions *opts = nullptr); int32 GetPositionalDmgTaken(Mob *attacker); @@ -1502,7 +1502,7 @@ protected: virtual #endif int GetBaseSkillDamage(EQ::skills::SkillType skill, Mob *target = nullptr); - virtual int32 GetFocusEffect(focusType type, uint16 spell_id, Mob *caster = nullptr) { return 0; } + virtual int32 GetFocusEffect(focusType type, uint16 spell_id, Mob *caster = nullptr, bool from_buff_tic = false) { return 0; } void CalculateNewFearpoint(); float FindGroundZ(float new_x, float new_y, float z_offset=0.0); float FindDestGroundZ(glm::vec3 dest, float z_offset=0.0); @@ -1738,8 +1738,6 @@ protected: glm::vec3 m_TargetRing; - // we might want to do this differently, we gotta do max NPC buffs ... which is 97 - uint32 m_spellHitsLeft[EQ::spells::TOTAL_BUFFS]; // Used to track which spells will have their numhits incremented when spell finishes casting GravityBehavior flymode; bool m_targetable; int QGVarDuration(const char *fmt); diff --git a/zone/npc.h b/zone/npc.h index 845ff87bb..d6c52915e 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -575,7 +575,7 @@ protected: virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates = false); virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); AISpellsVar_Struct AISpellVar; - int32 GetFocusEffect(focusType type, uint16 spell_id); + int32 GetFocusEffect(focusType type, uint16 spell_id, Mob* caster, bool from_buff_tic = false); uint16 innate_proc_spell_id; uint32 npc_spells_effects_id; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 23c5c631a..959ef2365 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -234,8 +234,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove snprintf(effect_desc, _EDLEN, "Current Hitpoints: %+i", effect_value); #endif // SE_CurrentHP is calculated at first tick if its a dot/buff - if (buffslot >= 0) + if (buffslot >= 0) { + //This is here so dots with hit counters tic down on initial cast. + if (effect_value < 0) { + caster->GetActDoTDamage(spell_id, effect_value, this, false); + } break; + } if (spells[spell_id].limit_value[i] && !PassCastRestriction(spells[spell_id].limit_value[i])) { break; //no messages are given on live if this fails. @@ -2987,6 +2992,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove break; } + case SE_HealOverTime: { + //This is here so buffs with hit counters tic down on initial cast. + caster->GetActSpellHealing(spell_id, effect_value, nullptr, false); + } + case SE_PersistentEffect: MakeAura(spell_id); break; @@ -3071,7 +3081,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove case SE_TrueNorth: case SE_WaterBreathing: case SE_MovementSpeed: - case SE_HealOverTime: case SE_PercentXPIncrease: case SE_DivineSave: case SE_Accuracy: @@ -3808,8 +3817,9 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster) } case SE_HealOverTime: { effect_value = CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod); - if (caster) - effect_value = caster->GetActSpellHealing(buff.spellid, effect_value); + if (caster) { + effect_value = caster->GetActSpellHealing(buff.spellid, effect_value, nullptr, true); + } HealDamage(effect_value, caster, buff.spellid); // healing aggro would go here; removed for now @@ -6307,7 +6317,7 @@ uint16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { return 0; } -int32 Client::GetFocusEffect(focusType type, uint16 spell_id, Mob *caster) +int32 Client::GetFocusEffect(focusType type, uint16 spell_id, Mob *caster, bool from_buff_tic) { if (IsBardSong(spell_id) && type != focusFcBaseEffects && type != focusSpellDuration && type != focusReduceRecastTime) { return 0; @@ -6542,13 +6552,11 @@ int32 Client::GetFocusEffect(focusType type, uint16 spell_id, Mob *caster) if(focusspell_tracker && rand_effectiveness && focus_max_real2 != 0) realTotal2 = CalcFocusEffect(type, focusspell_tracker, spell_id, false, original_caster_id, caster); - // For effects like gift of mana that only fire once, save the spellid into an array that consists of all available buff slots. - if(buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) { - m_spellHitsLeft[buff_tracker] = focusspell_tracker; + if(!from_buff_tic && buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) { + CheckNumHitsRemaining(NumHit::MatchingSpells, buff_tracker); } } - // AA Focus if (aabonuses.FocusEffects[type]){ @@ -6589,7 +6597,7 @@ int32 Client::GetFocusEffect(focusType type, uint16 spell_id, Mob *caster) return realTotal + realTotal2 + realTotal3 + worneffect_bonus; } -int32 NPC::GetFocusEffect(focusType type, uint16 spell_id, Mob* caster) { +int32 NPC::GetFocusEffect(focusType type, uint16 spell_id, Mob* caster, bool from_buff_tic) { int32 realTotal = 0; int32 realTotal2 = 0; @@ -6704,9 +6712,8 @@ int32 NPC::GetFocusEffect(focusType type, uint16 spell_id, Mob* caster) { realTotal2 = CalcFocusEffect(type, focusspell_tracker, spell_id, false, original_caster_id, caster); } - // For effects like gift of mana that only fire once, save the spellid into an array that consists of all available buff slots. - if(buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) { - m_spellHitsLeft[buff_tracker] = focusspell_tracker; + if(!from_buff_tic && buff_tracker >= 0 && buffs[buff_tracker].hit_number > 0) { + CheckNumHitsRemaining(NumHit::MatchingSpells, buff_tracker); } } @@ -6779,31 +6786,9 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, uint16 spell_id) } else if (IsClient()) { // still have numhits and client, update CastToClient()->SendBuffNumHitPacket(buffs[buff_slot], buff_slot); } - } else { - for (int d = 0; d < buff_max; d++) { - if (!m_spellHitsLeft[d]) - continue; - - if (IsValidSpell(buffs[d].spellid) && m_spellHitsLeft[d] == buffs[d].spellid) { - -#ifdef BOTS - buff_name = spells[buffs[d].spellid].name; - buff_counter = (buffs[d].hit_number - 1); - buff_update = true; -#endif - - if (--buffs[d].hit_number == 0) { - CastOnNumHitFade(buffs[d].spellid); - m_spellHitsLeft[d] = 0; - if (!TryFadeEffect(d)) - BuffFadeBySlot(d, true); - } else if (IsClient()) { // still have numhits and client, update - CastToClient()->SendBuffNumHitPacket(buffs[d], d); - } - } - } - } - } else { + } + } + else { for (int d = 0; d < buff_max; d++) { if (IsValidSpell(buffs[d].spellid) && buffs[d].hit_number > 0 && spells[buffs[d].spellid].hit_number_type == static_cast(type)) { @@ -7095,12 +7080,12 @@ bool Mob::DoHPToManaCovert(uint16 mana_cost) return false; } -int32 Mob::GetFcDamageAmtIncoming(Mob *caster, int32 spell_id) +int32 Mob::GetFcDamageAmtIncoming(Mob *caster, int32 spell_id, bool from_buff_tic) { //THIS is target of spell cast int32 dmg = 0; - dmg += GetFocusEffect(focusFcDamageAmtIncoming, spell_id, caster); //SPA 297 SE_FcDamageAmtIncoming - dmg += GetFocusEffect(focusFcSpellDamageAmtIncomingPC, spell_id, caster); //SPA 484 SE_Fc_Spell_Damage_Amt_IncomingPC + dmg += GetFocusEffect(focusFcDamageAmtIncoming, spell_id, caster, from_buff_tic); //SPA 297 SE_FcDamageAmtIncoming + dmg += GetFocusEffect(focusFcSpellDamageAmtIncomingPC, spell_id, caster, from_buff_tic); //SPA 484 SE_Fc_Spell_Damage_Amt_IncomingPC return dmg; } diff --git a/zone/spells.cpp b/zone/spells.cpp index f019a6cd4..08c77b737 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1613,7 +1613,6 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo } if(IsClient()) { - CheckNumHitsRemaining(NumHit::MatchingSpells); TrySympatheticProc(target, spell_id); }