diff --git a/zone/mob.cpp b/zone/mob.cpp index e056a81c2..accd36bb0 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3223,7 +3223,7 @@ void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on, int lev if(twinproc_chance && zone->random.Roll(twinproc_chance)) twinproc = true; - if (IsBeneficialSpell(spell_id)) { + if (IsBeneficialSpell(spell_id) && (!IsNPC() || (IsNPC() && CastToNPC()->GetInnateProcSpellID() != spell_id))) { // NPC innate procs don't take this path ever SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff, true, level_override); if(twinproc) SpellOnTarget(spell_id, this, false, false, 0, true, level_override); diff --git a/zone/mob.h b/zone/mob.h index a01a4b8f5..b80667b02 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -265,7 +265,7 @@ public: bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1); virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1); virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, - CastAction_type &CastAction, EQEmu::CastingSlot slot); + CastAction_type &CastAction, EQEmu::CastingSlot slot, bool isproc = false); virtual bool CheckFizzle(uint16 spell_id); virtual bool CheckSpellLevelRestriction(uint16 spell_id); virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster); diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index eb795f6c3..eb14865ce 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -2362,8 +2362,10 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { return a.priority > b.priority; }); - if (IsValidSpell(attack_proc_spell)) + if (IsValidSpell(attack_proc_spell)) { AddProcToWeapon(attack_proc_spell, true, proc_chance); + innate_proc_spell_id = attack_proc_spell; + } if (IsValidSpell(range_proc_spell)) AddRangedProc(range_proc_spell, (rproc_chance + 100)); diff --git a/zone/npc.cpp b/zone/npc.cpp index 15e96f3bf..1fc27dc5a 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -233,6 +233,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if npc_spells_id = 0; HasAISpell = false; HasAISpellEffects = false; + innate_proc_spell_id = 0; if(GetClass() == MERCERNARY_MASTER && RuleB(Mercs, AllowMercs)) { diff --git a/zone/npc.h b/zone/npc.h index 0023d4273..d3e7928a2 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -407,6 +407,7 @@ public: void mod_npc_killed_merit(Mob* c); void mod_npc_killed(Mob* oos); void AISpellsList(Client *c); + uint16 GetInnateProcSpellID() const { return innate_proc_spell_id; } uint32 GetHeroForgeModel() const { return herosforgemodel; } void SetHeroForgeModel(uint32 model) { herosforgemodel = model; } @@ -454,6 +455,7 @@ protected: virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); AISpellsVar_Struct AISpellVar; int16 GetFocusEffect(focusType type, uint16 spell_id); + uint16 innate_proc_spell_id; uint32 npc_spells_effects_id; std::vector AIspellsEffects; diff --git a/zone/spells.cpp b/zone/spells.cpp index 855a2917c..38c38b212 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1349,7 +1349,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo } -bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, CastingSlot slot) +bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, CastingSlot slot, bool isproc) { /* The basic types of spells: @@ -1396,6 +1396,11 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce targetType = ST_GroupClientAndPet; } + // NPC innate procs override the target type to single target. + // Yes. This code will cause issues if they have the proc as innate AND on a weapon. Oh well. + if (isproc && IsNPC() && CastToNPC()->GetInnateProcSpellID() == spell_id) + targetType = ST_Target; + if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){ Message_StringID(13,SPELL_NEED_TAR); return false; @@ -1983,7 +1988,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui //determine the type of spell target we have CastAction_type CastAction; - if(!DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction, slot)) + if(!DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction, slot, isproc)) return(false); Log.Out(Logs::Detail, Logs::Spells, "Spell %d: target type %d, target %s, AE center %s", spell_id, CastAction, spell_target?spell_target->GetName():"NONE", ae_center?ae_center->GetName():"NONE");