diff --git a/changelog.txt b/changelog.txt index 8e86f0023..6a1148e15 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,14 +3,22 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) == 02/10/2014 == demonstar55 (Secrets): Re-wrote the entity list to be a std::map. This should be used for direct entityID lookups and is noticably faster performance-wise. Also should result in less nil pointers potentially. Secrets: Fixed a crash issue that could occur on #repop related to quest timers. +Kayen: Divine Arbiration and other similar spell effects will now utilize a spell range check. +Kayen: Revised how heal amount is calculated to properly incorporate all current focus effects/bonuses. +Kayen: Various updates/fixes/clean-ups to focus effect related code. Focus effect limits should now all work properly. == 02/09/2014 == Sorvani: Added new spawn condition onchange action: DoRepopIfReady. Choosing this will not repop mobs when the spawn condition is enabled if they have an existing respawn timer. Additionally, this condition will not even attempt repop when the condition is is changed to disabled. Will be in use on PEQ for: Cragbeast Queen in Natimbi. Secrets: Fixed a weird crash issue with deletion of pointers if task loading fails. -== 02/2/2014 == -Kayen: Revised how spell/dot damage is calculated to properly incorporated all current focus effects/bonuses. +== 02/8/2014 == +Kayen: Various updates/fixes/clean-ups to focus effect related code. Focus effect limits should now all work properly. +== 02/7/2014 == +Kayen: Revised how heal amount is calculated to properly incorporate all current focus effects/bonuses. + +== 02/2/2014 == +Kayen: Revised how spell/dot damage is calculated to properly incorporate all current focus effects/bonuses. Required SQL: utils/sql/git/2014_02_02_SpellCriticalsAA.sql diff --git a/common/spdat.h b/common/spdat.h index a59dd88e5..35f928789 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -36,6 +36,7 @@ #define EFFECT_COUNT 12 #define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2) #define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists. +#define MaxLimitInclude 12 //Number(x 0.5) of focus Limiters that have inclusive checksm used when calcing focus effects const int Z_AGGRO=10; @@ -289,8 +290,8 @@ typedef enum { #define SE_LimitMinDur 140 // implemented #define SE_LimitInstant 141 // implemented #define SE_LimitMinLevel 142 // implemented -#define SE_LimitCastTime 143 // implemented -#define SE_FfCastTimeMax 144 // not used +#define SE_LimitCastTimeMin 143 // implemented +#define SE_LimitCastTimeMax 144 // implemented (*not used in any known live spell) #define SE_Teleport2 145 // implemented - Banishment of the Pantheon #define SE_ElectricityResist 146 // *not implemented (Lightning Rod: 23233) #define SE_PercentalHeal 147 // implemented @@ -442,7 +443,7 @@ typedef enum { #define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front. #define SE_CriticalSpellChance 294 // implemented - increase chance to critical hit and critical damage modifier. //#define SE_ReduceTimerSpecial 295 // not used -#define SE_SpellVulnerability 296 // implemented - increase in incoming spell damage +#define SE_FcSpellVulnerability 296 // implemented - increase in incoming spell damage #define SE_FcDamageAmtIncoming 297 // implemented - debuff that adds points damage to spells cast on target (focus effect). #define SE_ChangeHeight 298 // implemented #define SE_WakeTheDead 299 // implemented @@ -457,7 +458,7 @@ typedef enum { #define SE_SuspendMinion 308 // not implemented as bonus #define SE_YetAnotherGate 309 // implemented #define SE_ReduceReuseTimer 310 // implemented -#define SE_CombatSkills 311 // implemented +#define SE_LimitCombatSkills 311 // implemented - Excludes focus from procs (except if proc is a memorizable spell) #define SE_Sanctuary 312 // *not implemented #define SE_ForageAdditionalItems 313 // implemented[AA] - chance to forage additional items #define SE_Invisibility2 314 // implemented - fixed duration invisible @@ -494,7 +495,7 @@ typedef enum { #define SE_AssassinationLevel 345 // not implemented as bonus - AA Assisination max level to kill #define SE_HeadShotLevel 346 // not implemented as bonus - AA HeadShot max level to kill #define SE_DoubleRangedAttack 347 // implemented - chance at an additional archery attack (consumes arrow) -#define SE_LimitManaCost 348 // implemented +#define SE_LimitManaMin 348 // implemented #define SE_ShieldEquipHateMod 349 // implemented[AA] Increase melee hate when wearing a shield. #define SE_ManaBurn 350 // implemented - Drains mana for damage/heal at a defined ratio up to a defined maximum amount of mana. #define SE_PersistentEffect 351 // *not implemented. creates a trap/totem that casts a spell (spell id + base1?) when anything comes near it. can probably make a beacon for this @@ -535,22 +536,22 @@ typedef enum { #define SE_CastOnCurer 386 // implemented - Casts a spell on the person curing #define SE_CastOnCure 387 // implemented - Casts a spell on the cured person #define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA) -#define SE_Forceful_Rejuv 389 // Refresh spell icons -#define SE_SetRecastTimer 390 // *not implemented - Sets recast timers to specific value, focus limited. -#define SE_IncreaseHitDmgTaken 391 // implemented - Most likely a simple negative mitigation modifier (Warlords fury: 23528) -#define SE_AdditionalHeal2 392 // implemented - Adds or removes healing from spells -#define SE_HealRate2 393 // implemented - HealRate with focus restrictions. +#define SE_FcTimerRefresh 389 // implemented - Refresh spell icons +#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited. +#define SE_LimitManaMax 391 // implemented +#define SE_FcHealAmt 392 // implemented - Adds or removes healing from spells +#define SE_FcHealPctIncoming 393 // implemented - HealRate with focus restrictions. #define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions. -#define SE_CriticalHealRate 395 // implemented[AA] - Increases chance of having a heal crit when cast on you. [focus limited] -#define SE_AdditionalHeal 396 // implemented - Adds a direct healing amount to spells +#define SE_FcHealPctCritIncoming 395 // implemented[AA] - Increases chance of having a heal crit when cast on you. [focus limited] +#define SE_FcHealAmtCrit 396 // implemented - Adds a direct healing amount to spells #define SE_PetMeleeMitigation 397 // *not implemented[AA] - additional mitigation to your pets. #define SE_SwarmPetDuration 398 // implemented - Affects the duration of swarm pets -#define SE_Twincast 399 // implemented - cast 2 spells for every 1 +#define SE_FcTwincast 399 // implemented - cast 2 spells for every 1 #define SE_HealGroupFromMana 400 // implemented - Drains mana and heals for each point of mana drained #define SE_ManaDrainWithDmg 401 // implemented - Deals damage based on the amount of mana drained #define SE_EndDrainWithDmg 402 // implemented - Deals damage for the amount of endurance drained -#define SE_Ff_SpellClass 403 // *not implemented - -#define SE_LimitExcludeSkill 404 // implemented - Limit a focus to exclude spells cast using a specific skill. +#define SE_LimitSpellClass 403 // *not implemented - unclear what this refers too (not 'right click' spell bar) +#define SE_LimitSpellSubclass 404 // *not implemented - unclear what this refers too (not 'right click' spell bar) #define SE_TwoHandBluntBlock 405 // implemented - chance to block attacks when using two hand blunt weapons (similiar to shield block) #define SE_CastonNumHitFade 406 // implemented - casts a spell when a buff fades due to its numhits being depleted #define SE_CastonFocusEffect 407 // implemented - casts a spell if focus limits are met (ie triggers when a focus effects is applied) @@ -560,16 +561,16 @@ typedef enum { #define SE_LimitClass 411 // implemented - Limits to spells of a certain class (Note: The class value in dbase is +1 in relation to item class value) #define SE_LimitRace 412 // implemented - Limits to spells cast by a certain race (Note: not used in any known live spells) #define SE_FcBaseEffects 413 // implemented - Increases the power of bard songs, skill attacks, runes, bard allowed foci, damage/heal -#define SE_LimitSpellSkill 414 // implemented - Limit a focus to include spells cast using a specific skill. +#define SE_LimitCastingSkill 414 // implemented - Limit a focus to include spells cast using a specific skill. //#define SE_FFItemClass 415 // not used #define SE_ACv2 416 // implemented - New AC spell effect #define SE_ManaRegen_v2 417 // implemented - New mana regen effect #define SE_SkillDamageAmount2 418 // implemented - adds skill damage directly to certain attacks #define SE_AddMeleeProc 419 // implemented - Adds a proc #define SE_FcLimitUse 420 // implemented - increases numhits count by percent (Note: not used in any known live spells) -#define SE_IncreaseNumHits 421 // implemented[AA] - increases number of hits a buff has till fade. (focus) -#define SE_FfLimitUseMin 422 // implemented - limit a focus to require a min amount of numhits value (used with above) -#define SE_FfLimitUseType 423 // implemented - limit a focus to require a certain numhits type +#define SE_FcIncreaseNumHits 421 // implemented[AA] - increases number of hits a buff has till fade. (focus) +#define SE_LimitUseMin 422 // implemented - limit a focus to require a min amount of numhits value (used with above) +#define SE_LimitUseType 423 // implemented - limit a focus to require a certain numhits type #define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace #define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626) #define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index b60381687..37af3021d 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1212,6 +1212,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) case SE_CriticalMend: newbon->CriticalMend += base1; break; + + case SE_HealRate: + newbon->HealRate += base1; + break; } } } @@ -1603,10 +1607,6 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->MeleeMitigation -= effect_value; break; - case SE_IncreaseHitDmgTaken: - newbon->MeleeMitigation += effect_value; - break; - case SE_CriticalHitChance: { @@ -2773,12 +2773,12 @@ uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_eff case SE_TriggerOnCast: //return focusTriggerOnCast; return 0; //This is calculated as an actual bonus - case SE_SpellVulnerability: + case SE_FcSpellVulnerability: return focusSpellVulnerability; case SE_BlockNextSpellFocus: //return focusBlockNextSpell; return 0; //This is calculated as an actual bonus - case SE_Twincast: + case SE_FcTwincast: return focusTwincast; case SE_SympatheticProc: return focusSympatheticProc; @@ -2792,24 +2792,26 @@ uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_eff return focusFcDamageAmtIncoming; case SE_FcHealAmtIncoming: return focusFcHealAmtIncoming; - case SE_HealRate2: - return focusHealRate; + case SE_FcHealPctIncoming: + return focusFcHealPctIncoming; case SE_FcBaseEffects: return focusFcBaseEffects; - case SE_IncreaseNumHits: + case SE_FcIncreaseNumHits: return focusIncreaseNumHits; case SE_FcLimitUse: return focusFcLimitUse; case SE_FcMute: return focusFcMute; + case SE_FcTimerRefresh: + return focusFcTimerRefresh; case SE_FcStunTimeMod: return focusFcStunTimeMod; - case SE_CriticalHealRate: - return focusCriticalHealRate; - case SE_AdditionalHeal2: - return focusAdditionalHeal2; - case SE_AdditionalHeal: - return focusAdditionalHeal; + case SE_FcHealPctCritIncoming: + return focusFcHealPctCritIncoming; + case SE_FcHealAmt: + return focusFcHealAmt; + case SE_FcHealAmtCrit: + return focusFcHealAmtCrit; } return 0; } @@ -3115,12 +3117,6 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) aabonuses.MeleeMitigation = effect_value; break; - case SE_IncreaseHitDmgTaken: - spellbonuses.MeleeMitigation = effect_value; - itembonuses.MeleeMitigation = effect_value; - aabonuses.MeleeMitigation = effect_value; - break; - case SE_CriticalHitChance: { for(int e = 0; e < HIGHEST_SKILL+1; e++) diff --git a/zone/bot.cpp b/zone/bot.cpp index a1241626f..1736b58bd 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -6736,7 +6736,7 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) if((spell.classes[(GetClass()%16) - 1]) < base1) LimitFound = true; break; - case SE_LimitCastTime: + case SE_LimitCastTimeMin: if (spell.cast_time < base1) LimitFound = true; break; @@ -6782,7 +6782,7 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) } break; - case SE_LimitManaCost: + case SE_LimitManaMin: if(spell.mana < base1) LimitFound = true; break; @@ -6800,7 +6800,7 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) } break; - case SE_CombatSkills: + case SE_LimitCombatSkills: // 1 is for disciplines only if(base1 == 1 && !IsDiscipline(spell_id)) LimitFound = true; @@ -6817,13 +6817,13 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) break; - case SE_LimitSpellSkill: + case SE_LimitCastingSkill: LimitSpellSkill = true; if(base1 == spell.skill) SpellSkill_Found = true; break; - case SE_LimitExcludeSkill:{ + case SE_LimitSpellSubclass:{ int16 spell_skill = spell.skill * -1; if(base1 == spell_skill) LimitFound = true; @@ -6941,7 +6941,7 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) } break; } - case SE_SpellVulnerability: + case SE_FcSpellVulnerability: { if(type == focusSpellVulnerability) { @@ -6958,7 +6958,7 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) } break; } - case SE_Twincast: + case SE_FcTwincast: { if(type == focusTwincast) { @@ -7057,7 +7057,7 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) break; } - case SE_IncreaseNumHits: + case SE_FcIncreaseNumHits: { if(type == focusIncreaseNumHits) value = base1; @@ -7338,7 +7338,7 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel return(0); break; - case SE_LimitCastTime: + case SE_LimitCastTimeMin: if (spells[spell_id].cast_time < (uint16)focus_spell.base[i]) return(0); break; @@ -7398,7 +7398,7 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel } break; - case SE_LimitManaCost: + case SE_LimitManaMin: if(spell.mana < focus_spell.base[i]) return 0; break; @@ -7413,7 +7413,7 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel break; - case SE_CombatSkills: + case SE_LimitCombatSkills: // 1 is for disciplines only if(focus_spell.base[i] == 1 && !IsDiscipline(spell_id)) return 0; @@ -7429,13 +7429,13 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel return 0; break; - case SE_LimitSpellSkill: + case SE_LimitCastingSkill: LimitSpellSkill = true; if(focus_spell.base[i] == spell.skill) SpellSkill_Found = true; break; - case SE_LimitExcludeSkill:{ + case SE_LimitSpellSubclass:{ int16 spell_skill = spell.skill * -1; if(focus_spell.base[i] == spell_skill) return 0; @@ -7602,7 +7602,7 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel break; } - case SE_SpellVulnerability: + case SE_FcSpellVulnerability: { if(bottype == BotfocusSpellVulnerability) { @@ -7619,7 +7619,7 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel } break; } - case SE_Twincast: + case SE_FcTwincast: { if(bottype == BotfocusTwincast) { @@ -7715,7 +7715,7 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel break; } - case SE_IncreaseNumHits: + case SE_FcIncreaseNumHits: { if(bottype == BotfocusIncreaseNumHits) value = focus_spell.base[i]; @@ -9119,23 +9119,6 @@ void Bot::SetAttackTimer() { } } -int32 Bot::Additional_SpellDmg(uint16 spell_id, bool bufftick) -{ - int32 spell_dmg = 0; - spell_dmg += GetBotFocusEffect(BotfocusFcDamageAmtCrit, spell_id); - spell_dmg += GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); - - //For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it) - if (bufftick){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return spell_dmg /= duration; - else - return 0; - } - return spell_dmg; -} - int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (spells[spell_id].targettype == ST_Self) @@ -9195,8 +9178,8 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); - if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value)*ratio/100; + if(itembonuses.SpellDmg && spells[spell_id].classes[(botclass%16) - 1] >= botlevel - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value); @@ -9219,71 +9202,74 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); - if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value); + if(itembonuses.SpellDmg && spells[spell_id].classes[(botclass%16) - 1] >= botlevel - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); return value; } -int32 Bot::Additional_Heal(uint16 spell_id) -{ - int32 heal_amt = 0; +int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { + + if (target == nullptr) + target = this; - heal_amt += GetBotFocusEffect(BotfocusAdditionalHeal, spell_id); - heal_amt += GetBotFocusEffect(BotfocusAdditionalHeal2, spell_id); - - if (heal_amt){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return heal_amt /= duration; - } - - return heal_amt; -} - -int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value) { - int32 modifier = 100; - int16 heal_amt = 0; - modifier += GetBotFocusEffect(BotfocusImprovedHeal, spell_id); - modifier += GetBotFocusEffect(BotfocusFcBaseEffects, spell_id); - heal_amt += Additional_Heal(spell_id); - int chance = 0; + int32 value_BaseEffect = 0; + int16 chance = 0; + int8 modifier = 1; + bool Critical = false; + + value_BaseEffect = value + (value*GetBotFocusEffect(BotfocusFcBaseEffects, spell_id)/100); + + value = value_BaseEffect; + value += int(value_BaseEffect*GetBotFocusEffect(BotfocusImprovedHeal, spell_id)/100); + + // Instant Heals if(spells[spell_id].buffduration < 1) { - uint8 botlevel = GetLevel(); - uint8 botclass = GetClass(); - // Formula = HealAmt * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant heal more than the spell itself. - if(this->itembonuses.HealAmt && spells[spell_id].classes[(botclass%16) - 1] >= botlevel - 5) { - heal_amt = this->itembonuses.HealAmt * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000; - if(heal_amt > value) - heal_amt = value; - } - // Check for buffs that affect the healrate of the target and critical heal rate of target - if(GetTarget()) { - value += value * GetHealRate(spell_id) / 100; - chance += GetCriticalHealRate(spell_id); - } + chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - //Live AA - Healing Gift, Theft of Life - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; + chance += target->GetBotFocusIncoming(BotfocusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalHealDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) { + Critical = true; + modifier = 2; //At present time no critical heal amount modifier SPA exists. + } + + value *= modifier; + value += GetBotFocusEffect(BotfocusFcHealAmtCrit, spell_id) * modifier; + value += GetBotFocusEffect(BotfocusFcHealAmt, spell_id); + value += target->GetBotFocusIncoming(BotfocusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + + if(itembonuses.HealAmt && spells[spell_id].classes[(botclass%16) - 1] >= botlevel - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier; - if(MakeRandomInt(0,99) < chance) { - entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier / 50) + heal_amt*2)); - return ((value * modifier / 50) + heal_amt*2); - } - else{ - return ((value * modifier / 100) + heal_amt); - } + value += value*target->GetHealRate(spell_id, this)/100; + + if (Critical) + entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value); + + return value; } - // Hots + + //Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value] else { - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - if(MakeRandomInt(0,99) < chance) - return ((value * modifier / 50) + heal_amt*2); + + chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; + + chance += target->GetBotFocusIncoming(BotfocusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalRegenDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) + return (value * 2); } - return ((value * modifier / 100) + heal_amt); + return value; } int32 Bot::GetActSpellCasttime(uint16 spell_id, int32 casttime) { diff --git a/zone/bot.h b/zone/bot.h index 9412abe02..66e283116 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -86,13 +86,13 @@ public: BotfocusSwarmPetDuration, BotfocusReduceRecastTime, BotfocusBlockNextSpell, - BotfocusHealRate, + BotfocusFcHealPctIncoming, BotfocusFcDamageAmtIncoming, BotfocusFcBaseEffects, BotfocusIncreaseNumHits, - BotfocusCriticalHealRate, - BotfocusAdditionalHeal2, - BotfocusAdditionalHeal, + BotfocusFcHealPctCritIncoming, + BotfocusFcHealAmt, + BotfocusFcHealAmtCrit, }; enum BotTradeType { // types of trades a bot can do @@ -301,10 +301,8 @@ public: // Mob Spell Virtual Override Methods virtual void SpellProcess(); - int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false); - int32 Additional_Heal(uint16 spell_id); - virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target); - virtual int32 GetActSpellHealing(uint16 spell_id, int32 value); + virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target == nullptr); + virtual int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target == nullptr); virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); virtual int32 GetActSpellCost(uint16 spell_id, int32 cost); virtual float GetActSpellRange(uint16 spell_id, float range); diff --git a/zone/client.h b/zone/client.h index 4d736ce18..c2ef8675e 100644 --- a/zone/client.h +++ b/zone/client.h @@ -472,11 +472,9 @@ public: inline virtual int16 GetDelayDeath() const { return aabonuses.DelayDeath + spellbonuses.DelayDeath + itembonuses.DelayDeath + 11; } - int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false); - int32 Additional_Heal(uint16 spell_id); float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false); - int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob *target = nullptr); - int32 GetActSpellHealing(uint16 spell_id, int32 value); + int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr); + int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr); int32 GetActSpellCost(uint16 spell_id, int32); int32 GetActSpellDuration(uint16 spell_id, int32); int32 GetActSpellCasttime(uint16 spell_id, int32); diff --git a/zone/common.h b/zone/common.h index 92cd91ea6..c400c5f56 100644 --- a/zone/common.h +++ b/zone/common.h @@ -71,19 +71,20 @@ typedef enum { //focus types focusSwarmPetDuration, focusReduceRecastTime, focusBlockNextSpell, - focusHealRate, + focusFcHealPctIncoming, focusFcDamageAmtIncoming, focusFcHealAmtIncoming, focusFcBaseEffects, focusIncreaseNumHits, focusFcLimitUse, focusFcMute, + focusFcTimerRefresh, focusFcStunTimeMod, - focusCriticalHealRate, - focusAdditionalHeal2, - focusAdditionalHeal, + focusFcHealPctCritIncoming, + focusFcHealAmt, + focusFcHealAmtCrit, } focusType; //Any new FocusType needs to be added to the Mob::IsFocus function -#define HIGHEST_FOCUS focusAdditionalHeal //Should always be last focusType in enum +#define HIGHEST_FOCUS focusFcHealAmtCrit //Should always be last focusType in enum enum { SPECATK_SUMMON = 1, diff --git a/zone/effects.cpp b/zone/effects.cpp index c03f3b2bf..bd14af6f7 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -40,23 +40,6 @@ float Client::GetActSpellRange(uint16 spell_id, float range, bool IsBard) } -int32 Client::Additional_SpellDmg(uint16 spell_id, bool bufftick) -{ - int32 spell_dmg = 0; - spell_dmg += GetFocusEffect(focusFcDamageAmtCrit, spell_id); - spell_dmg += GetFocusEffect(focusFcDamageAmt, spell_id); - - //For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it) - if (bufftick){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return spell_dmg /= duration; - else - return 0; - } - return spell_dmg; -} - int32 NPC::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { //Quest scale all NPC spell damage via $npc->SetSpellFocusDMG(value) @@ -138,7 +121,7 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value)*ratio/100; + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value); @@ -162,7 +145,7 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value); + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); return value; } @@ -184,7 +167,7 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { if (chance > 0 && (MakeRandomInt(1, 100) <= chance)) { - int32 ratio = 100; + int32 ratio = 200; ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease; value = value_BaseEffect*ratio/100; @@ -199,8 +182,11 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) + GetFocusEffect(focusFcDamageAmt, spell_id); - if (extra_dmg) - extra_dmg /= CalcBuffDuration(this, this, spell_id); + if (extra_dmg) { + int duration = CalcBuffDuration(this, this, spell_id); + if (duration > 0) + extra_dmg /= duration; + } value -= extra_dmg; @@ -220,41 +206,18 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { GetFocusEffect(focusFcDamageAmtCrit, spell_id) + GetFocusEffect(focusFcDamageAmt, spell_id); - if (extra_dmg) - extra_dmg /= CalcBuffDuration(this, this, spell_id); + if (extra_dmg) { + int duration = CalcBuffDuration(this, this, spell_id); + if (duration > 0) + extra_dmg /= duration; + } value -= extra_dmg; return value; } - /* - int32 modifier = 100; - int16 spell_dmg = 0; - int16 critChance = 0; - int32 ratio = 0; - - modifier += GetFocusEffect(focusImprovedDamage, spell_id); - critChance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance; - ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease; - spell_dmg += Additional_SpellDmg(spell_id,true); - - if (spellbonuses.CriticalDotDecay) - critChance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay); - - if (critChance > 0){ - if (MakeRandomInt(0, 99) < critChance){ - modifier += modifier*ratio/100; - return (((value*modifier/100)-spell_dmg)*2); - } - } - - return ((value*modifier/100)-spell_dmg); - */ - - - -int32 Mob::GetExtraSpellDmg(uint16 spell_id, int32 extra_spell_dmg, int32 base_spell_dmg) +int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg) { int total_cast_time = 0; @@ -264,105 +227,98 @@ int32 Mob::GetExtraSpellDmg(uint16 spell_id, int32 extra_spell_dmg, int32 base_s total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time; if (total_cast_time > 0 && total_cast_time <= 2500) - extra_spell_dmg = extra_spell_dmg*25/100; + extra_spell_amt = extra_spell_amt*25/100; else if (total_cast_time > 2500 && total_cast_time < 7000) - extra_spell_dmg = extra_spell_dmg*(0.167*((total_cast_time - 1000)/1000)); + extra_spell_amt = extra_spell_amt*(0.167*((total_cast_time - 1000)/1000)); else - extra_spell_dmg = extra_spell_dmg * total_cast_time / 7000; + extra_spell_amt = extra_spell_amt * total_cast_time / 7000; - extra_spell_dmg = -extra_spell_dmg; - - if(extra_spell_dmg*2 < base_spell_dmg) + if(extra_spell_amt*2 < base_spell_dmg) return 0; - return extra_spell_dmg; + return extra_spell_amt; } -//Scale all NPC spell healing via SetSpellFocusHeal(value) -int32 NPC::GetActSpellHealing(uint16 spell_id, int32 value) { +int32 NPC::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { - int32 modifier = 100; - modifier += SpellFocusHeal; + //Scale all NPC spell healing via SetSpellFocusHeal(value) - // Check for buffs that affect the healrate of the target - if(this->GetTarget()) - { - value += value * GetHealRate(spell_id) / 100; - } + value += value*SpellFocusHeal/100; - return (value * modifier / 100); + if (target) { + value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + value += value*target->GetHealRate(spell_id, this)/100; + } + + return value; } -int32 Client::Additional_Heal(uint16 spell_id) -{ - int32 heal_amt = 0; +int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { + + if (target == nullptr) + target = this; - heal_amt += GetFocusEffect(focusAdditionalHeal, spell_id); - heal_amt += GetFocusEffect(focusAdditionalHeal2, spell_id); - heal_amt -= GetFocusEffect(focusFcHealAmtIncoming, spell_id); - - if (heal_amt){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return heal_amt /= duration; - } - - return heal_amt; -} - -int32 Client::GetActSpellHealing(uint16 spell_id, int32 value) { - - int32 modifier = 100; - int16 heal_amt = 0; - modifier += GetFocusEffect(focusImprovedHeal, spell_id); - modifier += GetFocusEffect(focusFcBaseEffects, spell_id); - heal_amt += Additional_Heal(spell_id); - int chance = 0; + int32 value_BaseEffect = 0; + int16 chance = 0; + int8 modifier = 1; + bool Critical = false; + + value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100); + + value = value_BaseEffect; + value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100); + // Instant Heals - if(spells[spell_id].buffduration < 1) - { - // Formula = HealAmt * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant heal more than the spell itself. - if(this->itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) { - heal_amt = this->itembonuses.HealAmt * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000; - if(heal_amt > value) - heal_amt = value; - } + if(spells[spell_id].buffduration < 1) { - // Check for buffs that affect the healrate of the target and critical heal rate of target - if(GetTarget()){ - value += value * GetHealRate(spell_id) / 100; - chance += GetCriticalHealRate(spell_id); - } + chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - //Live AA - Healing Gift, Theft of Life - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; + chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); - if (spellbonuses.CriticalRegenDecay) - chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + if (spellbonuses.CriticalHealDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) { + Critical = true; + modifier = 2; //At present time no critical heal amount modifier SPA exists. + } + + value *= modifier; + value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier; + value += GetFocusEffect(focusFcHealAmt, spell_id); + value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + + if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier; - if(MakeRandomInt(0,99) < chance) { - entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier / 50) + heal_amt*2)); - return ((value * modifier / 50) + heal_amt*2); - } - else{ - return ((value * modifier / 100) + heal_amt); - } + value += value*target->GetHealRate(spell_id, this)/100; + + if (Critical) + entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value); + + return value; } - // Hots + + //Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value] else { - chance += itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; + + chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; + + chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); if (spellbonuses.CriticalRegenDecay) - chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); - if(MakeRandomInt(0,99) < chance) - return ((value * modifier / 50) + heal_amt*2); + if(chance && (MakeRandomInt(0,99) < chance)) + return (value * 2); } - return ((value * modifier / 100) + heal_amt); + + return value; } + int32 Client::GetActSpellCost(uint16 spell_id, int32 cost) { // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell diff --git a/zone/groups.cpp b/zone/groups.cpp index 429987bb3..aa50ba2c9 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -1057,17 +1057,27 @@ void Client::LeaveGroup() { isgrouped = false; } -void Group::HealGroup(uint32 heal_amt, Mob* caster) +void Group::HealGroup(uint32 heal_amt, Mob* caster, int32 range) { if (!caster) return; + if (!range) + range = 200; + + float distance; + float range2 = range*range; + + int numMem = 0; unsigned int gi = 0; for(; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ - numMem += 1; + distance = caster->DistNoRoot(*members[gi]); + if(distance <= range2){ + numMem += 1; + } } } @@ -1075,23 +1085,38 @@ void Group::HealGroup(uint32 heal_amt, Mob* caster) for(gi = 0; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ - //members[gi]->SetHP(members[gi]->GetHP() + heal_amt); - members[gi]->HealDamage(heal_amt, caster); - members[gi]->SendHPUpdate(); + distance = caster->DistNoRoot(*members[gi]); + if(distance <= range2){ + members[gi]->HealDamage(heal_amt, caster); + members[gi]->SendHPUpdate(); + } } } } -void Group::BalanceHP(int32 penalty) +void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) { + if (!caster) + return; + + if (!range) + range = 200; + int dmgtaken = 0, numMem = 0; + + float distance; + float range2 = range*range; + unsigned int gi = 0; for(; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ - dmgtaken += (members[gi]->GetMaxHP() - members[gi]->GetHP()); - numMem += 1; + distance = caster->DistNoRoot(*members[gi]); + if(distance <= range2){ + dmgtaken += (members[gi]->GetMaxHP() - members[gi]->GetHP()); + numMem += 1; + } } } @@ -1100,27 +1125,42 @@ void Group::BalanceHP(int32 penalty) for(gi = 0; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ - if((members[gi]->GetMaxHP() - dmgtaken) < 1){ //this way the ability will never kill someone - members[gi]->SetHP(1); //but it will come darn close - members[gi]->SendHPUpdate(); - } - else{ - members[gi]->SetHP(members[gi]->GetMaxHP() - dmgtaken); - members[gi]->SendHPUpdate(); + distance = caster->DistNoRoot(*members[gi]); + if(distance <= range2){ + if((members[gi]->GetMaxHP() - dmgtaken) < 1){ //this way the ability will never kill someone + members[gi]->SetHP(1); //but it will come darn close + members[gi]->SendHPUpdate(); + } + else{ + members[gi]->SetHP(members[gi]->GetMaxHP() - dmgtaken); + members[gi]->SendHPUpdate(); + } } } } } -void Group::BalanceMana(int32 penalty) +void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) { + if (!caster) + return; + + if (!range) + range = 200; + + float distance; + float range2 = range*range; + int manataken = 0, numMem = 0; unsigned int gi = 0; for(; gi < MAX_GROUP_MEMBERS; gi++) { - if(members[gi]){ - manataken += (members[gi]->GetMaxMana() - members[gi]->GetMana()); - numMem += 1; + if(members[gi]){ + distance = caster->DistNoRoot(*members[gi]); + if(distance <= range2){ + manataken += (members[gi]->GetMaxMana() - members[gi]->GetMana()); + numMem += 1; + } } } @@ -1129,15 +1169,18 @@ void Group::BalanceMana(int32 penalty) for(gi = 0; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ - if((members[gi]->GetMaxMana() - manataken) < 1){ - members[gi]->SetMana(1); - if (members[gi]->IsClient()) - members[gi]->CastToClient()->SendManaUpdate(); - } - else{ - members[gi]->SetMana(members[gi]->GetMaxMana() - manataken); - if (members[gi]->IsClient()) - members[gi]->CastToClient()->SendManaUpdate(); + distance = caster->DistNoRoot(*members[gi]); + if(distance <= range2){ + if((members[gi]->GetMaxMana() - manataken) < 1){ + members[gi]->SetMana(1); + if (members[gi]->IsClient()) + members[gi]->CastToClient()->SendManaUpdate(); + } + else{ + members[gi]->SetMana(members[gi]->GetMaxMana() - manataken); + if (members[gi]->IsClient()) + members[gi]->CastToClient()->SendManaUpdate(); + } } } } diff --git a/zone/groups.h b/zone/groups.h index 10b4fcffe..c5a3f8ab1 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -86,9 +86,9 @@ public: uint16 GetAvgLevel(); bool LearnMembers(); void VerifyGroup(); - void BalanceHP(int32 penalty); - void BalanceMana(int32 penalty); - void HealGroup(uint32 heal_amt, Mob* caster); + void BalanceHP(int32 penalty, int32 range = 0, Mob* caster = nullptr); + void BalanceMana(int32 penalty, int32 range = 0, Mob* caster = nullptr); + void HealGroup(uint32 heal_amt, Mob* caster, int32 range = 0); inline void SetGroupAAs(GroupLeadershipAA_Struct *From) { memcpy(&LeaderAbilities, From, sizeof(GroupLeadershipAA_Struct)); } inline void GetGroupAAs(GroupLeadershipAA_Struct *Into) { memcpy(Into, &LeaderAbilities, sizeof(GroupLeadershipAA_Struct)); } void UpdateGroupAAs(); diff --git a/zone/merc.cpp b/zone/merc.cpp index 7c7dcf60c..6da94f3e3 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -2771,22 +2771,6 @@ int16 Merc::GetFocusEffect(focusType type, uint16 spell_id) { return realTotal + realTotal2 + realTotal3; } -int32 Merc::Additional_SpellDmg(uint16 spell_id, bool bufftick) -{ - int32 spell_dmg = 0; - spell_dmg += GetFocusEffect(focusFcDamageAmtCrit, spell_id); - spell_dmg += GetFocusEffect(focusFcDamageAmt, spell_id); - - //For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it) - if (bufftick){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return spell_dmg /= duration; - else - return 0; - } - return spell_dmg; -} int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { @@ -2836,7 +2820,7 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value)*ratio/100; + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; value = (value * GetSpellScale() / 100); @@ -2862,76 +2846,75 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value); + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); value = (value * GetSpellScale() / 100); return value; } -int32 Merc::Additional_Heal(uint16 spell_id) -{ - int32 heal_amt = 0; +int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { + + if (target == nullptr) + target = this; - heal_amt += GetFocusEffect(focusAdditionalHeal, spell_id); - heal_amt += GetFocusEffect(focusAdditionalHeal2, spell_id); - heal_amt += GetFocusEffect(focusFcHealAmtIncoming, spell_id); - - if (heal_amt){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return heal_amt /= duration; - } - - return heal_amt; -} - -int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value) { - - int32 modifier = 100; - int16 heal_amt = 0; - modifier += GetFocusEffect(focusImprovedHeal, spell_id); - modifier += GetFocusEffect(focusFcBaseEffects, spell_id); - heal_amt += Additional_Heal(spell_id); - int chance = 0; + int32 value_BaseEffect = 0; + int16 chance = 0; + int8 modifier = 1; + bool Critical = false; + + value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100); + + value = value_BaseEffect; + value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100); + // Instant Heals - if(spells[spell_id].buffduration < 1) - { - // Formula = HealAmt * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant heal more than the spell itself. - if(this->itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) { - heal_amt = this->itembonuses.HealAmt * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000; - if(heal_amt > value) - heal_amt = value; - } + if(spells[spell_id].buffduration < 1) { - // Check for buffs that affect the healrate of the target and critical heal rate of target - if(GetTarget()){ - value += value * GetHealRate(spell_id) / 100; - chance += GetCriticalHealRate(spell_id); - } + chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - //Live AA - Healing Gift, Theft of Life - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; + chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalHealDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) { + Critical = true; + modifier = 2; //At present time no critical heal amount modifier SPA exists. + } + + value *= modifier; + value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier; + value += GetFocusEffect(focusFcHealAmt, spell_id); + value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + + if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier; - if(MakeRandomInt(0,99) < chance) { - entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier / 50) + heal_amt*2)); - heal_amt = ((value * modifier / 50) + heal_amt*2); - } - else{ - heal_amt = ((value * modifier / 100) + heal_amt); - } + value += value*target->GetHealRate(spell_id, this)/100; + + if (Critical) + entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value); + + return value; } - // Hots + + //Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value] else { - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - if(MakeRandomInt(0,99) < chance) - heal_amt = ((value * modifier / 50) + heal_amt*2); + + chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; + + chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalRegenDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) + return (value * 2); } - heal_amt = (heal_amt * GetHealScale() / 100); - - return heal_amt; + return value; } int32 Merc::GetActSpellCost(uint16 spell_id, int32 cost) diff --git a/zone/merc.h b/zone/merc.h index 09b9df811..fd7f69fa4 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -77,10 +77,8 @@ public: Corpse* GetGroupMemberCorpse(); // Merc Spell Casting Methods - int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false); - int32 Additional_Heal(uint16 spell_id); virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr); - virtual int32 GetActSpellHealing(uint16 spell_id, int32 value); + virtual int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr); virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); virtual int32 GetActSpellCost(uint16 spell_id, int32 cost); int8 GetChanceToCastBySpellType(int16 spellType); diff --git a/zone/mob.cpp b/zone/mob.cpp index cd79b2a0a..dabacd425 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3336,7 +3336,7 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id) int buff_count = GetMaxTotalSlots(); for(int i = 0; i < buff_count; i++) { - if(IsEffectInSpell(buffs[i].spellid, SE_Twincast)) + if(IsEffectInSpell(buffs[i].spellid, SE_FcTwincast)) { int32 focus = CalcFocusEffect(focusTwincast, buffs[i].spellid, spell_id); if(focus > 0) @@ -3378,7 +3378,7 @@ int32 Mob::GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining) int buff_count = GetMaxTotalSlots(); for(int i = 0; i < buff_count; i++) { - if((IsValidSpell(buffs[i].spellid) && IsEffectInSpell(buffs[i].spellid, SE_SpellVulnerability))){ + if((IsValidSpell(buffs[i].spellid) && IsEffectInSpell(buffs[i].spellid, SE_FcSpellVulnerability))){ int32 focus = caster->CalcFocusEffect(focusSpellVulnerability, buffs[i].spellid, spell_id); @@ -3429,37 +3429,19 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used) return skilldmg_mod; } -int16 Mob::GetHealRate(uint16 spell_id) -{ - Mob* target = GetTarget(); - +int16 Mob::GetHealRate(uint16 spell_id, Mob* caster) { + int16 heal_rate = 0; - if (target){ - heal_rate = target->itembonuses.HealRate + target->spellbonuses.HealRate; - - if (target->IsClient()) - heal_rate += target->CastToClient()->GetFocusEffect(focusHealRate, spell_id); - - if(heal_rate < -99) - heal_rate = -99; - } + heal_rate += itembonuses.HealRate + spellbonuses.HealRate + aabonuses.HealRate; + heal_rate += GetFocusIncoming(focusFcHealPctIncoming, SE_FcHealPctIncoming, caster, spell_id); + if(heal_rate < -99) + heal_rate = -99; + return heal_rate; } -int16 Mob::GetCriticalHealRate(uint16 spell_id) -{ - Mob* target = GetTarget(); - - int16 critical_heal_rate = 0; - - if (target && target->IsClient()) - critical_heal_rate = target->CastToClient()->GetFocusEffect(focusCriticalHealRate, spell_id); - - return critical_heal_rate; -} - bool Mob::TryFadeEffect(int slot) { if(IsValidSpell(buffs[slot].spellid)) @@ -4669,7 +4651,7 @@ int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) { if (!IsValidSpell(spell_id)) return false; - int spell_level = spells[spell_id].classes[(GetClass()%16) - 1]; + int spell_level = spells[spell_id].classes[(GetClass()%16) - 1]; int effect_value = 0; int lvlModifier = 100; @@ -4679,15 +4661,15 @@ int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) { for (int i = 0; i < EFFECT_COUNT; i++){ if(spells[buffs[slot].spellid].effectid[i] == spelleffect) { - int critchance = spells[buffs[slot].spellid].base[i]; + int critchance = spells[buffs[slot].spellid].base[i]; int decay = spells[buffs[slot].spellid].base2[i]; - int lvldiff = spell_level - spells[buffs[slot].spellid].max[i]; + int lvldiff = spell_level - spells[buffs[slot].spellid].max[i]; if(lvldiff > 0 && decay > 0) { - lvlModifier -= decay*lvldiff; + lvlModifier -= decay*lvldiff; if (lvlModifier > 0){ - critchance = (critchance*lvlModifier)/100; + critchance = (critchance*lvlModifier)/100; effect_value += critchance; } } diff --git a/zone/mob.h b/zone/mob.h index 796170b34..a0ad73578 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -172,7 +172,7 @@ public: void NegateSpellsBonuses(uint16 spell_id); virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false) { return range;} virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr) { return value; } - virtual int32 GetActSpellHealing(uint16 spell_id, int32 value) { return value; } + virtual int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr) { return value; } virtual int32 GetActSpellCost(uint16 spell_id, int32 cost){ return cost;} virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration){ return duration;} virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); @@ -548,10 +548,10 @@ public: void TrySympatheticProc(Mob *target, uint32 spell_id); bool TryFadeEffect(int slot); uint16 GetSpellEffectResistChance(uint16 spell_id); - int16 GetHealRate(uint16 spell_id); - int16 GetCriticalHealRate(uint16 spell_id); + int16 GetHealRate(uint16 spell_id, Mob* caster = nullptr); int32 GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining); int32 GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill = false, uint16 skill=0); + int32 GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id); int16 GetSkillDmgTaken(const SkillUseTypes skill_used); void DoKnockback(Mob *caster, uint32 pushback, uint32 pushup); int16 CalcResistChanceBonus(); @@ -574,7 +574,7 @@ public: bool DoHPToManaCovert(uint16 mana_cost = 0); int32 ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard = false); int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect); - int32 GetExtraSpellDmg(uint16 spell_id, int32 extra_spell_dmg, int32 base_spell_dmg); + int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg); void ModSkillDmgTaken(SkillUseTypes skill_num, int value); int16 GetModSkillDmgTaken(const SkillUseTypes skill_num); diff --git a/zone/npc.h b/zone/npc.h index 324826b37..bcb69e0d7 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -110,7 +110,7 @@ public: int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr); - int32 GetActSpellHealing(uint16 spell_id, int32 value); + int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr); inline void SetSpellFocusDMG(int32 NewSpellFocusDMG) {SpellFocusDMG = NewSpellFocusDMG;} inline void SetSpellFocusHeal(int32 NewSpellFocusHeal) {SpellFocusHeal = NewSpellFocusHeal;} int32 SpellFocusDMG; diff --git a/zone/raids.cpp b/zone/raids.cpp index 1a706e41c..bf6f76d5c 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -461,11 +461,17 @@ uint32 Raid::GetTotalRaidDamage(Mob* other) return total; } -void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid) +void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, int32 range) { if (!caster) return; + if (!range) + range = 200; + + float distance; + float range2 = range*range; + int numMem = 0; unsigned int gi = 0; for(; gi < MAX_RAID_MEMBERS; gi++) @@ -473,7 +479,10 @@ void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid) if(members[gi].member){ if(members[gi].GroupNumber == gid) { - numMem += 1; + distance = caster->DistNoRoot(*members[gi].member); + if(distance <= range2){ + numMem += 1; + } } } } @@ -484,25 +493,41 @@ void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid) if(members[gi].member){ if(members[gi].GroupNumber == gid) { - members[gi].member->SetHP(members[gi].member->GetHP() + heal_amt); - members[gi].member->SendHPUpdate(); + distance = caster->DistNoRoot(*members[gi].member); + if(distance <= range2){ + members[gi].member->SetHP(members[gi].member->GetHP() + heal_amt); + members[gi].member->SendHPUpdate(); + } } } } } -void Raid::BalanceHP(int32 penalty, uint32 gid) +void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) { + if (!caster) + return; + + if (!range) + range = 200; + int dmgtaken = 0, numMem = 0; int gi = 0; + + float distance; + float range2 = range*range; + for(; gi < MAX_RAID_MEMBERS; gi++) { if(members[gi].member){ if(members[gi].GroupNumber == gid) { - dmgtaken += (members[gi].member->GetMaxHP() - members[gi].member->GetHP()); - numMem += 1; + distance = caster->DistNoRoot(*members[gi].member); + if(distance <= range2){ + dmgtaken += (members[gi].member->GetMaxHP() - members[gi].member->GetHP()); + numMem += 1; + } } } } @@ -514,21 +539,33 @@ void Raid::BalanceHP(int32 penalty, uint32 gid) if(members[gi].member){ if(members[gi].GroupNumber == gid) { - if((members[gi].member->GetMaxHP() - dmgtaken) < 1){//this way the ability will never kill someone - members[gi].member->SetHP(1); //but it will come darn close - members[gi].member->SendHPUpdate(); - } - else{ - members[gi].member->SetHP(members[gi].member->GetMaxHP() - dmgtaken); - members[gi].member->SendHPUpdate(); + distance = caster->DistNoRoot(*members[gi].member); + if(distance <= range2){ + if((members[gi].member->GetMaxHP() - dmgtaken) < 1){//this way the ability will never kill someone + members[gi].member->SetHP(1); //but it will come darn close + members[gi].member->SendHPUpdate(); + } + else{ + members[gi].member->SetHP(members[gi].member->GetMaxHP() - dmgtaken); + members[gi].member->SendHPUpdate(); + } } } } } } -void Raid::BalanceMana(int32 penalty, uint32 gid) +void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) { + if (!caster) + return; + + if (!range) + range = 200; + + float distance; + float range2 = range*range; + int manataken = 0, numMem = 0; int gi = 0; for(; gi < MAX_RAID_MEMBERS; gi++) @@ -536,8 +573,11 @@ void Raid::BalanceMana(int32 penalty, uint32 gid) if(members[gi].member){ if(members[gi].GroupNumber == gid) { - manataken += (members[gi].member->GetMaxMana() - members[gi].member->GetMana()); - numMem += 1; + distance = caster->DistNoRoot(*members[gi].member); + if(distance <= range2){ + manataken += (members[gi].member->GetMaxMana() - members[gi].member->GetMana()); + numMem += 1; + } } } } @@ -549,15 +589,18 @@ void Raid::BalanceMana(int32 penalty, uint32 gid) if(members[gi].member){ if(members[gi].GroupNumber == gid) { - if((members[gi].member->GetMaxMana() - manataken) < 1){ - members[gi].member->SetMana(1); - if (members[gi].member->IsClient()) - members[gi].member->CastToClient()->SendManaUpdate(); - } - else{ - members[gi].member->SetMana(members[gi].member->GetMaxMana() - manataken); - if (members[gi].member->IsClient()) - members[gi].member->CastToClient()->SendManaUpdate(); + distance = caster->DistNoRoot(*members[gi].member); + if(distance <= range2){ + if((members[gi].member->GetMaxMana() - manataken) < 1){ + members[gi].member->SetMana(1); + if (members[gi].member->IsClient()) + members[gi].member->CastToClient()->SendManaUpdate(); + } + else{ + members[gi].member->SetMana(members[gi].member->GetMaxMana() - manataken); + if (members[gi].member->IsClient()) + members[gi].member->CastToClient()->SendManaUpdate(); + } } } } diff --git a/zone/raids.h b/zone/raids.h index 811a233c7..c8c2f61e4 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -147,9 +147,9 @@ public: void CastGroupSpell(Mob* caster,uint16 spellid, uint32 gid); void SplitExp(uint32 exp, Mob* other); uint32 GetTotalRaidDamage(Mob* other); - void BalanceHP(int32 penalty, uint32 gid); - void BalanceMana(int32 penalty, uint32 gid); - void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid); + void BalanceHP(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr); + void BalanceMana(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr); + void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, int32 range = 0); void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr); void GroupBardPulse(Mob* caster, uint16 spellid, uint32 gid); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index bb875f90f..0c4d30ad0 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -363,7 +363,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(caster) - dmg = caster->GetActSpellHealing(spell_id, dmg); + dmg = caster->GetActSpellHealing(spell_id, dmg, this); HealDamage(dmg, caster); } @@ -415,7 +415,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) int32 val = spell.max[i]; if(caster) - val = caster->GetActSpellHealing(spell_id, val); + val = caster->GetActSpellHealing(spell_id, val, this); int32 mhp = GetMaxHP(); int32 cap = mhp * spell.base[i] / 100; @@ -2396,7 +2396,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } else if(dmg > 0) { //healing spell... if(caster) - dmg = caster->GetActSpellHealing(spell_id, dmg); + dmg = caster->GetActSpellHealing(spell_id, dmg, this); HealDamage(dmg, caster); } #ifdef SPELL_EFFECT_SPAM @@ -2445,7 +2445,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) gid = r->GetGroup(caster->GetName()); if(gid < 11) { - r->BalanceHP(spell.base[i], gid); + r->BalanceHP(spell.base[i], gid, spell.range, caster); break; } } @@ -2455,7 +2455,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(!g) break; - g->BalanceHP(spell.base[i]); + g->BalanceHP(spell.base[i], spell.range, caster); break; } @@ -2473,7 +2473,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) gid = r->GetGroup(caster->GetName()); if(gid < 11) { - r->BalanceMana(spell.base[i], gid); + r->BalanceMana(spell.base[i], gid, spell.range, caster); break; } } @@ -2483,7 +2483,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(!g) break; - g->BalanceMana(spell.base[i]); + g->BalanceMana(spell.base[i], spell.range, caster); break; } @@ -2535,13 +2535,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - case SE_Forceful_Rejuv: + case SE_FcTimerRefresh: { if(IsClient()) { for(unsigned int i =0 ; i < MAX_PP_MEMSPELL; ++i) { if(IsValidSpell(CastToClient()->m_pp.mem_spells[i])) { - CastToClient()->m_pp.spellSlotRefresh[i] = 1; - CastToClient()->GetPTimers().Clear(&database, (pTimerSpellStart + CastToClient()->m_pp.mem_spells[i])); + if (CalcFocusEffect(focusFcTimerRefresh, spell_id, CastToClient()->m_pp.mem_spells[i])){ + CastToClient()->m_pp.spellSlotRefresh[i] = 1; + CastToClient()->GetPTimers().Clear(&database, (pTimerSpellStart + CastToClient()->m_pp.mem_spells[i])); + } } } SetMana(GetMana()); @@ -2577,7 +2579,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) gid = r->GetGroup(caster->GetName()); if(gid < 11) { - r->HealGroup(heal_amt,caster, gid); + r->HealGroup(heal_amt,caster, gid, spell.range); break; } } @@ -2589,7 +2591,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - g->HealGroup(heal_amt, caster); + g->HealGroup(heal_amt, caster, spell.range); break; } @@ -2825,17 +2827,17 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_LimitMinDur: case SE_LimitInstant: case SE_LimitMinLevel: - case SE_LimitCastTime: - case SE_LimitManaCost: - case SE_CombatSkills: + case SE_LimitCastTimeMin: + case SE_LimitManaMin: + case SE_LimitCombatSkills: case SE_SpellDurationIncByTic: case SE_TriggerOnCast: case SE_HealRate: case SE_SkillDamageTaken: - case SE_SpellVulnerability: + case SE_FcSpellVulnerability: case SE_SpellTrigger: case SE_ApplyEffect: - case SE_Twincast: + case SE_FcTwincast: case SE_DelayDeath: case SE_InterruptCasting: case SE_ImprovedSpellEffect: @@ -2867,7 +2869,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_AntiGate: case SE_Fearless: case SE_FcDamageAmtCrit: - case SE_AdditionalHeal: + case SE_FcHealAmtCrit: case SE_CastOnCurer: case SE_CastOnCure: case SE_CastonNumHitFade: @@ -2878,16 +2880,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_ACv2: case SE_ManaRegen_v2: case SE_FcDamagePctCrit: - case SE_AdditionalHeal2: - case SE_HealRate2: + case SE_FcHealAmt: + case SE_FcHealPctIncoming: case SE_CriticalHealDecay: case SE_CriticalRegenDecay: case SE_FcDamageAmtIncoming: - case SE_LimitSpellSkill: + case SE_LimitCastingSkill: case SE_MitigateDamageShield: case SE_FcBaseEffects: case SE_LimitClass: - case SE_LimitExcludeSkill: + case SE_LimitSpellSubclass: case SE_BlockBehind: case SE_ShieldBlock: case SE_PetCriticalHit: @@ -2922,11 +2924,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_UnfailingDivinity: case SE_ChannelChanceSpells: case SE_ChannelChanceItems: - case SE_CriticalHealRate: - case SE_IncreaseNumHits: + case SE_FcHealPctCritIncoming: + case SE_FcIncreaseNumHits: case SE_CastonFocusEffect: case SE_FcHealAmtIncoming: - case SE_IncreaseHitDmgTaken: + case SE_LimitManaMax: case SE_DoubleRangedAttack: case SE_ShieldEquipHateMod: case SE_ShieldEquipDmgMod: @@ -2934,11 +2936,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_LimitRace: case SE_FcLimitUse: case SE_FcMute: - case SE_FfLimitUseType: + case SE_LimitUseType: case SE_FcStunTimeMod: case SE_StunBashChance: case SE_IncreaseChanceMemwipe: case SE_CriticalMend: + case SE_LimitCastTimeMax: { break; } @@ -3341,7 +3344,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste effect_value = CalcSpellEffectValue(spell_id, i, caster_level); if(caster) effect_value = caster->GetActSpellHealing(spell_id, effect_value); - effect_value += effect_value * (itembonuses.HealRate + spellbonuses.HealRate) / 100; + HealDamage(effect_value, caster); //healing aggro would go here; removed for now break; @@ -3975,16 +3978,13 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) int lvlModifier = 100; int spell_level = 0; int lvldiff = 0; - bool LimitSpellSkill = false; - bool SpellSkill_Found = false; - bool LimitSpellEffect = false; - bool SpellEffect_Found = false; uint32 effect = 0; int32 base1 = 0; int32 base2 = 0; uint32 slot = 0; - bool LimitFound = false; + bool LimitFailure = false; + bool LimitInclude[MaxLimitInclude] = { false }; int FocusCount = 0; std::map >::const_iterator find_iter = aa_effects.find(aa_ID); @@ -4000,21 +4000,30 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) base2 = iter->second.base2; slot = iter->second.slot; - //AA Foci's can contain multiple focus effects within the same AA. - //To handle this we will not automatically return zero if a limit is found. - //Instead if limit is found and multiple effects, we will reset the limit check - //when the next valid focus effect is found. + /* + AA Foci's can contain multiple focus effects within the same AA. + To handle this we will not automatically return zero if a limit is found. + Instead if limit is found and multiple focus effects, we will reset the limit check + when the next valid focus effect is found. + */ + if (IsFocusEffect(0, 0, true,effect) || (effect == SE_TriggerOnCast)){ FocusCount++; //If limit found on prior check next, else end loop. if (FocusCount > 1){ - if (LimitFound){ + + for(int e = 0; e < MaxLimitInclude; e+=2) { + if (LimitInclude[e] && !LimitInclude[e+1]) + LimitFailure = true; + } + + if (LimitFailure){ value = 0; - LimitFound = false; - LimitSpellSkill = false; - SpellSkill_Found = false; - LimitSpellEffect = false; - SpellEffect_Found = false; + LimitFailure = false; + + for(int e = 0; e < MaxLimitInclude; e++) { + LimitInclude[e] = false; //Reset array + } } else{ @@ -4030,165 +4039,185 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) break; //Handle Focus Limits + case SE_LimitResist: - if(base1) - { - if(spell.resisttype != base1) - LimitFound = true; + if(base1 < 0){ + if(spell.resisttype == -base1) //Exclude + LimitFailure = true; } - break; + else { + LimitInclude[0] = true; + if (spell.resisttype == base1) //Include + LimitInclude[1] = true; + } + break; + case SE_LimitInstant: if(spell.buffduration) - LimitFound = true; - break; + LimitFailure = true; + break; + case SE_LimitMaxLevel: spell_level = spell.classes[(GetClass()%16) - 1]; lvldiff = spell_level - base1; //every level over cap reduces the effect by base2 percent unless from a clicky when ItemCastsUseFocus is true - if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)) - { - if(base2 > 0) - { + if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)) { + if(base2 > 0){ lvlModifier -= base2*lvldiff; if(lvlModifier < 1) - LimitFound = true; - } - else { - LimitFound = true; + LimitFailure = true; } + else + LimitFailure = true; } - break; + break; + case SE_LimitMinLevel: if((spell.classes[(GetClass()%16) - 1]) < base1) - LimitFound = true; - break; - case SE_LimitCastTime: + LimitFailure = true; + break; + + case SE_LimitCastTimeMin: if (spell.cast_time < base1) - LimitFound = true; - break; + LimitFailure = true; + break; + + case SE_LimitCastTimeMax: + if (spell.cast_time > base1) + LimitFailure = true; + break; + case SE_LimitSpell: - // Exclude spell(any but this) - if(base1 < 0) { - if (spell_id == (base1*-1)) - LimitFound = true; - } + if(base1 < 0) { //Exclude + if (spell_id == -base1) + LimitFailure = true; + } else { - // Include Spell(only this) - if (spell_id != base1) - LimitFound = true; + LimitInclude[2] = true; + if (spell_id == base1) //Include + LimitInclude[3] = true; } - break; + break; + case SE_LimitMinDur: if (base1 > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) - LimitFound = true; - break; + LimitFailure = true; + break; + case SE_LimitEffect: - // Exclude effect (any but this) - if (base1 < 0) { - if (IsEffectInSpell(spell_id, (base1 * -1))) - LimitFound = true; - } else { - // Include effect (only this) - if (!IsEffectInSpell(spell_id, base1)) - LimitFound = true; + if(base1 < 0){ + if(IsEffectInSpell(spell_id,-base1)) //Exclude + LimitFailure = true; + } + else{ + LimitInclude[4] = true; + if(IsEffectInSpell(spell_id,base1)) //Include + LimitInclude[5] = true; } - break; + break; + case SE_LimitSpellType: switch(base1) { case 0: if (!IsDetrimentalSpell(spell_id)) - LimitFound = true; + LimitFailure = true; break; case 1: if (!IsBeneficialSpell(spell_id)) - LimitFound = true; + LimitFailure = true; break; } - break; + break; - case SE_LimitManaCost: + case SE_LimitManaMin: if(spell.mana < base1) - LimitFound = true; - break; + LimitFailure = true; + break; + + case SE_LimitManaMax: + if(spell.mana > base1) + LimitFailure = true; + break; case SE_LimitTarget: - // Exclude - if(base1 < 0){ - if(-base1 == spell.targettype) - LimitFound = true; - } - // Include - else { - if(base1 != spell.targettype) - LimitFound = true; - } - break; + if (base1 < 0) { + if (-base1 == spell.targettype) //Exclude + LimitFailure = true; + } + else { + LimitInclude[6] = true; + if (base1 == spell.targettype) //Include + LimitInclude[7] = true; + } + break; - case SE_CombatSkills: - // 1 is for disciplines only - if(base1 == 1 && !IsDiscipline(spell_id)) - LimitFound = true; - // 0 is spells only - else if(base1 == 0 && IsDiscipline(spell_id)) - LimitFound = true; - break; + + case SE_LimitCombatSkills: + if (base1 == 0){ + if((spell.cast_time == 0) && (spell.recast_time == 0) && (spell.recovery_time == 0)) //Exclude procs + LimitFailure = true; + } + break; case SE_LimitSpellGroup: - if(base1 > 0 && base1 != spell.spellgroup) - LimitFound = true; - else if(base1 < 0 && base1 == spell.spellgroup) - LimitFound = true; - break; + if(base1 < 0) { + if (-base1 == spell.spellgroup) //Exclude + LimitFailure = true; + } + else { + LimitInclude[8] = true; + if (base1 == spell.spellgroup) //Include + LimitInclude[9] = true; + } + break; - - case SE_LimitSpellSkill: - LimitSpellSkill = true; - if(base1 == spell.skill) - SpellSkill_Found = true; - break; - - case SE_LimitExcludeSkill:{ - int16 spell_skill = spell.skill * -1; - if(base1 == spell_skill) - LimitFound = true; - break; + case SE_LimitCastingSkill: + if(base1 < 0) { + if(-base1 == spell.skill) + LimitFailure = true; } + else { + LimitInclude[10] = true; + if(base1 == spell.skill) + LimitInclude[11] = true; + } + break; case SE_LimitClass: //Do not use this limit more then once per spell. If multiple class, treat value like items would. if (!PassLimitClass(base1, GetClass())) - LimitFound = true; - break; + LimitFailure = true; + break; case SE_LimitRace: - if (base1 != GetRace()) - LimitFound = true; - break; + if (base1 != GetRace()) + LimitFailure = true; + break; - case SE_FfLimitUseMin: - if (base1 > spell.numhits) - LimitFound = true; - break; + case SE_LimitUseMin: + if (base1 > spell.numhits) + LimitFailure = true; + break; - case SE_FfLimitUseType: - if (base1 != spell.numhitstype) - LimitFound = true; - break; + case SE_LimitUseType: + if (base1 != spell.numhitstype) + LimitFailure = true; + break; //Handle Focus Effects case SE_ImprovedDamage: if (type == focusImprovedDamage && base1 > value) value = base1; - break; + break; case SE_ImprovedHeal: if (type == focusImprovedHeal && base1 > value) value = base1; - break; + break; case SE_ReduceManaCost: - if (type == focusManaCost ) + if (type == focusManaCost) value = base1; break; @@ -4233,23 +4262,15 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) break; case SE_SpellHateMod: - if (type == focusSpellHateMod) - { - if(value != 0) - { - if(value > 0) - { + if (type == focusSpellHateMod ) { + if(value != 0) { + if(value > 0){ if(base1 > value) - { value = base1; - } } - else - { + else{ if(base1 < value) - { value = base1; - } } } else @@ -4258,196 +4279,123 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) break; case SE_ReduceReuseTimer: - { if(type == focusReduceRecastTime) value = base1 / 1000; - break; - } case SE_TriggerOnCast: - { - if(type == focusTriggerOnCast) - { + if(type == focusTriggerOnCast){ if(MakeRandomInt(0, 100) <= base1){ value = base2; } else{ value = 0; - LimitFound = true; + LimitFailure = true; } - } break; - } - case SE_SpellVulnerability: - { + } + + case SE_FcSpellVulnerability: if(type == focusSpellVulnerability) - { value = base1; - } break; - } + case SE_BlockNextSpellFocus: - { - if(type == focusBlockNextSpell) - { + if(type == focusBlockNextSpell){ if(MakeRandomInt(1, 100) <= base1) value = 1; } break; - } - case SE_Twincast: - { + + case SE_FcTwincast: if(type == focusTwincast) - { value = base1; - } break; - } - /* case SE_SympatheticProc: - { - if(type == focusSympatheticProc) - { - float ProcChance, ProcBonus; - int16 ProcRateMod = base1; //Baseline is 100 for most Sympathetic foci - int32 cast_time = GetActSpellCasttime(spell_id, spells[spell_id].cast_time); - GetSympatheticProcChances(ProcBonus, ProcChance, cast_time, ProcRateMod); - - if(MakeRandomFloat(0, 1) <= ProcChance) - value = focus_id; - - else - value = 0; - } + //No AA support at this time. break; - } - */ + case SE_FcDamageAmt: - { if(type == focusFcDamageAmt) value = base1; - break; - } case SE_FcDamageAmtCrit: - { if(type == focusFcDamageAmtCrit) value = base1; - break; - } case SE_FcDamageAmtIncoming: - { if(type == focusFcDamageAmtIncoming) value = base1; - break; - } case SE_FcHealAmtIncoming: - { if(type == focusFcHealAmtIncoming) value = base1; - break; - } - case SE_CriticalHealRate: - { - if (type == focusCriticalHealRate) + case SE_FcHealPctCritIncoming: + if (type == focusFcHealPctCritIncoming) value = base1; - break; - } - case SE_AdditionalHeal: - { - if(type == focusAdditionalHeal) + case SE_FcHealAmtCrit: + if(type == focusFcHealAmtCrit) value = base1; - break; - } - case SE_AdditionalHeal2: - { - if(type == focusAdditionalHeal2) + case SE_FcHealAmt: + if(type == focusFcHealAmt) value = base1; - break; - } - case SE_HealRate2: - { - if(type == focusHealRate) + case SE_FcHealPctIncoming: + if(type == focusFcHealPctIncoming) value = base1; - break; - } case SE_FcBaseEffects: - { if (type == focusFcBaseEffects) value = base1; - break; - } + case SE_FcDamagePctCrit: - { if(type == focusFcDamagePctCrit) value = base1; - break; - } - case SE_IncreaseNumHits: - { + case SE_FcIncreaseNumHits: if(type == focusIncreaseNumHits) value = base1; - break; - } - case SE_FcLimitUse: - { if(type == focusFcLimitUse) value = base1; - break; - } - case SE_FcMute: - { if(type == focusFcMute) value = base1; - break; - } case SE_FcStunTimeMod: - { if(type == focusFcStunTimeMod) value = base1; - break; - } } } - if (LimitSpellSkill && !SpellSkill_Found) - LimitFound = true; + for(int e = 0; e < MaxLimitInclude; e+=2) { + if (LimitInclude[e] && !LimitInclude[e+1]) + return 0; + } - if (LimitSpellEffect && !SpellEffect_Found) - LimitFound = true; - - if (LimitFound) + if (LimitFailure) return 0; return(value*lvlModifier/100); @@ -4468,54 +4416,60 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo int lvlModifier = 100; int spell_level = 0; int lvldiff = 0; - bool LimitSpellSkill = false; - bool SpellSkill_Found = false; - bool LimitSpellEffect = false; - bool SpellEffect_Found = false; uint32 Caston_spell_id = 0; + bool LimitInclude[MaxLimitInclude] = { false }; + /* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice spells. + 0/1 SE_LimitResist + 2/3 SE_LimitSpell + 4/5 SE_LimitEffect + 6/7 SE_LimitTarget + 8/9 SE_LimitSpellGroup: + 10/11 SE_LimitCastingSkill: + Remember: Update MaxLimitInclude in spdat.h if adding new limits that require Includes + */ + for (int i = 0; i < EFFECT_COUNT; i++) { switch (focus_spell.effectid[i]) { + case SE_Blank: break; - //check limits - case SE_LimitResist:{ - if(focus_spell.base[i]){ - if(spell.resisttype != focus_spell.base[i]) - return(0); + case SE_LimitResist: + if(focus_spell.base[i] < 0){ + if (spell.resisttype == -focus_spell.base[i]) //Exclude + return 0; + } + else { + LimitInclude[0] = true; + if (spell.resisttype == focus_spell.base[i]) //Include + LimitInclude[1] = true; } break; - } - case SE_LimitInstant:{ + + case SE_LimitInstant: if(spell.buffduration) - return(0); + return 0; break; - } - case SE_LimitMaxLevel:{ + case SE_LimitMaxLevel: if (IsNPC()) break; spell_level = spell.classes[(GetClass()%16) - 1]; lvldiff = spell_level - focus_spell.base[i]; //every level over cap reduces the effect by focus_spell.base2[i] percent unless from a clicky when ItemCastsUseFocus is true - if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)) - { - if(focus_spell.base2[i] > 0) - { + if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)){ + if(focus_spell.base2[i] > 0){ lvlModifier -= focus_spell.base2[i]*lvldiff; if(lvlModifier < 1) return 0; } else - { return 0; - } } break; - } - + case SE_LimitMinLevel: if (IsNPC()) break; @@ -4523,19 +4477,25 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo return(0); break; - case SE_LimitCastTime: + case SE_LimitCastTimeMin: if (spells[spell_id].cast_time < (uint16)focus_spell.base[i]) return(0); break; + case SE_LimitCastTimeMax: + if (spells[spell_id].cast_time > (uint16)focus_spell.base[i]) + return(0); + break; + case SE_LimitSpell: - if(focus_spell.base[i] < 0) { //exclude spell - if (spell_id == (focus_spell.base[i]*-1)) - return(0); - } else { - //this makes the assumption that only one spell can be explicitly included... - if (spell_id != focus_spell.base[i]) + if(focus_spell.base[i] < 0) { //Exclude + if (spell_id == -focus_spell.base[i]) return(0); + } + else { + LimitInclude[2] = true; + if (spell_id == focus_spell.base[i]) //Include + LimitInclude[3] = true; } break; @@ -4546,37 +4506,19 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo case SE_LimitEffect: if(focus_spell.base[i] < 0){ - if(IsEffectInSpell(spell_id,(focus_spell.base[i] * -1))){ //we limit this effect, can't have + if(IsEffectInSpell(spell_id,-focus_spell.base[i])) //Exclude return 0; } - } else{ - if(focus_spell.base[i] == SE_SummonPet) //summoning haste special case - { //must have one of the three pet effects to qualify - if(!IsEffectInSpell(spell_id, SE_SummonPet) && - !IsEffectInSpell(spell_id, SE_NecPet) && - !IsEffectInSpell(spell_id, SE_SummonBSTPet)) - { - return 0; - } - } - //else if(!SpellEffect_Found && (!IsEffectInSpell(spell_id,focus_spell.base[i])){ //we limit this effect, must have - // return 0; - //} + LimitInclude[4] = true; + if(IsEffectInSpell(spell_id,focus_spell.base[i])) //Include + LimitInclude[5] = true; } - - if(focus_spell.base[i] >= 0){ - LimitSpellEffect = true; - if (IsEffectInSpell(spell_id,focus_spell.base[i])) - SpellEffect_Found = true; - } - break; case SE_LimitSpellType: - switch( focus_spell.base[i] ) - { + switch( focus_spell.base[i]){ case 0: if (!IsDetrimentalSpell(spell_id)) return 0; @@ -4590,50 +4532,59 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo } break; - case SE_LimitManaCost: - if(spell.mana < focus_spell.base[i]) - return 0; + case SE_LimitManaMin: + if(spell.mana < focus_spell.base[i]) + return 0; + break; + + case SE_LimitManaMax: + if(spell.mana > focus_spell.base[i]) + return 0; break; case SE_LimitTarget: - // Exclude - if((focus_spell.base[i] < 0) && -focus_spell.base[i] == spell.targettype) - return 0; - // Include - else if (focus_spell.base[i] > 0 && focus_spell.base[i] != spell.targettype) - return 0; - + if (focus_spell.base[i] < 0) { + if (-focus_spell.base[i] == spell.targettype) //Exclude + return 0; + } + else { + LimitInclude[6] = true; + if (focus_spell.base[i] == spell.targettype) //Include + LimitInclude[7] = true; + } break; - case SE_CombatSkills: - // 1 is for disciplines only - if(focus_spell.base[i] == 1 && !IsDiscipline(spell_id)) - return 0; - // 0 is for spells only - else if(focus_spell.base[i] == 0 && IsDiscipline(spell_id)) + case SE_LimitCombatSkills: + if (focus_spell.base[i] == 0){ + if((spell.cast_time == 0) && (spell.recast_time == 0) && (spell.recovery_time == 0)) //Exclude procs return 0; + } break; case SE_LimitSpellGroup: - if(focus_spell.base[i] > 0 && focus_spell.base[i] != spell.spellgroup) + if(focus_spell.base[i] < 0) { + if (-focus_spell.base[i] == spell.spellgroup) //Exclude return 0; - else if(focus_spell.base[i] < 0 && focus_spell.base[i] == spell.spellgroup) - return 0; - break; - - case SE_LimitSpellSkill: - LimitSpellSkill = true; - if(focus_spell.base[i] == spell.skill) - SpellSkill_Found = true; - break; - - case SE_LimitExcludeSkill:{ - int16 spell_skill = spell.skill * -1; - if(focus_spell.base[i] == spell_skill) - return 0; - break; } + else { + LimitInclude[8] = true; + if (focus_spell.base[i] == spell.spellgroup) //Include + LimitInclude[9] = true; + } + break; + case SE_LimitCastingSkill: + if(focus_spell.base[i] < 0) { + if(-focus_spell.base[i] == spell.skill) + return 0; + } + else { + LimitInclude[10] = true; + if(focus_spell.base[i] == spell.skill) + LimitInclude[11] = true; + } + break; + case SE_LimitClass: //Do not use this limit more then once per spell. If multiple class, treat value like items would. if (!PassLimitClass(focus_spell.base[i], GetClass())) @@ -4645,12 +4596,12 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo return 0; break; - case SE_FfLimitUseMin: + case SE_LimitUseMin: if (focus_spell.base[i] > spell.numhits) return 0; break; - case SE_FfLimitUseType: + case SE_LimitUseType: if (focus_spell.base[i] != spell.numhitstype) return 0; break; @@ -4663,7 +4614,6 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo //handle effects case SE_ImprovedDamage: - // No Spell used this, its handled by different spell effect IDs. if (type == focusImprovedDamage) { // This is used to determine which focus should be used for the random calculation if(best_focus) { @@ -4685,6 +4635,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo } } break; + case SE_ImprovedHeal: if (type == focusImprovedHeal) { if(best_focus) { @@ -4703,6 +4654,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo } } break; + case SE_ReduceManaCost: if (type == focusManaCost) { if(best_focus) { @@ -4724,70 +4676,54 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo case SE_IncreaseSpellHaste: if (type == focusSpellHaste && focus_spell.base[i] > value) - { value = focus_spell.base[i]; - } break; + case SE_IncreaseSpellDuration: if (type == focusSpellDuration && focus_spell.base[i] > value) - { value = focus_spell.base[i]; - } break; + case SE_SpellDurationIncByTic: if (type == focusSpellDurByTic && focus_spell.base[i] > value) - { value = focus_spell.base[i]; - } break; + case SE_SwarmPetDuration: if (type == focusSwarmPetDuration && focus_spell.base[i] > value) - { value = focus_spell.base[i]; - } break; + case SE_IncreaseRange: if (type == focusRange && focus_spell.base[i] > value) - { value = focus_spell.base[i]; - } break; + case SE_ReduceReagentCost: if (type == focusReagentCost && focus_spell.base[i] > value) - { value = focus_spell.base[i]; - } break; + case SE_PetPowerIncrease: if (type == focusPetPower && focus_spell.base[i] > value) - { value = focus_spell.base[i]; - } break; + case SE_SpellResistReduction: if (type == focusResistRate && focus_spell.base[i] > value) - { value = focus_spell.base[i]; - } break; + case SE_SpellHateMod: - if (type == focusSpellHateMod) - { - if(value != 0) - { - if(value > 0) - { + if (type == focusSpellHateMod){ + if(value != 0){ + if(value > 0){ if(focus_spell.base[i] > value) - { value = focus_spell.base[i]; - } } - else - { + else{ if(focus_spell.base[i] < value) - { value = focus_spell.base[i]; - } } } else @@ -4796,55 +4732,28 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; case SE_ReduceReuseTimer: - { if(type == focusReduceRecastTime) value = focus_spell.base[i] / 1000; - break; - } case SE_TriggerOnCast: - { - if(type == focusTriggerOnCast) - { - if(MakeRandomInt(0, 100) <= focus_spell.base[i]) + if(type == focusTriggerOnCast){ + if(MakeRandomInt(1, 100) <= focus_spell.base[i]) value = focus_spell.base2[i]; - else value = 0; } + break; - break; - } - case SE_SpellVulnerability: - { - if(type == focusSpellVulnerability) - { - value = focus_spell.base[i]; - } - break; - } case SE_BlockNextSpellFocus: - { - if(type == focusBlockNextSpell) - { + if(type == focusBlockNextSpell){ if(MakeRandomInt(1, 100) <= focus_spell.base[i]) value = 1; } break; - } - case SE_Twincast: - { - if(type == focusTwincast) - { - value = focus_spell.base[i]; - } - break; - } + case SE_SympatheticProc: - { - if(type == focusSympatheticProc) - { + if(type == focusSympatheticProc) { float ProcChance, ProcBonus; int16 ProcRateMod = focus_spell.base[i]; //Baseline is 100 for most Sympathetic foci int32 cast_time = GetActSpellCasttime(spell_id, spells[spell_id].cast_time); @@ -4857,118 +4766,91 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo value = 0; } break; - } + + case SE_FcSpellVulnerability: + if(type == focusSpellVulnerability) + value = focus_spell.base[i]; + break; + + case SE_FcTwincast: + if(type == focusTwincast) + value = focus_spell.base[i]; + break; + case SE_FcDamageAmt: - { if(type == focusFcDamageAmt) value = focus_spell.base[i]; - break; - } case SE_FcDamageAmtCrit: - { if(type == focusFcDamageAmtCrit) value = focus_spell.base[i]; - break; - } case SE_FcDamageAmtIncoming: - { if(type == focusFcDamageAmtIncoming) value = focus_spell.base[i]; - break; - } case SE_FcHealAmtIncoming: - { if(type == focusFcHealAmtIncoming) value = focus_spell.base[i]; - break; - } - case SE_CriticalHealRate: - { - if (type == focusCriticalHealRate) - value = focus_spell.base[i]; - - break; - } - - case SE_AdditionalHeal: - { - if(type == focusAdditionalHeal) - value = focus_spell.base[i]; - - break; - } - - case SE_AdditionalHeal2: - { - if(type == focusAdditionalHeal2) - value = focus_spell.base[i]; - - break; - } - - case SE_HealRate2: - { - if(type == focusHealRate) - value = focus_spell.base[i]; - - break; - } - - case SE_FcBaseEffects: - { - if (type == focusFcBaseEffects) - value = focus_spell.base[i]; - - break; - } case SE_FcDamagePctCrit: - { if(type == focusFcDamagePctCrit) value = focus_spell.base[i]; - break; - } - case SE_IncreaseNumHits: - { + case SE_FcHealPctCritIncoming: + if (type == focusFcHealPctCritIncoming) + value = focus_spell.base[i]; + break; + + case SE_FcHealAmtCrit: + if(type == focusFcHealAmtCrit) + value = focus_spell.base[i]; + break; + + case SE_FcHealAmt: + if(type == focusFcHealAmt) + value = focus_spell.base[i]; + break; + + case SE_FcHealPctIncoming: + if(type == focusFcHealPctIncoming) + value = focus_spell.base[i]; + break; + + case SE_FcBaseEffects: + if (type == focusFcBaseEffects) + value = focus_spell.base[i]; + break; + + case SE_FcIncreaseNumHits: if(type == focusIncreaseNumHits) value = focus_spell.base[i]; - break; - } - case SE_FcLimitUse: - { if(type == focusFcLimitUse) value = focus_spell.base[i]; - break; - } case SE_FcMute: - { if(type == focusFcMute) value = focus_spell.base[i]; - break; - } case SE_FcStunTimeMod: - { if(type == focusFcStunTimeMod) value = focus_spell.base[i]; - break; - } + + case SE_FcTimerRefresh: + if(type == focusFcTimerRefresh) + value = focus_spell.base[i]; + break; #if EQDEBUG >= 6 //this spits up a lot of garbage when calculating spell focuses @@ -4977,13 +4859,13 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo LogFile->write(EQEMuLog::Normal, "CalcFocusEffect: unknown effectid %d", focus_spell.effectid[i]); #endif } + } - //Check for spell skill limits. - if (LimitSpellSkill && !SpellSkill_Found) - return 0; - if (LimitSpellEffect && !SpellEffect_Found) - return 0; + for(int e = 0; e < MaxLimitInclude; e+=2) { + if (LimitInclude[e] && !LimitInclude[e+1]) + return 0; + } if (Caston_spell_id){ if(IsValidSpell(Caston_spell_id) && (Caston_spell_id != spell_id)) @@ -5330,7 +5212,7 @@ void Mob::CheckNumHitsRemaining(uint8 type, uint32 buff_slot, uint16 spell_id) Field 175 = numhits type 1: [Incoming Hit Attempts] (323=SE_DefensiveProc, 172=SE_AvoidMeleeChance, 1=SE_ArmorClass, 40=SE_DivineAura) 2: [Outgoing Hit Attempts] (185=SE_DamageModifer, 184=SE_HitChance) - 3: [Incoming Spells] (180=SE_ResistSpellChance, 296=SE_SpellVulnerability) //Note: Determinetal spells only unless proven otherwise + 3: [Incoming Spells] (180=SE_ResistSpellChance, 296=SE_FcSpellVulnerability) //Note: Determinetal spells only unless proven otherwise 4: NONE 5: [Outgoing Hit Successes] (220=SE_SkillDamageAmount, 178=SE_MeleeLifetap, 121=SE_ReverseDS, ?373=SE_CastOnWearoff) 6: [Incoming Hit Successes] (59=SE_DamageShield, 197=SE_SkillDamageTaken, 162=define SE_MitigateMeleeDamage) @@ -5635,7 +5517,7 @@ int32 Mob::GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill, if (!skill_found){ if ((spells[buffs[i].spellid].effectid[e] == SE_LimitToSkill) || - (spells[buffs[i].spellid].effectid[e] == SE_LimitSpellSkill)){ + (spells[buffs[i].spellid].effectid[e] == SE_LimitCastingSkill)){ limit_exists = true; if (spells[buffs[i].spellid].base[e] == skill) @@ -5662,6 +5544,58 @@ int32 Mob::GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill, return dmg; } +int32 Mob::GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id) { + + /* + This is a general function for calculating best focus effect values for focus effects that exist on targets but modify incoming spells. + Should be used when checking for foci that can exist on clients or npcs ect. + Example: When your target has a focus limited buff that increases amount of healing on them. + */ + + if (!caster) + return 0; + + int value = 0; + + if (spellbonuses.FocusEffects[type]){ + uint32 buff_count = GetMaxTotalSlots(); + for(int i = 0; i < buff_count; i++){ + + int32 tmp_focus = 0; + int tmp_buffslot = -1; + + int buff_count = GetMaxTotalSlots(); + for(int i = 0; i < buff_count; i++) { + + if((IsValidSpell(buffs[i].spellid) && IsEffectInSpell(buffs[i].spellid, effect))){ + + int32 focus = caster->CalcFocusEffect(type, buffs[i].spellid, spell_id); + + if (!focus) + continue; + + if (tmp_focus && focus > tmp_focus){ + tmp_focus = focus; + tmp_buffslot = i; + } + + else if (!tmp_focus){ + tmp_focus = focus; + tmp_buffslot = i; + } + } + } + + value = tmp_focus; + + if (tmp_buffslot >= 0) + CheckNumHitsRemaining(7, tmp_buffslot); + } + + } + return value; +} + int32 Mob::ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard) { // 9-17-12: This is likely causing crashes, disabled till can resolve. diff --git a/zone/spells.cpp b/zone/spells.cpp index 795887e02..d3b24cd78 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2689,7 +2689,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, effect1 == SE_LimitMinDur || effect1 == SE_LimitInstant || effect1 == SE_LimitMinLevel || - effect1 == SE_LimitCastTime) + effect1 == SE_LimitCastTimeMin) continue; /*