/// <summary> /// Adds a thing to the map. /// </summary> /// <param name="map">Doom map the thing should be added to</param> /// <param name="x">X coordinate of the tile on which the thing should be spawned</param> /// <param name="y">Y coordinate of the tile on which the thing should be spanwed</param> /// <param name="thingType">Type of thing</param> /// <param name="angle">Angle the thing should face</param> /// <param name="options">Thing options</param> private void AddThing(DoomMap map, int x, int y, int thingType, int angle = (int)DEFAULT_ANGLE, ThingOptions options = ThingOptions.AllSkills) { map.Things.Add( new Thing( (int)((x + .5f) * MapGenerator.TILE_SIZE), (int)((y + .5f) * -MapGenerator.TILE_SIZE), thingType, angle, options)); }
/// <summary> /// Creates the sectors on the Doom map. /// </summary> /// <param name="map">The Doom map</param> private void CreateSectors(DoomMap map) { int x, y; map.Sectors.Clear(); for (x = 0; x < MapSubWidth; x++) { for (y = 0; y < MapSubHeight; y++) { if (Sectors[x, y] != -2) { continue; // Cell was already checked } if (SubTiles[x, y] == TileType.Wall) { Sectors[x, y] = -1; continue; } Stack <Point> pixels = new Stack <Point>(); Point pt = new Point(x, y); pixels.Push(pt); while (pixels.Count > 0) { Point a = pixels.Pop(); if (a.X < MapSubWidth && a.X > 0 && a.Y < MapSubHeight && a.Y > 0) { if ((Sectors[a.X, a.Y] == -2) && (SubTiles[a.X, a.Y].Equals(SubTiles[x, y]))) { Sectors[a.X, a.Y] = SectorsInfo.Count; pixels.Push(new Point(a.X - 1, a.Y)); pixels.Push(new Point(a.X + 1, a.Y)); pixels.Push(new Point(a.X, a.Y - 1)); pixels.Push(new Point(a.X, a.Y + 1)); } } } SectorInfo sectorInfo = new SectorInfo(SubTiles[x, y], Theme, ThemeTextures); SectorsInfo.Add(sectorInfo); map.Sectors.Add( new Sector( sectorInfo.FloorHeight, sectorInfo.CeilingHeight, sectorInfo.FloorTexture, sectorInfo.CeilingTexture, sectorInfo.LightLevel, sectorInfo.SectorSpecial, 0)); } } }
IEnumerator CreateMap() { //destroy all children of map parent for (int i = 0; i < mapParent.childCount; i++) { GameObject.Destroy(mapParent.GetChild(i).gameObject); } yield return(new WaitForEndOfFrame()); //use this if you want to select one map in particular //if (mapSelected == 1) { mapSelected = 23; } openedMap = reader.newWad.maps[mapSelected - 1]; //use this if you want to pick a selection of maps to choose from instead of going through the whole list //int[] mapMapper = { 3, 20, 26, 28, 30, 35 }; //openedMap = reader.newWad.maps[mapMapper[(mapSelected - 1) % mapMapper.Length] - 1]; //display map Debug.Log("MAP: " + mapSelected); //read and play music MUS mus = reader.ReadMusEntry(mapSelected - 1); midiplayer.PlayMusic(musmid.WriteMidi(mus, mus.name)); //fill in any missing map information fillInfo(openedMap); float minx = 0; float miny = 0; foreach (Vector3 vert in openedMap.vertexes) { if (vert.x > minx) { minx = vert.x; } if (vert.z > miny) { miny = vert.z; } } skybox.transform.position = new Vector3(minx, 0, miny); //add sectors and monsters to map AddSectors(); SetSkyboxTexture(); AddThings(); skyboxScript.ChangeSky(); }
/// <summary> /// Creates the map linedefs and sidedefs /// </summary> /// <param name="map">Doom map in which to write linedefs and sidedefs</param> private void CreateLines(DoomMap map) { int x, y; bool[,,] linesSet = new bool[MapSubWidth, MapSubHeight, 4]; for (x = 0; x < MapSubWidth; x++) { for (y = 0; y < MapSubHeight; y++) { int sector = GetSector(x, y); if (sector < 0) { continue; // Tile is a wall, do nothing } for (int i = 0; i < 4; i++) { if (linesSet[x, y, i]) { continue; // Line already drawn } Point neighborDirection = GetTileSideOffset((TileSide)i); int neighborSector = GetSector(x + neighborDirection.X, y + neighborDirection.Y); if (sector == neighborSector) { continue; // Same sector on both sides, no need to add a line } if ((neighborSector >= 0) && ((i == (int)TileSide.South) || (i == (int)TileSide.East))) { continue; // Make sure two-sided lines aren't drawn twice } bool vertical = (neighborDirection.X != 0); int length = AddLine(map, new Point(x, y), (TileSide)i, vertical, sector, neighborSector); for (int j = 0; j < length; j++) { Point segmentPosition = new Point(x, y).Add(vertical ? new Point(0, j) : new Point(j, 0)); if (!IsSubPointOnMap(segmentPosition)) { continue; } linesSet[segmentPosition.X, segmentPosition.Y, i] = true; } } } } }
/// <summary> /// Add a certain number of things from an array of thing types to a map. /// </summary> /// <param name="map">The Doom map on which to add things</param> /// <param name="count">The number of things to add</param> /// <param name="generationFlags">Special flags for thing generation</param> /// <param name="thingTypes">Array of thing types to select from</param> private void AddThings(DoomMap map, int count, ThingsGeneratorFlags generationFlags, params int[] thingTypes) { if ((count < 1) || (thingTypes.Length == 0)) { return; } for (int i = 0; i < count; i++) { if (FreeTiles.Count == 0) { return; } ThingOptions options = ThingOptions.AllSkills; switch (generationFlags) { case ThingsGeneratorFlags.MoreThingsInEasyMode: if (Toolbox.RandomInt(4) == 0) { options = ThingOptions.Skill12 | ThingOptions.Skill3; } else if (Toolbox.RandomInt(3) == 0) { options = ThingOptions.Skill12; } break; case ThingsGeneratorFlags.MoreThingsInHardMode: if (Toolbox.RandomInt(3) == 0) { options = ThingOptions.Skill3 | ThingOptions.Skill45; } else if (Toolbox.RandomInt(2) == 0) { options = ThingOptions.Skill45; } break; } int thingType = Toolbox.RandomFromArray(thingTypes); Point pt = Toolbox.RandomFromList(FreeTiles); AddThing(map, pt.X, pt.Y, thingType, Toolbox.RandomInt(360), options); FreeTiles.Remove(pt); } }
/// <summary> /// Create all required things on a map. /// </summary> /// <param name="map">The Doom map on which to create things</param> /// <param name="subTiles">Map sub-tiles generated by MapGenerator</param> public void CreateThings(DoomMap map, TileType[,] subTiles) { int i, x, y; FreeTiles.Clear(); for (x = 0; x < subTiles.GetLength(0); x += MapGenerator.SUBTILE_DIVISIONS) { for (y = 0; y < subTiles.GetLength(1); y += MapGenerator.SUBTILE_DIVISIONS) { switch (subTiles[x, y]) { case TileType.Door: case TileType.DoorSide: case TileType.Entrance: case TileType.Exit: case TileType.Secret: case TileType.Wall: continue; } FreeTiles.Add(new Point(x / MapGenerator.SUBTILE_DIVISIONS, y / MapGenerator.SUBTILE_DIVISIONS)); } } if (Preferences.GenerateEntranceAndExit) { AddPlayerStarts(map, subTiles); // Single-player and coop starts (spawned on entrances, or next to each other is none found) AddThings(map, DEATHMATCH_STARTS_COUNT, 0, 11); // Deathmatch starts (spawned anywhere on the map) } float thingsCountMultiplier = FreeTiles.Count / 1000.0f; // Bigger map = more things if (Preferences.GenerateThings) { for (i = 0; i < Preferences.THINGS_CATEGORY_COUNT; i++) { AddThings(map, (ThingCategory)i, (int)(Preferences.ThingsCount[i][0] * thingsCountMultiplier), (int)(Preferences.ThingsCount[i][1] * thingsCountMultiplier)); } } }
/// <summary> /// Generates the map. /// </summary> /// <param name="name">Map name (MAP01, E1M1, etc)</param> /// <param name="bitmap">PNG to generate the file from</param> /// <returns>A Doom map</returns> public DoomMap Generate(string name, Bitmap bitmap) { if (bitmap == null) { return(null); } DoomMap map = new DoomMap(name); CreateTheme(bitmap); CreateArrays(bitmap); CreateSectors(map); CreateLines(map); using (ThingsGenerator thingsGenerator = new ThingsGenerator(Preferences)) { thingsGenerator.CreateThings(map, SubTiles); } return(map); }
/// <summary> /// Adds player starts to the map /// </summary> /// <param name="map">Doom map to add player starts to</param> /// <param name="subTiles">Map sub-tiles generated by MapGenerator</param> private void AddPlayerStarts(DoomMap map, TileType[,] subTiles) { int x, y; List <Point> entrances = new List <Point>(); // Spawn a single-player/coop entrance for each of the four players for (int player = 1; player <= 4; player++) { bool foundAnEntrance = false; // First try to look for a free "entrance" tile for (x = 0; x < subTiles.GetLength(0); x += MapGenerator.SUBTILE_DIVISIONS) { for (y = 0; y < subTiles.GetLength(1); y += MapGenerator.SUBTILE_DIVISIONS) { if (!foundAnEntrance && (subTiles[x, y] == TileType.Entrance)) { Point entranceTile = new Point(x / MapGenerator.SUBTILE_DIVISIONS, y / MapGenerator.SUBTILE_DIVISIONS); if (entrances.Contains(entranceTile)) { continue; // Entrance already in use } AddThing(map, x / MapGenerator.SUBTILE_DIVISIONS, y / MapGenerator.SUBTILE_DIVISIONS, player); entrances.Add(entranceTile); foundAnEntrance = true; } } } if (foundAnEntrance) { continue; } // No "entrance" tile found for this player, so... if (FreeTiles.Count > 0) { Point tile; // ...if no player entrance has been selected yet, spawn the player on a random free tile if (entrances.Count == 0) { tile = Toolbox.RandomFromList(FreeTiles); } // ...else spawn the player on the nearest free tile from player 1 start else { tile = (from Point t in FreeTiles select t).OrderBy(t => t.Distance(entrances[0])).First(); } FreeTiles.Remove(tile); AddThing(map, tile.X, tile.Y, player); entrances.Add(tile); foundAnEntrance = true; } if (foundAnEntrance) { continue; } // No free spot, put the player start in the northwest map corner. // Should never happen unless the map is entirely made of walls, doors or other unpassable stuff. // Might be outside a sector but at least the map won't crash with a "no player start found" error. AddThing(map, player - 1, 0, player); entrances.Add(new Point(player - 1, 0)); } }
public virtual void Run() { DateTime begin = DateTime.Now; try { Entities output = null; if (doomMap != null) { // If this is a Doom map extracted from a WAD //Window.setProgress(jobnum, 0, doomMap.getSubSectors().size(), "Decompiling..."); WADDecompiler decompiler = new WADDecompiler(doomMap, jobnum, this); output = decompiler.decompile(); } else { DecompilerThread.OnMessage(this, "Opening file " + BSPFile.FullName); //Window.setProgress(jobnum, 0, 1, "Reading..."); BSPReader reader = new BSPReader(BSPFile, openAs); reader.readBSP(); //if (!reader.WAD) { BSPObject = reader.BSPData; /*try { * Window.setProgress(jobnum, 0, reader.BSPData.getBrushes().size() + reader.BSPData.getEntities().size(), "Decompiling..."); * } catch (System.NullReferenceException e) { * try { * Window.setProgress(jobnum, 0, reader.BSPData.getLeaves().size() + reader.BSPData.getEntities().size(), "Decompiling..."); * } catch (System.NullReferenceException f) { * Window.setProgress(jobnum, 0, 1, "Decompiling..."); // What's going on here? Put in a failsafe progress bar for now * } * }*/ switch (reader.Version) { case mapType.TYPE_QUAKE: //DecompilerThread.OnMessage(this, "ERROR: Algorithm for decompiling Quake BSPs not written yet.",Window.VERBOSITY_ALWAYS); //throw new java.lang.Exception(); // Throw an exception to the exception handler to indicate it didn't work QuakeDecompiler decompiler29 = new QuakeDecompiler(reader.BSPData, jobnum, this); output = decompiler29.decompile(); break; case mapType.TYPE_NIGHTFIRE: BSP42Decompiler decompiler42 = new BSP42Decompiler(reader.BSPData, jobnum, this); output = decompiler42.decompile(); break; case mapType.TYPE_QUAKE2: case mapType.TYPE_SIN: case mapType.TYPE_SOF: case mapType.TYPE_DAIKATANA: BSP38Decompiler decompiler38 = new BSP38Decompiler(reader.BSPData, jobnum, this); output = decompiler38.decompile(); break; case mapType.TYPE_SOURCE17: case mapType.TYPE_SOURCE18: case mapType.TYPE_SOURCE19: case mapType.TYPE_SOURCE20: case mapType.TYPE_SOURCE21: case mapType.TYPE_SOURCE22: case mapType.TYPE_SOURCE23: case mapType.TYPE_SOURCE27: case mapType.TYPE_DMOMAM: case mapType.TYPE_VINDICTUS: case mapType.TYPE_TACTICALINTERVENTION: SourceBSPDecompiler sourceDecompiler = new SourceBSPDecompiler(reader.BSPData, jobnum, this); output = sourceDecompiler.decompile(); break; case mapType.TYPE_QUAKE3: case mapType.TYPE_RAVEN: case mapType.TYPE_COD: case mapType.TYPE_COD2: case mapType.TYPE_COD4: case mapType.TYPE_STEF2: case mapType.TYPE_STEF2DEMO: case mapType.TYPE_MOHAA: case mapType.TYPE_FAKK: BSP46Decompiler decompiler46 = new BSP46Decompiler(reader.BSPData, jobnum, this); output = decompiler46.decompile(); break; case mapType.TYPE_DOOM: case mapType.TYPE_HEXEN: foreach (DoomMap map in reader.DoomMaps) { WADDecompiler wadDecompiler = new WADDecompiler(map, jobnum, this); Entities holyshit = wadDecompiler.decompile(); MAPMaker.outputMaps(holyshit, map.MapName, map.Folder + map.WadName + "\\", map.Version); } break; default: DecompilerThread.OnMessage(this, "ERROR: Unknown BSP version: " + reader.Version); throw new System.Exception(); // Throw an exception to the exception handler to indicate it didn't work } //} } if (output != null) { //Window.setProgress(jobnum, 1, 1, "Saving..."); if (doomMap == null) { MAPMaker.outputMaps(output, BSPObject.MapNameNoExtension, BSPObject.Folder, BSPObject.Version); } else { MAPMaker.outputMaps(output, doomMap.MapName, doomMap.Folder + doomMap.WadName + "\\", doomMap.Version); } } //Window.setProgress(jobnum, 1, 1, "Done!"); //System.Drawing.Color tempAux = System.Drawing.Color.FromArgb(64, 192, 64); //Window.setProgressColor(jobnum, ref tempAux); DateTime end = DateTime.Now; DecompilerThread.OnMessage(this, "Time taken: " + (end - begin).ToString() + (char)0x0D + (char)0x0A); OnFinish(this, jobnum); } catch (System.OutOfMemoryException) { string st = ""; if (openAs != mapType.TYPE_UNDEFINED) { st = "VM ran out of memory on job " + (jobnum + 1) + ". Are you using \"Open as...\" with the wrong game?" + (char)0x0D + (char)0x0A + "If not, please let me know on the issue tracker!" + (char)0x0D + (char)0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry"; } else { st = "VM ran out of memory on job " + (jobnum + 1) + "." + (char)0x0D + (char)0x0A + "Please let me know on the issue tracker!" + (char)0x0D + (char)0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry"; } //Window.setProgress(jobnum, 1, 1, "ERROR! See log!"); //System.Drawing.Color tempAux4 = System.Drawing.Color.FromArgb(255, 128, 128); //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'" //Window.setProgressColor(jobnum, ref tempAux4); OnError(this, st); } catch (Exception e) { string st; if (openAs != mapType.TYPE_UNDEFINED) { //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" st = "" + (char)0x0D + (char)0x0A + "Exception caught in job " + (jobnum + 1) + ": " + e + (char)0x0D + (char)0x0A + "Are you using \"Open as...\" with the wrong game?" + (char)0x0D + (char)0x0A + "If not, please let me know on the issue tracker!" + (char)0x0D + (char)0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry"; } else { //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" st = "" + (char)0x0D + (char)0x0A + "Exception caught in job " + (jobnum + 1) + ": " + e + (char)0x0D + (char)0x0A + "Please let me know on the issue tracker!" + (char)0x0D + (char)0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry"; } /*System.String stackTrace = "Stack Trace: " + (char) 0x0D + (char) 0x0A; * StackTraceElement[] trace = e.getStackTrace(); * for (int i = 0; i < trace.length; i++) * { * stackTrace += (trace[i].toString() + Window.LF); * } * //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" * DecompilerThread.OnMessage(this, e.Message + Window.LF + stackTrace); * DecompilerThread.OnMessage(this, ); * Window.setProgress(jobnum, 1, 1, "ERROR! See log!"); * System.Drawing.Color tempAux3 = System.Drawing.Color.FromArgb(255, 128, 128); * //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'" * Window.setProgressColor(jobnum, ref tempAux3);*/ OnError(this, st); } finally { doomMap = null; BSPObject = null; BSPFile = null; Thread.CurrentThread.Abort(); } /*else * { * Window.print("Job " + (jobnum + 1) + " aborted by user."); * Window.print(" When: While initializing job."); * DecompilerThread.OnMessage(this, ); * Window.setProgress(jobnum, 1, 1, "Aborted!"); * System.Drawing.Color tempAux5 = System.Drawing.Color.FromArgb(255, 128, 128); * //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'" * Window.setProgressColor(jobnum, ref tempAux5); * SupportClass.ThreadClass.Current().Interrupt(); * }*/ //Window.setAbortButtonEnabled(jobnum, false); }
public DecompilerThread(DoomMap doomMap, int jobNum, mapType openAs) { this.doomMap = doomMap; this.jobnum = jobNum; }
void ReadMAPEntries() { for (int i = 0; i < newWad.directory.Count - 1; i++) { if (newWad.directory[i + 1].name.Contains("THINGS") && newWad.directory[i].size == 0) { DoomMap newMap = new DoomMap(); DrctEntry dirEntry = newWad.directory[i]; newMap.name = dirEntry.name; //THINGS lump if (newWad.directory[i + 1].name.Contains("THINGS")) { byte[] thingBytes = new byte[newWad.directory[i + 1].size]; wadOpener.Position = newWad.directory[i + 1].filepos; wadOpener.Read(thingBytes, 0, thingBytes.Length); for (int j = 0; j < newWad.directory[i + 1].size; j += 10) { THINGS newThing = new THINGS(); newThing.xPos = BitConverter.ToInt16(thingBytes, j + 0); newThing.yPos = BitConverter.ToInt16(thingBytes, j + 2); newThing.angle = BitConverter.ToInt16(thingBytes, j + 4); newThing.thingType = BitConverter.ToInt16(thingBytes, j + 6); newThing.thingOptions = BitConverter.ToInt16(thingBytes, j + 8); newMap.things.Add(newThing); } } //LINEDEEFS lump if (newWad.directory[i + 2].name.Contains("LINEDEFS")) { byte[] lineDefBytes = new byte[newWad.directory[i + 2].size]; wadOpener.Position = newWad.directory[i + 2].filepos; wadOpener.Read(lineDefBytes, 0, lineDefBytes.Length); for (int j = 0; j < newWad.directory[i + 2].size; j += 14) { LINEDEFS newLineDef = new LINEDEFS(); newLineDef.firstVertIndex = BitConverter.ToInt16(lineDefBytes, j + 0); newLineDef.lastVertIndex = BitConverter.ToInt16(lineDefBytes, j + 2); newLineDef.flags = BitConverter.ToInt16(lineDefBytes, j + 4); newLineDef.types = BitConverter.ToInt16(lineDefBytes, j + 6); newLineDef.tag = BitConverter.ToInt16(lineDefBytes, j + 8); newLineDef.side1Index = BitConverter.ToInt16(lineDefBytes, j + 10); newLineDef.side2Index = BitConverter.ToInt16(lineDefBytes, j + 12); newMap.linedefs.Add(newLineDef); } } //SIDEDEFS lump if (newWad.directory[i + 3].name.Contains("SIDEDEFS")) { byte[] sideDefBytes = new byte[newWad.directory[i + 3].size]; wadOpener.Position = newWad.directory[i + 3].filepos; wadOpener.Read(sideDefBytes, 0, sideDefBytes.Length); for (int j = 0; j < newWad.directory[i + 3].size; j += 30) { SIDEDEFS newSideDef = new SIDEDEFS(); newSideDef.xOfs = BitConverter.ToInt16(sideDefBytes, j + 0); newSideDef.yOfs = BitConverter.ToInt16(sideDefBytes, j + 2); newSideDef.upTex = new String(System.Text.Encoding.ASCII.GetChars(sideDefBytes, j + 4, 8)).ToUpper(); newSideDef.lowTex = new String(System.Text.Encoding.ASCII.GetChars(sideDefBytes, j + 12, 8)).ToUpper(); newSideDef.midTex = new String(System.Text.Encoding.ASCII.GetChars(sideDefBytes, j + 20, 8)).ToUpper(); newSideDef.secNum = BitConverter.ToInt16(sideDefBytes, j + 28); newSideDef.upTex = newSideDef.upTex.Replace("\0", ""); newSideDef.lowTex = newSideDef.lowTex.Replace("\0", ""); newSideDef.midTex = newSideDef.midTex.Replace("\0", ""); newMap.sidedefs.Add(newSideDef); } } //VERTEXES lump if (newWad.directory[i + 4].name.Contains("VERTEXES")) { byte[] vertexBytes = new byte[newWad.directory[i + 4].size]; wadOpener.Position = newWad.directory[i + 4].filepos; wadOpener.Read(vertexBytes, 0, vertexBytes.Length); for (int j = 0; j < newWad.directory[i + 4].size; j += 4) { Vector3 newVertex = new Vector3(0, 0, 0); newVertex.x = BitConverter.ToInt16(vertexBytes, j + 0); newVertex.z = BitConverter.ToInt16(vertexBytes, j + 2); newMap.vertexes.Add(newVertex); } } //SECTORS lump if (newWad.directory[i + 8].name.Contains("SECTORS")) { byte[] secBytes = new byte[newWad.directory[i + 8].size]; wadOpener.Position = newWad.directory[i + 8].filepos; wadOpener.Read(secBytes, 0, secBytes.Length); for (int j = 0; j < newWad.directory[i + 8].size; j += 26) { SECTORS newSec = new SECTORS(); newSec.floorHeight = BitConverter.ToInt16(secBytes, j + 0); newSec.ceilingHeight = BitConverter.ToInt16(secBytes, j + 2); newSec.floorFlat = new String(System.Text.Encoding.ASCII.GetChars(secBytes, j + 4, 8)); newSec.ceilingFlat = new String(System.Text.Encoding.ASCII.GetChars(secBytes, j + 12, 8)); newSec.lightLevel = BitConverter.ToInt16(secBytes, j + 20); newSec.specialSec = BitConverter.ToInt16(secBytes, j + 22); newSec.sectorTag = BitConverter.ToInt16(secBytes, j + 24); newSec.floorFlat = newSec.floorFlat.Replace("\0", ""); newSec.ceilingFlat = newSec.ceilingFlat.Replace("\0", ""); newMap.sectors.Add(newSec); } } //BLOCKMAPS lump if (newWad.directory[i + 10].name.Contains("BLOCKMAP")) { byte[] blockBytes = new byte[newWad.directory[i + 10].size]; wadOpener.Position = newWad.directory[i + 10].filepos; wadOpener.Read(blockBytes, 0, blockBytes.Length); BLOCKMAP newBlockmap = new BLOCKMAP(); newBlockmap.xcoord = BitConverter.ToInt16(blockBytes, 0); newBlockmap.ycoord = BitConverter.ToInt16(blockBytes, 2); newBlockmap.numColumns = BitConverter.ToInt16(blockBytes, 4); newBlockmap.numRows = BitConverter.ToInt16(blockBytes, 6); int N = newBlockmap.numColumns * newBlockmap.numRows; //Offsets for (int j = 8; j < (8 + (2 * (N - 1))); j += 2) // (8 + (2 * (N - 1))) IS DEFINITELY RIGHT { newBlockmap.Offsets.Add(BitConverter.ToUInt16(blockBytes, j) * 2); //multiply this times 2 so its right } foreach (int offset in newBlockmap.Offsets) { int line = 0; int blockOffset = offset; // List<int> newBlock = new List<int>(); Block blk = new Block(); do { line = BitConverter.ToUInt16(blockBytes, blockOffset + 2); //newBlock.Add(line); if (line == 0xFFFF) { continue; } blk.lines.Add(newMap.linedefs[line]); blockOffset += 2; } while (line != 0xFFFF); newBlockmap.blocks.Add(blk); } newMap.blockmap = newBlockmap; } newWad.maps.Add(newMap); //Store the map in newWad } } }
/// <summary> /// Constructor. /// </summary> /// <param name="args">Command line parameters</param> public PNGToWad(params string[] args) { string[] mapBitmapFiles = (from string file in args where File.Exists(file) && Path.GetExtension(file).ToLowerInvariant() == ".png" select file).ToArray(); if (mapBitmapFiles.Length == 0) { Console.WriteLine("Missing parameters or no valid PNG file in the parameters."); Console.WriteLine("Syntax is: PixelsOfDoom.exe SomeImage.png [SomeOtherImage.png] [YetAnotherImage.png]..."); Console.ReadKey(); return; } string wadFile = Path.GetFileNameWithoutExtension(mapBitmapFiles[0]) + ".wad"; // Output file is the name of the first file with a WAD extension. #if DEBUG Preferences config = new Preferences(@"..\Release\Preferences.ini"); #else Preferences config = new Preferences("Preferences.ini"); #endif MapGenerator generator = new MapGenerator(config); WadFile wad = new WadFile(); for (int i = 0; i < mapBitmapFiles.Length; i++) { int mapNumber = i + 1; if ((config.Doom1Format && (mapNumber > 9)) || (!config.Doom1Format && (mapNumber > 99))) // Too many maps, stop here { break; } #if !DEBUG try { #endif string mapName = config.Doom1Format ? $"E{config.Episode:0}M{mapNumber:0}" : $"MAP{mapNumber:00}"; using (Bitmap bitmap = (Bitmap)Image.FromFile(mapBitmapFiles[i])) { using (DoomMap map = generator.Generate(mapName, bitmap)) { map.AddToWad(wad); } } #if !DEBUG } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); Console.WriteLine(); continue; } #endif } wad.SaveToFile(wadFile); wad.Dispose(); generator.Dispose(); if (config.BuildNodes) { Process bspProcess; switch (Environment.OSVersion.Platform) { case PlatformID.Win32NT: case PlatformID.Win32S: case PlatformID.Win32Windows: case PlatformID.WinCE: Console.WriteLine("Building nodes with bsp-w32.exe..."); #if DEBUG bspProcess = Process.Start(@"..\Release\bsp-w32.exe", $"\"{wadFile}\" -o \"{wadFile}\""); #else bspProcess = Process.Start("bsp-w32.exe", $"\"{wadFile}\" -o \"{wadFile}\""); #endif bspProcess.WaitForExit(); if (bspProcess.ExitCode != 0) { Console.WriteLine("Failed to build nodes!"); } break; } } }
// CONSTRUCTORS // This constructor sets up everything to convert a Doom map into brushes compatible with modern map editors. // I don't know if this is decompiling, per se. I don't know if Doom maps were ever compiled or if they just had nodes built. public WADDecompiler(DoomMap doomMap, int jobnum, DecompilerThread parent) { this.doomMap = doomMap; this.jobnum = jobnum; this.parent = parent; }
void fillInfo(DoomMap map) { // find and remember each sector's tag and index map.sectorsByTag.Clear(); for (int i = 0; i < map.sectors.Count; i++) { SECTORS sector = map.sectors[i]; sector.lines.Clear(); sector.otherLines.Clear(); sector.sectorIndex = i; if (sector.sectorTag == 0) { continue; } if (!map.sectorsByTag.ContainsKey(sector.sectorTag)) { map.sectorsByTag.Add(sector.sectorTag, new List <SECTORS> { sector }); } else { map.sectorsByTag[sector.sectorTag].Add(sector); } } // set sector's default movement bounds foreach (SECTORS sector in map.sectors) { sector.floorBounds = new int[2] { sector.floorHeight, sector.floorHeight }; sector.ceilingBounds = new int[2] { sector.ceilingHeight, sector.ceilingHeight }; } foreach (LINEDEFS line in map.linedefs) { line.map = map; line.getVerts(); //store the vertex information inside the linedef line.getSidedefs(); //store the sidedefs in the linedef for easier access SECTORS front = line.getFrontSector(); SECTORS back = line.getBackSector(); // tag dynamic sectors if (LineDefTypes.types.ContainsKey(line.types)) { switch (LineDefTypes.types[line.types].category) { case LineDefTypes.Category.Door: LineDefTypes.LineDefDoorType doorType = (LineDefTypes.types[line.types] as LineDefTypes.LineDefDoorType); // tag door sectors if (doorType.isLocal() && back != null) { back.isMovingCeiling = true; back.isDoor = true; } else if (!doorType.isLocal() && map.sectorsByTag.ContainsKey(line.tag)) { map.sectorsByTag[line.tag].ForEach(x => x.isMovingCeiling = true); map.sectorsByTag[line.tag].ForEach(x => x.isDoor = true); } break; case LineDefTypes.Category.Floor: // tag floor sectors if (map.sectorsByTag.ContainsKey(line.tag)) { map.sectorsByTag[line.tag].ForEach(x => x.isMovingFloor = true); } break; case LineDefTypes.Category.Lift: // tag lift sectors if (map.sectorsByTag.ContainsKey(line.tag)) { map.sectorsByTag[line.tag].ForEach(x => x.isMovingFloor = true); } break; case LineDefTypes.Category.Ceiling: // tag ceiling sectors if (map.sectorsByTag.ContainsKey(line.tag)) { map.sectorsByTag[line.tag].ForEach(x => x.isMovingCeiling = true); } break; case LineDefTypes.Category.Crusher: // tag crusher sectors if (map.sectorsByTag.ContainsKey(line.tag)) { map.sectorsByTag[line.tag].ForEach(x => x.isMovingCeiling = true); } break; } } if (front == null && back == null) //if this line is BROKEN { continue; //we ignore it } else if (front == back) //if the front and the back are the same, it is inside a single sector { //if the line is internal to the sector, theres a special place in the sector class for them front.otherLines.Add(line); } else if (front != null) //if the front is defined, add the front { front.lines.Add(line); if (back != null) { back.lines.Add(line);//add the line to the sector on its back as well..if it exists } } else { back.lines.Add(line); //if all else fails, the line must be backwards } } // find and remember each sector's neighboring sectors foreach (SECTORS sector in map.sectors) { foreach (LINEDEFS line in sector.lines) { if (line.getFrontSector() != sector && line.getFrontSector() != null && !sector.neighbors.Contains(line.getFrontSector())) { sector.neighbors.Add(line.getFrontSector()); } if (line.getBackSector() != sector && line.getBackSector() != null && !sector.neighbors.Contains(line.getBackSector())) { sector.neighbors.Add(line.getBackSector()); } } } //set sector's movement bounds foreach (LINEDEFS line in map.linedefs) { if (!LineDefTypes.types.ContainsKey(line.types)) { continue; } if (LineDefTypes.types[line.types].category == LineDefTypes.Category.Door) { LineDefTypes.LineDefDoorType doorType = LineDefTypes.types[line.types] as LineDefTypes.LineDefDoorType; if (doorType.isLocal()) { UpdateSectorBounds(line.getBackSector(), line); continue; } } if (line.tag != 0 && map.sectorsByTag.ContainsKey(line.tag)) { foreach (SECTORS sector in map.sectorsByTag[line.tag]) { UpdateSectorBounds(sector, line); } } } }
public virtual void Run() { DateTime begin = DateTime.Now; try { Entities output = null; if (doomMap != null) { // If this is a Doom map extracted from a WAD //Window.setProgress(jobnum, 0, doomMap.getSubSectors().size(), "Decompiling..."); WADDecompiler decompiler = new WADDecompiler(doomMap, jobnum, this); output = decompiler.decompile(); } else { DecompilerThread.OnMessage(this, "Opening file " + BSPFile.FullName); //Window.setProgress(jobnum, 0, 1, "Reading..."); BSPReader reader = new BSPReader(BSPFile, openAs); reader.readBSP(); //if (!reader.WAD) { BSPObject = reader.BSPData; /*try { Window.setProgress(jobnum, 0, reader.BSPData.getBrushes().size() + reader.BSPData.getEntities().size(), "Decompiling..."); } catch (System.NullReferenceException e) { try { Window.setProgress(jobnum, 0, reader.BSPData.getLeaves().size() + reader.BSPData.getEntities().size(), "Decompiling..."); } catch (System.NullReferenceException f) { Window.setProgress(jobnum, 0, 1, "Decompiling..."); // What's going on here? Put in a failsafe progress bar for now } }*/ switch (reader.Version){ case mapType.TYPE_QUAKE: //DecompilerThread.OnMessage(this, "ERROR: Algorithm for decompiling Quake BSPs not written yet.",Window.VERBOSITY_ALWAYS); //throw new java.lang.Exception(); // Throw an exception to the exception handler to indicate it didn't work QuakeDecompiler decompiler29 = new QuakeDecompiler(reader.BSPData, jobnum, this); output = decompiler29.decompile(); break; case mapType.TYPE_NIGHTFIRE: BSP42Decompiler decompiler42 = new BSP42Decompiler(reader.BSPData, jobnum, this); output = decompiler42.decompile(); break; case mapType.TYPE_QUAKE2: case mapType.TYPE_SIN: case mapType.TYPE_SOF: case mapType.TYPE_DAIKATANA: BSP38Decompiler decompiler38 = new BSP38Decompiler(reader.BSPData, jobnum, this); output = decompiler38.decompile(); break; case mapType.TYPE_SOURCE17: case mapType.TYPE_SOURCE18: case mapType.TYPE_SOURCE19: case mapType.TYPE_SOURCE20: case mapType.TYPE_SOURCE21: case mapType.TYPE_SOURCE22: case mapType.TYPE_SOURCE23: case mapType.TYPE_SOURCE27: case mapType.TYPE_DMOMAM: case mapType.TYPE_VINDICTUS: case mapType.TYPE_TACTICALINTERVENTION: SourceBSPDecompiler sourceDecompiler = new SourceBSPDecompiler(reader.BSPData, jobnum, this); output = sourceDecompiler.decompile(); break; case mapType.TYPE_QUAKE3: case mapType.TYPE_RAVEN: case mapType.TYPE_COD: case mapType.TYPE_COD2: case mapType.TYPE_COD4: case mapType.TYPE_STEF2: case mapType.TYPE_STEF2DEMO: case mapType.TYPE_MOHAA: case mapType.TYPE_FAKK: BSP46Decompiler decompiler46 = new BSP46Decompiler(reader.BSPData, jobnum, this); output = decompiler46.decompile(); break; case mapType.TYPE_DOOM: case mapType.TYPE_HEXEN: foreach (DoomMap map in reader.DoomMaps) { WADDecompiler wadDecompiler = new WADDecompiler(map, jobnum, this); Entities holyshit = wadDecompiler.decompile(); MAPMaker.outputMaps(holyshit, map.MapName, map.Folder + map.WadName + "\\", map.Version); } break; default: DecompilerThread.OnMessage(this, "ERROR: Unknown BSP version: " + reader.Version); throw new System.Exception(); // Throw an exception to the exception handler to indicate it didn't work } //} } if (output != null) { //Window.setProgress(jobnum, 1, 1, "Saving..."); if (doomMap == null) { MAPMaker.outputMaps(output, BSPObject.MapNameNoExtension, BSPObject.Folder, BSPObject.Version); } else { MAPMaker.outputMaps(output, doomMap.MapName, doomMap.Folder + doomMap.WadName + "\\", doomMap.Version); } } //Window.setProgress(jobnum, 1, 1, "Done!"); //System.Drawing.Color tempAux = System.Drawing.Color.FromArgb(64, 192, 64); //Window.setProgressColor(jobnum, ref tempAux); DateTime end = DateTime.Now; DecompilerThread.OnMessage(this, "Time taken: " + (end - begin).ToString() + (char) 0x0D + (char) 0x0A); OnFinish(this, jobnum); } catch (System.OutOfMemoryException) { string st = ""; if (openAs != mapType.TYPE_UNDEFINED) { st = "VM ran out of memory on job " + (jobnum + 1) + ". Are you using \"Open as...\" with the wrong game?" + (char) 0x0D + (char) 0x0A + "If not, please let me know on the issue tracker!" + (char) 0x0D + (char) 0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry"; } else { st = "VM ran out of memory on job " + (jobnum + 1) + "." + (char) 0x0D + (char) 0x0A + "Please let me know on the issue tracker!" + (char) 0x0D + (char) 0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry"; } //Window.setProgress(jobnum, 1, 1, "ERROR! See log!"); //System.Drawing.Color tempAux4 = System.Drawing.Color.FromArgb(255, 128, 128); //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'" //Window.setProgressColor(jobnum, ref tempAux4); OnError(this, st); } catch (Exception e) { string st; if (openAs != mapType.TYPE_UNDEFINED) { //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" st="" + (char) 0x0D + (char) 0x0A + "Exception caught in job " + (jobnum + 1) + ": " + e + (char) 0x0D + (char) 0x0A + "Are you using \"Open as...\" with the wrong game?" + (char) 0x0D + (char) 0x0A + "If not, please let me know on the issue tracker!" + (char) 0x0D + (char) 0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry"; } else { //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" st="" + (char) 0x0D + (char) 0x0A + "Exception caught in job " + (jobnum + 1) + ": " + e + (char) 0x0D + (char) 0x0A + "Please let me know on the issue tracker!" + (char) 0x0D + (char) 0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry"; } /*System.String stackTrace = "Stack Trace: " + (char) 0x0D + (char) 0x0A; StackTraceElement[] trace = e.getStackTrace(); for (int i = 0; i < trace.length; i++) { stackTrace += (trace[i].toString() + Window.LF); } //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" DecompilerThread.OnMessage(this, e.Message + Window.LF + stackTrace); DecompilerThread.OnMessage(this, ); Window.setProgress(jobnum, 1, 1, "ERROR! See log!"); System.Drawing.Color tempAux3 = System.Drawing.Color.FromArgb(255, 128, 128); //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'" Window.setProgressColor(jobnum, ref tempAux3);*/ OnError(this, st); } finally { doomMap = null; BSPObject = null; BSPFile = null; Thread.CurrentThread.Abort(); } /*else { Window.print("Job " + (jobnum + 1) + " aborted by user."); Window.print(" When: While initializing job."); DecompilerThread.OnMessage(this, ); Window.setProgress(jobnum, 1, 1, "Aborted!"); System.Drawing.Color tempAux5 = System.Drawing.Color.FromArgb(255, 128, 128); //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'" Window.setProgressColor(jobnum, ref tempAux5); SupportClass.ThreadClass.Current().Interrupt(); }*/ //Window.setAbortButtonEnabled(jobnum, false); }
/// <summary> /// Adds a new linedef (and its sidedef(s)) to the map. /// </summary> /// <param name="map">The Doom map</param> /// <param name="position">Line start position</param> /// <param name="neighborDirection">Direction to the line's neighbor sector</param> /// <param name="vertical">Is the line vertical (on the Y-axis) or horizontal (on the X-axis)</param> /// <param name="sector">Index of the sector this line faces</param> /// <param name="neighborSector">Index of the sector this line is turned against</param> /// <returns></returns> private int AddLine(DoomMap map, Point position, TileSide neighborDirection, bool vertical, int sector, int neighborSector) { bool flipVectors = false; Point vertexOffset = Point.Empty; Point neighborOffset = GetTileSideOffset(neighborDirection); Point neighborPosition; bool needsFlipping = SectorsInfo[sector].LinedefSpecial > 0; switch (neighborDirection) { case TileSide.West: flipVectors = true; break; case TileSide.East: vertexOffset = new Point(1, 0); break; case TileSide.South: flipVectors = true; vertexOffset = new Point(0, 1); break; } int v1 = map.AddVertex(position.Add(vertexOffset).Mult(VERTEX_POSITION_MULTIPLIER)); int length = 0; Point direction = vertical ? new Point(0, 1) : new Point(1, 0); do { position = position.Add(direction); neighborPosition = position.Add(neighborOffset); length++; if ((GetSector(position) != sector) || (GetSector(neighborPosition) != neighborSector)) { break; } } while (true); int v2 = map.AddVertex(position.Add(vertexOffset).Mult(VERTEX_POSITION_MULTIPLIER)); if (flipVectors) { v1 += v2; v2 = v1 - v2; v1 -= v2; } // Quick hack to flip two integers without temporary variable if (neighborSector < 0) // neighbor is a wall, create an impassible linedef { map.Sidedefs.Add(new Sidedef(0, 0, "-", "-", SectorsInfo[sector].WallTexture, sector)); map.Linedefs.Add(new Linedef(v1, v2, LinedefFlags.Impassible | LinedefFlags.LowerUnpegged, 0, 0, -1, map.Sidedefs.Count - 1)); } else // neighbor is another sector, create a two-sided linedef { int lineSpecial = Math.Max(SectorsInfo[sector].LinedefSpecial, SectorsInfo[neighborSector].LinedefSpecial); map.Sidedefs.Add(CreateTwoSidedSidedef(neighborSector, SectorsInfo[neighborSector], SectorsInfo[sector])); map.Sidedefs.Add(CreateTwoSidedSidedef(sector, SectorsInfo[sector], SectorsInfo[neighborSector])); if (needsFlipping) { map.Linedefs.Add(new Linedef(v2, v1, LinedefFlags.TwoSided, lineSpecial, 0, map.Sidedefs.Count - 1, map.Sidedefs.Count - 2)); } else { map.Linedefs.Add(new Linedef(v1, v2, LinedefFlags.TwoSided, lineSpecial, 0, map.Sidedefs.Count - 2, map.Sidedefs.Count - 1)); } } return(length); }
/// <summary> /// Adds a random number of things from a certain ThingCategory. /// </summary> /// <param name="map">The Doom map on which to add things</param> /// <param name="thingCategory">The thing category from which to pick thing types</param> /// <param name="minCount">Min number of things to add</param> /// <param name="maxCount">Max number of things to add</param> /// <param name="generationFlags">Special flags for thing generation</param> private void AddThings(DoomMap map, ThingCategory thingCategory, int minCount, int maxCount, ThingsGeneratorFlags generationFlags = 0) { int count = Toolbox.RandomInt(minCount, maxCount + 1); AddThings(map, count, generationFlags, Preferences.ThingsTypes[(int)thingCategory]); }
// METHODS public void readBSP() { try { version = Version; byte[] theLump = new byte[0]; BSPObject = new BSP(BSPFile.FullName, version); switch(version) { case mapType.TYPE_VINDICTUS: case mapType.TYPE_TACTICALINTERVENTION: case mapType.TYPE_SOURCE17: case mapType.TYPE_SOURCE18: case mapType.TYPE_SOURCE19: case mapType.TYPE_SOURCE20: case mapType.TYPE_SOURCE21: case mapType.TYPE_SOURCE22: case mapType.TYPE_SOURCE23: case mapType.TYPE_SOURCE27: case mapType.TYPE_DMOMAM: DecompilerThread.OnMessage(this, "Source BSP"); stream.Seek(8, SeekOrigin.Begin); int test = br.ReadInt32(); if(bigEndian) { test = DataReader.swapEndian(test); } if(test < 1032) { // If what's usually the offset is less than the length of the header and directory isL4D2 = true; // This is Left 4 Dead 2 } // Lump 35, Game lump // Need to handle this here in order to detect Vindictus maps. // This lump SUCKS. It's a lump containing nested lumps for game specific data. // What we need out of it is the static prop lump. theLump = readLumpNum(35); try { readGameLump(theLump, lumpOffset); } catch { dumpLump(theLump); } for(int i=0;i<64;i++) { try { switch(i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.TexDatas = SourceTexData.createLump(theLump); break; case 3: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.Nodes = Node.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.TexInfo = TexInfo.createLump(theLump, version); break; case 7: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.Leaves = Leaf.createLump(theLump, version); break; case 12: theLump = readLumpNum(i); BSPObject.Edges = Edge.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.SurfEdges = new NumList(theLump, NumList.dataType.INT); break; case 14: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 17: theLump = readLumpNum(i); if(version == mapType.TYPE_VINDICTUS) { BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.UINT); } else { BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.USHORT); } break; case 18: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 19: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 26: theLump = readLumpNum(i); BSPObject.DispInfos = SourceDispInfo.createLump(theLump, version); break; case 27: theLump = readLumpNum(i); BSPObject.OriginalFaces = Face.createLump(theLump, version); break; case 33: theLump = readLumpNum(i); BSPObject.DispVerts = SourceDispVertex.createLump(theLump); break; case 40: theLump = readLumpNum(i); if (Settings.extractZip) { Console.Write("Extracting internal PAK file... "); writeLump(BSPObject.MapName+".zip", theLump); } break; case 42: theLump = readLumpNum(i); BSPObject.Cubemaps = SourceCubemap.createLump(theLump, version); break; case 43: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 44: theLump = readLumpNum(i); BSPObject.TexTable = new NumList(theLump, NumList.dataType.INT); break; case 48: theLump = readLumpNum(i); BSPObject.DispTris = new NumList(theLump, NumList.dataType.USHORT); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_NIGHTFIRE: DecompilerThread.OnMessage(this, "BSP v42 (Nightfire)"); for(int i=0;i<18;i++) { try { switch(i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 3: theLump = readLumpNum(i); BSPObject.Materials = Texture.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 9: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 11: theLump = readLumpNum(i); BSPObject.Leaves = Leaf.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.UINT); break; case 14: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 15: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 16: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 17: theLump = readLumpNum(i); BSPObject.TexInfo = TexInfo.createLump(theLump, version); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_QUAKE2: case mapType.TYPE_SIN: case mapType.TYPE_DAIKATANA: case mapType.TYPE_SOF: DecompilerThread.OnMessage(this, "BSP v38 (Quake 2/SiN/Daikatana/Soldier of Fortune)"); for(int i=0;i<19;i++) { try { switch(i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Nodes = Node.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 8: theLump = readLumpNum(i); BSPObject.Leaves = Leaf.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.USHORT); break; case 11: theLump = readLumpNum(i); BSPObject.Edges = Edge.createLump(theLump, version); break; case 12: theLump = readLumpNum(i); BSPObject.SurfEdges = new NumList(theLump, NumList.dataType.INT); break; case 13: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 14: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 15: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; /*case 18: theLump = readLumpNum(i); BSPObject.AreaPortals = AreaPortal.createLump(theLump, version); break;*/ } } catch { dumpLump(theLump); } } break; case mapType.TYPE_QUAKE: DecompilerThread.OnMessage(this, "Quake 1/Half-life BSP"); for (int i = 0; i < 15; i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 3: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.Nodes = Node.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.TexInfo = TexInfo.createLump(theLump, version); break; case 7: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.Leaves = Leaf.createLump(theLump, version); break; case 11: theLump = readLumpNum(i); BSPObject.MarkSurfaces = new NumList(theLump, NumList.dataType.USHORT); break; case 12: theLump = readLumpNum(i); BSPObject.Edges = Edge.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.SurfEdges = new NumList(theLump, NumList.dataType.INT); break; case 14: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_STEF2: case mapType.TYPE_STEF2DEMO: DecompilerThread.OnMessage(this, "Star Trek Elite Force 2 BSP"); for (int i = 0; i < 30; i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 12: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 15: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 16: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_MOHAA: DecompilerThread.OnMessage(this, "MOHAA BSP (modified id Tech 3)"); for(int i=0;i<28;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 3: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 11: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 12: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 14: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; //case 24: // theLump = readLumpNum(i); // BSPObject.StaticProps = StaticProp.createLump(theLump); // break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_FAKK: DecompilerThread.OnMessage(this, "Heavy Metal FAKK² BSP"); for(int i=0;i<20;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 11: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 14: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_RAVEN: case mapType.TYPE_QUAKE3: DecompilerThread.OnMessage(this, "BSP v46 (id Tech 3)"); for(int i=0;i<18;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 7: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 8: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 9: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_COD: DecompilerThread.OnMessage(this, "BSP v59 (Call of Duty)"); for(int i=0;i<33;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 3: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 27: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 29: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_COD2: DecompilerThread.OnMessage(this, "Call of Duty 2 BSP"); for(int i=0;i<40;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 35: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 37: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_COD4: DecompilerThread.OnMessage(this, "Call of Duty 4 BSP"); for(int i=0;i<55;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 8: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 37: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 39: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_DOOM: case mapType.TYPE_HEXEN: DecompilerThread.OnMessage(this, "WAD file found"); stream.Seek(4, SeekOrigin.Begin); int numLumps = br.ReadInt32(); for(int i=0;i<numLumps;i++) { string name = getLumpName(i); if((name.Length == 5 && name[0] == 'M' && name[1] == 'A' && name[2] == 'P' && name[3] >= '0' && name[3] <= '9' && name[4] >= '0' && name[4] <= '9') || ((name.Length == 4 && name[0] == 'E' && name[1] >= '0' && name[1] <= '9' && name[2] == 'M' && name[3] >= '0' && name[3] <= '9'))) { if(getLumpName(i+11) == "BEHAVIOR") { version = mapType.TYPE_HEXEN; } DecompilerThread.OnMessage(this, "Map: " + name); DoomMap currentMap = new DoomMap(BSPFile.FullName, name, version); int[] headerInfo = getLumpInfo(i); if (headerInfo[1] > 0 && Settings.extractZip) { Console.Write("Extracting Map Header "); writeLump(name+".txt", readLumpNum(i)); } currentMap.Things = DThing.createLump(readLumpNum(i+1), version); currentMap.Linedefs = DLinedef.createLump(readLumpNum(i+2), version); currentMap.Sidedefs = DSidedef.createLump(readLumpNum(i+3)); currentMap.Vertices = Vertex.createLump(readLumpNum(i+4), version); currentMap.Segments = DSegment.createLump(readLumpNum(i+5)); currentMap.SubSectors = Edge.createLump(readLumpNum(i+6), version); currentMap.Nodes = DNode.createLump(readLumpNum(i+7)); currentMap.Sectors = DSector.createLump(readLumpNum(i+8)); doomMaps.Add(currentMap); currentMap.printBSPReport(); } } break; default: DecompilerThread.OnMessage(this, "Tried to populate structures for a format not implemented yet!"); break; } BSPObject.printBSPReport(); } catch (System.IO.IOException) { DecompilerThread.OnMessage(this, "Unable to access BSP file! Is it open in another program?"); } br.Close(); }