// Things and thing categories
        private void LoadSpriteCategories()
        {
            // Get thing categories
            IDictionary dic = cfg.ReadSetting("spritetypes", new Hashtable());

            foreach (DictionaryEntry de in dic)
            {
                if (de.Value is IDictionary)
                {
                    // Make a category
                    SpriteCategory thingcat = new SpriteCategory(cfg, de.Key.ToString(), enums);

                    // Add all things in category to the big list
                    foreach (SpriteInfo t in thingcat.Sprites)
                    {
                        if (!things.ContainsKey(t.Index))
                        {
                            things.Add(t.Index, t);
                        }
                        else
                        {
                            General.ErrorLogger.Add(ErrorType.Warning, "Sprite number " + t.Index + " is defined more than once (as \"" + things[t.Index].Title + "\" and \"" + t.Title + "\") in game configuration \"" + this.Name + "\"");
                        }
                    }

                    // Add category to list
                    thingcategories.Add(thingcat);
                }
            }
        }
 // Constructor
 internal SpriteInfo(int tileindex)
 {
     // Initialize
     this.tileindex = tileindex;
     this.category  = null;
     this.title     = "Sprite";
     this.color     = 0;
     //this.radius = 10f;
     //this.height = 20f;
     this.fixedsize = false;
     this.isknown   = false;
 }
        // Constructor
        public SpriteInfo(SpriteCategory cat, int tileindex, string title)
        {
            // Initialize
            this.tileindex = tileindex;
            this.category  = cat;
            this.title     = title;
            //this.actor = null;
            this.isknown = true;
            //this.args = new ArgumentInfo[Linedef.NUM_ARGS];
            //for(int i = 0; i < Linedef.NUM_ARGS; i++) this.args[i] = new ArgumentInfo(i);

            // Read properties
            //this.sprite = cat.Sprite;
            this.color = cat.Color;
            //this.arrow = (cat.Arrow != 0);
            //this.radius = cat.Radius;
            //this.height = cat.Height;
            //this.hangs = (cat.Hangs != 0);
            //this.blocking = cat.Blocking;
            //this.errorcheck = cat.ErrorCheck;
            this.fixedsize = cat.FixedSize;
            //this.absolutez = cat.AbsoluteZ;
            //this.spritescale = new SizeF(cat.SpriteScale, cat.SpriteScale);

            // Safety
            //if(this.radius < 4f) this.radius = 8f;

            // Make long name for sprite lookup

            /*if(this.sprite.Length <= 8)
             *      this.spritelongname = Lump.MakeLongName(this.sprite);
             * else
             *      this.spritelongname = long.MaxValue;*/

            // We have no destructor
            //GC.SuppressFinalize(this);
        }
        // Constructor
        internal SpriteInfo(SpriteCategory cat, int tileindex, Configuration cfg, IDictionary <string, EnumList> enums)
        {
            string key = "spritetypes." + cat.Name + "." + tileindex.ToString(CultureInfo.InvariantCulture) + ".";

            // Initialize
            this.tileindex = tileindex;
            this.category  = cat;
            this.isknown   = true;

            // Read properties
            this.title = cfg.ReadSetting(key + "title", "<" + key + ">");
            //this.sprite = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".sprite", cat.Sprite);
            this.color = cfg.ReadSetting(key + "color", cat.Color);
            //this.arrow = (cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".arrow", cat.Arrow) != 0);
            //this.radius = cfg.ReadSetting(key + "width", cat.Radius);
            //this.height = cfg.ReadSetting(key + "height", cat.Height);
            //this.hangs = (cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".hangs", cat.Hangs) != 0);
            //this.blocking = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".blocking", cat.Blocking);
            //this.errorcheck = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".error", cat.ErrorCheck);
            this.fixedsize = cfg.ReadSetting(key + "fixedsize", cat.FixedSize);

            //this.absolutez = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".absolutez", cat.AbsoluteZ);
            //float sscale = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".spritescale", cat.SpriteScale);
            //this.spritescale = new SizeF(sscale, sscale);

            // Read property infos
            hitaginfo   = new PropertyInfo(cfg, key + "hitag", PropertyType.HiTag, enums);
            lotaginfo   = new PropertyInfo(cfg, key + "lotag", PropertyType.LoTag, enums);
            paletteinfo = new PropertyInfo(cfg, key + "palette", PropertyType.Palette, enums);
            angleinfo   = new PropertyInfo(cfg, key + "angle", PropertyType.AngleBuild, enums);

            // Read sprite angles
            List <int> spriteangles = new List <int>();
            string     anglessstr   = cfg.ReadSetting(key + "spriteangles", string.Empty);

            if (!string.IsNullOrEmpty(anglessstr) && !General.GetNumbersFromString(anglessstr, spriteangles, false))
            {
                General.ErrorLogger.Add(ErrorType.Warning, "Unable to get Sprite angles from string \"" + anglessstr + "\" while parsing Sprite \"" + tileindex + " - " + this.title + "\"");
            }

            if (spriteangles.Count == 8)
            {
                //TODO: implement sprite rotations...
            }

            // Read the args
            //for(int i = 0; i < Linedef.NUM_ARGS; i++)
            //this.args[i] = new ArgumentInfo(cfg, "thingtypes." + cat.Name + "." + key, i, enums);

            // Safety
            //if(this.radius < 4f) this.radius = 8f;

            // Make long name for sprite lookup

            /*if(this.sprite.Length <= 8)
             *      this.spritelongname = Lump.MakeLongName(this.sprite);
             * else
             *      this.spritelongname = long.MaxValue;*/

            // We have no destructor
            //GC.SuppressFinalize(this);
        }