UltimateZoneBuilder/Source/Plugins/UDBScript/API/MapWrapper.cs
biwa e2374102ee
UDBScript asynchronous execution (#684)
Script run by UDBScript are now executed asynchronously
2022-01-03 14:33:34 +01:00

1190 lines
34 KiB
C#

#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<http://www.gnu.org/licenses/>.
*/
#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 ================== Variables
private MapSet map;
private VisualCameraWrapper visualcamera;
private Vector2D mousemappos;
#endregion
#region ================== Properties
/// <summary>
/// `true` if the map is in Doom format, `false` if it isn't. Read-only.
/// </summary>
public bool isDoom
{
get
{
return General.Map.DOOM;
}
}
/// <summary>
/// `true` if the map is in Hexen format, `false` if it isn't. Read-only.
/// </summary>
public bool isHexen
{
get
{
return General.Map.HEXEN;
}
}
/// <summary>
/// `true` if the map is in UDMF, `false` if it isn't. Read-only.
/// </summary>
public bool isUDMF
{
get
{
return General.Map.UDMF;
}
}
/// <summary>
/// The map coordinates of the mouse position as a `Vector2D`. Read-only.
/// </summary>
public Vector2D mousePosition
{
get
{
return mousemappos;
}
}
/// <summary>
/// `VisualCamera` object with information about the position of the camera in visual mode. Read-only.
/// </summary>
public VisualCameraWrapper camera
{
get
{
return visualcamera;
}
}
#endregion
#region ================== Constructors
internal MapWrapper()
{
map = General.Map.Map;
visualcamera = new VisualCameraWrapper();
if (General.Editing.Mode is ClassicMode)
mousemappos = ((ClassicMode)General.Editing.Mode).MouseMapPos;
else
mousemappos = ((VisualMode)General.Editing.Mode).GetHitPosition();
}
#endregion
#region ================== Methods
/// <summary>
/// Returns the given point snapped to the current grid.
/// </summary>
/// <param name="pos">Point that should be snapped to the grid</param>
/// <returns>Snapped position as `Vector2D`</returns>
public Vector2DWrapper snappedToGrid(object pos)
{
try
{
return new Vector2DWrapper(General.Map.Grid.SnappedToGrid((Vector2D)BuilderPlug.Me.GetVectorFromObject(pos, false)));
}
catch (CantConvertToVectorException e)
{
throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message);
}
}
/// <summary>
/// Returns an `Array` of all `Thing`s in the map.
/// </summary>
/// <returns>`Array` of `Thing`s</returns>
public ThingWrapper[] getThings()
{
List<ThingWrapper> things = new List<ThingWrapper>(General.Map.Map.Things.Count);
foreach (Thing t in General.Map.Map.Things)
if(!t.IsDisposed)
things.Add(new ThingWrapper(t));
return things.ToArray();
}
/// <summary>
/// Returns an `Array` of all `Sector`s in the map.
/// </summary>
/// <returns>`Array` of `Sector`s</returns>
public SectorWrapper[] getSectors()
{
List<SectorWrapper> sectors = new List<SectorWrapper>(General.Map.Map.Sectors.Count);
foreach (Sector s in General.Map.Map.Sectors)
if (!s.IsDisposed)
sectors.Add(new SectorWrapper(s));
return sectors.ToArray();
}
/// <summary>
/// Returns an `Array` of all `Sidedef`s in the map.
/// </summary>
/// <returns>`Array` of `Sidedef`s</returns>
public SidedefWrapper[] getSidedefs()
{
List<SidedefWrapper> sidedefs = new List<SidedefWrapper>(General.Map.Map.Sidedefs.Count);
foreach (Sidedef sd in General.Map.Map.Sidedefs)
if (!sd.IsDisposed)
sidedefs.Add(new SidedefWrapper(sd));
return sidedefs.ToArray();
}
/// <summary>
/// Returns an `Array` of all `Linedef`s in the map.
/// </summary>
/// <returns>`Array` of `Linedef`s</returns>
public LinedefWrapper[] getLinedefs()
{
List<LinedefWrapper> linedefs = new List<LinedefWrapper>(General.Map.Map.Linedefs.Count);
foreach (Linedef ld in General.Map.Map.Linedefs)
if (!ld.IsDisposed)
linedefs.Add(new LinedefWrapper(ld));
return linedefs.ToArray();
}
/// <summary>
/// Returns an `Array` of all `Vertex` in the map.
/// </summary>
/// <returns>`Array` of `Vertex`</returns>
public VertexWrapper[] getVertices()
{
List<VertexWrapper> vertices = new List<VertexWrapper>(General.Map.Map.Vertices.Count);
foreach (Vertex v in General.Map.Map.Vertices)
if (!v.IsDisposed)
vertices.Add(new VertexWrapper(v));
return vertices.ToArray();
}
/// <summary>
/// Stitches marked geometry with non-marked geometry.
/// </summary>
/// <param name="mergemode">Mode to merge by</param>
/// <returns>`true` if successful, `false` if failed</returns>
public bool stitchGeometry(MergeGeometryMode mergemode = MergeGeometryMode.CLASSIC)
{
return General.Map.Map.StitchGeometry(mergemode);
}
/// <summary>
/// Snaps all vertices and things to the map format accuracy. Call this to ensure the vertices and things are at valid coordinates.
/// </summary>
/// <param name="usepreciseposition">`true` if decimal places defined by the map format should be used, `false` if no decimal places should be used</param>
public void snapAllToAccuracy(bool usepreciseposition = true)
{
General.Map.Map.SnapAllToAccuracy(usepreciseposition);
}
/// <summary>
/// Gets a new tag.
/// </summary>
/// <param name="usedtags">`Array` of tags to skip</param>
/// <returns>The new tag</returns>
public int getNewTag(int[] usedtags = null)
{
if (usedtags == null)
return General.Map.Map.GetNewTag();
else
return General.Map.Map.GetNewTag(usedtags.ToList());
}
/// <summary>
/// Gets multiple new tags.
/// </summary>
/// <param name="count">Number of tags to get</param>
/// <returns>`Array` of the new tags</returns>
public int[] getMultipleNewTags(int count)
{
return General.Map.Map.GetMultipleNewTags(count).ToArray();
}
/// <summary>
/// Gets the `Linedef` that's nearest to the specified position.
/// </summary>
/// <param name="pos">Position to check against</param>
/// <param name="maxrange">Maximum range (optional)</param>
/// <returns>Nearest `Linedef`</returns>
public LinedefWrapper nearestLinedef(object pos, double maxrange = double.NaN)
{
try
{
Vector2D v = (Vector2D)BuilderPlug.Me.GetVectorFromObject(pos, false);
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);
}
}
/// <summary>
/// Gets the `Thing` that's nearest to the specified position.
/// </summary>
/// <param name="pos">Position to check against</param>
/// <param name="maxrange">Maximum range (optional)</param>
/// <returns>Nearest `Linedef`</returns>
public ThingWrapper nearestThing(object pos, double maxrange = double.NaN)
{
try
{
Vector2D v = (Vector2D)BuilderPlug.Me.GetVectorFromObject(pos, false);
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);
}
}
/// <summary>
/// Gets the `Vertex` that's nearest to the specified position.
/// </summary>
/// <param name="pos">Position to check against</param>
/// <param name="maxrange">Maximum range (optional)</param>
/// <returns>Nearest `Vertex`</returns>
public VertexWrapper nearestVertex(object pos, double maxrange = double.NaN)
{
try
{
Vector2D v = (Vector2D)BuilderPlug.Me.GetVectorFromObject(pos, false);
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);
}
}
/// <summary>
/// Gets the `Sidedef` that's nearest to the specified position.
/// </summary>
/// <param name="pos">Position to check against</param>
/// <param name="maxrange">Maximum range (optional)</param>
/// <returns>Nearest `Sidedef`</returns>
public SidedefWrapper nearestSidedef(object pos)
{
try
{
Vector2D v = (Vector2D)BuilderPlug.Me.GetVectorFromObject(pos, false);
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);
}
}
/// <summary>
/// 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.
/// ```
/// Map.drawLines([
/// new Vector2D(64, 0),
/// new Vector2D(128, 0),
/// new Vector2D(128, 64),
/// new Vector2D(64, 64),
/// new Vector2D(64, 0)
/// ]);
///
/// Map.drawLines([
/// [ 0, 0 ],
/// [ 64, 0 ],
/// [ 64, 64 ],
/// [ 0, 64 ],
/// [ 0, 0 ]
/// ]);
/// ```
/// </summary>
/// <param name="data">`Array` of positions</param>
/// <returns>`true` if drawing was successful, `false` if it wasn't</returns>
public bool drawLines(object data)
{
if (!data.GetType().IsArray)
throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Data must be supplied as an array");
List<DrawnVertex> vertices = new List<DrawnVertex>();
foreach(object item in (object[])data)
{
try
{
Vector2D v = (Vector2D)BuilderPlug.Me.GetVectorFromObject(item, false);
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
/// <summary>
/// Sets the `marked` property of all map elements. Can be passed `true` to mark all map elements.
/// </summary>
/// <param name="mark">`false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true`</param>
public void clearAllMarks(bool mark=false)
{
General.Map.Map.ClearAllMarks(mark);
}
/// <summary>
/// Sets the `marked` property of all vertices. Can be passed `true` to mark all vertices.
/// </summary>
/// <param name="mark">`false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true`</param>
public void clearMarkedVertices(bool mark=false)
{
General.Map.Map.ClearMarkedVertices(mark);
}
/// <summary>
/// Sets the `marked` property of all `Thing`s. Can be passed `true` to mark all `Thing`s.
/// </summary>
/// <param name="mark">`false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true`</param>
public void clearMarkedThings(bool mark=false)
{
General.Map.Map.ClearMarkedThings(mark);
}
/// <summary>
/// Sets the `marked` property of all `Linedef`s. Can be passed `true` to mark all `Linedef`s.
/// </summary>
/// <param name="mark">`false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true`</param>
public void clearMarkeLinedefs(bool mark=false)
{
General.Map.Map.ClearMarkedLinedefs(mark);
}
/// <summary>
/// Sets the `marked` property of all `Sidedef`s. Can be passed `true` to mark all `Sidedef`s.
/// </summary>
/// <param name="mark">`false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true`</param>
public void clearMarkeSidedefs(bool mark = false)
{
General.Map.Map.ClearMarkedSidedefs(mark);
}
/// <summary>
/// Sets the `marked` property of all `Sector`s. Can be passed `true` to mark all `Sector`s.
/// </summary>
/// <param name="mark">`false` to set the `marked` property to `false` (default), `true` to set the `marked` property to `true`</param>
public void clearMarkeSectors(bool mark = false)
{
General.Map.Map.ClearMarkedSectors(mark);
}
/// <summary>
/// Inverts all marks of all map elements.
/// </summary>
public void invertAllMarks()
{
General.Map.Map.InvertAllMarks();
}
/// <summary>
/// Inverts the `marked` property of all vertices.
/// </summary>
public void invertMarkedVertices()
{
General.Map.Map.InvertMarkedVertices();
}
/// <summary>
/// Inverts the `marked` property of all `Thing`s.
/// </summary>
public void invertMarkedThings()
{
General.Map.Map.InvertMarkedThings();
}
/// <summary>
/// Inverts the `marked` property of all `Linedef`s.
/// </summary>
public void invertMarkedLinedefs()
{
General.Map.Map.InvertMarkedLinedefs();
}
/// <summary>
/// Inverts the `marked` property of all `Sidedef`s.
/// </summary>
public void invertMarkedSidedefs()
{
General.Map.Map.InvertMarkedSidedefs();
}
/// <summary>
/// Inverts the `marked` property of all `Sector`s.
/// </summary>
public void invertMarkedSectors()
{
General.Map.Map.InvertMarkedSectors();
}
/// <summary>
/// Gets all marked (default) or unmarked vertices.
/// </summary>
/// <param name="mark">`true` to get all marked vertices (default), `false` to get all unmarked vertices</param>
/// <returns></returns>
public VertexWrapper[] getMarkedVertices(bool mark=true)
{
List<VertexWrapper> vertices = new List<VertexWrapper>();
foreach (Vertex v in General.Map.Map.Vertices)
if(v.Marked == mark)
vertices.Add(new VertexWrapper(v));
return vertices.ToArray();
}
/// <summary>
/// Gets all marked (default) or unmarked `Thing`s.
/// </summary>
/// <param name="mark">`true` to get all marked `Thing`s (default), `false` to get all unmarked `Thing`s</param>
/// <returns></returns>
public ThingWrapper[] getMarkedThings(bool mark = true)
{
List<ThingWrapper> things = new List<ThingWrapper>();
foreach (Thing t in General.Map.Map.Things)
if (t.Marked == mark)
things.Add(new ThingWrapper(t));
return things.ToArray();
}
/// <summary>
/// Gets all marked (default) or unmarked `Linedef`s.
/// </summary>
/// <param name="mark">`true` to get all marked `Linedef`s (default), `false` to get all unmarked `Linedef`s</param>
/// <returns></returns>
public LinedefWrapper[] getMarkedLinedefs(bool mark = true)
{
List<LinedefWrapper> linedefs = new List<LinedefWrapper>();
foreach (Linedef ld in General.Map.Map.Linedefs)
if (ld.Marked == mark)
linedefs.Add(new LinedefWrapper(ld));
return linedefs.ToArray();
}
/// <summary>
/// Gets all marked (default) or unmarked `Sidedef`s.
/// </summary>
/// <param name="mark">`true` to get all marked `Sidedef`s (default), `false` to get all unmarked `Sidedef`s</param>
/// <returns></returns>
public SidedefWrapper[] getMarkedSidedefs(bool mark = true)
{
List<SidedefWrapper> sidedefs = new List<SidedefWrapper>();
foreach (Sidedef sd in General.Map.Map.Sidedefs)
if (sd.Marked == mark)
sidedefs.Add(new SidedefWrapper(sd));
return sidedefs.ToArray();
}
/// <summary>
/// Gets all marked (default) or unmarked `Sector`s.
/// </summary>
/// <param name="mark">`true` to get all marked `Sector`s (default), `false` to get all unmarked `Sector`s</param>
/// <returns></returns>
public SectorWrapper[] getMarkedSectors(bool mark = true)
{
List<SectorWrapper> sectors = new List<SectorWrapper>();
foreach (Sector s in General.Map.Map.Sectors)
if (s.Marked == mark)
sectors.Add(new SectorWrapper(s));
return sectors.ToArray();
}
/// <summary>
/// Marks (default) or unmarks all selected vertices.
/// </summary>
/// <param name="mark">`true` to mark all selected vertices (default), `false` to unmark</param>
public void markSelectedVertices(bool mark=true)
{
General.Map.Map.MarkSelectedVertices(true, mark);
}
/// <summary>
/// Marks (default) or unmarks all selected `Linedef`s.
/// </summary>
/// <param name="mark">`true` to mark all selected `Linedef`s (default), `false` to unmark</param>
public void markSelectedLinedefs(bool mark = true)
{
General.Map.Map.MarkSelectedLinedefs(true, mark);
}
/// <summary>
/// Marks (default) or unmarks all selected `Sector`s.
/// </summary>
/// <param name="mark">`true` to mark all selected `Sector`s (default), `false` to unmark</param>
public void markSelectedSectors(bool mark = true)
{
General.Map.Map.MarkSelectedSectors(true, mark);
}
/// <summary>
/// Marks (default) or unmarks all selected `Thing`s.
/// </summary>
/// <param name="mark">`true` to mark all selected `Thing`s (default), `false` to unmark</param>
public void markSelectedThings(bool mark = true)
{
General.Map.Map.MarkSelectedThings(true, mark);
}
#endregion
#region ================== Selected
/// <summary>
/// Gets all selected (default) or unselected vertices.
/// </summary>
/// <param name="selected">`true` to get all selected vertices, `false` to get all unselected ones</param>
/// <returns>`Array` of `Vertex`</returns>
public VertexWrapper[] getSelectedVertices(bool selected=true)
{
List<VertexWrapper> vertices = new List<VertexWrapper>();
if (General.Editing.Mode is BaseVisualMode)
{
List<Vertex> 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();
}
/// <summary>
/// Get the currently highlighted `Vertex`.
/// </summary>
/// <returns>The currently highlighted `Vertex` or `null` if no `Vertex` is highlighted</returns>
public VertexWrapper getHighlightedVertex()
{
Vertex v = General.Editing.Mode.HighlightedObject as Vertex;
if (v != null)
return new VertexWrapper(v);
return null;
}
/// <summary>
/// Gets the currently selected `Vertex`s *or*, if no `Vertex`s are selected, a currently highlighted `Vertex`.
/// </summary>
/// <returns>`Array` of `Vertex`</returns>
public VertexWrapper[] getSelectedOrHighlightedVertices()
{
if (General.Map.Map.SelectedVerticessCount > 0)
{
List<VertexWrapper> linedefs = new List<VertexWrapper>();
foreach (Vertex v in General.Map.Map.Vertices)
if (v.Selected)
linedefs.Add(new VertexWrapper(v));
return linedefs.ToArray();
}
else
{
Vertex v = General.Editing.Mode.HighlightedObject as Vertex;
if (v != null)
return new VertexWrapper[] { new VertexWrapper(v) };
}
return new VertexWrapper[] { };
}
/// <summary>
/// Gets all selected (default) or unselected `Thing`s.
/// </summary>
/// <param name="selected">`true` to get all selected `Thing`s, `false` to get all unselected ones</param>
/// <returns>`Array` of `Thing`s</returns>
public ThingWrapper[] getSelectedThings(bool selected = true)
{
List<ThingWrapper> things = new List<ThingWrapper>();
if (General.Editing.Mode is BaseVisualMode)
{
List<Thing> 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();
}
/// <summary>
/// Get the currently highlighted `Thing`.
/// </summary>
/// <returns>The currently highlighted `Thing` or `null` if no `Thing` is highlighted</returns>
public ThingWrapper getHighlightedThing()
{
Thing t = General.Editing.Mode.HighlightedObject as Thing;
if (t != null)
return new ThingWrapper(t);
return null;
}
/// <summary>
/// Gets the currently selected `Thing`s *or*, if no `Thing`s are selected, a currently highlighted `Thing`.
/// </summary>
/// <returns>`Array` of `Thing`s</returns>
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[] { };
}
/// <summary>
/// Gets all selected (default) or unselected `Sector`s.
/// </summary>
/// <param name="selected">`true` to get all selected `Sector`s, `false` to get all unselected ones</param>
/// <returns>`Array` of `Sector`s</returns>
public SectorWrapper[] getSelectedSectors(bool selected = true)
{
List<SectorWrapper> sectors = new List<SectorWrapper>();
if (General.Editing.Mode is BaseVisualMode)
{
List<Sector> 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();
}
/// <summary>
/// Get the currently highlighted `Sector`.
/// </summary>
/// <returns>The currently highlighted `Sector` or `null` if no `Sector` is highlighted</returns>
public SectorWrapper getHighlightedSector()
{
if (General.Editing.Mode is BaseVisualMode)
{
VisualSector s = General.Editing.Mode.HighlightedObject as VisualSector;
if (s != null)
return new SectorWrapper(s.Sector);
}
else
{
Sector s = General.Editing.Mode.HighlightedObject as Sector;
if (s != null)
return new SectorWrapper(s);
}
return null;
}
/// <summary>
/// Gets the currently selected `Sector`s *or*, if no `Sector`s are selected, a currently highlighted `Sector`.
/// </summary>
/// <returns>`Array` of `Sector`s</returns>
public SectorWrapper[] getSelectedOrHighlightedSectors()
{
SectorWrapper[] things = getSelectedSectors(true);
if (things.Length > 0)
return things;
SectorWrapper highlight = getHighlightedSector();
if (highlight != null)
return new SectorWrapper[] { highlight };
return new SectorWrapper[] { };
}
/// <summary>
/// Gets all selected (default) or unselected `Linedef`s.
/// </summary>
/// <param name="selected">`true` to get all selected `Linedef`s, `false` to get all unselected ones</param>
/// <returns>`Array` of `Linedef`s</returns>
public LinedefWrapper[] getSelectedLinedefs(bool selected = true)
{
List<LinedefWrapper> linedefs = new List<LinedefWrapper>();
if (General.Editing.Mode is BaseVisualMode)
{
List<Linedef> 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();
}
/// <summary>
/// Get the currently highlighted `Linedef`.
/// </summary>
/// <returns>The currently highlighted `Linedef` or `null` if no `Linedef` is highlighted</returns>
public LinedefWrapper getHighlightedLinedef()
{
if (General.Editing.Mode is BaseVisualMode)
{
Sidedef sd = General.Editing.Mode.HighlightedObject as Sidedef;
if (sd != null)
return new LinedefWrapper(sd.Line);
}
else
{
Linedef ld = General.Editing.Mode.HighlightedObject as Linedef;
if (ld != null)
return new LinedefWrapper(ld);
}
return null;
}
/// <summary>
/// Gets the currently selected `Linedef`s *or*, if no `Linede`f`s are selected, a currently highlighted `Linedef`.
/// </summary>
/// <returns>`Array` of `Linedef`s</returns>
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<LinedefWrapper> linedefs = new List<LinedefWrapper>();
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<LinedefWrapper> linedefs = new List<LinedefWrapper>();
foreach (Linedef ld in General.Map.Map.Linedefs)
if (ld.Selected)
linedefs.Add(new LinedefWrapper(ld));
return linedefs.ToArray();
}
}
*/
/// <summary>
/// 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`.
/// </summary>
/// <param name="selected">`true` to get all `Sidedef`s of all selected `Linedef`s, `false` to get all `Sidedef`s of all unselected `Linedef`s</param>
/// <returns>`Array` of `Sidedef`</returns>
public SidedefWrapper[] getSidedefsFromSelectedLinedefs(bool selected = true)
{
List<SidedefWrapper> sidedefs = new List<SidedefWrapper>();
if (General.Editing.Mode is BaseVisualMode)
{
List<Sidedef> 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();
}
/// <summary>
/// Gets the `Sidedef`s of the currently selected `Linedef`s *or*, if no `Linede`f`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`.
/// </summary>
/// <returns>`Array` of `Sidedef`s</returns>
/// <version>3</version>
public SidedefWrapper[] getSidedefsFromSelectedOrHighlightedLinedefs()
{
List<SidedefWrapper> sidedefs = new List<SidedefWrapper>(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();
}
/// <summary>
/// Clears all selected map elements.
/// </summary>
public void clearAllSelected()
{
General.Map.Map.ClearAllSelected();
}
/// <summary>
/// Clears all selected vertices.
/// </summary>
public void clearSelectedVertices()
{
General.Map.Map.ClearSelectedVertices();
}
/// <summary>
/// Clears all selected `Thing`s.
/// </summary>
public void clearSelectedThings()
{
General.Map.Map.ClearSelectedThings();
}
/// <summary>
/// Clears all selected `Sector`s.
/// </summary>
public void clearSelectedSectors()
{
General.Map.Map.ClearSelectedSectors();
}
#endregion
#region ================== Creation
/// <summary>
/// Creates a new `Vertex` at the given position. The position can be a `Vector2D` or an `Array` of two numbers.
/// ```
/// var v1 = Map.createVertex(new Vector2D(32, 64));
/// var v2 = Map.createVertex([ 32, 64 ]);
/// ```
/// </summary>
/// <param name="pos">Position where the `Vertex` should be created at</param>
/// <returns>The created `Vertex`</returns>
public VertexWrapper createVertex(object pos)
{
try
{
Vector2D v = (Vector2D)BuilderPlug.Me.GetVectorFromObject(pos, false);
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);
}
}
/// <summary>
/// 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 = Map.createThing(new Vector2D(32, 64));
/// var t2 = Map.createThing([ 32, 64 ]);
/// var t3 = Map.createThing(new Vector2D(32, 64), 3001); // Create an Imp
/// var t4 = Map.createThing([ 32, 64 ], 3001); // Create an Imp
/// ```
/// </summary>
/// <param name="pos">Position where the `Thing` should be created at</param>
/// <param name="type">Thing type (optional)</param>
/// <returns>The new `Thing`</returns>
public ThingWrapper createThing(object pos, int type=0)
{
try
{
if(type < 0)
throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Thing type can not be negative.");
object v = BuilderPlug.Me.GetVectorFromObject(pos, true);
Thing t = General.Map.Map.CreateThing();
if(t == null)
throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Failed to create new thing.");
General.Settings.ApplyCleanThingSettings(t);
if (type > 0)
t.Type = type;
if(v is Vector2D)
t.Move((Vector2D)v);
else if(v is Vector3D)
t.Move((Vector3D)v);
t.UpdateConfiguration();
return new ThingWrapper(t);
}
catch (CantConvertToVectorException e)
{
throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message);
}
}
#endregion
#region ================== Merging/Joining
/// <summary>
/// Joins `Sector`s, keeping lines shared by the `Sector`s. All `Sector`s will be joined with the first `Sector` in the array.
/// </summary>
/// <param name="sectors">`Array` of `Sector`s</param>
public void joinSectors(SectorWrapper[] sectors)
{
List<Sector> secs = new List<Sector>();
foreach (SectorWrapper sw in sectors)
secs.Add(sw.Sector);
JoinMergeSectors(secs, false);
}
/// <summary>
/// Merges `Sector`s, deleting lines shared by the `Sector`s. All `Sector`s will be merged into the first `Sector` in the array.
/// </summary>
/// <param name="sectors">`Array` of `Sector`s</param>
public void mergeSectors(SectorWrapper[] sectors)
{
List<Sector> secs = new List<Sector>();
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<Sector> sectors, bool removelines)
{
// Remove lines in betwen joining sectors?
if (removelines)
{
// Go for all selected linedefs
List<Linedef> selectedlines = new List<Linedef>();
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<Sector> orderedselection = new List<Sector>(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
}
}