diff --git a/common/ruletypes.h b/common/ruletypes.h index e9599e09b..11a55c423 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -397,6 +397,7 @@ RULE_BOOL(Spells, FlatItemExtraSpellAmt, false) // allow SpellDmg stat to affect RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the target type to single target. +RULE_BOOL(Spells, OldRainTargets, false) // use old incorrectly implemented max targets for rains RULE_CATEGORY_END() RULE_CATEGORY(Combat) diff --git a/zone/beacon.cpp b/zone/beacon.cpp index 27f86fce7..e5ea9f38f 100644 --- a/zone/beacon.cpp +++ b/zone/beacon.cpp @@ -68,6 +68,7 @@ Beacon::Beacon(Mob *at_mob, int lifetime) resist_adjust = 0; spell_iterations = 0; caster_id = 0; + max_targets = 4; // default if(lifetime) remove_timer.Start(); @@ -93,10 +94,10 @@ bool Beacon::Process() ) { Mob *caster = entity_list.GetMob(caster_id); - if(caster && spell_iterations--) + if(caster && spell_iterations-- && max_targets) { bool affect_caster = (!caster->IsNPC() && !caster->IsAIControlled()); //NPC AE spells do not affect the NPC caster - entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust); + entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust, &max_targets); } else { @@ -126,6 +127,8 @@ void Beacon::AELocationSpell(Mob *caster, uint16 cast_spell_id, int16 resist_adj this->resist_adjust = resist_adjust; spell_iterations = spells[spell_id].AEDuration / 2500; spell_iterations = spell_iterations < 1 ? 1 : spell_iterations; // at least 1 + if (spells[spell_id].aemaxtargets) + max_targets = spells[spell_id].aemaxtargets; spell_timer.Start(2500); spell_timer.Trigger(); } diff --git a/zone/beacon.h b/zone/beacon.h index b79ed318c..c22189dfd 100644 --- a/zone/beacon.h +++ b/zone/beacon.h @@ -56,6 +56,7 @@ protected: int16 resist_adjust; int spell_iterations; Timer spell_timer; + int max_targets; uint16 caster_id; private: diff --git a/zone/effects.cpp b/zone/effects.cpp index e7933a833..0585f3c50 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -694,7 +694,7 @@ void EntityList::AETaunt(Client* taunter, float range, int32 bonus_hate) // causes caster to hit every mob within dist range of center with // spell_id. // NPC spells will only affect other NPCs with compatible faction -void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster, int16 resist_adjust) +void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster, int16 resist_adjust, int *max_targets) { Mob *curmob = nullptr; @@ -709,9 +709,13 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ bool bad = IsDetrimentalSpell(spell_id); bool isnpc = caster->IsNPC(); - int MAX_TARGETS_ALLOWED = 4; - if (spells[spell_id].aemaxtargets) + if (RuleB(Spells, OldRainTargets)) + max_targets = nullptr; // ignore it! + + int MAX_TARGETS_ALLOWED = max_targets ? *max_targets : 4; + + if (!max_targets && spells[spell_id].aemaxtargets) MAX_TARGETS_ALLOWED = spells[spell_id].aemaxtargets; int iCounter = 0; @@ -789,8 +793,10 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ } if (!isnpc || spells[spell_id].aemaxtargets) //npcs are not target limited (unless casting a spell with a target limit)... - iCounter++; + iCounter++; // should really pull out the MAX_TARGETS_ALLOWED calc so we can break early ... } + if (max_targets) + *max_targets = *max_targets - std::min(iCounter, *max_targets); // could be higher than the count } void EntityList::MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster) diff --git a/zone/entity.h b/zone/entity.h index 94078691a..e2224d05d 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -357,7 +357,7 @@ public: void AEAttack(Mob *attacker, float dist, int Hand = EQEmu::inventory::slotPrimary, int count = 0, bool IsFromSpell = false); void AETaunt(Client *caster, float range=0, int32 bonus_hate=0); - void AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true, int16 resist_adjust = 0); + void AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true, int16 resist_adjust = 0, int *max_targets = nullptr); void MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true); void AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);