private void HandleMessage(int start, int len)
        {
            if (statusTotal > 0)
            {
                statusCount++;
                if (statusCount == statusTotal)
                    statusTotal = 0;
                else
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                    {
                        serverText.Text = ((int)((float)statusCount * 100.0 / (float)statusTotal)) + "% - " + status;
                    }));
            }
            int messageid = messages[start++];
            len--;
            int payload = start;
            switch (messageid)
            {
                case 0x01: // connect request - c2s only
                    break;
                case 0x02: //error
                    {
                        string error = Encoding.ASCII.GetString(messages, payload, len);
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                            {
                                MessageBox.Show(error);
                            }));
                        socket.Close();
                        busy = false;
                    }
                    break;
                case 0x03: //connection approved
                    {
                        if (loginLevel == 1) loginLevel = 2;
                        playerSlot = messages[payload];
                        SendMessage(4);
                        SendMessage(0x10);
                        SendMessage(0x2a);
                        //send buffs
                        //send inventory
                        //send dyes
                        SendMessage(6);
                        if (loginLevel == 2) loginLevel = 3;
                    }
                    break;
                case 0x04: //player appearance
                    //ignore other players
                    break;
                case 0x05: //inventory items
                    //ignore player inventory
                    break;
                case 0x06: //request world info - c2s only
                    break;
                case 0x07: //world info
                    {
                        gameTime = BitConverter.ToInt32(messages, payload); payload += 4;
                        dayNight = messages[payload++] == 1;
                        moonPhase = messages[payload++];
                        bloodMoon = messages[payload++] == 1;
                        payload++; //eclipse
                        tilesWide = BitConverter.ToInt32(messages, payload); payload += 4;
                        tilesHigh = BitConverter.ToInt32(messages, payload); payload += 4;
                        spawnX = BitConverter.ToInt32(messages, payload); payload += 4;
                        spawnY = BitConverter.ToInt32(messages, payload); payload += 4;
                        groundLevel = BitConverter.ToInt32(messages, payload); payload += 4;
                        rockLevel = BitConverter.ToInt32(messages, payload); payload += 4;
                        worldID = BitConverter.ToInt32(messages, payload); payload += 4;
                        payload++; //moon type
                        for (int i = 0; i < 3; i++)
                        {
                            treeX[i] = BitConverter.ToInt32(messages, payload); payload += 4;
                        }
                        for (int i = 0; i < 4; i++)
                            treeStyle[i] = messages[payload++];
                        for (int i = 0; i < 3; i++)
                        {
                            caveBackX[i] = BitConverter.ToInt32(messages, payload); payload += 4;
                        }
                        for (int i = 0; i < 4; i++)
                            caveBackStyle[i] = messages[payload++];
                        for (int i = 0; i < 8; i++)
                            styles[i] = messages[payload++];
                        iceBackStyle = messages[payload++];
                        jungleBackStyle = messages[payload++];
                        hellBackStyle = messages[payload++];
                        payload += 4; //wind speed
                        payload++; //number of clouds
                        byte flags = messages[payload++];
                        byte flags2 = messages[payload++];
                        payload += 4; //max rain
                        string title = Encoding.ASCII.GetString(messages, payload, start + len - payload);
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            Title = title;
                        }));
                        smashedOrb = (flags & 1) == 1;
                        killedBoss1 = (flags & 2) == 2;
                        killedBoss2 = (flags & 4) == 4;
                        killedBoss3 = (flags & 8) == 8;
                        hardMode = (flags & 16) == 16;
                        killedClown = (flags & 32) == 32;
                        killedPlantBoss = (flags & 128) == 128;
                        killedMechBoss1 = (flags2 & 1) == 1;
                        killedMechBoss2 = (flags2 & 2) == 2;
                        killedMechBoss3 = (flags2 & 4) == 4;
                        killedMechBossAny = (flags2 & 8) == 8;
                        crimson = (flags2 & 32) == 32;
                        meteorSpawned = false;
                        killedFrost = false;
                        killedGoblins = false;
                        killedPirates = false;
                        killedQueenBee = false;
                        savedMechanic = false;
                        savedTinkerer = false;
                        savedWizard = false;
                        goblinsDelay = 0;
                        altarsSmashed = 0;
                        ResizeMap();
                        if (loginLevel == 3)
                        {
                            sectionsWide = (tilesWide / 200);
                            sectionsHigh = (tilesHigh / 150);
                            sentSections = new bool[sectionsWide, sectionsHigh];
                            loginLevel = 4;
                            for (int y = 0; y < tilesHigh; y++) //set all tiles to blank
                                for (int x = 0; x < tilesWide; x++)
                                {
                                    tiles[x, y].isActive = false;
                                    tiles[x, y].wall = 0;
                                    tiles[x, y].liquid = 0;
                                    tiles[x, y].hasRedWire = false;
                                    tiles[x, y].hasGreenWire = false;
                                    tiles[x, y].hasBlueWire = false;
                                    tiles[x, y].half = false;
                                    tiles[x, y].actuator = false;
                                    tiles[x, y].inactive = false;
                                    tiles[x, y].color = 0;
                                    tiles[x, y].wallColor = 0;
                                }
                            SendMessage(8); //request initial tile data
                        }
                        chests.Clear();
                        signs.Clear();
                        npcs.Clear();
                        loadPlayerMap();
                    }
                    break;
                case 0x08: //request initial tile data - c2s only
                    break;
                case 0x09: //status text
                    {
                        statusTotal = BitConverter.ToInt32(messages, payload); payload += 4;
                        statusCount = 0;
                        status = Encoding.ASCII.GetString(messages, payload, start + len - payload);
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            serverText.Text = status;
                        }));
                    }
                    break;
                case 0x0a: //tile row data
                    {
                        int width = BitConverter.ToInt16(messages, payload); payload += 2;
                        int startx = BitConverter.ToInt32(messages, payload); payload += 4;
                        int y = BitConverter.ToInt32(messages, payload); payload += 4;
                        for (int x = startx; x < startx + width; x++)
                        {
                            Tile tile = tiles[x, y];
                            byte flags = messages[payload++];
                            byte flags2 = messages[payload++];
                            tile.isActive = (flags & 1) == 1;
                            tile.hasRedWire = (flags & 16) == 16;
                            tile.half = (flags & 32) == 32;
                            tile.actuator = (flags & 64) == 64;
                            tile.inactive = (flags & 128) == 128;
                            tile.hasGreenWire = (flags2 & 1) == 1;
                            tile.hasBlueWire = (flags2 & 2) == 2;
                            tile.slope = (byte)((flags2 & 0x30) >> 4);
                            if ((flags2 & 4) == 4)
                                tile.color = messages[payload++];
                            else
                                tile.color = 0;
                            if ((flags2 & 8) == 8)
                                tile.wallColor = messages[payload++];
                            else
                                tile.wallColor = 0;
                            if (tile.isActive)
                            {
                                tile.type = messages[payload++];
                                if (tileInfos[tile.type].hasExtra)
                                {
                                    tile.u = BitConverter.ToInt16(messages, payload); payload += 2;
                                    tile.v = BitConverter.ToInt16(messages, payload); payload += 2;
                                }
                                else
                                {
                                    tile.u = -1;
                                    tile.v = -1;
                                }
                            }
                            if ((flags & 4) == 4)
                            {
                                tile.wall = messages[payload++];
                                tile.wallu = -1;
                                tile.wallv = -1;
                            }
                            else
                                tile.wall = 0;
                            if ((flags & 8) == 8)
                            {
                                tile.liquid = messages[payload++];
                                tile.isLava = messages[payload] == 1;
                                tile.isHoney = messages[payload] == 2;
                                payload++;
                            }
                            else
                                tile.liquid = 0;
                            int rle = BitConverter.ToInt16(messages, payload); payload += 2;
                            for (int r = x + 1; r < x + 1 + rle; r++)
                            {
                                tiles[r, y].isActive = tiles[x, y].isActive;
                                tiles[r, y].type = tiles[x, y].type;
                                tiles[r, y].u = tiles[x, y].u;
                                tiles[r, y].v = tiles[x, y].v;
                                tiles[r, y].wall = tiles[x, y].wall;
                                tiles[r, y].wallu = -1;
                                tiles[r, y].wallv = -1;
                                tiles[r, y].liquid = tiles[x, y].liquid;
                                tiles[r, y].isLava = tiles[x, y].isLava;
                                tiles[r, y].isHoney = tiles[x, y].isHoney;
                                tiles[r, y].hasRedWire = tiles[x, y].hasRedWire;
                                tiles[r, y].hasGreenWire = tiles[x, y].hasGreenWire;
                                tiles[r, y].hasBlueWire = tiles[x, y].hasBlueWire;
                                tiles[r, y].half = tiles[x, y].half;
                                tiles[r, y].actuator = tiles[x, y].actuator;
                                tiles[r, y].inactive = tiles[x, y].inactive;
                                tiles[r, y].slope = tiles[x, y].slope;
                                tiles[r, y].color = tiles[x, y].color;
                                tiles[r, y].wallColor = tiles[x, y].wallColor;
                            }
                            x += rle;
                        }
                    }
                    break;
                case 0x0b: //recalculate u/v
                    {
                        int startx = BitConverter.ToInt16(messages, payload); payload += 4;
                        int starty = BitConverter.ToInt16(messages, payload); payload += 4;
                        int endx = BitConverter.ToInt16(messages, payload); payload += 2;
                        int endy = BitConverter.ToInt16(messages, payload);

                        for (int y = starty; y <= endy; y++)
                            for (int x = startx; x <= endx; x++)
                                sentSections[x, y] = true;

                        startx *= 200;
                        starty *= 150;
                        endx = (endx + 1) * 200;
                        endy = (endy + 1) * 150;

                        for (int y = starty; y < endy; y++)
                            for (int x = startx; x < endx; x++)
                            {
                                Tile tile = tiles[x, y];
                                if (tile.isActive && !tileInfos[tile.type].hasExtra)
                                {
                                    tile.u = -1;
                                    tile.v = -1;
                                }
                                if (tile.wall > 0)
                                {
                                    tile.wallu = -1;
                                    tile.wallv = -1;
                                }
                            }
                        if (loginLevel == 5)
                            fetchNextSection();
                    }
                    break;
                case 0x0c: //player spawned
                    break;
                case 0x0d: //player control
                    break;
                case 0x0e: //set active players
                    break;
                case 0x10: //player life
                    break;
                case 0x11: //modify tile
                    break;
                case 0x12: //set time
                    break;
                case 0x13: //open/close door
                    break;
                case 0x14: //update tile block
                    break;
                case 0x15: //update item
                    break;
                case 0x16: //set item owner
                    break;
                case 0x17: //update NPC
                    {
                        int slot = BitConverter.ToInt16(messages, payload); payload += 2;
                        float posx = BitConverter.ToSingle(messages, payload); payload += 4;
                        float posy = BitConverter.ToSingle(messages, payload); payload += 4;
                        payload += 9; //skip velocity and target
                        byte flags = messages[payload++];
                        payload += 4; //skip life
                        //skip any applicable AI
                        if ((flags & 32) == 32) payload += 4;
                        if ((flags & 16) == 16) payload += 4;
                        if ((flags & 8) == 8) payload += 4;
                        if ((flags & 4) == 4) payload += 4;
                        int id = BitConverter.ToInt16(messages, payload);
                        bool found = false;
                        for (int i = 0; i < npcs.Count; i++)
                        {
                            if (npcs[i].slot == slot)
                            {
                                npcs[i].x = posx;
                                npcs[i].y = posy;
                                npcs[i].sprite = id;
                                found = true;
                                addNPCToMenu(npcs[i]);
                            }
                        }
                        if (!found)
                        {
                            for (int i = 0; i < friendlyNPCs.Length; i++)
                                if (friendlyNPCs[i].id == id) //we found a friendly npc
                                {
                                    NPC npc = new NPC();
                                    npc.isHomeless = true; //homeless for now
                                    npc.title = friendlyNPCs[i].title;
                                    npc.name = "";
                                    npc.num = friendlyNPCs[i].num;
                                    npc.sprite = id;
                                    npc.x = posx;
                                    npc.y = posy;
                                    npc.slot = slot;
                                    npcs.Add(npc);
                                    addNPCToMenu(npc);
                                }
                        }
                    }
                    break;
                case 0x18: //strike npc
                    break;
                case 0x19: //chat
                    break;
                case 0x1a: //damage player
                    break;
                case 0x1b: //update projectile
                    break;
                case 0x1c: //damage npc
                    break;
                case 0x1d: //destroy projectile
                    break;
                case 0x1e: //pvp toggled
                    break;
                case 0x1f: //request open chest - c2s only
                    break;
                case 0x20: //set chest item
                    break;
                case 0x21: //open chest
                    break;
                case 0x22: //destroy chest
                    break;
                case 0x23: //heal player
                    break;
                case 0x24: //set zones
                    break;
                case 0x25: //request password.
                    {
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            ServerPassword s = new ServerPassword();
                            if (s.ShowDialog() == true)
                                SendMessage(0x26, s.Password);
                            else
                            {
                                socket.Close();
                                serverText.Text = "Login cancelled.";
                                busy = false;
                            }
                        }));
                    }
                    break;
                case 0x26: //login - c2s only
                    break;
                case 0x27: //unassign item
                    break;
                case 0x28: //talk to npc
                    break;
                case 0x29: //animate flail
                    break;
                case 0x2a: //set mana
                    break;
                case 0x2b: //replenish mana
                    break;
                case 0x2c: //kill player
                    break;
                case 0x2d: //change party
                    break;
                case 0x2e: //read sign - c2s only
                    break;
                case 0x2f: //edit sign
                    break;
                case 0x30: //adjust liquids
                    break;
                case 0x31: //okay to spawn
                    if (loginLevel == 4)
                    {
                        loginLevel = 5;
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                            {
                                serverText.Text = "";
                                render.SetWorld(tilesWide, tilesHigh, groundLevel, rockLevel, styles, treeX, treeStyle, caveBackX, caveBackStyle, jungleBackStyle, hellBackStyle, npcs);
                                loaded = true;
                                curX = spawnX;
                                curY = spawnY;
                                if (render.Textures != null && render.Textures.Valid)
                                {
                                    UseTextures.IsChecked = true;
                                    curScale = 16.0;
                                }
                                RenderMap();
                            }));
                        SendMessage(0x0c); //spawn
                        if (tilesWide == 8400) //large world
                        {
                            //give the user a choice to map a remote large world
                            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                            {
                                if (MessageBox.Show(this, "Mapping remote large worlds is not recommend.\nContinue to map the rest of the world?", "Map Whole World",
                                MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                                {
                                    fetchNextSection(); //start fetching the world
                                }
                                else
                                {
                                    socket.Close();
                                    busy = false;
                                }
                            }));
                        }
                        else
                            fetchNextSection(); //start fetching the world
                    }
                    break;
                case 0x32: //set buffs
                    break;
                case 0x33: //old man answer
                    break;
                case 0x34: //unlock chest
                    break;
                case 0x35: //add npc buff
                    break;
                case 0x36: //set npc buffs
                    break;
                case 0x37: //add player buff
                    break;
                case 0x38: //set npc names
                    {
                        int id = BitConverter.ToInt16(messages, payload); payload += 2;
                        string name = Encoding.ASCII.GetString(messages, payload, start + len - payload);
                        for (int i = 0; i < npcs.Count; i++)
                        {
                            if (npcs[i].sprite == id)
                            {
                                npcs[i].name = name;
                                addNPCToMenu(npcs[i]);
                            }
                        }
                    }
                    break;
                case 0x39: //set balance stats
                    break;
                case 0x3a: //play harp
                    break;
                case 0x3b: //flip switch
                    break;
                case 0x3c: //move npc home
                    {
                        int slot = BitConverter.ToInt16(messages, payload); payload += 2;
                        int x = BitConverter.ToInt16(messages, payload); payload += 2;
                        int y = BitConverter.ToInt16(messages, payload); payload += 2;
                        byte homeless = messages[payload];
                        for (int i = 0; i < npcs.Count; i++)
                        {
                            if (npcs[i].slot == slot)
                            {
                                npcs[i].isHomeless = homeless == 1;
                                npcs[i].homeX = x;
                                npcs[i].homeY = y;
                                addNPCToMenu(npcs[i]);
                                break;
                            }
                        }
                    }
                    break;
                case 0x3d: //summon boss
                    break;
                case 0x3e: //ninja dodge
                    break;
                case 0x3f: //paint tile
                    break;
                case 0x40: //paint wall
                    break;
                case 0x41: //teleport npc
                    break;
                case 0x42: //heal player
                    break;
                case 0x44: //unknown
                    break;
                default: // ignore unknown messages
                    break;
            }
        }
 private void addNPCToMenu(NPC npc)
 {
     string name;
     if (npc.name == "")
         name = npc.title;
     else
         name = npc.name + " the " + npc.title;
     if (!npc.isHomeless)
     {
         Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
         {
             MenuItem item;
             for (int i = 0; i < NPCs.Items.Count; i++)
             {
                 item = (MenuItem)NPCs.Items[i];
                 if (item.Tag == npc)
                 {
                     item.Header = String.Format("Jump to {0}'s Home", name);
                     return;
                 }
             }
             item = new MenuItem();
             item.Header = String.Format("Jump to {0}'s Home", name);
             item.Click += new RoutedEventHandler(jumpNPC);
             item.Tag = npc;
             NPCs.Items.Add(item);
             NPCs.IsEnabled = true;
         }));
     }
     else
     {
         Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
         {
             MenuItem item;
             for (int i = 0; i < NPCs.Items.Count; i++)
             {
                 item = (MenuItem)NPCs.Items[i];
                 if (item.Tag == npc)
                 {
                     item.Header = String.Format("Jump to {0}'s Location", name);
                     return;
                 }
             }
             item = new MenuItem();
             item.Header = String.Format("Jump to {0}'s Location", name);
             item.Click += new RoutedEventHandler(jumpNPC);
             item.Tag = npc;
             NPCs.Items.Add(item);
             NPCs.IsEnabled = true;
         }));
     }
 }
        private void Load(string world, Del done)
        {
            ThreadStart loadThread = delegate()
            {
                try
                {
                    currentWorld = world;
                    bool foundInvalid = false;

                    string invalid = "";
                    using (BinaryReader b = new BinaryReader(File.Open(world, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
                    {
                        int version = b.ReadInt32(); //now we care about the version
                        if (version > MapVersion) // new map format
                            throw new Exception("Unsupported map version: " + version);
                        string title = b.ReadString();
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            Title = title;
                        }));
                        worldID = b.ReadInt32();
                        b.BaseStream.Seek(16, SeekOrigin.Current); //skip bounds
                        tilesHigh = b.ReadInt32();
                        tilesWide = b.ReadInt32();
                        moonType = 0;
                        if (version >= 63)
                            moonType = b.ReadByte();
                        treeX[0] = treeX[1] = treeX[2] = 0;
                        treeStyle[0] = treeStyle[1] = treeStyle[2] = treeStyle[3] = 0;
                        if (version >= 44)
                        {
                            treeX[0] = b.ReadInt32();
                            treeX[1] = b.ReadInt32();
                            treeX[2] = b.ReadInt32();
                            treeStyle[0] = b.ReadInt32();
                            treeStyle[1] = b.ReadInt32();
                            treeStyle[2] = b.ReadInt32();
                            treeStyle[3] = b.ReadInt32();
                        }
                        caveBackX[0] = caveBackX[1] = caveBackX[2] = 0;
                        caveBackStyle[0] = caveBackStyle[1] = caveBackStyle[2] = caveBackStyle[3] = 0;
                        iceBackStyle = jungleBackStyle = hellBackStyle = 0;
                        if (version >= 60)
                        {
                            caveBackX[0] = b.ReadInt32();
                            caveBackX[1] = b.ReadInt32();
                            caveBackX[2] = b.ReadInt32();
                            caveBackStyle[0] = b.ReadInt32();
                            caveBackStyle[1] = b.ReadInt32();
                            caveBackStyle[2] = b.ReadInt32();
                            caveBackStyle[3] = b.ReadInt32();
                            iceBackStyle = b.ReadInt32();
                            if (version >= 61)
                            {
                                jungleBackStyle = b.ReadInt32();
                                hellBackStyle = b.ReadInt32();
                            }
                        }
                        spawnX = b.ReadInt32();
                        spawnY = b.ReadInt32();
                        groundLevel = (int)b.ReadDouble();
                        rockLevel = (int)b.ReadDouble();
                        gameTime = b.ReadDouble();
                        dayNight = b.ReadBoolean();
                        moonPhase = b.ReadInt32();
                        bloodMoon = b.ReadBoolean();
                        eclipse = false;
                        if (version >= 70)
                            eclipse = b.ReadBoolean();
                        dungeonX = b.ReadInt32();
                        dungeonY = b.ReadInt32();
                        crimson = false;
                        if (version >= 56)
                            crimson = b.ReadBoolean();
                        killedBoss1 = b.ReadBoolean();
                        killedBoss2 = b.ReadBoolean();
                        killedBoss3 = b.ReadBoolean();
                        killedQueenBee = false;
                        if (version >= 66)
                            killedQueenBee = b.ReadBoolean();
                        killedMechBoss1 = killedMechBoss2 = killedMechBoss3 = killedMechBossAny = false;
                        if (version >= 44)
                        {
                            killedMechBoss1 = b.ReadBoolean();
                            killedMechBoss2 = b.ReadBoolean();
                            killedMechBoss3 = b.ReadBoolean();
                            killedMechBossAny = b.ReadBoolean();
                        }
                        killedPlantBoss = killedGolemBoss = false;
                        if (version >= 64)
                        {
                            killedPlantBoss = b.ReadBoolean();
                            killedGolemBoss = b.ReadBoolean();
                        }
                        savedTinkerer = savedWizard = savedMechanic = killedGoblins = killedClown = killedFrost = killedPirates = false;
                        if (version >= 29)
                        {
                            savedTinkerer = b.ReadBoolean();
                            savedWizard = b.ReadBoolean();
                            if (version >= 34)
                                savedMechanic = b.ReadBoolean();
                            killedGoblins = b.ReadBoolean();
                            if (version >= 32)
                                killedClown = b.ReadBoolean();
                            if (version >= 37)
                                killedFrost = b.ReadBoolean();
                            if (version >= 56)
                                killedPirates = b.ReadBoolean();
                        }
                        smashedOrb = b.ReadBoolean();
                        meteorSpawned = b.ReadBoolean();
                        shadowOrbCount = b.ReadByte();
                        altarsSmashed = 0;
                        hardMode = false;
                        if (version >= 23)
                        {
                            altarsSmashed = b.ReadInt32();
                            hardMode = b.ReadBoolean();
                        }
                        goblinsDelay = b.ReadInt32();
                        goblinsSize = b.ReadInt32();
                        goblinsType = b.ReadInt32();
                        goblinsX = b.ReadDouble();

                        isRaining = false;
                        rainTime = 0;
                        maxRain = 0.0F;
                        oreTier1 = 107;
                        oreTier2 = 108;
                        oreTier3 = 111;
                        if (version >= 23 && altarsSmashed == 0)
                            oreTier1 = oreTier2 = oreTier3 = -1;
                        if (version >= 53)
                        {
                            isRaining = b.ReadBoolean();
                            rainTime = b.ReadInt32();
                            maxRain = b.ReadSingle();
                            if (version >= 54)
                            {
                                oreTier1 = b.ReadInt32();
                                oreTier2 = b.ReadInt32();
                                oreTier3 = b.ReadInt32();
                            }
                        }
                        if (version >= 55)
                        {
                            int numstyles = 3;
                            if (version >= 60)
                                numstyles = 8;
                            for (int i = 0; i < numstyles; i++)
                                styles[i] = b.ReadByte();
                            //skip clouds
                            if (version >= 60)
                            {
                                b.BaseStream.Seek(4, SeekOrigin.Current);
                                if (version >= 62) //skip wind
                                    b.BaseStream.Seek(6, SeekOrigin.Current);
                            }
                        }

                        ResizeMap();
                        for (int x = 0; x < tilesWide; x++)
                        {
                            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                            {
                                serverText.Text = ((int)((float)x * 100.0 / (float)tilesWide)) + "% - Reading tiles";
                            }));
                            for (int y = 0; y < tilesHigh; y++)
                            {
                                tiles[x, y].isActive = b.ReadBoolean();
                                if (tiles[x, y].isActive)
                                {
                                    tiles[x, y].type = b.ReadByte();
                                    if (tiles[x, y].type > MaxTile) // something screwy in the map
                                    {
                                        tiles[x, y].isActive = false;
                                        foundInvalid = true;
                                        invalid = String.Format("{0} is not a valid tile type", tiles[x, y].type);
                                    }
                                    else if (tileInfos[tiles[x, y].type].hasExtra)
                                    {
                                        // torches and platforms didn't have extra in older versions.
                                        if ((version < 28 && tiles[x, y].type == 4) ||
                                            (version < 40 && tiles[x, y].type == 19))
                                        {
                                            tiles[x, y].u = -1;
                                            tiles[x, y].v = -1;
                                        }
                                        else
                                        {
                                            tiles[x, y].u = b.ReadInt16();
                                            tiles[x, y].v = b.ReadInt16();
                                            if (tiles[x, y].type == 144) //timer
                                                tiles[x, y].v = 0;
                                        }
                                    }
                                    else
                                    {
                                        tiles[x, y].u = -1;
                                        tiles[x, y].v = -1;
                                    }

                                    if (version >= 48 && b.ReadBoolean())
                                    {
                                        tiles[x, y].color = b.ReadByte();
                                    }
                                }
                                if (version <= 25)
                                    b.ReadBoolean(); //skip obsolete hasLight
                                if (b.ReadBoolean())
                                {
                                    tiles[x, y].wall = b.ReadByte();
                                    if (tiles[x, y].wall > MaxWall)  // bad wall
                                    {
                                        foundInvalid = true;
                                        invalid = String.Format("{0} is not a valid wall type", tiles[x, y].wall);
                                        tiles[x, y].wall = 0;
                                    }
                                    if (version >= 48 && b.ReadBoolean())
                                        tiles[x, y].wallColor = b.ReadByte();
                                    tiles[x, y].wallu = -1;
                                    tiles[x, y].wallv = -1;
                                }
                                else
                                    tiles[x, y].wall = 0;
                                if (b.ReadBoolean())
                                {
                                    tiles[x, y].liquid = b.ReadByte();
                                    tiles[x, y].isLava = b.ReadBoolean();
                                    if (version >= 51)
                                        tiles[x, y].isHoney = b.ReadBoolean();
                                }
                                else
                                    tiles[x, y].liquid = 0;
                                tiles[x, y].hasRedWire = false;
                                tiles[x, y].hasGreenWire = false;
                                tiles[x, y].hasBlueWire = false;
                                tiles[x, y].half = false;
                                tiles[x, y].actuator = false;
                                tiles[x, y].inactive = false;
                                tiles[x, y].slope = 0;
                                if (version >= 33)
                                {
                                    tiles[x, y].hasRedWire = b.ReadBoolean();
                                    if (version >= 43)
                                    {
                                        tiles[x, y].hasGreenWire = b.ReadBoolean();
                                        tiles[x, y].hasBlueWire = b.ReadBoolean();
                                    }
                                    if (version >= 41)
                                    {
                                        tiles[x, y].half = b.ReadBoolean();
                                        if (version >= 49)
                                            tiles[x, y].slope = b.ReadByte();
                                        if (!tileInfos[tiles[x, y].type].solid)
                                        {
                                            tiles[x, y].half = false;
                                            tiles[x, y].slope = 0;
                                        }
                                        if (version >= 42)
                                        {
                                            tiles[x, y].actuator = b.ReadBoolean();
                                            tiles[x, y].inactive = b.ReadBoolean();
                                        }
                                    }
                                }
                                if (version >= 25) //RLE
                                {
                                    int rle = b.ReadInt16();
                                    for (int r = y + 1; r < y + 1 + rle; r++)
                                    {
                                        tiles[x, r].isActive = tiles[x, y].isActive;
                                        tiles[x, r].type = tiles[x, y].type;
                                        tiles[x, r].u = tiles[x, y].u;
                                        tiles[x, r].v = tiles[x, y].v;
                                        tiles[x, r].wall = tiles[x, y].wall;
                                        tiles[x, r].wallu = -1;
                                        tiles[x, r].wallv = -1;
                                        tiles[x, r].liquid = tiles[x, y].liquid;
                                        tiles[x, r].isLava = tiles[x, y].isLava;
                                        tiles[x, r].isHoney = tiles[x, y].isHoney;
                                        tiles[x, r].hasRedWire = tiles[x, y].hasRedWire;
                                        tiles[x, r].hasGreenWire = tiles[x, y].hasGreenWire;
                                        tiles[x, r].hasBlueWire = tiles[x, y].hasBlueWire;
                                        tiles[x, r].half = tiles[x, y].half;
                                        tiles[x, r].slope = tiles[x, y].slope;
                                        tiles[x, r].actuator = tiles[x, y].actuator;
                                        tiles[x, r].inactive = tiles[x, y].inactive;
                                        tiles[x, r].color = tiles[x, y].color;
                                        tiles[x, r].wallColor = tiles[x, y].wallColor;
                                    }
                                    y += rle;
                                }
                            }
                        }
                        int itemsPerChest = 40;
                        if (version < 58)
                            itemsPerChest = 20;
                        chests.Clear();
                        for (int i = 0; i < 1000; i++)
                        {
                            if (b.ReadBoolean())
                            {
                                Chest chest = new Chest();
                                chest.items = new ChestItem[itemsPerChest];
                                chest.x = b.ReadInt32();
                                chest.y = b.ReadInt32();
                                for (int ii = 0; ii < itemsPerChest; ii++)
                                {
                                    if (version < 59)
                                        chest.items[ii].stack = b.ReadByte();
                                    else
                                        chest.items[ii].stack = b.ReadInt16();
                                    if (chest.items[ii].stack > 0)
                                    {
                                        string name = "Unknown";
                                        if (version >= 38) //item names not stored
                                        {
                                            Int32 itemid = b.ReadInt32();
                                            if (itemid < 0)
                                            {
                                                itemid = -itemid;
                                                if (itemid < itemNames2.Length)
                                                    name = itemNames2[itemid];
                                            }
                                            else if (itemid < itemNames.Length)
                                                name = itemNames[itemid];
                                        }
                                        else
                                            name = b.ReadString();
                                        string prefix = "";
                                        if (version >= 36) //item prefixes
                                        {
                                            int pfx = b.ReadByte();
                                            if (pfx < prefixes.Length)
                                                prefix = prefixes[pfx];
                                        }
                                        chest.items[ii].name = name;
                                        chest.items[ii].prefix = prefix;
                                    }
                                }
                                chests.Add(chest);
                            }
                        }
                        signs.Clear();
                        for (int i = 0; i < 1000; i++)
                        {
                            if (b.ReadBoolean())
                            {
                                Sign sign = new Sign();
                                sign.text = b.ReadString();
                                sign.x = b.ReadInt32();
                                sign.y = b.ReadInt32();
                                signs.Add(sign);
                            }
                        }
                        npcs.Clear();
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            NPCs.Items.Clear();
                            serverText.Text = "Loading NPCs...";
                        }));
                        while (b.ReadBoolean())
                        {
                            NPC npc = new NPC();
                            npc.title = b.ReadString();
                            npc.name = "";
                            npc.x = b.ReadSingle();
                            npc.y = b.ReadSingle();
                            npc.isHomeless = b.ReadBoolean();
                            npc.homeX = b.ReadInt32();
                            npc.homeY = b.ReadInt32();

                            npc.order = -1;
                            npc.num = 0;
                            npc.sprite = 0;
                            for (int i = 0; i < friendlyNPCs.Length; i++)
                                if (friendlyNPCs[i].title == npc.title)
                                {
                                    npc.sprite = friendlyNPCs[i].id;
                                    npc.num = friendlyNPCs[i].num;
                                    npc.order = friendlyNPCs[i].order;
                                }

                            npcs.Add(npc);
                            addNPCToMenu(npc);
                        }
                        if (version >= 31) //read npcs
                        {
                            int numNames = 9;
                            if (version >= 34)
                                numNames++;
                            if (version >= 65)
                                numNames += 8;
                            for (int i = 0; i < numNames; i++)
                            {
                                string name = b.ReadString();
                                for (int j = 0; j < npcs.Count; j++)
                                {
                                    if (npcs[j].order == i)
                                    {
                                        npcs[j].name = name;
                                        addNPCToMenu(npcs[j]);
                                    }
                                }
                            }
                        }
                    }
                    if (foundInvalid)
                    {
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            MessageBox.Show("Found problems with the map: " + invalid + "\nIt may not display properly.", "Warning");
                        }));
                    }
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                    {
                        serverText.Text = "Loading Fog of War...";
                    }));
                    //load player's map
                    loadPlayerMap();

                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            QuickHiliteToggle.IsEnabled = true;
                            render.SetWorld(tilesWide, tilesHigh, groundLevel, rockLevel, styles, treeX, treeStyle, caveBackX, caveBackStyle, jungleBackStyle, hellBackStyle, npcs);
                            loaded = true;
                            done();
                        }));
                    calculateLight();
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            serverText.Text = "";
                        }));
                }
                catch (Exception e)
                {
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            MessageBox.Show(e.Message);
                            loaded = false;
                            serverText.Text = "";
                            done();
                        }));
                }
            };
            new Thread(loadThread).Start();
        }
        private void LoadNPCs(BinaryReader b, int version)
        {
            npcs.Clear();
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
            {
                NPCs.Items.Clear();
                serverText.Text = "Loading NPCs...";
            }));
            while (b.ReadBoolean())
            {
                NPC npc = new NPC();
                npc.title = b.ReadString();
                npc.name = "";
                if (version >= 83)
                    npc.name = b.ReadString();
                npc.x = b.ReadSingle();
                npc.y = b.ReadSingle();
                npc.isHomeless = b.ReadBoolean();
                npc.homeX = b.ReadInt32();
                npc.homeY = b.ReadInt32();

                npc.order = -1;
                npc.num = 0;
                npc.sprite = 0;
                for (int i = 0; i < friendlyNPCs.Length; i++)
                    if (friendlyNPCs[i].title == npc.title)
                    {
                        npc.sprite = friendlyNPCs[i].id;
                        npc.num = friendlyNPCs[i].num;
                        npc.order = friendlyNPCs[i].order;
                    }

                npcs.Add(npc);
                addNPCToMenu(npc);
            }
            if (version >= 31 && version <= 83) //read npcs
            {
                int numNames = 9;
                if (version >= 34)
                    numNames++;
                if (version >= 65)
                    numNames += 8;
                if (version >= 79)
                    numNames++;
                for (int i = 0; i < numNames; i++)
                {
                    string name = b.ReadString();
                    for (int j = 0; j < npcs.Count; j++)
                    {
                        if (npcs[j].order == i)
                        {
                            npcs[j].name = name;
                            addNPCToMenu(npcs[j]);
                        }
                    }
                }
            }
        }
