mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-12-01 16:12:33 +00:00
5b2b149b40
Improved UDBScript to version 5: - Added Plane class - Added BlockMap, BlockEntry, and BlackMapQueryResult classes - Sector class - Added getLabelPositions method to get the position of sector labels (where tags, effects etc. are displayed) - Added support for JavaScript BigInt for UDMF fields. This means it's not necessary anymore to use UniValue to assign integers to new UDMF fields. Instead it can be done like this: sector.fields.my_int_field = 1n; - Added type information file (udbscript.d.ts)
1226 lines
35 KiB
C#
1226 lines
35 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 ================== Enums
|
|
|
|
/// <summary>
|
|
/// How geometry should be merged when geometry is stitched.
|
|
/// ```
|
|
/// UDB.Map.stitchGeometry(UDB.Map.MergeometryMode.MERGE);
|
|
/// ```
|
|
/// </summary>
|
|
/// <enum name="CLASSIC">Merge vertices only</enum>
|
|
/// <enum name="MERGE">Merge vertices and lines</enum>
|
|
/// <enum name="REPLACE">Merge vertices and lines, replacing sector geometry</enum>
|
|
[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
|
|
|
|
/// <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 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
|
|
|
|
/// <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(BuilderPlug.Me.GetVector3DFromObject(pos)));
|
|
}
|
|
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 as `MergeGeometryMode`</param>
|
|
/// <returns>`true` if successful, `false` if failed</returns>
|
|
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");
|
|
}
|
|
|
|
/// <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 = 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);
|
|
}
|
|
}
|
|
|
|
/// <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 = 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);
|
|
}
|
|
}
|
|
|
|
/// <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 = 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);
|
|
}
|
|
}
|
|
|
|
/// <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 = 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);
|
|
}
|
|
}
|
|
|
|
/// <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.
|
|
/// ```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 ]
|
|
/// ]);
|
|
/// ```
|
|
/// </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 = 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
|
|
|
|
/// <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 = 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> vertices = new List<VertexWrapper>();
|
|
|
|
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[] { };
|
|
}
|
|
|
|
/// <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()
|
|
{
|
|
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;
|
|
}
|
|
|
|
/// <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 = 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;
|
|
}
|
|
|
|
/// <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[] sectors = getSelectedSectors(true);
|
|
if (sectors.Length > 0)
|
|
return sectors;
|
|
|
|
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 = 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;
|
|
}
|
|
|
|
/// <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 `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`.
|
|
/// </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 = UDB.Map.createVertex(new Vector2D(32, 64));
|
|
/// var v2 = UDB.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 = 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);
|
|
}
|
|
}
|
|
|
|
/// <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 = 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
|
|
/// ```
|
|
/// </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.");
|
|
|
|
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
|
|
|
|
/// <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
|
|
}
|
|
}
|