diff --git a/changelog.txt b/changelog.txt index 2847b92e6..85fa4ecb5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,7 +5,9 @@ Kayen: Implemented spell_news fields - npc_no_los (check if LOS is required for spells) - InCombat, OutofCombat - Used together to restrict spells to only be cast while in/out of combat (beneficial) or if target is in/out of combat (detrimental). -Many new fields added and defined for future development. +-min_dist, min_dist_mod, max_dist, max_dist_mod - Scales spell power based on targets distance from caster. +*This will require further work to fully implement but will work with 90% of live spells as is. +*If making custom spells do not include effects that can't be scaled (like a spell trigger) Required SQL: utils/sql/git/required/2014_08_02_spells_new.sql diff --git a/common/spdat.cpp b/common/spdat.cpp index 75f1e9b88..8e93f4e1f 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -1040,6 +1040,15 @@ bool IsCastonFadeDurationSpell(uint16 spell_id) return false; } +bool IsPowerDistModSpell(uint16 spell_id) +{ + if (IsValidSpell(spell_id) && + (spells[spell_id].max_dist_mod || spells[spell_id].min_dist_mod) && spells[spell_id].max_dist > spells[spell_id].min_dist) + return true; + + return false; +} + uint32 GetPartialMeleeRuneReduction(uint32 spell_id) { for (int i = 0; i < EFFECT_COUNT; ++i) diff --git a/common/spdat.h b/common/spdat.h index 510817121..ec068585c 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -845,6 +845,7 @@ bool IsPersistDeathSpell(uint16 spell_id); bool IsSuspendableSpell(uint16 spell_id); uint32 GetMorphTrigger(uint32 spell_id); bool IsCastonFadeDurationSpell(uint16 spell_id); +bool IsPowerDistModSpell(uint16 spell_id); uint32 GetPartialMeleeRuneReduction(uint32 spell_id); uint32 GetPartialMagicRuneReduction(uint32 spell_id); uint32 GetPartialMeleeRuneAmount(uint32 spell_id); diff --git a/zone/effects.cpp b/zone/effects.cpp index c298974db..27cccd0a9 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -740,6 +740,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ float dist = caster->GetAOERange(spell_id); float dist2 = dist * dist; + float dist_targ = 0; bool bad = IsDetrimentalSpell(spell_id); bool isnpc = caster->IsNPC(); @@ -755,7 +756,9 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ continue; if (curmob == caster && !affect_caster) //watch for caster too continue; - if (center->DistNoRoot(*curmob) > dist2) //make sure they are in range + + dist_targ = center->DistNoRoot(*curmob); + if (dist_targ > dist2) //make sure they are in range continue; if (isnpc && curmob->IsNPC()) { //check npc->npc casting FACTION_VALUE f = curmob->GetReverseFactionCon(caster); @@ -786,6 +789,8 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ continue; } + curmob->CalcSpellPowerDistanceMod(spell_id, dist_targ); + //if we get here... cast the spell. if (IsTargetableAESpell(spell_id) && bad) { if (iCounter < MAX_TARGETS_ALLOWED) { diff --git a/zone/groups.cpp b/zone/groups.cpp index 6aee5f38b..c9f6e9127 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -674,6 +674,7 @@ void Group::CastGroupSpell(Mob* caster, uint16 spell_id) { { distance = caster->DistNoRoot(*members[z]); if(distance <= range2) { + members[z]->CalcSpellPowerDistanceMod(spell_id, distance); caster->SpellOnTarget(spell_id, members[z]); #ifdef GROUP_BUFF_PETS if(members[z]->GetPet() && members[z]->HasPetAffinity() && !members[z]->GetPet()->IsCharmed()) diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index bb39d224a..f3de52544 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -567,20 +567,24 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range) //So keep a list of entity ids and look up after std::list id_list; range = range * range; + float dist_targ = 0; auto iterator = list.begin(); while (iterator != list.end()) { tHateEntry *h = (*iterator); if(range > 0) { - if(caster->DistNoRoot(*h->ent) <= range) + dist_targ = caster->DistNoRoot(*h->ent); + if(dist_targ <= range) { id_list.push_back(h->ent->GetID()); + h->ent->CalcSpellPowerDistanceMod(spell_id, dist_targ); } } else { id_list.push_back(h->ent->GetID()); + h->ent->CalcSpellPowerDistanceMod(spell_id, 0, caster); } ++iterator; } diff --git a/zone/mob.cpp b/zone/mob.cpp index a55390050..24b691e36 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -182,6 +182,7 @@ Mob::Mob(const char* in_name, has_numhits = false; has_MGB = false; has_ProjectIllusion = false; + SpellPowerDistanceMod = 0; if(in_aa_title>0) aa_title = in_aa_title; diff --git a/zone/mob.h b/zone/mob.h index 1793e0864..15f1728ec 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -615,6 +615,9 @@ public: bool ImprovedTaunt(); bool TryRootFadeByDamage(int buffslot, Mob* attacker); int16 GetSlowMitigation() const {return slow_mitigation;} + void CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster = nullptr); + inline int16 GetSpellPowerDistanceMod() const { return SpellPowerDistanceMod; }; + inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; }; void ModSkillDmgTaken(SkillUseTypes skill_num, int value); int16 GetModSkillDmgTaken(const SkillUseTypes skill_num); @@ -1114,6 +1117,7 @@ protected: bool has_numhits; bool has_MGB; bool has_ProjectIllusion; + int16 SpellPowerDistanceMod; // Bind wound Timer bindwound_timer; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 0ee88a154..864bf004c 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -186,6 +186,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) buffs[buffslot].numhits = numhit; } + bool _IsPowerDistModSpell = false; + if (IsPowerDistModSpell(spell_id)) + _IsPowerDistModSpell = true; + else + SetSpellPowerDistanceMod(0); + // iterate through the effects in the spell for (i = 0; i < EFFECT_COUNT; i++) { @@ -198,6 +204,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(spell_id == SPELL_LAY_ON_HANDS && caster && caster->GetAA(aaImprovedLayOnHands)) effect_value = GetMaxHP(); + if (_IsPowerDistModSpell) + effect_value += (effect_value*(GetSpellPowerDistanceMod()/100)/100); + #ifdef SPELL_EFFECT_SPAM effect_desc[0] = 0; #endif @@ -6444,4 +6453,24 @@ bool Mob::CheckSpellCategory(uint16 spell_id, int category_id, int effect_id){ return false; } - \ No newline at end of file + +void Mob::CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster) +{ + if (IsPowerDistModSpell(spell_id)){ + + float distance = 0; + + if (caster && !range) + distance = caster->CalculateDistance(GetX(), GetY(), GetZ()); + else + distance = sqrt(range); + + float dm_range = spells[spell_id].max_dist - spells[spell_id].min_dist; + float dm_mod_interval = spells[spell_id].max_dist_mod - spells[spell_id].min_dist_mod; + float dist_from_min = distance - spells[spell_id].min_dist; + float mod = spells[spell_id].min_dist_mod + (dist_from_min * (dm_mod_interval/dm_range)); + mod *= 100.0f; + + SetSpellPowerDistanceMod(static_cast(mod)); + } +} \ No newline at end of file diff --git a/zone/spells.cpp b/zone/spells.cpp index 6757a7ba6..f5bd8f09d 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1915,6 +1915,8 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 Message_StringID(13, TARGET_OUT_OF_RANGE); return(false); } + + spell_target->CalcSpellPowerDistanceMod(spell_id, dist2); } // @@ -2114,16 +2116,20 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 if((heading_to_target >= angle_start && heading_to_target <= 360.0f) || (heading_to_target >= 0.0f && heading_to_target <= angle_end)) { - if(CheckLosFN(spell_target)) + if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los){ + (*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this); SpellOnTarget(spell_id, spell_target, false, true, resist_adjust); + } } } else { if(heading_to_target >= angle_start && heading_to_target <= angle_end) { - if(CheckLosFN((*iter))) + if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los){ + (*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this); SpellOnTarget(spell_id, (*iter), false, true, resist_adjust); + } } } ++iter;