Beispiel #5
0
        private void Load(string world, Del done)
        {
            ThreadStart loadThread = delegate()
            {
                try
                {
                    currentWorld = world;
                    bool foundInvalid = false;

                    string invalid = "";
                    using (BinaryReader b = new BinaryReader(File.Open(world,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)))
                    {
                        uint version = b.ReadUInt32(); //now we care about the version
                        if (version > MapVersion) // new map format
                            throw new Exception("Unsupported map version: "+version);
                        string title = b.ReadString();
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            Title = title;
                        }));
                        b.BaseStream.Seek(20, SeekOrigin.Current); //skip id and bounds
                        tilesHigh = b.ReadInt32();
                        tilesWide = b.ReadInt32();
                        spawnX = b.ReadInt32();
                        spawnY = b.ReadInt32();
                        groundLevel = (int)b.ReadDouble();
                        rockLevel = (int)b.ReadDouble();
                        gameTime = b.ReadDouble();
                        dayNight = b.ReadBoolean();
                        moonPhase = b.ReadInt32();
                        bloodMoon = b.ReadBoolean();
                        dungeonX = b.ReadInt32();
                        dungeonY = b.ReadInt32();
                        killedBoss1 = b.ReadBoolean();
                        killedBoss2 = b.ReadBoolean();
                        killedBoss3 = b.ReadBoolean();
                        savedTinkerer = savedWizard = savedMechanic = killedGoblins = killedClown = killedFrost = false;
                        if (version >= 29)
                        {
                            savedTinkerer = b.ReadBoolean();
                            savedWizard = b.ReadBoolean();
                            if (version >= 34)
                                savedMechanic = b.ReadBoolean();
                            killedGoblins = b.ReadBoolean();
                            if (version >= 32)
                                killedClown = b.ReadBoolean();
                            if (version >= 37)
                                killedFrost = b.ReadBoolean();
                        }
                        smashedOrb = b.ReadBoolean();
                        meteorSpawned = b.ReadBoolean();
                        shadowOrbCount = b.ReadByte();
                        altarsSmashed = 0;
                        hardMode = false;
                        if (version >= 23)
                        {
                            altarsSmashed = b.ReadInt32();
                            hardMode = b.ReadBoolean();
                        }
                        goblinsDelay = b.ReadInt32();
                        goblinsSize = b.ReadInt32();
                        goblinsType = b.ReadInt32();
                        goblinsX = b.ReadDouble();
                        ResizeMap();
                        for (int x = 0; x < tilesWide; x++)
                        {
                            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                            {
                                serverText.Text = ((int)((float)x * 100.0 / (float)tilesWide)) + "% - Reading tiles";
                            }));
                            for (int y = 0; y < tilesHigh; y++)
                            {
                                tiles[x, y].isActive = b.ReadBoolean();
                                if (tiles[x, y].isActive)
                                {
                                    tiles[x, y].type = b.ReadByte();
                                    if (tiles[x, y].type > MaxTile) // something screwy in the map
                                    {
                                        tiles[x, y].isActive = false;
                                        foundInvalid = true;
                                        invalid = String.Format("{0} is not a valid tile type", tiles[x, y].type);
                                    }
                                    else if (tileInfos[tiles[x, y].type].hasExtra)
                                    {
                                        // torches didn't have extra in older versions.
                                        if (version < 0x1c && tiles[x, y].type == 4)
                                        {
                                            tiles[x, y].u = -1;
                                            tiles[x, y].v = -1;
                                        }
                                        else
                                        {
                                            tiles[x, y].u = b.ReadInt16();
                                            tiles[x, y].v = b.ReadInt16();
                                            if (tiles[x, y].type == 144) //timer
                                                tiles[x, y].v = 0;
                                        }
                                    }
                                    else
                                    {
                                        tiles[x, y].u = -1;
                                        tiles[x, y].v = -1;
                                    }
                                }
                                if (version <= 0x19)
                                    b.ReadBoolean(); //skip obsolete hasLight
                                if (b.ReadBoolean())
                                {
                                    tiles[x, y].wall = b.ReadByte();
                                    if (tiles[x, y].wall > MaxWall)  // bad wall
                                    {
                                        foundInvalid = true;
                                        invalid = String.Format("{0} is not a valid wall type", tiles[x, y].wall);
                                        tiles[x, y].wall = 0;
                                    }
                                    tiles[x, y].wallu = -1;
                                    tiles[x, y].wallv = -1;
                                }
                                else
                                    tiles[x, y].wall = 0;
                                if (b.ReadBoolean())
                                {
                                    tiles[x, y].liquid = b.ReadByte();
                                    tiles[x, y].isLava = b.ReadBoolean();
                                }
                                else
                                    tiles[x, y].liquid = 0;
                                if (version >= 0x21)
                                    tiles[x, y].hasWire = b.ReadBoolean();
                                else
                                    tiles[x, y].hasWire = false;
                                if (version >= 0x19) //RLE
                                {
                                    int rle = b.ReadInt16();
                                    for (int r = y + 1; r < y + 1 + rle; r++)
                                    {
                                        tiles[x, r].isActive = tiles[x, y].isActive;
                                        tiles[x, r].type = tiles[x, y].type;
                                        tiles[x, r].u = tiles[x, y].u;
                                        tiles[x, r].v = tiles[x, y].v;
                                        tiles[x, r].wall = tiles[x, y].wall;
                                        tiles[x, r].wallu = -1;
                                        tiles[x, r].wallv = -1;
                                        tiles[x, r].liquid = tiles[x, y].liquid;
                                        tiles[x, r].isLava = tiles[x, y].isLava;
                                        tiles[x, r].hasWire = tiles[x, y].hasWire;
                                    }
                                    y += rle;
                                }
                            }
                        }
                        chests.Clear();
                        for (int i = 0; i < 1000; i++)
                        {
                            if (b.ReadBoolean())
                            {
                                Chest chest = new Chest();
                                chest.items = new ChestItem[20];
                                chest.x = b.ReadInt32();
                                chest.y = b.ReadInt32();
                                for (int ii = 0; ii < 20; ii++)
                                {
                                    chest.items[ii].stack = b.ReadByte();
                                    if (chest.items[ii].stack > 0)
                                    {
                                        string name="Unknown";
                                        if (version >= 0x26) //item names not stored
                                        {
                                            Int32 itemid = b.ReadInt32();
                                            if (itemid < 0)
                                            {
                                                itemid = -itemid;
                                                if (itemid < itemNames2.Length)
                                                    name = itemNames2[itemid];
                                            }
                                            else if (itemid < itemNames.Length)
                                                name = itemNames[itemid];
                                        }
                                        else
                                            name = b.ReadString();
                                        string prefix = "";
                                        if (version >= 0x24) //item prefixes
                                        {
                                            int pfx = b.ReadByte();
                                            if (pfx < prefixes.Length)
                                                prefix = prefixes[pfx];
                                        }
                                        if (prefix != "")
                                            prefix += " ";
                                        chest.items[ii].name = prefix + name;
                                    }
                                }
                                chests.Add(chest);
                            }
                        }
                        signs.Clear();
                        for (int i = 0; i < 1000; i++)
                        {
                            if (b.ReadBoolean())
                            {
                                Sign sign = new Sign();
                                sign.text = b.ReadString();
                                sign.x = b.ReadInt32();
                                sign.y = b.ReadInt32();
                                signs.Add(sign);
                            }
                        }
                        npcs.Clear();
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            NPCs.Items.Clear();
                            serverText.Text = "Loading NPCs...";
                        }));
                        while (b.ReadBoolean())
                        {
                            NPC npc = new NPC();
                            npc.title = b.ReadString();
                            npc.name = "";
                            npc.x = b.ReadSingle();
                            npc.y = b.ReadSingle();
                            npc.isHomeless = b.ReadBoolean();
                            npc.homeX = b.ReadInt32();
                            npc.homeY = b.ReadInt32();

                            npc.order = -1;
                            npc.num = 0;
                            npc.sprite = 0;
                            for (int i=0;i<friendlyNPCs.Length;i++)
                                if (friendlyNPCs[i].title == npc.title)
                                {
                                    npc.sprite = friendlyNPCs[i].id;
                                    npc.num = friendlyNPCs[i].num;
                                    npc.order = friendlyNPCs[i].order;
                                }

                            npcs.Add(npc);
                            addNPCToMenu(npc);

                        }
                        if (version >= 31) //read npcs
                        {
                            int numNames = 9;
                            if (version>=34)
                                numNames++;
                            for (int i = 0; i < numNames; i++)
                            {
                                string name = b.ReadString();
                                for (int j = 0; j < npcs.Count; j++)
                                {
                                    if (npcs[j].order == i)
                                    {
                                        npcs[j].name = name;
                                        addNPCToMenu(npcs[j]);
                                    }
                                }
                            }
                        }
                    }
                    if (foundInvalid)
                    {
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            MessageBox.Show("Found problems with the map: " + invalid + "\nIt may not display properly.", "Warning");
                        }));
                    }
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            render.SetWorld(tilesWide, tilesHigh, groundLevel, rockLevel, npcs);
                            loaded = true;
                            done();
                        }));
                    calculateLight();
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            serverText.Text = "";
                        }));
                }
                catch (Exception e)
                {
                    Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            MessageBox.Show(e.Message);
                            loaded = false;
                            serverText.Text = "";
                            done();
                        }));
                }
            };
            new Thread(loadThread).Start();
        }
        private void HandleMessage(int start, int len)
        {
            if (statusTotal > 0)
            {
                statusCount++;
                if (statusCount == statusTotal)
                    statusTotal = 0;
                else
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                {
                    serverText.Text = ((int)((float)statusCount * 100.0 / (float)statusTotal)) + "% - " + status;
                }));
            }
            int messageid = messages[start++];
            len--;
            int payload = start;
            switch (messageid)
            {
                case 0x01: // connect request - c2s only
                    break;
                case 0x02: //error
                    {
                        string error = Encoding.ASCII.GetString(messages, payload, len);
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                            {
                                MessageBox.Show(error);
                            }));
                        socket.Close();
                        busy = false;
                    }
                    break;
                case 0x03: //connection approved
                    {
                        if (loginLevel == 1) loginLevel = 2;
                        playerSlot = messages[payload];
                        SendMessage(4);
                        SendMessage(0x10);
                        SendMessage(0x2a);
                        //send buffs
                        //send inventory
                        SendMessage(6);
                        if (loginLevel == 2) loginLevel = 3;
                    }
                    break;
                case 0x04: //player appearance
                    //ignore other players
                    break;
                case 0x05: //inventory items
                    //ignore player inventory
                    break;
                case 0x06: //request world info - c2s only
                    break;
                case 0x07: //world info
                    {
                        gameTime = BitConverter.ToInt32(messages, payload); payload += 4;
                        dayNight = messages[payload++] == 1;
                        moonPhase = messages[payload++];
                        bloodMoon = messages[payload++] == 1;
                        tilesWide = BitConverter.ToInt32(messages, payload); payload += 4;
                        tilesHigh = BitConverter.ToInt32(messages, payload); payload += 4;
                        spawnX = BitConverter.ToInt32(messages, payload); payload += 4;
                        spawnY = BitConverter.ToInt32(messages, payload); payload += 4;
                        groundLevel = BitConverter.ToInt32(messages, payload); payload += 4;
                        rockLevel = BitConverter.ToInt32(messages, payload); payload += 4;
                        payload += 4; //skip world id
                        byte flags = messages[payload++];
                        string title = Encoding.ASCII.GetString(messages, payload, start + len - payload);
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            Title = title;
                        }));
                        smashedOrb = (flags & 1) == 1;
                        killedBoss1 = (flags & 2) == 2;
                        killedBoss2 = (flags & 4) == 4;
                        killedBoss3 = (flags & 8) == 8;
                        hardMode = (flags & 16) == 16;
                        killedClown = (flags & 32) == 32;
                        meteorSpawned = false;
                        killedFrost = false;
                        killedGoblins = false;
                        savedMechanic = false;
                        savedTinkerer = false;
                        savedWizard = false;
                        goblinsDelay = 0;
                        altarsSmashed = 0;
                        ResizeMap();
                        if (loginLevel == 3)
                        {
                            sectionsWide = (tilesWide / 200);
                            sectionsHigh = (tilesHigh / 150);
                            sentSections = new bool[sectionsWide, sectionsHigh];
                            loginLevel = 4;
                            for (int y = 0; y < tilesHigh; y++) //set all tiles to blank
                                for (int x = 0; x < tilesWide; x++)
                                {
                                    tiles[x, y].isActive = false;
                                    tiles[x, y].wall = 0;
                                    tiles[x, y].liquid = 0;
                                    tiles[x, y].hasWire = false;
                                }
                            SendMessage(8); //request initial tile data
                        }
                    }
                    break;
                case 0x08: //request initial tile data - c2s only
                    break;
                case 0x09: //status text
                    {
                        statusTotal = BitConverter.ToInt32(messages, payload); payload += 4;
                        statusCount = 0;
                        status = Encoding.ASCII.GetString(messages, payload, start + len - payload);
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            serverText.Text = status;
                        }));
                    }
                    break;
                case 0x0a: //tile row data
                    {
                        int width = BitConverter.ToInt16(messages, payload); payload += 2;
                        int startx = BitConverter.ToInt32(messages, payload); payload += 4;
                        int y = BitConverter.ToInt32(messages, payload); payload += 4;
                        for (int x = startx; x < startx + width; x++)
                        {
                            Tile tile = tiles[x, y];
                            byte flags = messages[payload++];
                            tile.isActive = (flags & 1) == 1;
                            tile.hasWire = (flags & 16) == 16;
                            if (tile.isActive)
                            {
                                tile.type = messages[payload++];
                                if (tileInfos[tile.type].hasExtra)
                                {
                                    tile.u = BitConverter.ToInt16(messages, payload); payload += 2;
                                    tile.v = BitConverter.ToInt16(messages, payload); payload += 2;
                                }
                                else
                                {
                                    tile.u = -1;
                                    tile.v = -1;
                                }
                            }
                            if ((flags & 4) == 4)
                            {
                                tile.wall = messages[payload++];
                                tile.wallu = -1;
                                tile.wallv = -1;
                            }
                            else
                                tile.wall = 0;
                            if ((flags & 8) == 8)
                            {
                                tile.liquid = messages[payload++];
                                tile.isLava = messages[payload++] == 1;
                            }
                            else
                                tile.liquid = 0;
                            int rle = BitConverter.ToInt16(messages, payload); payload += 2;
                            for (int r = x + 1; r < x + 1 + rle; r++)
                            {
                                tiles[r, y].isActive = tiles[x, y].isActive;
                                tiles[r, y].type = tiles[x, y].type;
                                tiles[r, y].u = tiles[x, y].u;
                                tiles[r, y].v = tiles[x, y].v;
                                tiles[r, y].wall = tiles[x, y].wall;
                                tiles[r, y].wallu = -1;
                                tiles[r, y].wallv = -1;
                                tiles[r, y].liquid = tiles[x, y].liquid;
                                tiles[r, y].isLava = tiles[x, y].isLava;
                                tiles[r, y].hasWire = tiles[x, y].hasWire;
                            }
                            x += rle;
                        }
                    }
                    break;
                case 0x0b: //recalculate u/v
                    {
                        int startx = BitConverter.ToInt32(messages, payload); payload += 4;
                        int starty = BitConverter.ToInt32(messages, payload); payload += 4;
                        int endx = BitConverter.ToInt32(messages, payload); payload += 4;
                        int endy = BitConverter.ToInt32(messages, payload);

                        for (int y = starty; y<= endy; y++)
                            for (int x = startx; x <= endx; x++)
                                sentSections[x, y] = true;

                        startx *= 200;
                        starty *= 150;
                        endx = (endx + 1) * 200;
                        endy = (endy + 1) * 150;

                        for (int y=starty;y<endy;y++)
                            for (int x = startx; x < endx; x++)
                            {
                                Tile tile = tiles[x, y];
                                if (tile.isActive && !tileInfos[tile.type].hasExtra)
                                {
                                    tile.u = -1;
                                    tile.v = -1;
                                }
                                if (tile.wall > 0)
                                {
                                    tile.wallu = -1;
                                    tile.wallv = -1;
                                }
                            }
                        if (loginLevel == 5)
                            fetchNextSection();
                    }
                    break;
                case 0x0c: //player spawned
                    break;
                case 0x0d: //player control
                    break;
                case 0x0e: //set active players
                    break;
                case 0x10: //player life
                    break;
                case 0x11: //modify tile
                    break;
                case 0x12: //set time
                    break;
                case 0x13: //open/close door
                    break;
                case 0x14: //update tile block
                    break;
                case 0x15: //update item
                    break;
                case 0x16: //set item owner
                    break;
                case 0x17: //update NPC
                    {
                        int slot = BitConverter.ToInt16(messages, payload); payload += 2;
                        float posx = BitConverter.ToSingle(messages, payload); payload += 4;
                        float posy = BitConverter.ToSingle(messages, payload); payload += 4;
                        payload += 32; //don't care about velocity, target, ai, or direction
                        int id = BitConverter.ToInt16(messages, payload);
                        bool found = false;
                        for (int i = 0; i < npcs.Count; i++)
                        {
                            if (npcs[i].slot == slot)
                            {
                                npcs[i].x = posx;
                                npcs[i].y = posy;
                                npcs[i].sprite = id;
                                found = true;
                                addNPCToMenu(npcs[i]);
                            }
                        }
                        if (!found)
                        {
                            for (int i = 0; i < friendlyNPCs.Length; i++)
                                if (friendlyNPCs[i].id == id) //we found a friendly npc
                                {
                                    NPC npc = new NPC();
                                    npc.isHomeless = true; //homeless for now
                                    npc.title = friendlyNPCs[i].title;
                                    npc.name = "";
                                    npc.num = friendlyNPCs[i].num;
                                    npc.sprite = id;
                                    npc.x = posx;
                                    npc.y = posy;
                                    npc.slot = slot;
                                    npcs.Add(npc);
                                    addNPCToMenu(npc);
                                }
                        }
                    }
                    break;
                case 0x18: //strike npc
                    break;
                case 0x19: //chat
                    break;
                case 0x1a: //damage player
                    break;
                case 0x1b: //update projectile
                    break;
                case 0x1c: //damage npc
                    break;
                case 0x1d: //destroy projectile
                    break;
                case 0x1e: //pvp toggled
                    break;
                case 0x1f: //request open chest - c2s only
                    break;
                case 0x20: //set chest item
                    break;
                case 0x21: //open chest
                    break;
                case 0x22: //destroy chest
                    break;
                case 0x23: //heal player
                    break;
                case 0x24: //set zones
                    break;
                case 0x25: //request password.
                    {
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                        {
                            ServerPassword s = new ServerPassword();
                            if (s.ShowDialog() == true)
                                SendMessage(0x26, s.Password);
                            else
                            {
                                socket.Close();
                                serverText.Text = "Login cancelled.";
                                busy = false;
                            }
                        }));
                    }
                    break;
                case 0x26: //login - c2s only
                    break;
                case 0x27: //unassign item
                    break;
                case 0x28: //talk to npc
                    break;
                case 0x29: //animate flail
                    break;
                case 0x2a: //set mana
                    break;
                case 0x2b: //replenish mana
                    break;
                case 0x2c: //kill player
                    break;
                case 0x2d: //change party
                    break;
                case 0x2e: //read sign - c2s only
                    break;
                case 0x2f: //edit sign
                    break;
                case 0x30: //adjust liquids
                    break;
                case 0x31: //okay to spawn
                    if (loginLevel == 4)
                    {
                        loginLevel = 5;
                        Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                            {
                                serverText.Text = "";
                                render.SetWorld(tilesWide, tilesHigh, groundLevel, rockLevel, npcs);
                                loaded = true;
                                curX = spawnX;
                                curY = spawnY;
                                if (render.Textures!=null && render.Textures.Valid)
                                {
                                    UseTextures.IsChecked = true;
                                    curScale = 16.0;
                                }
                                RenderMap();
                            }));
                        SendMessage(0x0c); //spawn
                        if (tilesWide == 8400) //large world
                        {
                            socket.Close();
                            busy = false;
                            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
                            {
                                MessageBox.Show("Will not map remote large worlds\nother than the spawn point");
                            }));
                        }
                        else
                            fetchNextSection(); //start fetching the world
                    }
                    break;
                case 0x32: //set buffs
                    break;
                case 0x33: //old man answer
                    break;
                case 0x34: //unlock chest
                    break;
                case 0x35: //add npc buff
                    break;
                case 0x36: //set npc buffs
                    break;
                case 0x37: //add player buff
                    break;
                case 0x38: //set npc names
                    {
                        int id = BitConverter.ToInt16(messages, payload); payload += 2;
                        string name = Encoding.ASCII.GetString(messages, payload, start + len - payload);
                        for (int i = 0; i < npcs.Count; i++)
                        {
                            if (npcs[i].sprite == id)
                            {
                                npcs[i].name = name;
                                addNPCToMenu(npcs[i]);
                            }
                        }
                    }
                    break;
                case 0x39: //set balance stats
                    break;
                case 0x3a: //play harp
                    break;
                case 0x3b: //flip switch
                    break;
                case 0x3c: //move npc home
                    {
                        int slot=BitConverter.ToInt16(messages,payload); payload+=2;
                        int x=BitConverter.ToInt16(messages,payload); payload+=2;
                        int y=BitConverter.ToInt16(messages,payload); payload+=2;
                        byte homeless=messages[payload];
                        for (int i = 0; i < npcs.Count; i++)
                        {
                            if (npcs[i].slot == slot)
                            {
                                npcs[i].isHomeless = homeless == 1;
                                npcs[i].homeX = x;
                                npcs[i].homeY = y;
                                addNPCToMenu(npcs[i]);
                                break;
                            }
                        }
                    }
                    break;
                default: // ignore unknown messages
                    break;
            }
        }