#region ================== Copyright (c) 2021 Boris Iwanski /* * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.If not, see. */ #endregion #region ================== Namespaces using System; using System.Collections.Generic; using System.Linq; using CodeImp.DoomBuilder.BuilderModes; using CodeImp.DoomBuilder.Editing; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.VisualModes; #endregion namespace CodeImp.DoomBuilder.UDBScript.Wrapper { internal class MapWrapper { #region ================== Enums /// /// How geometry should be merged when geometry is stitched. /// ``` /// UDB.Map.stitchGeometry(UDB.Map.MergeometryMode.MERGE); /// ``` /// /// Merge vertices only /// Merge vertices and lines /// Merge vertices and lines, replacing sector geometry [UDBScriptSettings(MinVersion = 5)] public enum MergeGeometryMode { CLASSIC = Map.MergeGeometryMode.CLASSIC, MERGE = Map.MergeGeometryMode.MERGE, REPLACE = Map.MergeGeometryMode.REPLACE } #endregion #region ================== Variables private MapSet map; private VisualCameraWrapper visualcamera; private Vector2D mousemappos; private object highlightedobject; #endregion #region ================== Properties /// /// `true` if the map is in Doom format, `false` if it isn't. Read-only. /// public bool isDoom { get { return General.Map.DOOM; } } /// /// `true` if the map is in Hexen format, `false` if it isn't. Read-only. /// public bool isHexen { get { return General.Map.HEXEN; } } /// /// `true` if the map is in UDMF, `false` if it isn't. Read-only. /// public bool isUDMF { get { return General.Map.UDMF; } } /// /// The map coordinates of the mouse position as a `Vector2D`. Read-only. /// public Vector2D mousePosition { get { return mousemappos; } } /// /// `VisualCamera` object with information about the position of the camera in visual mode. Read-only. /// public VisualCameraWrapper camera { get { return visualcamera; } } #endregion #region ================== Constructors internal MapWrapper() { map = General.Map.Map; visualcamera = new VisualCameraWrapper(); // If the main window loses focus before the script is running General.Editing.Mode.HighlightedObject will always be null, so cache it here highlightedobject = General.Editing.Mode.HighlightedObject; if (General.Editing.Mode is ClassicMode) mousemappos = ((ClassicMode)General.Editing.Mode).MouseMapPos; else mousemappos = ((VisualMode)General.Editing.Mode).GetHitPosition(); } #endregion #region ================== Methods /// /// Returns the given point snapped to the current grid. /// /// Point that should be snapped to the grid /// Snapped position as `Vector2D` public Vector2DWrapper snappedToGrid(object pos) { try { return new Vector2DWrapper(General.Map.Grid.SnappedToGrid(BuilderPlug.Me.GetVector3DFromObject(pos))); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns an `Array` of all `Thing`s in the map. /// /// `Array` of `Thing`s public ThingWrapper[] getThings() { List things = new List(General.Map.Map.Things.Count); foreach (Thing t in General.Map.Map.Things) if(!t.IsDisposed) things.Add(new ThingWrapper(t)); return things.ToArray(); } /// /// Returns an `Array` of all `Sector`s in the map. /// /// `Array` of `Sector`s public SectorWrapper[] getSectors() { List sectors = new List(General.Map.Map.Sectors.Count); foreach (Sector s in General.Map.Map.Sectors) if (!s.IsDisposed) sectors.Add(new SectorWrapper(s)); return sectors.ToArray(); } /// /// Returns an `Array` of all `Sidedef`s in the map. /// /// `Array` of `Sidedef`s public SidedefWrapper[] getSidedefs() { List sidedefs = new List(General.Map.Map.Sidedefs.Count); foreach (Sidedef sd in General.Map.Map.Sidedefs) if (!sd.IsDisposed) sidedefs.Add(new SidedefWrapper(sd)); return sidedefs.ToArray(); } /// /// Returns an `Array` of all `Linedef`s in the map. /// /// `Array` of `Linedef`s public LinedefWrapper[] getLinedefs() { List linedefs = new List(General.Map.Map.Linedefs.Count); foreach (Linedef ld in General.Map.Map.Linedefs) if (!ld.IsDisposed) linedefs.Add(new LinedefWrapper(ld)); return linedefs.ToArray(); } /// /// Returns an `Array` of all `Vertex` in the map. /// /// `Array` of `Vertex` public VertexWrapper[] getVertices() { List vertices = new List(General.Map.Map.Vertices.Count); foreach (Vertex v in General.Map.Map.Vertices) if (!v.IsDisposed) vertices.Add(new VertexWrapper(v)); return vertices.ToArray(); } /// /// Stitches marked geometry with non-marked geometry. /// /// Mode to merge by as `MergeGeometryMode` /// `true` if successful, `false` if failed public bool stitchGeometry(MergeGeometryMode mergemode = MergeGeometryMode.CLASSIC) { if(mergemode == MergeGeometryMode.CLASSIC) return General.Map.Map.StitchGeometry(Map.MergeGeometryMode.CLASSIC); else if(mergemode == MergeGeometryMode.MERGE) return General.Map.Map.StitchGeometry(Map.MergeGeometryMode.MERGE); else if(mergemode == MergeGeometryMode.REPLACE) return General.Map.Map.StitchGeometry(Map.MergeGeometryMode.REPLACE); throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Unknown MergeGeometryMode value"); } /// /// Snaps all vertices and things to the map format accuracy. Call this to ensure the vertices and things are at valid coordinates. /// /// `true` if decimal places defined by the map format should be used, `false` if no decimal places should be used public void snapAllToAccuracy(bool usepreciseposition = true) { General.Map.Map.SnapAllToAccuracy(usepreciseposition); } /// /// Gets a new tag. /// /// `Array` of tags to skip /// The new tag public int getNewTag(int[] usedtags = null) { if (usedtags == null) return General.Map.Map.GetNewTag(); else return General.Map.Map.GetNewTag(usedtags.ToList()); } /// /// Gets multiple new tags. /// /// Number of tags to get /// `Array` of the new tags public int[] getMultipleNewTags(int count) { return General.Map.Map.GetMultipleNewTags(count).ToArray(); } /// /// Gets the `Linedef` that's nearest to the specified position. /// /// Position to check against /// Maximum range (optional) /// Nearest `Linedef` public LinedefWrapper nearestLinedef(object pos, double maxrange = double.NaN) { try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(pos); Linedef nearest = null; if (double.IsNaN(maxrange)) nearest = General.Map.Map.NearestLinedef(v); else nearest = General.Map.Map.NearestLinedefRange(v, maxrange); if (nearest == null) return null; return new LinedefWrapper(nearest); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Gets the `Thing` that's nearest to the specified position. /// /// Position to check against /// Maximum range (optional) /// Nearest `Linedef` public ThingWrapper nearestThing(object pos, double maxrange = double.NaN) { try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(pos); Thing nearest = null; if (double.IsNaN(maxrange)) nearest = General.Map.Map.NearestThingSquareRange(v, double.MaxValue); else nearest = General.Map.Map.NearestThingSquareRange(v, maxrange); if (nearest == null) return null; return new ThingWrapper(nearest); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Gets the `Vertex` that's nearest to the specified position. /// /// Position to check against /// Maximum range (optional) /// Nearest `Vertex` public VertexWrapper nearestVertex(object pos, double maxrange = double.NaN) { try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(pos); Vertex nearest = null; if (double.IsNaN(maxrange)) nearest = General.Map.Map.NearestVertexSquareRange(v, double.MaxValue); else nearest = General.Map.Map.NearestVertexSquareRange(v, maxrange); if (nearest == null) return null; return new VertexWrapper(nearest); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Gets the `Sidedef` that's nearest to the specified position. /// /// Position to check against /// Maximum range (optional) /// Nearest `Sidedef` public SidedefWrapper nearestSidedef(object pos) { try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(pos); Sidedef nearest = MapSet.NearestSidedef(General.Map.Map.Sidedefs, v); if (nearest == null) return null; return new SidedefWrapper(nearest); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Draws lines. Data has to be an `Array` of `Array` of numbers, `Vector2D`s, `Vector3D`s, or objects with x and y properties. Note that the first and last element have to be at the same positions to make a complete drawing. /// ```js /// UDB.Map.drawLines([ /// new UDB.Vector2D(64, 0), /// new UDB.Vector2D(128, 0), /// new UDB.Vector2D(128, 64), /// new UDB.Vector2D(64, 64), /// new UDB.Vector2D(64, 0) /// ]); /// /// UDB.Map.drawLines([ /// [ 0, 0 ], /// [ 64, 0 ], /// [ 64, 64 ], /// [ 0, 64 ], /// [ 0, 0 ] /// ]); /// ``` /// /// `Array` of positions /// `true` if drawing was successful, `false` if it wasn't public bool drawLines(object data) { if (!data.GetType().IsArray) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Data must be supplied as an array"); List vertices = new List(); foreach(object item in (object[])data) { try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(item); DrawnVertex dv = new DrawnVertex(); dv.pos = v; dv.stitch = dv.stitchline = true; vertices.Add(dv); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } if(vertices.Count < 2) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Array must have at least 2 values"); bool success = Tools.DrawLines(vertices); // Snap to map format accuracy General.Map.Map.SnapAllToAccuracy(); // Update map. This has to run on the UI thread BuilderPlug.Me.ScriptRunnerForm.RunAction(() => General.Map.Map.Update()); // Update textures General.Map.Data.UpdateUsedTextures(); return success; } #endregion #region ================== Marks /// /// Sets the `marked` property of all map elements. Can be passed `true` to mark all map elements. /// /// `false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true` public void clearAllMarks(bool mark=false) { General.Map.Map.ClearAllMarks(mark); } /// /// Sets the `marked` property of all vertices. Can be passed `true` to mark all vertices. /// /// `false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true` public void clearMarkedVertices(bool mark=false) { General.Map.Map.ClearMarkedVertices(mark); } /// /// Sets the `marked` property of all `Thing`s. Can be passed `true` to mark all `Thing`s. /// /// `false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true` public void clearMarkedThings(bool mark=false) { General.Map.Map.ClearMarkedThings(mark); } /// /// Sets the `marked` property of all `Linedef`s. Can be passed `true` to mark all `Linedef`s. /// /// `false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true` public void clearMarkeLinedefs(bool mark=false) { General.Map.Map.ClearMarkedLinedefs(mark); } /// /// Sets the `marked` property of all `Sidedef`s. Can be passed `true` to mark all `Sidedef`s. /// /// `false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true` public void clearMarkeSidedefs(bool mark = false) { General.Map.Map.ClearMarkedSidedefs(mark); } /// /// Sets the `marked` property of all `Sector`s. Can be passed `true` to mark all `Sector`s. /// /// `false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true` public void clearMarkeSectors(bool mark = false) { General.Map.Map.ClearMarkedSectors(mark); } /// /// Inverts all marks of all map elements. /// public void invertAllMarks() { General.Map.Map.InvertAllMarks(); } /// /// Inverts the `marked` property of all vertices. /// public void invertMarkedVertices() { General.Map.Map.InvertMarkedVertices(); } /// /// Inverts the `marked` property of all `Thing`s. /// public void invertMarkedThings() { General.Map.Map.InvertMarkedThings(); } /// /// Inverts the `marked` property of all `Linedef`s. /// public void invertMarkedLinedefs() { General.Map.Map.InvertMarkedLinedefs(); } /// /// Inverts the `marked` property of all `Sidedef`s. /// public void invertMarkedSidedefs() { General.Map.Map.InvertMarkedSidedefs(); } /// /// Inverts the `marked` property of all `Sector`s. /// public void invertMarkedSectors() { General.Map.Map.InvertMarkedSectors(); } /// /// Gets all marked (default) or unmarked vertices. /// /// `true` to get all marked vertices (default), `false` to get all unmarked vertices /// public VertexWrapper[] getMarkedVertices(bool mark=true) { List vertices = new List(); foreach (Vertex v in General.Map.Map.Vertices) if(v.Marked == mark) vertices.Add(new VertexWrapper(v)); return vertices.ToArray(); } /// /// Gets all marked (default) or unmarked `Thing`s. /// /// `true` to get all marked `Thing`s (default), `false` to get all unmarked `Thing`s /// public ThingWrapper[] getMarkedThings(bool mark = true) { List things = new List(); foreach (Thing t in General.Map.Map.Things) if (t.Marked == mark) things.Add(new ThingWrapper(t)); return things.ToArray(); } /// /// Gets all marked (default) or unmarked `Linedef`s. /// /// `true` to get all marked `Linedef`s (default), `false` to get all unmarked `Linedef`s /// public LinedefWrapper[] getMarkedLinedefs(bool mark = true) { List linedefs = new List(); foreach (Linedef ld in General.Map.Map.Linedefs) if (ld.Marked == mark) linedefs.Add(new LinedefWrapper(ld)); return linedefs.ToArray(); } /// /// Gets all marked (default) or unmarked `Sidedef`s. /// /// `true` to get all marked `Sidedef`s (default), `false` to get all unmarked `Sidedef`s /// public SidedefWrapper[] getMarkedSidedefs(bool mark = true) { List sidedefs = new List(); foreach (Sidedef sd in General.Map.Map.Sidedefs) if (sd.Marked == mark) sidedefs.Add(new SidedefWrapper(sd)); return sidedefs.ToArray(); } /// /// Gets all marked (default) or unmarked `Sector`s. /// /// `true` to get all marked `Sector`s (default), `false` to get all unmarked `Sector`s /// public SectorWrapper[] getMarkedSectors(bool mark = true) { List sectors = new List(); foreach (Sector s in General.Map.Map.Sectors) if (s.Marked == mark) sectors.Add(new SectorWrapper(s)); return sectors.ToArray(); } /// /// Marks (default) or unmarks all selected vertices. /// /// `true` to mark all selected vertices (default), `false` to unmark public void markSelectedVertices(bool mark=true) { General.Map.Map.MarkSelectedVertices(true, mark); } /// /// Marks (default) or unmarks all selected `Linedef`s. /// /// `true` to mark all selected `Linedef`s (default), `false` to unmark public void markSelectedLinedefs(bool mark = true) { General.Map.Map.MarkSelectedLinedefs(true, mark); } /// /// Marks (default) or unmarks all selected `Sector`s. /// /// `true` to mark all selected `Sector`s (default), `false` to unmark public void markSelectedSectors(bool mark = true) { General.Map.Map.MarkSelectedSectors(true, mark); } /// /// Marks (default) or unmarks all selected `Thing`s. /// /// `true` to mark all selected `Thing`s (default), `false` to unmark public void markSelectedThings(bool mark = true) { General.Map.Map.MarkSelectedThings(true, mark); } #endregion #region ================== Selected /// /// Gets all selected (default) or unselected vertices. /// /// `true` to get all selected vertices, `false` to get all unselected ones /// `Array` of `Vertex` public VertexWrapper[] getSelectedVertices(bool selected=true) { List vertices = new List(); if (General.Editing.Mode is BaseVisualMode) { List selectedvertices = ((BaseVisualMode)General.Editing.Mode).GetSelectedVertices(); foreach (Vertex v in General.Map.Map.Vertices) if (selectedvertices.Contains(v) == selected) vertices.Add(new VertexWrapper(v)); } else { foreach (Vertex v in map.GetSelectedVertices(selected)) if (v.Selected == selected) vertices.Add(new VertexWrapper(v)); } return vertices.ToArray(); } /// /// Get the currently highlighted `Vertex`. /// /// The currently highlighted `Vertex` or `null` if no `Vertex` is highlighted public VertexWrapper getHighlightedVertex() { Vertex v = highlightedobject as Vertex; if (v != null) return new VertexWrapper(v); return null; } /// /// Gets the currently selected `Vertex`s *or*, if no `Vertex`s are selected, a currently highlighted `Vertex`. /// /// `Array` of `Vertex` public VertexWrapper[] getSelectedOrHighlightedVertices() { if (General.Map.Map.SelectedVerticessCount > 0) { List vertices = new List(); foreach (Vertex v in General.Map.Map.Vertices) if (v.Selected) vertices.Add(new VertexWrapper(v)); return vertices.ToArray(); } else { Vertex v = General.Editing.Mode.HighlightedObject as Vertex; if (v != null) return new VertexWrapper[] { new VertexWrapper(v) }; } return new VertexWrapper[] { }; } /// /// Gets all selected (default) or unselected `Thing`s. /// /// `true` to get all selected `Thing`s, `false` to get all unselected ones /// `Array` of `Thing`s public ThingWrapper[] getSelectedThings(bool selected = true) { List things = new List(); if (General.Editing.Mode is BaseVisualMode) { List selectedthings = ((BaseVisualMode)General.Editing.Mode).GetSelectedThings(); foreach (Thing t in General.Map.Map.Things) if (selectedthings.Contains(t) == selected) things.Add(new ThingWrapper(t)); } else { foreach (Thing t in map.GetSelectedThings(selected)) if (t.Selected == selected) things.Add(new ThingWrapper(t)); } return things.ToArray(); } /// /// Get the currently highlighted `Thing`. /// /// The currently highlighted `Thing` or `null` if no `Thing` is highlighted public ThingWrapper getHighlightedThing() { if (General.Editing.Mode is BaseVisualMode) { VisualThing t = highlightedobject as VisualThing; if (t != null) return new ThingWrapper(t.Thing); } else { Thing t = highlightedobject as Thing; if (t != null) return new ThingWrapper(t); } return null; } /// /// Gets the currently selected `Thing`s *or*, if no `Thing`s are selected, a currently highlighted `Thing`. /// /// `Array` of `Thing`s public ThingWrapper[] getSelectedOrHighlightedThings() { ThingWrapper[] things = getSelectedThings(true); if (things.Length > 0) return things; ThingWrapper highlight = getHighlightedThing(); if (highlight != null) return new ThingWrapper[] { highlight }; return new ThingWrapper[] { }; } /// /// Gets all selected (default) or unselected `Sector`s. /// /// `true` to get all selected `Sector`s, `false` to get all unselected ones /// `Array` of `Sector`s public SectorWrapper[] getSelectedSectors(bool selected = true) { List sectors = new List(); if (General.Editing.Mode is BaseVisualMode) { List selectedsectors = ((BaseVisualMode)General.Editing.Mode).GetSelectedSectors(); foreach (Sector s in General.Map.Map.Sectors) if (selectedsectors.Contains(s) == selected) sectors.Add(new SectorWrapper(s)); } else { foreach (Sector s in map.GetSelectedSectors(selected)) if (s.Selected == selected) sectors.Add(new SectorWrapper(s)); } return sectors.ToArray(); } /// /// Get the currently highlighted `Sector`. /// /// The currently highlighted `Sector` or `null` if no `Sector` is highlighted public SectorWrapper getHighlightedSector() { if (General.Editing.Mode is BaseVisualMode) { VisualSector s = highlightedobject as VisualSector; if (s != null) return new SectorWrapper(s.Sector); } else { Sector s = highlightedobject as Sector; if (s != null) return new SectorWrapper(s); } return null; } /// /// Gets the currently selected `Sector`s *or*, if no `Sector`s are selected, a currently highlighted `Sector`. /// /// `Array` of `Sector`s public SectorWrapper[] getSelectedOrHighlightedSectors() { SectorWrapper[] sectors = getSelectedSectors(true); if (sectors.Length > 0) return sectors; SectorWrapper highlight = getHighlightedSector(); if (highlight != null) return new SectorWrapper[] { highlight }; return new SectorWrapper[] { }; } /// /// Gets all selected (default) or unselected `Linedef`s. /// /// `true` to get all selected `Linedef`s, `false` to get all unselected ones /// `Array` of `Linedef`s public LinedefWrapper[] getSelectedLinedefs(bool selected = true) { List linedefs = new List(); if (General.Editing.Mode is BaseVisualMode) { List selectedlinedefs = ((BaseVisualMode)General.Editing.Mode).GetSelectedLinedefs(); foreach (Linedef ld in General.Map.Map.Linedefs) if(selectedlinedefs.Contains(ld) == selected) linedefs.Add(new LinedefWrapper(ld)); } else { foreach (Linedef ld in map.GetSelectedLinedefs(selected)) if (ld.Selected == selected) linedefs.Add(new LinedefWrapper(ld)); } return linedefs.ToArray(); } /// /// Get the currently highlighted `Linedef`. /// /// The currently highlighted `Linedef` or `null` if no `Linedef` is highlighted public LinedefWrapper getHighlightedLinedef() { if (General.Editing.Mode is BaseVisualMode) { Sidedef sd = highlightedobject as Sidedef; if (sd != null) return new LinedefWrapper(sd.Line); } else { Linedef ld = highlightedobject as Linedef; if (ld != null) return new LinedefWrapper(ld); } return null; } /// /// Gets the currently selected `Linedef`s *or*, if no `Linede`f`s are selected, a currently highlighted `Linedef`. /// /// `Array` of `Linedef`s public LinedefWrapper[] getSelectedOrHighlightedLinedefs() { LinedefWrapper[] linedefs = getSelectedLinedefs(true); if (linedefs.Length > 0) return linedefs; LinedefWrapper highlight = getHighlightedLinedef(); if (highlight != null) return new LinedefWrapper[] { highlight }; return new LinedefWrapper[] { }; } /* public LinedefWrapper[] getAnyLinedefs() { if (General.Map.Map.SelectedLinedefsCount > 0) { List linedefs = new List(); foreach (Linedef ld in General.Map.Map.Linedefs) if (ld.Selected) linedefs.Add(new LinedefWrapper(ld)); return linedefs.ToArray(); } else if (General.Editing.Mode.HighlightedObject != null && General.Editing.Mode.HighlightedObject is Linedef) { return new LinedefWrapper[] { new LinedefWrapper((Linedef)General.Editing.Mode.HighlightedObject) }; } else { List linedefs = new List(); foreach (Linedef ld in General.Map.Map.Linedefs) if (ld.Selected) linedefs.Add(new LinedefWrapper(ld)); return linedefs.ToArray(); } } */ /// /// Gets all `Sidedef`s from the selected `Linedef`s. /// In classic modes this will return both sidedefs of 2-sided lines, in visual mode it will only return the actually selected `Sidedef`. /// /// `true` to get all `Sidedef`s of all selected `Linedef`s, `false` to get all `Sidedef`s of all unselected `Linedef`s /// `Array` of `Sidedef` public SidedefWrapper[] getSidedefsFromSelectedLinedefs(bool selected = true) { List sidedefs = new List(); if (General.Editing.Mode is BaseVisualMode) { List selectedsidedefs = ((BaseVisualMode)General.Editing.Mode).GetSelectedSidedefs(); foreach (Sidedef sd in General.Map.Map.Sidedefs) if (selectedsidedefs.Contains(sd) == selected) sidedefs.Add(new SidedefWrapper(sd)); } else { foreach (Sidedef sd in General.Map.Map.GetSidedefsFromSelectedLinedefs(selected)) sidedefs.Add(new SidedefWrapper(sd)); } return sidedefs.ToArray(); } /// /// Gets the `Sidedef`s of the currently selected `Linedef`s *or*, if no `Linedef`s are selected, the `Sidedef`s of the currently highlighted `Linedef`. /// In classic modes this will return both sidedefs of 2-sided lines, in visual mode it will only return the actually selected `Sidedef`. /// /// `Array` of `Sidedef`s /// 3 public SidedefWrapper[] getSidedefsFromSelectedOrHighlightedLinedefs() { List sidedefs = new List(getSidedefsFromSelectedLinedefs(true)); if(sidedefs.Count > 0) return sidedefs.ToArray(); // Nothing selected, so let's see if anything is highlighted LinedefWrapper highlight = getHighlightedLinedef(); if (highlight != null) { if (highlight.front != null) sidedefs.Add(highlight.front); if (highlight.back != null) sidedefs.Add(highlight.back); } return sidedefs.ToArray(); } /// /// Clears all selected map elements. /// public void clearAllSelected() { General.Map.Map.ClearAllSelected(); } /// /// Clears all selected vertices. /// public void clearSelectedVertices() { General.Map.Map.ClearSelectedVertices(); } /// /// Clears all selected `Thing`s. /// public void clearSelectedThings() { General.Map.Map.ClearSelectedThings(); } /// /// Clears all selected `Sector`s. /// public void clearSelectedSectors() { General.Map.Map.ClearSelectedSectors(); } #endregion #region ================== Creation /// /// Creates a new `Vertex` at the given position. The position can be a `Vector2D` or an `Array` of two numbers. /// ``` /// var v1 = UDB.Map.createVertex(new Vector2D(32, 64)); /// var v2 = UDB.Map.createVertex([ 32, 64 ]); /// ``` /// /// Position where the `Vertex` should be created at /// The created `Vertex` public VertexWrapper createVertex(object pos) { try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(pos); Vertex newvertex = General.Map.Map.CreateVertex(v); if(newvertex == null) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Failed to create new vertex"); return new VertexWrapper(newvertex); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Creates a new `Thing` at the given position. The position can be a `Vector2D`, `Vector3D`, or an `Array` of two numbers or three numbers (note that the z position only works for game configurations that support vertical pos. A thing type can be supplied optionally. /// ``` /// var t1 = UDB.Map.createThing(new UDB.Vector2D(32, 64)); /// var t2 = UDB.Map.createThing([ 32, 64 ]); /// var t3 = UDB.Map.createThing(new UDB.Vector2D(32, 64), 3001); // Create an Imp /// var t4 = UDB.Map.createThing([ 32, 64 ], 3001); // Create an Imp /// ``` /// /// Position where the `Thing` should be created at /// Thing type (optional) /// The new `Thing` public ThingWrapper createThing(object pos, int type=0) { try { if(type < 0) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Thing type can not be negative."); Vector2D v = BuilderPlug.Me.GetVector3DFromObject(pos); Thing t = General.Map.Map.CreateThing(); if(t == null) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Failed to create new thing."); General.Settings.ApplyCleanThingSettings(t, type); t.Move(v); t.UpdateConfiguration(); return new ThingWrapper(t); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } #endregion #region ================== Merging/Joining /// /// Joins `Sector`s, keeping lines shared by the `Sector`s. All `Sector`s will be joined with the first `Sector` in the array. /// /// `Array` of `Sector`s public void joinSectors(SectorWrapper[] sectors) { List secs = new List(); foreach (SectorWrapper sw in sectors) secs.Add(sw.Sector); JoinMergeSectors(secs, false); } /// /// Merges `Sector`s, deleting lines shared by the `Sector`s. All `Sector`s will be merged into the first `Sector` in the array. /// /// `Array` of `Sector`s public void mergeSectors(SectorWrapper[] sectors) { List secs = new List(); foreach (SectorWrapper sw in sectors) secs.Add(sw.Sector); JoinMergeSectors(secs, true); } // Helper method for joining/merging sectors. Pretty much a direct copy from sectors mode private void JoinMergeSectors(List sectors, bool removelines) { // Remove lines in betwen joining sectors? if (removelines) { // Go for all selected linedefs List selectedlines = new List(); foreach (Sector s in sectors) foreach (Sidedef sd in s.Sidedefs) if (!selectedlines.Contains(sd.Line)) selectedlines.Add(sd.Line); foreach (Linedef ld in selectedlines) { // Front and back side? if ((ld.Front != null) && (ld.Back != null)) { // Both a selected sector, but not the same? if (sectors.Contains(ld.Front.Sector) && sectors.Contains(ld.Back.Sector) && (ld.Front.Sector != ld.Back.Sector)) { // Remove this line ld.Dispose(); } } } } // Find the first sector that is not disposed //List orderedselection = new List(General.Map.Map.GetSelectedSectors(true)); Sector first = null; foreach (Sector s in sectors) if (!s.IsDisposed) { first = s; break; } // Join all selected sectors with the first for (int i = 0; i < sectors.Count; i++) if ((sectors[i] != first) && !sectors[i].IsDisposed) sectors[i].Join(first); // Update BuilderPlug.Me.ScriptRunnerForm.RunAction(() => General.Map.Map.Update()); } #endregion } }