public BookTypes?GetBookType(TESObjectBOOK book)
        {
            if (book != null)
            {
                BookTypes t;
                if (this.type_map.TryGetValue(book.FormId, out t))
                {
                    return(t);
                }
            }

            return(null);
        }
        private BookTypes?DetermineBookType(TESObjectBOOK book)
        {
            // If we can't pick it up, must be special.
            if ((book.BookData.BookFlags & TESObjectBOOK.DataFlags.CantTake) != TESObjectBOOK.DataFlags.None)
            {
                return(BookTypes.Special);
            }

            // Teaches spell.
            if (book.IsSpellBook)
            {
                return(BookTypes.SpellBook);
            }

            // Advances skill.
            if (book.IsSkillBook)
            {
                return(BookTypes.SkillBook);
            }

            // Some special items don't have this keyword.
            if (!book.HasKeywordText("VendorItemBook"))
            {
                return(BookTypes.Special);
            }

            // Model path.
            string modelPath = book.ModelName.Text ?? "";

            modelPath = modelPath.ToLowerInvariant().Replace("\\", "/").Trim();
            if (modelPath.StartsWith("clutter/books/"))
            {
                modelPath = modelPath.Substring("clutter/books/".Length);
            }

            // Elder scroll looks like a book to all other conditions.
            if (modelPath.Contains("elderscroll"))
            {
                return(BookTypes.Special);
            }

            // This doesn't actually work because books don't have editor ID in game :(

            /*string editorName = book.EditorId;
             * if (!string.IsNullOrEmpty(editorName))
             * {
             *  if (editorName.StartsWith("dun")) // Some dungeon related journals or diaries are impossible to determine any other way.
             *      return BookTypes.Special;
             *  if (editorName.StartsWith("MGR")) // Mage questline books, like the ritual quest books or shalidor's insight, they are useless arcane images and duplicates of each other.
             *      return BookTypes.Special;
             * }*/

            // Pickup sound of a note or single page.
            {
                var sound = book.PickupSound;
                if (sound != null && sound.FormId == 0xC7A54)
                {
                    return(BookTypes.Note);
                }
            }

            // Modelpath says note.
            if (modelPath.Contains("note"))
            {
                return(BookTypes.Note);
            }

            // This usually catches all journals but some journals still look like books.
            if (modelPath.Contains("journal"))
            {
                return(BookTypes.Journal);
            }

            // Looks like normal book, although some journals or quest related dungeon stuff still fall here as well.
            return(BookTypes.NormalBook);
        }
        private TESEffectShader ShouldGlow(TESObjectREFR obj, NiPoint3 pos)
        {
            if (obj == null)
            {
                return(null);
            }

            var           form = obj.BaseForm;
            TESObjectBOOK book = null;

            if (form == null || (book = form as TESObjectBOOK) == null || book.IsRead)
            {
                return(null);
            }

            TESObjectCELL cell = null;

            if (obj.Node == null || (cell = obj.ParentCell) == null)
            {
                return(null);
            }

            var tes = TES.Instance;

            if (tes == null)
            {
                return(null);
            }

            if (!Memory.InvokeCdecl(_is_cell_loaded, tes.Cast <TES>(), cell.Cast <TESObjectCELL>(), 0).ToBool())
            {
                return(null);
            }

            var tracker = Tools.BookTracker.Instance;
            var type    = tracker.GetBookType(book);

            if (!type.HasValue)
            {
#if DEBUG_MSG
                NetScriptFramework.Main.WriteDebugMessage("Warning: " + book.ToString() + " does not have a type in tracker!");
#endif
                return(null);
            }

            int mask = 1 << (int)type.Value;
            if ((this._care_mask & mask) == 0)
            {
                return(null);
            }

            if (obj.Position.GetDistance(pos) > 8000.0f)
            {
                return(null);
            }

            var ls = this._shaders[(int)type.Value];
            if (ls.Count == 0)
            {
                return(null);
            }

            if (ls.Count == 1)
            {
                return(ls[0]);
            }

            return(ls[rnd.Next(0, ls.Count)]);
        }