diff --git a/common/ruletypes.h b/common/ruletypes.h index c0e740493..82c4f9ecc 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -378,6 +378,7 @@ RULE_BOOL(Spells, CazicTouchTargetsPetOwner, true, "If True, causes Cazic Touch RULE_BOOL(Spells, PreventFactionWarOnCharmBreak, false, "Enable spell interupts and dot removal on charm break to prevent faction wars.") RULE_BOOL(Spells, AllowDoubleInvis, false, "Allows you to cast invisibility spells on a player that is already invisible") RULE_BOOL(Spells, AllowSpellMemorizeFromItem, false, "Allows players to memorize spells by right-clicking spell scrolls") +RULE_BOOL(Spells, InvisRequiresGroup, false, "Invis requires the the target to be in group.") RULE_CATEGORY_END() RULE_CATEGORY(Combat) diff --git a/common/spdat.cpp b/common/spdat.cpp index d7b38096e..e5d85ba9e 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -260,6 +260,18 @@ bool IsDetrimentalSpell(uint16 spell_id) return !IsBeneficialSpell(spell_id); } +bool IsInvisSpell(uint16 spell_id) +{ + if (IsEffectInSpell(spell_id, SE_Invisibility) || + IsEffectInSpell(spell_id, SE_Invisibility2) || + IsEffectInSpell(spell_id, SE_InvisVsUndead) || + IsEffectInSpell(spell_id, SE_InvisVsUndead2) || + IsEffectInSpell(spell_id, SE_InvisVsAnimals)) { + return true; + } + return false; +} + bool IsInvulnerabilitySpell(uint16 spell_id) { return IsEffectInSpell(spell_id, SE_DivineAura); diff --git a/common/spdat.h b/common/spdat.h index e4ffb23be..3bcb17487 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -1083,6 +1083,7 @@ bool IsPercentalHealSpell(uint16 spell_id); bool IsGroupOnlySpell(uint16 spell_id); bool IsBeneficialSpell(uint16 spell_id); bool IsDetrimentalSpell(uint16 spell_id); +bool IsInvisSpell(uint16 spell_id); bool IsInvulnerabilitySpell(uint16 spell_id); bool IsCHDurationSpell(uint16 spell_id); bool IsPoisonCounterSpell(uint16 spell_id); diff --git a/zone/spells.cpp b/zone/spells.cpp index a26c9e2dc..12bc97493 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -431,6 +431,28 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot, // ok now we know the target casting_spell_targetid = target_id; + if (RuleB(Spells, InvisRequiresGroup) && IsInvisSpell(spell_id)) { + if (GetTarget() && GetTarget()->IsClient()) { + Client *spell_target = entity_list.GetClientByID(target_id); + if (spell_target && spell_target->GetID() != GetID()) { + if (!spell_target->IsGrouped()) { + InterruptSpell(spell_id); + Message(Chat::Red, "You cannot invis someone who is not in your group."); + return false; + } + else if (spell_target->IsGrouped()) { + Group *target_group = spell_target->GetGroup(); + Group *my_group = GetGroup(); + if (target_group && my_group && (target_group->GetID() != my_group->GetID())) { + InterruptSpell(spell_id); + Message(Chat::Red, "You cannot invis someone who is not in your group."); + return false; + } + } + } + } + } + // We don't get actual mana cost here, that's done when we consume the mana if (mana_cost == -1) mana_cost = spell.mana; @@ -2786,6 +2808,7 @@ int Mob::CalcBuffDuration(Mob *caster, Mob *target, uint16 spell_id, int32 caste spell_id != 287 && spell_id != 601 && IsEffectInSpell(spell_id, SE_Illusion)) res = 10000; // ~16h override + res = mod_buff_duration(res, caster, target, spell_id); LogSpells("Spell [{}]: Casting level [{}], formula [{}], base_duration [{}]: result [{}]",