public void OnModuleHeartbeat()
        {
            foreach (var entry in _state.NPCEffects)
            {
                CasterSpellVO casterModel = entry.Key;
                _state.NPCEffects[entry.Key] = entry.Value - 1;
                Data.Entities.CustomEffect entity = _db.CustomEffects.Single(x => x.CustomEffectID == casterModel.CustomEffectID);
                ICustomEffect handler             = App.ResolveByInterface <ICustomEffect>("CustomEffect." + entity.ScriptHandler);

                try
                {
                    handler?.Tick(casterModel.Caster, casterModel.Target);
                }
                catch (Exception ex)
                {
                    _error.LogError(ex, "OnModuleHeartbeat was unable to run specific effect script: " + entity.ScriptHandler);
                }


                // Kill the effect if it has expired, target is invalid, or target is dead.
                if (entry.Value <= 0 ||
                    !casterModel.Target.IsValid ||
                    casterModel.Target.CurrentHP <= -11)
                {
                    _state.EffectsToRemove.Add(entry.Key);

                    handler?.WearOff(casterModel.Caster, casterModel.Target);

                    if (casterModel.Caster.IsValid && casterModel.Caster.IsPlayer)
                    {
                        casterModel.Caster.SendMessage("Your effect '" + casterModel.EffectName + "' has worn off of " + casterModel.Target.Name);
                    }

                    casterModel.Target.DeleteLocalInt("CUSTOM_EFFECT_ACTIVE_" + casterModel.CustomEffectID);
                }
            }

            foreach (CasterSpellVO entry in _state.EffectsToRemove)
            {
                _state.NPCEffects.Remove(entry);
            }
            _state.EffectsToRemove.Clear();
        }
        public void ApplyCustomEffect(NWCreature oCaster, NWCreature oTarget, int customEffectID, int ticks, int effectLevel)
        {
            // Can't apply the effect if the existing one is stronger.
            int existingEffectLevel = GetActiveEffectLevel(oTarget, customEffectID);

            if (existingEffectLevel > effectLevel)
            {
                oCaster.SendMessage("A more powerful effect already exists on your target.");
                return;
            }

            Data.Entities.CustomEffect effectEntity = _db.CustomEffects.Single(x => x.CustomEffectID == customEffectID);

            // PC custom effects are tracked in the database.
            if (oTarget.IsPlayer)
            {
                PCCustomEffect entity = _db.PCCustomEffects.SingleOrDefault(x => x.PlayerID == oTarget.GlobalID && x.CustomEffectID == customEffectID);

                if (entity == null)
                {
                    entity = new PCCustomEffect
                    {
                        PlayerID       = oTarget.GlobalID,
                        CustomEffectID = customEffectID
                    };

                    _db.PCCustomEffects.Add(entity);
                }

                entity.Ticks = ticks;
                _db.SaveChanges();

                oTarget.SendMessage(effectEntity.StartMessage);
            }
            // NPCs custom effects are tracked in server memory.
            else
            {
                // Look for existing effect.
                foreach (var entry in _state.NPCEffects)
                {
                    CasterSpellVO casterSpellModel = entry.Key;

                    if (casterSpellModel.Caster.Equals(oCaster) &&
                        casterSpellModel.CustomEffectID == customEffectID &&
                        casterSpellModel.Target.Equals(oTarget))
                    {
                        _state.NPCEffects[entry.Key] = ticks;
                        return;
                    }
                }

                // Didn't find an existing effect. Create a new one.
                CasterSpellVO spellModel = new CasterSpellVO
                {
                    Caster         = oCaster,
                    CustomEffectID = customEffectID,
                    EffectName     = effectEntity.Name,
                    Target         = oTarget
                };

                _state.NPCEffects[spellModel] = ticks;
            }

            ICustomEffect handler = App.ResolveByInterface <ICustomEffect>("CustomEffect." + effectEntity.ScriptHandler);

            handler?.Apply(oCaster, oTarget);
            oTarget.SetLocalInt("CUSTOM_EFFECT_ACTIVE_" + customEffectID, effectLevel);
        }