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]); } } } } }
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; } }