private static IMacroCommand OnAction(byte[] data)
        {
            PacketReader reader = new PacketReader(data);

            reader.Skip(3);

            byte action = reader.ReadByte();
            string cmd = reader.ReadAnsiString(reader.Length - 4);

            switch (action) {
                case 0x24: // UseSkill
                    Debug.Assert(cmd.EndsWith(" 0"));
                    return new UseSkillMacroCommand(Byte.Parse(cmd.Remove(cmd.Length - 2)));

                case 0x56: // Cast
                    return new CastMacroCommand(Byte.Parse(cmd));

                case 0x58: // OpenDoor
                    return new OpenDoorMacroCommand();

                default:
                    return null;
            }
        }
        static CallbackResult OnCharacterStatus(byte[] data, CallbackResult prevResult)
        {
            lock (World.SyncRoot) {
                PacketReader reader = new PacketReader(data);

                if (reader.ReadByte() != 0x11) throw new Exception("Invalid packet passed to OnCharacterStatus.");

                ushort blockSize = reader.ReadUInt16();
                if (data.Length != blockSize)
                    Trace.WriteLine(String.Format("BlockSize ({0}) for dynamic packet 0x11 doesn't meet data lenght ({1}).", blockSize, data.Length), "World");

                uint serial = reader.ReadUInt32();

                RealCharacter chr = World.FindRealCharacter(serial);
                if (chr == null) {
                    Trace.WriteLine(String.Format("Cannot update status for unknown character (serial=0x{0:X8}).", serial), "World");
                    return CallbackResult.Normal;
                }

                chr.Name = reader.ReadAnsiString(30);
                chr.Hits = reader.ReadInt16();
                chr.MaxHits = reader.ReadInt16();
                chr.Renamable = reader.ReadByte() > 0;

                byte more = reader.ReadByte();

                if (more > 0) {
                    byte gender = reader.ReadByte();
                    chr.Strenght = reader.ReadInt16();
                    chr.Dexterity = reader.ReadInt16();
                    chr.Intelligence = reader.ReadInt16();
                    chr.Stamina = reader.ReadInt16();
                    chr.MaxStamina = reader.ReadInt16();
                    chr.Mana = reader.ReadInt16();
                    chr.MaxMana = reader.ReadInt16();
                    chr.Gold = reader.ReadInt32();
                    chr.Armor = reader.ReadUInt16();
                    chr.Weight = reader.ReadUInt16();
                }

            #if WORLDDEBUG
                Trace.WriteLine(String.Format("Character status updated ({0}).", chr.Description), "World");
            #endif

                ObjectChanged(serial, ObjectChangeType.CharUpdated, true);
                return CallbackResult.Normal;
            }
        }