public void Add(T entity) { if (entity == null) { throw new ArgumentNullException(nameof(entity)); } if (DbContext != null) { Entities?.Add(entity); } // DbContext.SaveChanges(); }
public void To_String() { var list = new Entities<Entity>(); var nestedEntity = new NestedEntity(); var testEntity = new TestEntity(nestedEntity); nestedEntity.Yo = "7"; testEntity.Zo = "8"; list.Add(testEntity); var builder = new StringBuilder(); builder.AppendLine("ZO, YO, "); builder.AppendLine("8, 7, "); Assert.That(list.ToString(), Is.EqualTo(builder.ToString())); }
/// <summary> /// 映射数据同步领域上下文范围 /// </summary> /// <typeparam name="LocalEntity">本地实体</typeparam> /// <typeparam name="TService">服务器端数据同步服务对象</typeparam> static void Mapping <LocalEntity>() where LocalEntity : Pharos.Logic.LocalEntity.BaseEntity, new() { var type = typeof(LocalEntity); var key = type.ToString(); var titleAttr = Attribute.GetCustomAttribute(type, typeof(ExcelAttribute)) as ExcelAttribute; if (titleAttr != null) { TableNames.Add(key, titleAttr.Title); } Entities.Add(key, new LocalEntity()); }
/// <summary> /// Initializes a new instance of the <see cref="SerializableEntityCollection"/> class. /// </summary> /// <param name="entities">The entities.</param> public SerializableEntityCollection(EntityCollection entities) : this() { foreach (var entity in entities.Entities) { Entities.Add(new SerializableEntity(entity)); } EntityName = entities.EntityName; ExtensionData = entities.ExtensionData; MinActiveRowVersion = entities.MinActiveRowVersion; MoreRecords = entities.MoreRecords; PagingCookie = entities.PagingCookie; TotalRecordCount = entities.TotalRecordCount; TotalRecordCountLimitExceeded = entities.TotalRecordCountLimitExceeded; }
private void AddEntityToDictionary(Entity entity) { if (!Entities.ContainsKey(entity.PlayerNumber)) { Entities.Add(entity.PlayerNumber, new Dictionary <EntityType, List <Entity> >()); } if (!Entities[entity.PlayerNumber].ContainsKey(entity.Type)) { Entities[entity.PlayerNumber].Add(entity.Type, new List <Entity>()); } Entities[entity.PlayerNumber][entity.Type].Add(entity); }
internal ushort GetPlayerId(string name) { List<Player> players = new List<Player>(Entities.Values.Where(e => e is Player).Cast<Player>()); Player player = players.FirstOrDefault(p => p.PlayerName == name); if (player == null) { // create and save new player with given name player = new Player(Configuration.World.NewPlayerSpawnPoint, name); Entities.Add(player.ID, player); Save(false); } return player.ID; }
public Task UpdateAsync(T entity, DateTimeOffset dateTimeOffset) { var matchingT = Entities.SingleOrDefault(x => x.Id == entity.Id); if (matchingT != null) { Entities.Remove(matchingT); } Entities.Add(entity); EventOccurred(entity); return(Task.CompletedTask); }
private void SmartDetect(string filename) { var detector = new FileHelpers.Detection.SmartFormatDetector(); var formats = detector.DetectFileFormat(filename); foreach (var format in formats) { Console.WriteLine("Format Detected, confidence:" + format.Confidence + "%"); var delimited = format.ClassBuilderAsDelimited; Console.WriteLine(" Delimiter:" + delimited.Delimiter); Console.WriteLine(" Fields:"); EntityStructure entityData = new EntityStructure(); string sheetname; sheetname = FileName; entityData.Viewtype = ViewType.File; entityData.DatabaseType = DataSourceType.Text; entityData.DataSourceID = FileName; entityData.DatasourceEntityName = FileName; entityData.Caption = FileName; entityData.EntityName = FileName; List <EntityField> Fields = new List <EntityField>(); int y = 0; foreach (var field in delimited.Fields) { Console.WriteLine(" " + field.FieldName + ": " + field.FieldType); EntityField f = new EntityField(); // f.tablename = sheetname; f.fieldname = field.FieldName; f.fieldtype = field.FieldType.ToString(); f.ValueRetrievedFromParent = false; f.EntityName = sheetname; f.FieldIndex = y; Fields.Add(f); y += 1; } entityData.Fields = new List <EntityField>(); entityData.Fields.AddRange(Fields); Entities.Clear(); EntitiesNames.Clear(); EntitiesNames.Add(filename); Entities.Add(entityData); } }
public int Insert(T entity) { if (entity == null) { throw new ArgumentNullException(); } Entities.Add(entity); //_context.Set<T>().Add(entity); var id = _context.SaveChanges(); return(id); }
private Entities GetListInRecurit(SqlDataReader reader) { Major major; Entities entities = new Entities(); while (reader.Read()) { major = new Major(); major.MajorId = reader.GetInt32(0); major.MajorName = reader.GetString(1); entities.Add(major); } return(entities); }
/// <summary> /// Insert entities as async /// </summary> /// <param name="entities">Entities</param> public virtual async Task InsertAsync(IEnumerable <T> entities) { if (entities == null) { throw new ArgumentNullException("entities"); } foreach (var entity in entities) { Entities.Add(entity); } await _context.SaveChangesAsync(); }
/// <summary> /// tracks entity of type <typeparamref name="TEntity"/> in the context. Creates a new /// <see cref="ExcelEntityBuilder{TEntity}"/> and calls the passed configuration method /// </summary> /// <typeparam name="TEntity">type of the domain object</typeparam> /// <param name="buildAction">gets called by this method and contains the builder configuration</param> public virtual void Entity <TEntity>(Action <ExcelEntityBuilder <TEntity> > buildAction) where TEntity : class { var entityBuilder = new ExcelEntityBuilder <TEntity>(); try { Entities.Add(typeof(TEntity), entityBuilder); } catch (ArgumentException e) { throw new ArgumentException($"The type '{typeof(TEntity)}' was already configured as a mapped entity in the excel context."); } buildAction(entityBuilder); }
public void Create(CiudadViewModel obj) { var entity = new Ciudade(); entity.Codigo = obj.Codigo; entity.Nombre = obj.NombreCiudad; entity.Iddepartamento = obj.IdDepartamento; entity.Fechacreacion = DateTime.Now; entities.Add(entity); entities.SaveChanges(); obj.Id = entity.Id; }
private void Attack(Planet p) { int shipsToAttack = p.Health > GameState.Ships ? GameState.Ships : p.Health; GameState.Ships -= shipsToAttack; HomePlanet hp = Entities.OfType <HomePlanet>().First(); for (int i = 0; i < shipsToAttack; i++) { Raylib.PlaySound(AssetManager.GetSound("shipLaunch")); Entities.Add(new Ship(hp.Pos, p)); } }
public RouteTestContext() : base() { Entities.Add(new Route(NextID, "Route 66")); Entities.Add(new Route(NextID, "Stairway to Heaven")); Entities.Add(new Route(NextID, "Bart Verminken met Bacon")); Entities.Add(new Route(NextID, "")); Entities.Add(new Route(NextID, "")); Entities.Add(new Route(NextID, "")); Entities.Add(new Route(NextID, "")); Entities.Add(new Route(NextID, "")); Entities.Add(new Route(NextID, "")); Entities.Add(new Route(NextID, "")); }
public async Task <T> CreateAsync(T entity) { ValidateAndThrow(entity); AddDefaultValue(ref entity); Entities.Add(entity); var effectedCount = await _context.SaveChangesAsync(); if (effectedCount == 0) { return(null); } return(entity); }
private void doSpawnEvent(SpawnEvent e) { Entities.Add(e.Entity); e.Entity.GameEngineEventHandler += (sender, args) => OnGameEngineEvent(sender, args); if (e.Entity is Ship) { (e.Entity as Ship).gameState = this; (e.Entity as Ship).FlavourTextEventHandler += OnFlavourText; } e.Entity.Position = e.Position; e.Entity.Velocity = e.Velocity; e.Entity.Orientation = e.Orientation; _physicsEngine.Register(e.Entity); }
/// <summary> /// Insert entities /// </summary> /// <param name="entities">Entities</param> public virtual void Insert(IEnumerable <T> entities) { if (entities == null) { throw new ArgumentNullException(nameof(entities)); } foreach (var entity in entities) { Entities.Add(entity); } _context.SaveChanges(); }
internal int Save(EventoViewModel obj) { var entity = new Evento(); if (obj.Id > 0) { entity = entities.Eventos.Where(e => e.Id == obj.Id).FirstOrDefault(); } entity.Nombre = obj.Nombre; entity.Multifuncion = obj.Funciones.Count > 0; entity.CantidadFunciones = obj.Funciones.Count; entity.FechaInicial = obj.FechaInicial; entity.FechaFinal = obj.FechaFinal; entity.Empresario_id = obj.Empresario_id; entity.Foto = obj.Foto; entity.Descripcion = obj.Descripcion; entity.EdadMinima = obj.EdadMinima; entity.EventoPublico = obj.EventoPublico == "Sí"; entity.TipoRecaudo_id = obj.TipoRecaudo_id; entity.EntradasxPedidoOcompra = obj.EntradasxPedidoOcompra; entity.EntradasxUsuario = obj.EntradasxUsuario; entity.AplicaServicio = obj.AplicaServicio == "Sí"; entity.CantidadDiasValides = obj.CantidadFunciones; entity.AforoTotal = obj.AforoTotal; entity.Estado = obj.Estado.ToString(); entity.UrlVideo = obj.UrlVideo; entity.StagesByMap = obj.StagesByMap; if (obj.Id <= 0) { entity.FechaCreacion = DateTime.Now; entities.Add(entity); } entities.SaveChanges(); obj.Id = entity.Id; return(obj.Id); }
public string Create(List <PreguntaViewModel> obj, int idEvento) { var mensaje = ""; try { foreach (var item in obj) { var entityPregunta = new PreguntasEvento(); entityPregunta.IdEvento = idEvento; entityPregunta.NumeroPregunta = item.NumeroPregunta; entityPregunta.TextoPregunta = item.TextoPregunta; entityPregunta.TipoRespuesta = item.TipoRespuesta; entities.Add(entityPregunta); entities.SaveChanges(); var id = entityPregunta.Id; foreach (var itemOpciones in item.Opciones) { var entityOpciones = new OpcionesPreguntaEvento(); entityOpciones.IdPregunta = id; entityOpciones.NumeroOpcion = itemOpciones.NumeroOpcion; entityOpciones.TextoOpcion = itemOpciones.TextoOpcion; entities.Add(entityOpciones); entities.SaveChanges(); } } mensaje = "OK"; } catch (Exception ex) { mensaje = ex.Source + ex.Message; } return(mensaje); }
public override void DrawBackground() { List <Entity> NewEntities = viewPort.Render(); foreach (Entity e in NewEntities) { Entity c = null; switch (e.Name) { case "ground": c = new Characters.Ground(this.gameObject); break; case "brick": c = new Characters.Brick(this.gameObject); break; case "pipeleftup": c = new Characters.Pipeleftup(this.gameObject); break; case "piperightup": c = new Characters.Piperightup(this.gameObject); break; case "pipeleft": c = new Characters.Pipeleft(this.gameObject); break; case "piperight": c = new Characters.Piperight(this.gameObject); break; case "coinbox": c = new Characters.CoinBox(this.gameObject); break; case "emptycoinbox": c = new Characters.EmptyCoinBox(this.gameObject); break; case "coinbounce": c = new Characters.CoinBounce(this.gameObject); break; case "block": c = new Characters.Block(this.gameObject); break; case "goomba": c = new Characters.Goomba(this.gameObject); break; case "koopatroopa": c = new Characters.KoopaTroopa(this.gameObject); break; } c.X = e.X; c.Y = e.Y; c.OriginTileCol = e.OriginTileCol; c.OriginTileRow = e.OriginTileRow; var xx = Entities.Where(x => x.OriginTileRow == c.OriginTileRow && x.OriginTileCol == c.OriginTileCol); if (xx.Count() == 0) { Entities.Add(c); } } NewEntities.Clear(); }
/// <summary> /// Insert /// </summary> /// <param name="entity">Entity object</param> public void Insert(T entity) { try { if (entity == null) { throw new ArgumentNullException("entity"); } OpenConnection(); Entities.Add(entity); DbContext.SaveChanges(); } catch (DbEntityValidationException dbEx) { foreach (DbEntityValidationResult item in dbEx.EntityValidationErrors) { // Get entry DbEntityEntry entry = item.Entry; switch (entry.State) { case EntityState.Added: entry.State = EntityState.Detached; break; case EntityState.Modified: entry.CurrentValues.SetValues(entry.OriginalValues); entry.State = EntityState.Unchanged; break; case EntityState.Deleted: entry.State = EntityState.Unchanged; break; } } var msg = dbEx.EntityValidationErrors .SelectMany(validationErrors => validationErrors.ValidationErrors) .Aggregate(string.Empty, (current, validationError) => current + (string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine)); var fail = new Exception(msg, dbEx); throw fail; } }
public void Create(MonedaViewModel obj) { var entity = new Tipomoneda(); entity.Nombre = obj.Nombre; entity.Codigo = obj.Codigo; entity.Simbolo = obj.Simbolo; entity.Decimales = obj.Decimales; entity.Fechacreacion = DateTime.Now; entities.Add(entity); entities.SaveChanges(); obj.Id = entity.Id; }
public void To_String() { var list = new Entities <Entity>(); var nestedEntity = new NestedEntity(); var testEntity = new TestEntity(nestedEntity); nestedEntity.Yo = "7"; testEntity.Zo = "8"; list.Add(testEntity); var builder = new StringBuilder(); builder.AppendLine("ZO, YO, "); builder.AppendLine("8, 7, "); Assert.AreEqual(builder.ToString(), list.ToString()); }
public ClassEntity RegisterClass(ClassType type, string className, TypeDefinition typeDefinition, NamespaceEntity namespaceEntity) { var namespaceQualifiedId = namespaceEntity.GetNamespaceQualifiedId(className); if (Entities.Any(e => e.NamespaceQualifiedId.Equals(namespaceQualifiedId))) { throw new InvalidOperationException($"Class entity with id '{namespaceQualifiedId}' already exists."); } var entity = new ClassEntity(type, className, namespaceQualifiedId, typeDefinition, namespaceEntity); Entities.Add(entity); return(entity); }
private Entities GetList(SqlDataReader reader) { Entities entities = new Entities(); Course course; while (reader.Read()) { course = new Course(); course.CourseId = reader.GetInt32(0); course.CourseName = reader.GetString(1); course.CourseType = (CourseType)reader.GetInt32(2); entities.Add(course); } return(entities); }
public T Create(T entity) { try { if (entity == null) { throw new ArgumentNullException(nameof(entity)); } return(Entities.Add(entity)); } catch (Exception ex) { throw ex; } }
public void Insert(T entity) { if (entity == null) { throw new ArgumentNullException(nameof(entity)); } if (entity is LoggedBaseEntity) { (entity as LoggedBaseEntity).InsertedDate = DateTime.Now; (entity as LoggedBaseEntity).UpdatedDate = DateTime.Now; } Entities.Add(entity); _context.SaveChanges(); }
public async void OnNavigatedTo(NavigationContext context) { if (!context.IsPopBack) { await ExecuteBusyAsync(async() => { allEntities = await inspectionService.QueryInspectionStatusListAsync(); foreach (var entity in allEntities.Where(x => x.IsChecked)) { Entities.Add(entity); } }); } }
public EnumEntity RegisterEnum(string enumName, NamespaceEntity namespaceEntity) { var namespaceQualifiedId = namespaceEntity.GetNamespaceQualifiedId(enumName); if (Entities.Any(e => e.NamespaceQualifiedId.Equals(namespaceQualifiedId))) { throw new InvalidOperationException($"Enum entity with id '{namespaceQualifiedId}' already exists."); } var entity = new EnumEntity(enumName, namespaceQualifiedId, namespaceEntity); Entities.Add(entity); return(entity); }
public override void Enter() { Button button = new Button(new Vector2f(GameOptions.Width / 2.0f, GameOptions.Height - 52.0f - 48.0f), "Main Menu"); button.OnClick += () => { //Game.PopState(); Game.SetState(new MainMenu()); return(true); }; Entities.Add(button); base.Enter(); }
private static Entities JoinInternal(EntityGroup g, string pname, object k) { var rlt = new Entities(); Entities list = g.GetEntities(); PropertyInfo info = null; foreach (Entity i in list) { if (info == null) { Type type = i.GetType(); info = type.GetProperty(pname); } if (k.Equals(info.GetValue(i))) { rlt.Add(i); } } return rlt; }
// METHODS // +decompile() // Attempts to convert a map in a Doom WAD into a usable .MAP file. This has many // challenges, not the least of which is the fact that the Doom engine didn't use // brushes (at least, not in any sane way). public virtual Entities decompile() { DecompilerThread.OnMessage(this, "Decompiling..."); DecompilerThread.OnMessage(this, doomMap.MapName); mapFile = new Entities(); Entity world = new Entity("worldspawn"); mapFile.Add(world); string[] lowerWallTextures = new string[doomMap.Sidedefs.Count]; string[] midWallTextures = new string[doomMap.Sidedefs.Count]; string[] higherWallTextures = new string[doomMap.Sidedefs.Count]; short[] sectorTag = new short[doomMap.Sectors.Count]; string playerStartOrigin = ""; // Since Doom relied on sectors to define a cieling and floor height, and nothing else, // need to find the minimum and maximum used Z values. This is because the Doom engine // is only a pseudo-3D engine. For all it cares, the cieling and floor extend to their // respective infinities. For a GC/Hammer map, however, this cannot be the case. int ZMin = 32767; // Even though the values in the map will never exceed these, use ints here to avoid int ZMax = - 32768; // overflows, in case the map DOES go within 32 units of these values. for (int i = 0; i < doomMap.Sectors.Count; i++) { DSector currentSector = doomMap.Sectors[i]; sectorTag[i] = currentSector.Tag; if (currentSector.FloorHeight < ZMin + 32) { ZMin = currentSector.FloorHeight - 32; // Can't use the actual value, because that IS the floor } else { if (currentSector.CielingHeight > ZMax - 32) { ZMax = currentSector.CielingHeight + 32; // or the cieling. Subtract or add a sane value to it. } } } // I need to analyze the binary tree and get more information, particularly the // parent nodes of each subsector and node, as well as whether it's the right or // left child of that node. These are extremely important, as the parent defines // boundaries for the children, as well as inheriting further boundaries from its // parents. These boundaries are invaluable for forming brushes. int[] nodeparents = new int[doomMap.Nodes.Count]; bool[] nodeIsLeft = new bool[doomMap.Nodes.Count]; for (int i = 0; i < doomMap.Nodes.Count; i++) { nodeparents[i] = - 1; // There should only be one node left with -1 as a parent. This SHOULD be the root. for (int j = 0; j < doomMap.Nodes.Count; j++) { if (doomMap.Nodes[j].Child1 == i) { nodeparents[i] = j; break; } else { if (doomMap.Nodes[j].Child2 == i) { nodeparents[i] = j; nodeIsLeft[i] = true; break; } } } } // Keep a list of what subsectors belong to which sector int[] subsectorSectors = new int[doomMap.SubSectors.Count]; // Keep a list of what sidedefs belong to what subsector as well int[][] subsectorSidedefs = new int[doomMap.SubSectors.Count][]; short[][] sideDefShifts = new short[2][]; for (int i2 = 0; i2 < 2; i2++) { sideDefShifts[i2] = new short[doomMap.Sidedefs.Count]; } // Figure out what sector each subsector belongs to, and what node is its parent. // Depending on sector "tags" this will help greatly in creation of brushbased entities, // and also helps in finding subsector floor and cieling heights. int[] ssparents = new int[doomMap.SubSectors.Count]; bool[] ssIsLeft = new bool[doomMap.SubSectors.Count]; for (int i = 0; i < doomMap.SubSectors.Count; i++) { //DecompilerThread.OnMessage(this, "Populating texture lists for subsector " + i); // First, find the subsector's parent and whether it is the left or right child. ssparents[i] = - 1; // No subsector should have a -1 in here for (int j = 0; j < doomMap.Nodes.Count; j++) { // When a node references a subsector, it is not referenced by negative // index, as future BSP versions do. The bits 0-14 ARE the index, and // bit 15 (which is the sign bit in two's compliment math) determines // whether or not it is a node or subsector. Therefore, we need to add // 2^15 to the number to produce the actual index. if (doomMap.Nodes[j].Child1 + 32768 == i) { ssparents[i] = j; break; } else { if (doomMap.Nodes[j].Child2 + 32768 == i) { ssparents[i] = j; ssIsLeft[i] = true; break; } } } // Second, figure out what sector a subsector belongs to, and the type of sector it is. subsectorSectors[i] = - 1; Edge currentsubsector = doomMap.SubSectors[i]; subsectorSidedefs[i] = new int[currentsubsector.NumSegs]; for (int j = 0; j < currentsubsector.NumSegs; j++) { // For each segment the subsector references DSegment currentsegment = doomMap.Segments[currentsubsector.FirstSeg + j]; DLinedef currentlinedef = doomMap.Linedefs[currentsegment.Linedef]; int currentsidedefIndex; int othersideIndex; if (currentsegment.Direction == 0) { currentsidedefIndex = currentlinedef.Right; othersideIndex = currentlinedef.Left; } else { currentsidedefIndex = currentlinedef.Left; othersideIndex = currentlinedef.Right; } subsectorSidedefs[i][j] = currentsidedefIndex; DSidedef currentSidedef = doomMap.Sidedefs[currentsidedefIndex]; if (currentlinedef.OneSided) { // A one-sided linedef should always be like this midWallTextures[currentsidedefIndex] = doomMap.WadName + "/" + currentSidedef.MidTexture; higherWallTextures[currentsidedefIndex] = "special/nodraw"; lowerWallTextures[currentsidedefIndex] = "special/nodraw"; sideDefShifts[X][currentsidedefIndex] = currentSidedef.OffsetX; sideDefShifts[Y][currentsidedefIndex] = currentSidedef.OffsetY; } else { // I don't really get why I need to apply these textures to the other side. But if it works I won't argue... if (!currentSidedef.MidTexture.Equals("-")) { midWallTextures[othersideIndex] = doomMap.WadName + "/" + currentSidedef.MidTexture; } else { midWallTextures[othersideIndex] = "special/nodraw"; } if (!currentSidedef.HighTexture.Equals("-")) { higherWallTextures[othersideIndex] = doomMap.WadName + "/" + currentSidedef.HighTexture; } else { higherWallTextures[othersideIndex] = "special/nodraw"; } if (!currentSidedef.LowTexture.Equals("-")) { lowerWallTextures[othersideIndex] = doomMap.WadName + "/" + currentSidedef.LowTexture; } else { lowerWallTextures[othersideIndex] = "special/nodraw"; } sideDefShifts[X][othersideIndex] = currentSidedef.OffsetX; sideDefShifts[Y][othersideIndex] = currentSidedef.OffsetY; } // Sometimes a subsector seems to belong to more than one sector. Only the reference in the first seg is true. if (j == 0) { subsectorSectors[i] = currentSidedef.Sector; } } } bool[] linedefFlagsDealtWith = new bool[doomMap.Linedefs.Count]; bool[] linedefSpecialsDealtWith = new bool[doomMap.Linedefs.Count]; MAPBrush[][] sectorFloorBrushes = new MAPBrush[doomMap.Sectors.Count][]; for (int i3 = 0; i3 < doomMap.Sectors.Count; i3++) { sectorFloorBrushes[i3] = new MAPBrush[0]; } MAPBrush[][] sectorCielingBrushes = new MAPBrush[doomMap.Sectors.Count][]; for (int i4 = 0; i4 < doomMap.Sectors.Count; i4++) { sectorCielingBrushes[i4] = new MAPBrush[0]; } // For one-sided linedefs referenced by more than one subsector bool[] outsideBrushAlreadyCreated = new bool[doomMap.Linedefs.Count]; int onePercent = (int)((doomMap.SubSectors.Count)/100); if(onePercent < 1) { onePercent = 1; } for (int i = 0; i < doomMap.SubSectors.Count; i++) { //DecompilerThread.OnMessage(this, "Creating brushes for subsector " + i); Edge currentsubsector = doomMap.SubSectors[i]; // Third, create a few brushes out of the geometry. MAPBrush cielingBrush = new MAPBrush(numBrshs++, 0, false); MAPBrush floorBrush = new MAPBrush(numBrshs++, 0, false); MAPBrush midBrush = new MAPBrush(numBrshs++, 0, false); MAPBrush sectorTriggerBrush = new MAPBrush(numBrshs++, 0, false); DSector currentSector = doomMap.Sectors[subsectorSectors[i]]; Vector3D[] roofPlane = new Vector3D[3]; double[] roofTexS = new double[3]; double[] roofTexT = new double[3]; roofPlane[0] = new Vector3D(0, Settings.planePointCoef, ZMax); roofPlane[1] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, ZMax); roofPlane[2] = new Vector3D(Settings.planePointCoef, 0, ZMax); roofTexS[0] = 1; roofTexT[1] = - 1; Vector3D[] cileingPlane = new Vector3D[3]; double[] cileingTexS = new double[3]; double[] cileingTexT = new double[3]; cileingPlane[0] = new Vector3D(0, 0, currentSector.CielingHeight); cileingPlane[1] = new Vector3D(Settings.planePointCoef, 0, currentSector.CielingHeight); cileingPlane[2] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, currentSector.CielingHeight); cileingTexS[0] = 1; cileingTexT[1] = - 1; Vector3D[] floorPlane = new Vector3D[3]; double[] floorTexS = new double[3]; double[] floorTexT = new double[3]; floorPlane[0] = new Vector3D(0, Settings.planePointCoef, currentSector.FloorHeight); floorPlane[1] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, currentSector.FloorHeight); floorPlane[2] = new Vector3D(Settings.planePointCoef, 0, currentSector.FloorHeight); floorTexS[0] = 1; floorTexT[1] = - 1; Vector3D[] foundationPlane = new Vector3D[3]; double[] foundationTexS = new double[3]; double[] foundationTexT = new double[3]; foundationPlane[0] = new Vector3D(0, 0, ZMin); foundationPlane[1] = new Vector3D(Settings.planePointCoef, 0, ZMin); foundationPlane[2] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, ZMin); foundationTexS[0] = 1; foundationTexT[1] = - 1; Vector3D[] topPlane = new Vector3D[3]; double[] topTexS = new double[3]; double[] topTexT = new double[3]; topPlane[0] = new Vector3D(0, Settings.planePointCoef, currentSector.CielingHeight); topPlane[1] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, currentSector.CielingHeight); topPlane[2] = new Vector3D(Settings.planePointCoef, 0, currentSector.CielingHeight); topTexS[0] = 1; topTexT[1] = - 1; Vector3D[] bottomPlane = new Vector3D[3]; double[] bottomTexS = new double[3]; double[] bottomTexT = new double[3]; bottomPlane[0] = new Vector3D(0, 0, currentSector.FloorHeight); bottomPlane[1] = new Vector3D(Settings.planePointCoef, 0, currentSector.FloorHeight); bottomPlane[2] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, currentSector.FloorHeight); bottomTexS[0] = 1; bottomTexT[1] = - 1; int nextNode = ssparents[i]; bool leftSide = ssIsLeft[i]; for (int j = 0; j < currentsubsector.NumSegs; j++) { // Iterate through the sidedefs defined by segments of this subsector DSegment currentseg = doomMap.Segments[currentsubsector.FirstSeg + j]; Vector3D start = doomMap.Vertices[currentseg.StartVertex].Vector; Vector3D end = doomMap.Vertices[currentseg.EndVertex].Vector; DLinedef currentLinedef = doomMap.Linedefs[(int) currentseg.Linedef]; Vector3D[] plane = new Vector3D[3]; double[] texS = new double[3]; double[] texT = new double[3]; plane[0] = new Vector3D(start.X, start.Y, ZMin); plane[1] = new Vector3D(end.X, end.Y, ZMin); plane[2] = new Vector3D(end.X, end.Y, ZMax); Vector3D linestart = new Vector3D(doomMap.Vertices[currentLinedef.Start].Vector.X, doomMap.Vertices[currentLinedef.Start].Vector.Y, ZMin); Vector3D lineend = new Vector3D(doomMap.Vertices[currentLinedef.End].Vector.X, doomMap.Vertices[currentLinedef.End].Vector.Y, ZMax); double sideLength = System.Math.Sqrt(System.Math.Pow(start.X - end.X, 2) + System.Math.Pow(start.Y - end.Y, 2)); bool upperUnpegged = !((currentLinedef.Flags[0] & ((sbyte) 1 << 3)) == 0); bool lowerUnpegged = !((currentLinedef.Flags[0] & ((sbyte) 1 << 4)) == 0); texS[0] = (start.X - end.X) / sideLength; texS[1] = (start.Y - end.Y) / sideLength; texS[2] = 0; texT[0] = 0; texT[1] = 0; texT[2] = - 1; double SShift = sideDefShifts[X][subsectorSidedefs[i][j]] - (texS[0] * end.X) - (texS[1] * end.Y); double lowTShift = 0; double highTShift = 0; if (!currentLinedef.OneSided) { DSector otherSideSector; if (doomMap.Sectors[doomMap.Sidedefs[currentLinedef.Left].Sector] == currentSector) { otherSideSector = doomMap.Sectors[doomMap.Sidedefs[currentLinedef.Right].Sector]; } else { otherSideSector = doomMap.Sectors[doomMap.Sidedefs[currentLinedef.Left].Sector]; } if (lowerUnpegged) { lowTShift = otherSideSector.CielingHeight; } else { lowTShift = currentSector.FloorHeight; } if (upperUnpegged) { highTShift = otherSideSector.CielingHeight; } else { highTShift = currentSector.CielingHeight; } lowTShift += sideDefShifts[Y][subsectorSidedefs[i][j]]; highTShift += sideDefShifts[Y][subsectorSidedefs[i][j]]; } MAPBrushSide low = new MAPBrushSide(plane, lowerWallTextures[subsectorSidedefs[i][j]], texS, SShift, texT, lowTShift, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide high = new MAPBrushSide(plane, higherWallTextures[subsectorSidedefs[i][j]], texS, SShift, texT, highTShift, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide mid; MAPBrushSide damage = new MAPBrushSide(plane, "special/trigger", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); if (currentLinedef.OneSided) { if (!outsideBrushAlreadyCreated[currentseg.Linedef]) { outsideBrushAlreadyCreated[currentseg.Linedef] = true; double highestCieling = currentSector.CielingHeight; double lowestFloor = currentSector.FloorHeight; if (currentSector.Tag != 0) { double temp = getHighestNeighborCielingHeight(subsectorSectors[i]); if (temp > highestCieling) { highestCieling = temp; } temp = getLowestNeighborFloorHeight(subsectorSectors[i]); if (temp < lowestFloor) { lowestFloor = temp; } } MAPBrush outsideBrush = null; if (lowestFloor <= highestCieling) { outsideBrush = MAPBrush.createFaceBrush(midWallTextures[subsectorSidedefs[i][j]], "special/nodraw", new Vector3D(linestart.X, linestart.Y, ZMin), new Vector3D(lineend.X, lineend.Y, ZMax), sideDefShifts[X][subsectorSidedefs[i][j]], sideDefShifts[Y][subsectorSidedefs[i][j]], lowerUnpegged, currentSector.CielingHeight, currentSector.FloorHeight); } else { outsideBrush = MAPBrush.createFaceBrush(midWallTextures[subsectorSidedefs[i][j]], "special/nodraw", new Vector3D(linestart.X, linestart.Y, lowestFloor), new Vector3D(lineend.X, lineend.Y, highestCieling), sideDefShifts[X][subsectorSidedefs[i][j]], sideDefShifts[Y][subsectorSidedefs[i][j]], lowerUnpegged, currentSector.CielingHeight, currentSector.FloorHeight); } world.Brushes.Add(outsideBrush); } mid = new MAPBrushSide(plane, "special/nodraw", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); } else { double midTShift = sideDefShifts[Y][subsectorSidedefs[i][j]]; if (lowerUnpegged) { midTShift += currentSector.FloorHeight; } else { midTShift += currentSector.CielingHeight; } mid = new MAPBrushSide(plane, midWallTextures[subsectorSidedefs[i][j]], texS, SShift, texT, midTShift, 0, 1, 1, 0, "wld_masked", 16, 0); if (!linedefFlagsDealtWith[currentseg.Linedef]) { linedefFlagsDealtWith[currentseg.Linedef] = true; if (!((currentLinedef.Flags[0] & ((sbyte) 1 << 0)) == 0)) { // Flag 0x0001 indicates "solid" but doesn't block bullets. It is assumed for all one-sided. MAPBrush solidBrush = MAPBrush.createFaceBrush("special/clip", "special/clip", linestart, lineend, 0, 0, false, 0, 0); world.Brushes.Add(solidBrush); } else { if (!((currentLinedef.Flags[0] & ((sbyte) 1 << 1)) == 0)) { // Flag 0x0002 indicates "monster clip". MAPBrush solidBrush = MAPBrush.createFaceBrush("special/enemyclip", "special/enemyclip", linestart, lineend, 0, 0, false, 0, 0); world.Brushes.Add(solidBrush); } } } DSidedef otherside = doomMap.Sidedefs[currentLinedef.Left]; if (currentLinedef.Action != 0 && !linedefSpecialsDealtWith[currentseg.Linedef]) { linedefSpecialsDealtWith[currentseg.Linedef] = true; Entity trigger = null; MAPBrush triggerBrush = MAPBrush.createFaceBrush("special/trigger", "special/trigger", linestart, lineend, 0, 0, false, 0, 0); if (doomMap.Version == mapType.TYPE_HEXEN) { bool[] bitset = new bool[16]; for (int k = 0; k < 8; k++) { bitset[k] = !((currentLinedef.Flags[0] & ((sbyte) k << 1)) == 0); } for (int k = 0; k < 8; k++) { bitset[k + 8] = !((currentLinedef.Flags[1] & ((sbyte) k << 1)) == 0); } if (bitset[10] && bitset[11] && !bitset[12]) { // Triggered when "Used" by player trigger = new Entity("func_button"); trigger["spawnflags"] = "1"; if (bitset[9]) { trigger["wait"] = "1"; } else { trigger["wait"] = "-1"; } } else { if (bitset[9]) { // Can be activated more than once trigger = new Entity("trigger_multiple"); trigger["wait"] = "1"; } else { trigger = new Entity("trigger_once"); } } switch (currentLinedef.Action) { case 21: // Floor lower to lowest surrounding floor case 22: // Floor lower to next lowest surrounding floor if (currentLinedef.Arguments[0] != 0) { trigger["target"] = "sector" + currentLinedef.Arguments[0] + "lowerfloor"; } else { trigger["target"] = "sectornum" + otherside.Sector + "lowerfloor"; } break; case 24: // Floor raise to highest surrounding floor case 25: // Floor raise to next highest surrounding floor if (currentLinedef.Arguments[0] != 0) { trigger["target"] = "sector" + currentLinedef.Arguments[0] + "raisefloor"; } else { trigger["target"] = "sectornum" + otherside.Sector + "raisefloor"; } break; case 70: // Teleport trigger = new Entity("trigger_teleport"); if (currentLinedef.Arguments[0] != 0) { trigger["target"] = "teledest" + currentLinedef.Arguments[0]; } else { trigger["target"] = "sector" + currentLinedef.Tag + "teledest"; } break; case 80: // Exec script // This is a toughie. I can't write a script-to-entity converter. trigger["target"] = "script" + currentLinedef.Arguments[0]; trigger["arg0"] = "" + currentLinedef.Arguments[2]; trigger["arg1"] = "" + currentLinedef.Arguments[3]; trigger["arg2"] = "" + currentLinedef.Arguments[4]; break; case 181: // PLANE_ALIGN trigger = null; if (!leftSide) { DSidedef getsector = doomMap.Sidedefs[currentLinedef.Left]; DSector copyheight = doomMap.Sectors[getsector.Sector]; short newHeight = copyheight.FloorHeight; //floorPlane[0]=new Vector3D(0, Settings.getPlanePointCoef(), 2000); //floorPlane[1]=new Vector3D(Settings.getPlanePointCoef(), Settings.getPlanePointCoef(), currentSector.getFloorHeight()); //floorPlane[2]=new Vector3D(Settings.getPlanePointCoef(), 0, currentSector.getFloorHeight()); } else { linedefSpecialsDealtWith[currentseg.Linedef] = false; } break; default: trigger = null; break; } } else { switch (currentLinedef.Action) { case 1: // Use Door. open, wait, close case 31: // Use Door. Open, stay. trigger = new Entity("func_button"); trigger["wait"] = "1"; if (currentLinedef.Action == 31) { trigger["wait"] = "-1"; } trigger["spawnflags"] = "1"; if (doomMap.Sectors[otherside.Sector].Tag == 0) { trigger["target"] = "sectornum" + otherside.Sector + "door"; if (currentLinedef.Action == 1) { sectorTag[otherside.Sector] = - 1; } if (currentLinedef.Action == 31) { sectorTag[otherside.Sector] = - 2; } } else { trigger["target"] = "sector" + doomMap.Sectors[otherside.Sector].Tag + "door"; } break; case 36: // Floor lower to 8 above next lowest neighboring sector case 38: // Floor lower to next lowest neighboring sector trigger = new Entity("trigger_once"); trigger["target"] = "sector" + currentLinedef.Tag + "lowerfloor"; break; case 62: // Floor lower to next lowest neighboring sector, wait 4s, goes back up trigger = new Entity("func_button"); trigger["target"] = "sector" + currentLinedef.Tag + "vator"; trigger["wait"] = "1"; trigger["spawnflags"] = "1"; break; case 63: // Door with button, retriggerable case 103: // Push button, one-time door open stay open trigger = new Entity("func_button"); trigger["target"] = "sector" + currentLinedef.Tag + "door"; trigger["wait"] = "1"; if (currentLinedef.Action == 103) { trigger["wait"] = "-1"; } trigger["spawnflags"] = "1"; break; case 88: // Walkover retriggerable elevator trigger trigger = new Entity("trigger_multiple"); trigger["target"] = "sector" + currentLinedef.Tag + "vator"; break; case 97: // Walkover retriggerable Teleport trigger = new Entity("trigger_teleport"); trigger["target"] = "sector" + currentLinedef.Tag + "teledest"; break; case 109: // Walkover one-time door open stay open trigger = new Entity("trigger_once"); trigger["target"] = "sector" + currentLinedef.Tag + "door"; break; } } if (trigger != null) { trigger.Brushes.Add(triggerBrush); mapFile.Add(trigger); } } } cielingBrush.add(high); midBrush.add(mid); floorBrush.add(low); sectorTriggerBrush.add(damage); } MAPBrushSide roof = new MAPBrushSide(roofPlane, "special/nodraw", roofTexS, 0, roofTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide cieling = new MAPBrushSide(cileingPlane, doomMap.WadName + "/" + currentSector.CielingTexture, cileingTexS, 0, cileingTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide floor = new MAPBrushSide(floorPlane, doomMap.WadName + "/" + currentSector.FloorTexture, floorTexS, 0, floorTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide foundation = new MAPBrushSide(foundationPlane, "special/nodraw", foundationTexS, 0, foundationTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide top = new MAPBrushSide(topPlane, "special/nodraw", topTexS, 0, topTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide bottom = new MAPBrushSide(bottomPlane, "special/nodraw", bottomTexS, 0, bottomTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide invertedFloor = new MAPBrushSide(Plane.flip(floorPlane), "special/trigger", floorTexS, 0, floorTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide damageTop = new MAPBrushSide(new Vector3D[]{floorPlane[0]+new Vector3D(0, 0, 1), floorPlane[1]+new Vector3D(0, 0, 1), floorPlane[2]+new Vector3D(0, 0, 1)}, "special/trigger", floorTexS, 0, floorTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); sectorTriggerBrush.add(damageTop); sectorTriggerBrush.add(invertedFloor); midBrush.add(top); midBrush.add(bottom); cielingBrush.add(cieling); cielingBrush.add(roof); floorBrush.add(floor); floorBrush.add(foundation); // Now need to add the data from node subdivisions. Neither segments nor nodes // will completely define a usable brush, but both of them together will. do { DNode currentNode = doomMap.Nodes[nextNode]; Vector3D start; Vector3D end; if (leftSide) { start = currentNode.VecHead+currentNode.VecTail; end = currentNode.VecHead; } else { start = currentNode.VecHead; end = currentNode.VecHead+currentNode.VecTail; } Vector3D[] plane = new Vector3D[3]; double[] texS = new double[3]; double[] texT = new double[3]; // This is somehow always correct. And I'm okay with that. plane[0] = new Vector3D(start.X, start.Y, ZMin); plane[1] = new Vector3D(end.X, end.Y, ZMin); plane[2] = new Vector3D(start.X, start.Y, ZMax); double sideLength = System.Math.Sqrt(System.Math.Pow(start.X - end.X, 2) + System.Math.Pow(start.Y - end.Y, 2)); texS[0] = (start.X - end.X) / sideLength; texS[1] = (start.Y - end.Y) / sideLength; texS[2] = 0; texT[0] = 0; texT[1] = 0; texT[2] = 1; MAPBrushSide low = new MAPBrushSide(plane, "special/nodraw", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide high = new MAPBrushSide(plane, "special/nodraw", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide mid = new MAPBrushSide(plane, "special/nodraw", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); MAPBrushSide damage = new MAPBrushSide(plane, "special/trigger", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); cielingBrush.add(high); midBrush.add(mid); floorBrush.add(low); sectorTriggerBrush.add(damage); leftSide = nodeIsLeft[nextNode]; nextNode = nodeparents[nextNode]; } while (nextNode != - 1); // Now we need to get rid of all the sides that aren't used. Get a list of // the useless sides from one brush, and delete those sides from all of them, // since they all have the same sides. int[] badSides = new int[0]; if (!Settings.dontCull) { badSides = MAPBrush.findUnusedPlanes(cielingBrush); // Need to iterate backward, since these lists go from low indices to high, and // the index of all subsequent items changes when something before it is removed. if (cielingBrush.NumSides - badSides.Length < 4) { DecompilerThread.OnMessage(this, "WARNING: Plane cull returned less than 4 sides for subsector " + i); badSides = new int[0]; } else { for (int j = badSides.Length - 1; j > - 1; j--) { cielingBrush.delete(badSides[j]); floorBrush.delete(badSides[j]); } } } MAPBrush[] newFloorList = new MAPBrush[sectorFloorBrushes[subsectorSectors[i]].Length + 1]; MAPBrush[] newCielingList = new MAPBrush[sectorCielingBrushes[subsectorSectors[i]].Length + 1]; for (int j = 0; j < sectorFloorBrushes[subsectorSectors[i]].Length; j++) { newFloorList[j] = sectorFloorBrushes[subsectorSectors[i]][j]; newCielingList[j] = sectorCielingBrushes[subsectorSectors[i]][j]; } newFloorList[newFloorList.Length - 1] = floorBrush; newCielingList[newCielingList.Length - 1] = cielingBrush; sectorFloorBrushes[subsectorSectors[i]] = newFloorList; sectorCielingBrushes[subsectorSectors[i]] = newCielingList; bool containsMiddle = false; for (int j = 0; j < midBrush.NumSides; j++) { if (!midBrush[j].Texture.ToUpper().Equals("special/nodraw".ToUpper())) { containsMiddle = true; break; } } if (containsMiddle && currentSector.CielingHeight > currentSector.FloorHeight) { Entity middleEnt = new Entity("func_illusionary"); if (midBrush.NumSides - badSides.Length >= 4) { for (int j = badSides.Length - 1; j > - 1; j--) { midBrush.delete(badSides[j]); } } middleEnt.Brushes.Add(midBrush); mapFile.Add(middleEnt); } Entity hurtMe = new Entity("trigger_hurt"); Entity triggerSecret = new Entity("trigger_bondsecret"); switch (currentSector.Type) { case 4: // 20% damage/s with lighting properties case 11: // 20% damage/s case 16: // 20% damage/s plus end level when player is almost dead hurtMe["dmg"] = "40"; if (!Settings.dontCull) { if (sectorTriggerBrush.NumSides - badSides.Length >= 4) { for (int j = badSides.Length - 1; j > - 1; j--) { sectorTriggerBrush.delete(badSides[j]); } } } hurtMe.Brushes.Add(sectorTriggerBrush); mapFile.Add(hurtMe); break; case 5: // 10% damage/s hurtMe["dmg"] = "20"; if (!Settings.dontCull) { if (sectorTriggerBrush.NumSides - badSides.Length >= 4) { for (int j = badSides.Length - 1; j > - 1; j--) { sectorTriggerBrush.delete(badSides[j]); } } } hurtMe.Brushes.Add(sectorTriggerBrush); mapFile.Add(hurtMe); break; case 7: // 5% damage/s hurtMe["dmg"] = "10"; if (!Settings.dontCull) { if (sectorTriggerBrush.NumSides - badSides.Length >= 4) { for (int j = badSides.Length - 1; j > - 1; j--) { sectorTriggerBrush.delete(badSides[j]); } } } hurtMe.Brushes.Add(sectorTriggerBrush); mapFile.Add(hurtMe); break; case 9: // "secret" triggerSecret["Sound"] = "common/mission_success.wav"; if (!Settings.dontCull) { if (sectorTriggerBrush.NumSides - badSides.Length >= 4) { for (int j = badSides.Length - 1; j > - 1; j--) { sectorTriggerBrush.delete(badSides[j]); } } } triggerSecret.Brushes.Add(sectorTriggerBrush); mapFile.Add(triggerSecret); break; case 10: // 30 seconds after level start, "close" like a door if (currentSector.Tag == 0) { sectorTag[subsectorSectors[i]] = - 3; } break; case 14: // 300 seconds after level start, "open" like a door if (currentSector.Tag == 0) { sectorTag[subsectorSectors[i]] = - 4; } break; default: if (!Settings.dontCull) { if (sectorTriggerBrush.NumSides - badSides.Length >= 4) { for (int j = badSides.Length - 1; j > - 1; j--) { sectorTriggerBrush.delete(badSides[j]); } } } if ((currentSector.Type & 96) != 0) { // "Generalized" pain sectors if ((currentSector.Type & 96) == 32) { hurtMe["dmg"] = "10"; } else { if ((currentSector.Type & 96) == 64) { hurtMe["dmg"] = "20"; } else { if ((currentSector.Type & 96) == 96) { hurtMe["dmg"] = "40"; } } } hurtMe.Brushes.Add(sectorTriggerBrush); mapFile.Add(hurtMe); } if ((currentSector.Type & 128) == 128) { // "Generalized" secret trigger triggerSecret["Sound"] = "common/mission_success.wav"; triggerSecret.Brushes.Add(sectorTriggerBrush); mapFile.Add(triggerSecret); } break; } if((i+1)%onePercent == 0) { parent.OnProgress(this, (i+1)/(double)(doomMap.SubSectors.Count)); } //Settings.setProgress(jobnum, i + 1, doomMap.SubSectors.Count, "Decompiling..."); } // Add the brushes to the map, as world by default, or entities if they are supported. for (int i = 0; i < doomMap.Sectors.Count; i++) { bool[] floorsUsed = new bool[sectorFloorBrushes[i].Length]; bool[] cielingsUsed = new bool[sectorCielingBrushes[i].Length]; if (sectorTag[i] == 0) { for (int j = 0; j < sectorFloorBrushes[i].Length; j++) { world.Brushes.Add(sectorFloorBrushes[i][j]); floorsUsed[j] = true; world.Brushes.Add(sectorCielingBrushes[i][j]); cielingsUsed[j] = true; } } else { if (sectorTag[i] == - 1 || sectorTag[i] == - 2 || sectorTag[i] == - 3 || sectorTag[i] == - 4) { // I'm using this to mean a door with no tag number Entity newDoor = new Entity("func_door"); newDoor["speed"] = "60"; newDoor["angles"] = "270 0 0"; newDoor["spawnflags"] = "256"; newDoor["targetname"] = "sectornum" + i + "door"; if (sectorTag[i] == - 1) { newDoor["wait"] = "4"; } else { if (sectorTag[i] == - 2) { newDoor["wait"] = "-1"; } } if (sectorTag[i] == - 3) { Entity triggerAuto = new Entity("trigger_auto"); triggerAuto["target"] = "sectornum" + i + "door_mm"; Entity multiManager = new Entity("multi_manager"); multiManager["sectornum" + i + "door"] = "30"; mapFile.Add(triggerAuto); mapFile.Add(multiManager); } if (sectorTag[i] == - 4) { newDoor["Spawnflags"] = "1"; Entity triggerAuto = new Entity("trigger_auto"); triggerAuto["target"] = "sectornum" + i + "door_mm"; Entity multiManager = new Entity("multi_manager"); multiManager["sectornum" + i + "door"] = "300"; mapFile.Add(triggerAuto); mapFile.Add(multiManager); } int lowestNeighborCielingHeight = getLowestNeighborCielingHeight(i); int lip = ZMax - lowestNeighborCielingHeight + 4; newDoor["lip"] = "" + lip; for (int j = 0; j < sectorFloorBrushes[i].Length; j++) { cielingsUsed[j] = true; newDoor.Brushes.Add(sectorCielingBrushes[i][j]); } mapFile.Add(newDoor); } else { for (int j = 0; j < doomMap.Linedefs.Count; j++) { DLinedef currentLinedef = doomMap.Linedefs[j]; int linedefTriggerType = currentLinedef.Action; if (doomMap.Version == mapType.TYPE_HEXEN) { switch (linedefTriggerType) { case 21: // Floor lower to lowest neighbor case 22: // Floor lower to nearest lower neighbor // I don't know where retriggerability is determined, or whether or not it goes back up. if (currentLinedef.Arguments[0] == sectorTag[i]) { Entity newFloor = new Entity("func_door"); newFloor["angles"] = "90 0 0"; newFloor["wait"] = "-1"; newFloor["speed"] = "" + currentLinedef.Arguments[1]; if (currentLinedef.Arguments[0] == 0) { newFloor["targetname"] = "sectornum" + i + "lowerfloor"; } else { newFloor["targetname"] = "sector" + currentLinedef.Arguments[0] + "lowerfloor"; } int lowestNeighborFloorHeight; if (linedefTriggerType == 21) { lowestNeighborFloorHeight = getLowestNeighborFloorHeight(i); } else { lowestNeighborFloorHeight = getNextLowestNeighborFloorHeight(i); } if (lowestNeighborFloorHeight == 32768) { lowestNeighborFloorHeight = doomMap.Sectors[i].FloorHeight; } int lip = ZMin - lowestNeighborFloorHeight; newFloor["lip"] = "" + System.Math.Abs(lip); for (int k = 0; k < sectorFloorBrushes[i].Length; k++) { if (!floorsUsed[k]) { floorsUsed[k] = true; newFloor.Brushes.Add(sectorFloorBrushes[i][k]); } } mapFile.Add(newFloor); } break; case 24: // Floor raise to highest neighbor case 25: // Floor raise to nearest higher neighbor // I don't know where retriggerability is determined, or whether or not it goes back up. if (currentLinedef.Arguments[0] == sectorTag[i]) { Entity newFloor = new Entity("func_door"); newFloor["angles"] = "270 0 0"; newFloor["wait"] = "-1"; newFloor["speed"] = "" + currentLinedef.Arguments[1]; if (currentLinedef.Arguments[0] == 0) { newFloor["targetname"] = "sectornum" + i + "raisefloor"; } else { newFloor["targetname"] = "sector" + currentLinedef.Arguments[0] + "raisefloor"; } int highestNeighborFloorHeight; if (linedefTriggerType == 24) { highestNeighborFloorHeight = getHighestNeighborFloorHeight(i); } else { highestNeighborFloorHeight = getNextHighestNeighborFloorHeight(i); } if (highestNeighborFloorHeight == - 32768) { highestNeighborFloorHeight = doomMap.Sectors[i].FloorHeight; } int lip = ZMin - highestNeighborFloorHeight; newFloor["lip"] = "" + System.Math.Abs(lip); for (int k = 0; k < sectorFloorBrushes[i].Length; k++) { if (!floorsUsed[k]) { floorsUsed[k] = true; newFloor.Brushes.Add(sectorFloorBrushes[i][k]); } } mapFile.Add(newFloor); } break; } } else { if (currentLinedef.Tag == sectorTag[i]) { switch (linedefTriggerType) { case 36: // Line crossed, floor lowers, stays 8 above next lowest case 38: // Line crossed, floor lowers, stays at next lowest Entity newFloor = new Entity("func_door"); newFloor["speed"] = "120"; newFloor["angles"] = "90 0 0"; newFloor["targetname"] = "sector" + sectorTag[i] + "lowerfloor"; newFloor["wait"] = "-1"; int lowestNeighborFloorHeight = getLowestNeighborFloorHeight(i); int lip = ZMin - lowestNeighborFloorHeight; if (linedefTriggerType == 36) { lip -= 8; } newFloor["lip"] = "" + System.Math.Abs(lip); for (int k = 0; k < sectorFloorBrushes[i].Length; k++) { if (!floorsUsed[k]) { floorsUsed[k] = true; newFloor.Brushes.Add(sectorFloorBrushes[i][k]); } } mapFile.Add(newFloor); break; case 63: // Push button, door opens, waits 4s, closes case 103: // Push button, door opens, stays case 109: // Cross line, door opens, stays Entity newDoor = new Entity("func_door"); newDoor["speed"] = "60"; newDoor["angles"] = "270 0 0"; newDoor["targetname"] = "sector" + sectorTag[i] + "door"; newDoor["wait"] = "-1"; if (sectorTag[i] == 63) { newDoor["wait"] = "4"; } int lowestNeighborCielingHeight = getLowestNeighborCielingHeight(i); lip = ZMax - lowestNeighborCielingHeight + 4; newDoor["lip"] = "" + lip; for (int k = 0; k < sectorFloorBrushes[i].Length; k++) { if (!cielingsUsed[k]) { cielingsUsed[k] = true; newDoor.Brushes.Add(sectorCielingBrushes[i][k]); } } mapFile.Add(newDoor); break; case 62: // Push button, Elevator goes down to lowest, wait 4s, goes up case 88: // Elevator goes down to lowest, wait 4s, goes up Entity newVator = new Entity("func_door"); newVator["speed"] = "120"; newVator["angles"] = "90 0 0"; newVator["targetname"] = "sector" + sectorTag[i] + "vator"; newVator["wait"] = "4"; lowestNeighborFloorHeight = getLowestNeighborFloorHeight(i); lip = System.Math.Abs(ZMin - lowestNeighborFloorHeight); newVator["lip"] = "" + lip; for (int k = 0; k < sectorFloorBrushes[i].Length; k++) { if (!floorsUsed[k]) { newVator.Brushes.Add(sectorFloorBrushes[i][k]); floorsUsed[k] = true; } } mapFile.Add(newVator); break; default: // I'd like to not use this evenutally, all the trigger types ought to be handled DecompilerThread.OnMessage(this, "WARNING: Unimplemented linedef trigger type " + linedefTriggerType + " for sector " + i + " tagged " + sectorTag[i]); for (int k = 0; k < sectorFloorBrushes[i].Length; k++) { if (!floorsUsed[k]) { world.Brushes.Add(sectorFloorBrushes[i][k]); floorsUsed[k] = true; } if (!cielingsUsed[k]) { world.Brushes.Add(sectorCielingBrushes[i][k]); cielingsUsed[k] = true; } } break; } } } } } } for (int j = 0; j < sectorFloorBrushes[i].Length; j++) { if (!cielingsUsed[j]) { world.Brushes.Add(sectorCielingBrushes[i][j]); } if (!floorsUsed[j]) { world.Brushes.Add(sectorFloorBrushes[i][j]); } } } // Convert THINGS for (int i = 0; i < doomMap.Things.Count; i++) { DThing currentThing = doomMap.Things[i]; // To find the true height of a thing, I need to iterate through nodes until I come to a subsector // definition. Then I need to use the floor height of the sector that subsector belongs to. Vector3D origin = currentThing.Origin; int subsectorIndex = doomMap.Nodes.Count - 1; while (subsectorIndex >= 0) { // Once child is negative, subsector is found DNode currentNode = doomMap.Nodes[subsectorIndex]; Vector3D start = currentNode.VecHead; Vector3D end = currentNode.VecHead+currentNode.VecTail; Plane currentPlane = new Plane(start, end, new Vector3D(start.X, start.Y, 1)); if (currentPlane.distance(origin) < 0) { subsectorIndex = currentNode.Child1; } else { subsectorIndex = currentNode.Child2; } } subsectorIndex += 32768; int sectorIndex = subsectorSectors[subsectorIndex]; DSector thingSector = doomMap.Sectors[sectorIndex]; if (origin.Z == 0) { origin.Z=thingSector.FloorHeight; } Entity thing = null; // Things from both Doom. Currently converting to appropriate Doom 3 entities. switch (currentThing.ClassNum) { case 1: // Single player spawn case 2: // coop case 3: // coop case 4: // coop thing = new Entity("info_player_start"); if (currentThing.ClassNum > 1) { thing["targetname"] = "coopspawn" + currentThing.ClassNum; } playerStartOrigin = origin.X + " " + origin.Y + " " + (origin.Z + 36); thing["origin"] = playerStartOrigin; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 11: // Deathmatch spawn thing = new Entity("info_player_deathmatch"); thing["origin"] = origin.X + " " + origin.Y + " " + (origin.Z + 36); thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 14: // Teleport destination thing = new Entity("info_teleport_destination"); if (currentThing.ID != 0) { thing["targetname"] = "teledest" + currentThing.ID; } else { thing["targetname"] = "sector" + thingSector.Tag + "teledest"; } thing["origin"] = origin.X + " " + origin.Y + " " + (origin.Z + 36); thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 17: // Big cell pack thing = new Entity("ammo_cells_large"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 82: // Super shotgun thing = new Entity("weapon_shotgun_double"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2001: // Shotgun thing = new Entity("weapon_shotgun"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2002: // Chaingun thing = new Entity("weapon_chaingun"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2003: // Rocket launcher thing = new Entity("weapon_rocketlauncher"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2004: // Plasma gun thing = new Entity("weapon_plasmagun"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2005: // Chainsaw thing = new Entity("weapon_chainsaw"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2006: // BFG9000 thing = new Entity("weapon_bfg"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2007: // Ammo clip thing = new Entity("ammo_clip_small"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2008: // Shotgun shells thing = new Entity("ammo_shells_small"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2010: // Rocket thing = new Entity("ammo_rockets_small"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2046: // Box of Rockets thing = new Entity("ammo_rockets_large"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2047: // Cell pack thing = new Entity("ammo_cells_small"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2048: // Box of ammo thing = new Entity("ammo_bullets_large"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; case 2049: // Box of shells thing = new Entity("ammo_shells_large"); thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z; thing["angles"] = "0 " + currentThing.Angle + " 0"; break; } if (thing != null) { mapFile.Add(thing); } } Entity playerequip = new Entity("game_player_equip"); playerequip["weapon_pistol"] = "1"; playerequip["origin"] = playerStartOrigin; mapFile.Add(playerequip); parent.OnProgress(this, 1.0); return mapFile; }
// METHODS // Attempt to turn the BSP into a .MAP file public virtual Entities decompile() { DecompilerThread.OnMessage(this, "Decompiling..."); // In the decompiler, it is not necessary to copy all entities to a new object, since // no writing is ever done back to the BSP file. mapFile = BSPObject.Entities; //int numAreaPortals=0; int numTotalItems = 0; int onePercent = (int)((BSPObject.Brushes.Count + BSPObject.Entities.Count)/100); if(onePercent < 1) { onePercent = 1; } int originalNumEntities = BSPObject.Entities.Count; // Need to keep track of this in this algorithm, since I create more entities on the fly for (int i = 0; i < originalNumEntities; i++) { // For each entity //DecompilerThread.OnMessage(this, "Entity " + i + ": " + mapFile[i]["classname"]); // getModelNumber() returns 0 for worldspawn, the *# for brush based entities, and -1 for everything else int currentModel = mapFile[i].ModelNumber; if (currentModel > - 1) { // If this is still -1 then it's strictly a point-based entity. Move on to the next one. Leaf[] leaves = BSPObject.getLeavesInModel(currentModel); int numLeaves = leaves.Length; bool[] brushesUsed = new bool[BSPObject.Brushes.Count]; // Keep a list of brushes already in the model, since sometimes the leaves lump references one brush several times numBrshs = 0; // Reset the brush count for each entity for (int j = 0; j < numLeaves; j++) { // For each leaf in the bunch Leaf currentLeaf = leaves[j]; int firstMarkBrushIndex = currentLeaf.FirstMarkBrush; int numBrushIndices = currentLeaf.NumMarkBrushes; if (numBrushIndices > 0) { // A lot of leaves reference no brushes. If this is one, this iteration of the j loop is finished for (int k = 0; k < numBrushIndices; k++) { // For each brush referenced long currentBrushIndex = BSPObject.MarkBrushes[firstMarkBrushIndex + k]; if (!brushesUsed[(int) currentBrushIndex]) { // If the current brush has NOT been used in this entity //Console.Write("Brush " + numBrshs); brushesUsed[(int) currentBrushIndex] = true; Brush brush = BSPObject.Brushes[(int) currentBrushIndex]; decompileBrush(brush, i); // Decompile the brush numBrshs++; numTotalItems++; if(numTotalItems%onePercent == 0) { parent.OnProgress(this, numTotalItems/(double)(BSPObject.Brushes.Count + BSPObject.Entities.Count)); } } } } } } numTotalItems++; // This entity if(numTotalItems%onePercent == 0) { parent.OnProgress(this, numTotalItems/(double)(BSPObject.Brushes.Count + BSPObject.Entities.Count)); } } // Find displacement faces and generate brushes for them for (int i = 0; i < BSPObject.Faces.Count; i++) { Face face = BSPObject.Faces[i]; if (face.Displacement > - 1) { SourceDispInfo disp = BSPObject.DispInfos[face.Displacement]; TexInfo currentTexInfo; if (face.Texture > - 1) { currentTexInfo = BSPObject.TexInfo[face.Texture]; } else { Vector3D[] axes = TexInfo.textureAxisFromPlane(BSPObject.Planes[face.Plane]); currentTexInfo = new TexInfo(axes[0], 0, axes[1], 0, 0, BSPObject.findTexDataWithTexture("tools/toolsclip")); } SourceTexData currentTexData = BSPObject.TexDatas[currentTexInfo.Texture]; string texture = BSPObject.Textures.getTextureAtOffset((uint)BSPObject.TexTable[currentTexData.StringTableIndex]); double[] textureU = new double[3]; double[] textureV = new double[3]; // Get the lengths of the axis vectors double SAxisLength = System.Math.Sqrt(System.Math.Pow((double) currentTexInfo.SAxis.X, 2) + System.Math.Pow((double) currentTexInfo.SAxis.Y, 2) + System.Math.Pow((double) currentTexInfo.SAxis.Z, 2)); double TAxisLength = System.Math.Sqrt(System.Math.Pow((double) currentTexInfo.TAxis.X, 2) + System.Math.Pow((double) currentTexInfo.TAxis.Y, 2) + System.Math.Pow((double) currentTexInfo.TAxis.Z, 2)); // In compiled maps, shorter vectors=longer textures and vice versa. This will convert their lengths back to 1. We'll use the actual scale values for length. double texScaleU = (1 / SAxisLength); // Let's use these values using the lengths of the U and V axes we found above. double texScaleV = (1 / TAxisLength); textureU[0] = ((double) currentTexInfo.SAxis.X / SAxisLength); textureU[1] = ((double) currentTexInfo.SAxis.Y / SAxisLength); textureU[2] = ((double) currentTexInfo.SAxis.Z / SAxisLength); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" double textureShiftU = (double) currentTexInfo.SShift; textureV[0] = ((double) currentTexInfo.TAxis.X / TAxisLength); textureV[1] = ((double) currentTexInfo.TAxis.Y / TAxisLength); textureV[2] = ((double) currentTexInfo.TAxis.Z / TAxisLength); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" double textureShiftV = (double) currentTexInfo.TShift; if (face.NumEdges != 4) { DecompilerThread.OnMessage(this, "Displacement face with " + face.NumEdges + " edges!"); } // Turn vertices and edges into arrays of vectors Vector3D[] froms = new Vector3D[face.NumEdges]; Vector3D[] tos = new Vector3D[face.NumEdges]; for (int j = 0; j < face.NumEdges; j++) { if (BSPObject.SurfEdges[face.FirstEdge + j] > 0) { froms[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j]].FirstVertex].Vector; tos[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j]].SecondVertex].Vector; } else { tos[j] = BSPObject.Vertices[BSPObject.Edges[(int) BSPObject.SurfEdges[face.FirstEdge + j] * (- 1)].FirstVertex].Vector; froms[j] = BSPObject.Vertices[BSPObject.Edges[(int) BSPObject.SurfEdges[face.FirstEdge + j] * (- 1)].SecondVertex].Vector; } } MAPBrush displacementBrush = MAPBrush.createBrushFromWind(froms, tos, texture, "TOOLS/TOOLSNODRAW", currentTexInfo); MAPDisplacement mapdisp = new MAPDisplacement(disp, BSPObject.DispVerts.getVertsInDisp(disp.DispVertStart, disp.Power)); displacementBrush[0].Displacement = mapdisp; mapFile[0].Brushes.Add(displacementBrush); } } for (int i = 0; i < BSPObject.StaticProps.Count; i++) { Entity newStaticProp = new Entity("prop_static"); SourceStaticProp currentProp = BSPObject.StaticProps[i]; newStaticProp["model"] = BSPObject.StaticProps.Dictionary[currentProp.DictionaryEntry]; newStaticProp["skin"] = currentProp.Skin + ""; newStaticProp["origin"] = currentProp.Origin.X + " " + currentProp.Origin.Y + " " + currentProp.Origin.Z; newStaticProp["angles"] = currentProp.Angles.X + " " + currentProp.Angles.Y + " " + currentProp.Angles.Z; newStaticProp["solid"] = currentProp.Solidity + ""; newStaticProp["fademindist"] = currentProp.MinFadeDist + ""; newStaticProp["fademaxdist"] = currentProp.MaxFadeDist + ""; newStaticProp["fadescale"] = currentProp.ForcedFadeScale + ""; if (currentProp.Targetname != null) { newStaticProp["targetname"] = currentProp.Targetname; } mapFile.Add(newStaticProp); } for (int i = 0; i < BSPObject.Cubemaps.Count; i++) { Entity newCubemap = new Entity("env_cubemap"); SourceCubemap currentCube = BSPObject.Cubemaps[i]; newCubemap["origin"] = currentCube.Origin.X + " " + currentCube.Origin.Y + " " + currentCube.Origin.Z; newCubemap["cubemapsize"] = currentCube.Size + ""; mapFile.Add(newCubemap); } if (!Settings.skipPlaneFlip) { DecompilerThread.OnMessage(this, "Num simple corrected brushes: " + numSimpleCorrects); DecompilerThread.OnMessage(this, "Num advanced corrected brushes: " + numAdvancedCorrects); DecompilerThread.OnMessage(this, "Num good brushes: " + numGoodBrushes); } parent.OnProgress(this, 1.0); return mapFile; }
public static Entities createLump(byte[] data) { int count = 0; bool inQuotes = false; // Keep track of whether or not we're currently in a set of quotation marks. // I came across a map where the idiot map maker used { and } within a value. This broke the code prior to revision 55. for (int i = 0; i < data.Length; i++) { if (inQuotes) { if (data[i] == '\"' && inQuotes) { inQuotes = false; } } else { if (data[i] == '\"') { inQuotes = true; } else { if (data[i] == '{') { count++; } } } } Entities lump = new Entities(data.Length, count); char currentChar; // The current character being read in the file. This is necessary because // we need to know exactly when the { and } characters occur and capture // all text between them. int offset = 0; for (int i = 0; i < count; i++) { // For every entity string current = ""; // This will be the resulting entity, fed into the Entity class currentChar = (char)data[offset]; // begin reading the file while (currentChar != '{') { // Eat bytes until we find the beginning of an entity structure offset++; currentChar = (char)data[offset]; } inQuotes = false; do { if (currentChar == '\"') { inQuotes = !inQuotes; } current += (currentChar + ""); // adds characters to the current string offset++; currentChar = (char)data[offset]; } while (currentChar != '}' || inQuotes); // Read bytes until we find the end of the current entity structure current += (currentChar + ""); // adds the '}' to the current string lump.Add(Entity.parseString(current)); } return lump; }