From 52d92b71814e6e364e0d5ada187c71f53238ab9c Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 2 Aug 2014 21:10:44 -0400 Subject: [PATCH] Implemented broad support for fields min_dist, min_dist_mod, max_dist, max_dist_mod - Scales spell power based on targets distance from caster. This implemented in a broad way to function with spells that would make sense to scale. Some work will still be needed on this. Be aware if making custom spells not everything will work and certain effects just should not be included (use common sense). --- changelog.txt | 4 +++- common/spdat.cpp | 9 +++++++++ common/spdat.h | 1 + zone/effects.cpp | 7 ++++++- zone/groups.cpp | 1 + zone/hate_list.cpp | 6 +++++- zone/mob.cpp | 1 + zone/mob.h | 4 ++++ zone/spell_effects.cpp | 31 ++++++++++++++++++++++++++++++- zone/spells.cpp | 10 ++++++++-- 10 files changed, 68 insertions(+), 6 deletions(-) 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;