mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-31 04:40:55 +00:00
Visual Mode: added "Lower Floor/Ceiling to adjacent sector" and "Raise Floor/Ceiling to adjacent sector" actions.
UDMF texture offsets are now used when splitting a linedef in UDMF map format. Some changes in auto texture alignment of newly drawn lines.
This commit is contained in:
parent
c6378809d5
commit
4a6897a6ed
4 changed files with 416 additions and 72 deletions
|
@ -1431,50 +1431,15 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
//mxd
|
//mxd
|
||||||
if(autoAlignTextureOffsets) {
|
if(autoAlignTextureOffsets && !General.Map.UDMF) {
|
||||||
//Auto-align new lines
|
//Auto-align new lines
|
||||||
if(newlines.Count > 1) {
|
if(newlines.Count > 1) {
|
||||||
float curLength = 0f;
|
|
||||||
float totalLength = 0f;
|
float totalLength = 0f;
|
||||||
|
|
||||||
foreach(Linedef l in newlines)
|
foreach(Linedef l in newlines)
|
||||||
totalLength += l.Length;
|
totalLength += l.Length;
|
||||||
|
|
||||||
bool reversed = newlines[0].End != newlines[1].Start;
|
autoAlignTexturesOnSides(newlines, totalLength, (newlines[0].End != newlines[1].Start));
|
||||||
|
|
||||||
foreach(Linedef l in newlines) {
|
|
||||||
if(l.Front != null) {
|
|
||||||
ImageData texture = null;
|
|
||||||
|
|
||||||
if(l.Front.MiddleRequired() && l.Front.MiddleTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Front.MiddleTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Front.MiddleTexture);
|
|
||||||
} else if(l.Front.HighRequired() && l.Front.HighTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Front.HighTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Front.HighTexture);
|
|
||||||
} else if(l.Front.LowRequired() && l.Front.LowTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Front.LowTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Front.LowTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(texture != null)
|
|
||||||
l.Front.OffsetX = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength));// % texture.Width);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(l.Back != null) {
|
|
||||||
ImageData texture = null;
|
|
||||||
|
|
||||||
if(l.Back.MiddleRequired() && l.Back.MiddleTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Back.MiddleTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Back.MiddleTexture);
|
|
||||||
} else if(l.Back.HighRequired() && l.Back.HighTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Back.HighTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Back.HighTexture);
|
|
||||||
} else if(l.Back.LowRequired() && l.Back.LowTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Back.LowTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Back.LowTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(texture != null)
|
|
||||||
l.Back.OffsetX = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength));// % texture.Width);
|
|
||||||
}
|
|
||||||
|
|
||||||
curLength += l.Length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1491,38 +1456,6 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(Linedef l in changedLines) {
|
|
||||||
if(l.Front != null) {
|
|
||||||
ImageData texture = null;
|
|
||||||
|
|
||||||
if(l.Front.MiddleRequired() && l.Front.MiddleTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Front.MiddleTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Front.MiddleTexture);
|
|
||||||
} else if(l.Front.HighRequired() && l.Front.HighTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Front.HighTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Front.HighTexture);
|
|
||||||
} else if(l.Front.LowRequired() && l.Front.LowTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Front.LowTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Front.LowTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (texture != null)
|
|
||||||
l.Front.OffsetX %= texture.Width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(l.Back != null) {
|
|
||||||
ImageData texture = null;
|
|
||||||
|
|
||||||
if(l.Back.MiddleRequired() && l.Back.MiddleTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Back.MiddleTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Back.MiddleTexture);
|
|
||||||
} else if(l.Back.HighRequired() && l.Back.HighTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Back.HighTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Back.HighTexture);
|
|
||||||
} else if(l.Back.LowRequired() && l.Back.LowTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Back.LowTexture)) {
|
|
||||||
texture = General.Map.Data.GetFlatImage(l.Back.LowTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (texture != null)
|
|
||||||
l.Back.OffsetX %= texture.Width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark new geometry only
|
// Mark new geometry only
|
||||||
General.Map.Map.ClearMarkedLinedefs(false);
|
General.Map.Map.ClearMarkedLinedefs(false);
|
||||||
General.Map.Map.ClearMarkedVertices(false);
|
General.Map.Map.ClearMarkedVertices(false);
|
||||||
|
@ -1532,6 +1465,45 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
private static void autoAlignTexturesOnSides(List<Linedef> lines, float totalLength, bool reversed) {
|
||||||
|
float curLength = 0f;
|
||||||
|
|
||||||
|
foreach(Linedef l in lines) {
|
||||||
|
if(l.Front != null) {
|
||||||
|
ImageData texture = null;
|
||||||
|
|
||||||
|
if(l.Front.MiddleRequired() && l.Front.MiddleTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Front.MiddleTexture)) {
|
||||||
|
texture = General.Map.Data.GetFlatImage(l.Front.MiddleTexture);
|
||||||
|
} else if(l.Front.HighRequired() && l.Front.HighTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Front.HighTexture)) {
|
||||||
|
texture = General.Map.Data.GetFlatImage(l.Front.HighTexture);
|
||||||
|
} else if(l.Front.LowRequired() && l.Front.LowTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Front.LowTexture)) {
|
||||||
|
texture = General.Map.Data.GetFlatImage(l.Front.LowTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(texture != null)
|
||||||
|
l.Front.OffsetX = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(l.Back != null) {
|
||||||
|
ImageData texture = null;
|
||||||
|
|
||||||
|
if(l.Back.MiddleRequired() && l.Back.MiddleTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Back.MiddleTexture)) {
|
||||||
|
texture = General.Map.Data.GetFlatImage(l.Back.MiddleTexture);
|
||||||
|
} else if(l.Back.HighRequired() && l.Back.HighTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Back.HighTexture)) {
|
||||||
|
texture = General.Map.Data.GetFlatImage(l.Back.HighTexture);
|
||||||
|
} else if(l.Back.LowRequired() && l.Back.LowTexture.Length > 1 && General.Map.Data.GetFlatExists(l.Back.LowTexture)) {
|
||||||
|
texture = General.Map.Data.GetFlatImage(l.Back.LowTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(texture != null)
|
||||||
|
l.Back.OffsetX = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
curLength += l.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -1777,7 +1749,7 @@ namespace CodeImp.DoomBuilder.Geometry
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Thing Alignment (mxd)
|
#region ================== Thing Alignment (mxd)
|
||||||
|
|
||||||
public static bool TryAlignThingToLine(Thing t, Linedef l) {
|
public static bool TryAlignThingToLine(Thing t, Linedef l) {
|
||||||
if(l.Back == null) {
|
if(l.Back == null) {
|
||||||
|
|
|
@ -27,6 +27,8 @@ using CodeImp.DoomBuilder.Rendering;
|
||||||
using SlimDX.Direct3D9;
|
using SlimDX.Direct3D9;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using CodeImp.DoomBuilder.IO;
|
using CodeImp.DoomBuilder.IO;
|
||||||
|
using CodeImp.DoomBuilder.Types;
|
||||||
|
using CodeImp.DoomBuilder.Data;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -816,7 +818,8 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
nsd.Marked = front.Marked;
|
nsd.Marked = front.Marked;
|
||||||
|
|
||||||
// Make texture offset adjustments
|
// Make texture offset adjustments
|
||||||
nsd.OffsetX += (int)Vector2D.Distance(this.start.Position, this.end.Position);
|
if(nsd.OffsetX != 0 || !General.Map.UDMF) //mxd
|
||||||
|
nsd.OffsetX += (int)Vector2D.Distance(this.start.Position, this.end.Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy back sidedef if exists
|
// Copy back sidedef if exists
|
||||||
|
@ -828,7 +831,18 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
nsd.Marked = back.Marked;
|
nsd.Marked = back.Marked;
|
||||||
|
|
||||||
// Make texture offset adjustments
|
// Make texture offset adjustments
|
||||||
back.OffsetX += (int)Vector2D.Distance(nl.start.Position, nl.end.Position);
|
//mxd
|
||||||
|
int distance = (int)Vector2D.Distance(nl.start.Position, nl.end.Position);
|
||||||
|
if(back.OffsetX != 0 || General.Map.UDMF)
|
||||||
|
if(distance != 0) applyTextureOffsetUDMF(back, distance);
|
||||||
|
else
|
||||||
|
back.OffsetX += distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
//mxd. Both sides of line are required, so we do it here...
|
||||||
|
if(nl.Front != null && General.Map.UDMF) {
|
||||||
|
int distance = (int)Vector2D.Distance(this.start.Position, this.end.Position);
|
||||||
|
if(distance != 0) applyTextureOffsetUDMF(nl.Front, distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return result
|
// Return result
|
||||||
|
@ -1055,6 +1069,73 @@ namespace CodeImp.DoomBuilder.Map
|
||||||
colorPresetIndex = -1;
|
colorPresetIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
private void applyTextureOffsetUDMF(Sidedef side, int distance) {
|
||||||
|
float scaleTop = side.Fields.GetValue("scalex_top", 1.0f);
|
||||||
|
float scaleMid = side.Fields.GetValue("scalex_mid", 1.0f);
|
||||||
|
float scaleLow = side.Fields.GetValue("scalex_bottom", 1.0f);
|
||||||
|
|
||||||
|
//top
|
||||||
|
if(side.HighTexture.Length > 1 && General.Map.Data.GetFlatExists(side.HighTexture)) {
|
||||||
|
ImageData texture = General.Map.Data.GetFlatImage(side.HighTexture);
|
||||||
|
|
||||||
|
if(side.Fields.ContainsKey("offsetx_top")) {
|
||||||
|
float value = side.Fields.GetValue("offsetx_top", 0f);
|
||||||
|
float offset = (float)(Math.Round((value + distance) * scaleTop) % texture.Width);
|
||||||
|
|
||||||
|
if(offset != 0)
|
||||||
|
side.Fields["offsetx_top"].Value = offset;
|
||||||
|
else
|
||||||
|
side.Fields.Remove("offsetx_top");
|
||||||
|
} else if(side.HighRequired()) {
|
||||||
|
float offset = (float)(Math.Round(distance * scaleTop) % texture.Width);
|
||||||
|
|
||||||
|
if(offset != 0)
|
||||||
|
side.Fields.Add("offsetx_top", new UniValue(UniversalType.Float, offset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//middle
|
||||||
|
if(side.MiddleTexture.Length > 1 && General.Map.Data.GetFlatExists(side.MiddleTexture)){
|
||||||
|
ImageData texture = General.Map.Data.GetFlatImage(side.MiddleTexture);
|
||||||
|
|
||||||
|
if(side.Fields.ContainsKey("offsetx_mid")) {
|
||||||
|
float value = side.Fields.GetValue("offsetx_mid", 0f);
|
||||||
|
float offset = (float)(Math.Round((value + distance) * scaleMid) % texture.Width);
|
||||||
|
|
||||||
|
if(offset != 0)
|
||||||
|
side.Fields["offsetx_mid"].Value = offset;
|
||||||
|
else
|
||||||
|
side.Fields.Remove("offsetx_mid");
|
||||||
|
} else if(side.MiddleRequired()) {
|
||||||
|
float offset = (float)(Math.Round(distance * scaleMid) % texture.Width);
|
||||||
|
|
||||||
|
if(offset != 0)
|
||||||
|
side.Fields.Add("offsetx_mid", new UniValue(UniversalType.Float, offset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//bottom
|
||||||
|
if(side.LowTexture.Length > 1 && General.Map.Data.GetFlatExists(side.LowTexture)){
|
||||||
|
ImageData texture = General.Map.Data.GetFlatImage(side.LowTexture);
|
||||||
|
|
||||||
|
if(side.Fields.ContainsKey("offsetx_bottom")) {
|
||||||
|
float value = side.Fields.GetValue("offsetx_bottom", 0f);
|
||||||
|
float offset = (float)(Math.Round((value + distance) * scaleLow) % texture.Width);
|
||||||
|
|
||||||
|
if(offset != 0)
|
||||||
|
side.Fields["offsetx_bottom"].Value = offset;
|
||||||
|
else
|
||||||
|
side.Fields.Remove("offsetx_bottom");
|
||||||
|
} else if(side.LowRequired()) {
|
||||||
|
float offset = (float)(Math.Round(distance * scaleLow) % texture.Width);
|
||||||
|
|
||||||
|
if(offset != 0)
|
||||||
|
side.Fields.Add("offsetx_bottom", new UniValue(UniversalType.Float, offset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// String representation
|
// String representation
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -494,6 +494,30 @@ raisesector1
|
||||||
repeat = true;
|
repeat = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
lowersectortonearest
|
||||||
|
{
|
||||||
|
title = "Lower Floor/Ceiling to adjacent sector";
|
||||||
|
category = "visual";
|
||||||
|
description = "Lowers the targeted or selected floors/ceilings to match the height of adjacent sector. Also drops selected things to floor.";
|
||||||
|
allowkeys = true;
|
||||||
|
allowmouse = true;
|
||||||
|
allowscroll = true;
|
||||||
|
default = 34; //PgDn
|
||||||
|
}
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
raisesectortonearest
|
||||||
|
{
|
||||||
|
title = "Raise Floor/Ceiling to adjacent sector";
|
||||||
|
category = "visual";
|
||||||
|
description = "Raises the targeted or selected floors/ceilings to match the height of adjacent sector. Also aligns selected things to ceiling.";
|
||||||
|
allowkeys = true;
|
||||||
|
allowmouse = true;
|
||||||
|
allowscroll = true;
|
||||||
|
default = 33; //PgUp
|
||||||
|
}
|
||||||
|
|
||||||
showvisualthings
|
showvisualthings
|
||||||
{
|
{
|
||||||
title = "Show Things";
|
title = "Show Things";
|
||||||
|
|
|
@ -1624,6 +1624,273 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
PostAction();
|
PostAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
[BeginAction("raisesectortonearest")]
|
||||||
|
public void RaiseSectorToNearest() {
|
||||||
|
Dictionary<Sector, VisualFloor> floors = new Dictionary<Sector, VisualFloor>();
|
||||||
|
Dictionary<Sector, VisualCeiling> ceilings = new Dictionary<Sector, VisualCeiling>();
|
||||||
|
List<BaseVisualThing> things = new List<BaseVisualThing>();
|
||||||
|
bool undoGroupCreated = false;
|
||||||
|
string alignFailDescription = string.Empty;
|
||||||
|
|
||||||
|
//get selection
|
||||||
|
if(selectedobjects.Count == 0) {
|
||||||
|
IVisualEventReceiver i = (target.picked as IVisualEventReceiver);
|
||||||
|
if(i is VisualFloor) {
|
||||||
|
VisualFloor vf = i as VisualFloor;
|
||||||
|
floors.Add(vf.Level.sector, vf);
|
||||||
|
} else if(i is VisualCeiling) {
|
||||||
|
VisualCeiling vc = i as VisualCeiling;
|
||||||
|
ceilings.Add(vc.Level.sector, vc);
|
||||||
|
} else if(i is BaseVisualThing) {
|
||||||
|
things.Add(i as BaseVisualThing);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach(IVisualEventReceiver i in selectedobjects) {
|
||||||
|
if(i is VisualFloor) {
|
||||||
|
VisualFloor vf = i as VisualFloor;
|
||||||
|
floors.Add(vf.Level.sector, vf);
|
||||||
|
} else if(i is VisualCeiling) {
|
||||||
|
VisualCeiling vc = i as VisualCeiling;
|
||||||
|
ceilings.Add(vc.Level.sector, vc);
|
||||||
|
} else if(i is BaseVisualThing) {
|
||||||
|
things.Add(i as BaseVisualThing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//process floors...
|
||||||
|
int maxSelectedHeight = int.MinValue;
|
||||||
|
int minSelectedCeilingHeight = int.MaxValue;
|
||||||
|
int targetHeight = int.MaxValue;
|
||||||
|
|
||||||
|
//get maximum floor height from selection
|
||||||
|
foreach(KeyValuePair<Sector, VisualFloor> group in floors) {
|
||||||
|
if(group.Key.FloorHeight > maxSelectedHeight)
|
||||||
|
maxSelectedHeight = group.Key.FloorHeight;
|
||||||
|
|
||||||
|
if(group.Key.CeilHeight < minSelectedCeilingHeight)
|
||||||
|
minSelectedCeilingHeight = group.Key.CeilHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get next higher floor from surrounding unselected sectors
|
||||||
|
foreach(KeyValuePair<Sector, VisualFloor> group in floors) {
|
||||||
|
foreach(Sidedef side in group.Key.Sidedefs) {
|
||||||
|
if(side.Other == null || ceilings.ContainsKey(side.Other.Sector) || floors.ContainsKey(side.Other.Sector))
|
||||||
|
continue;
|
||||||
|
if(side.Other.Sector.FloorHeight > maxSelectedHeight && side.Other.Sector.FloorHeight < targetHeight && side.Other.Sector.FloorHeight <= minSelectedCeilingHeight)
|
||||||
|
targetHeight = side.Other.Sector.FloorHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//change floor height
|
||||||
|
if(targetHeight != int.MaxValue) {
|
||||||
|
PreAction(UndoGroup.SectorHeightChange);
|
||||||
|
undoGroupCreated = true;
|
||||||
|
|
||||||
|
foreach(KeyValuePair<Sector, VisualFloor> group in floors) {
|
||||||
|
if(targetHeight != group.Key.FloorHeight)
|
||||||
|
group.Value.OnChangeTargetHeight(targetHeight - group.Key.FloorHeight);
|
||||||
|
}
|
||||||
|
} else if(floors.Count > 0) {
|
||||||
|
alignFailDescription = floors.Count > 1 ? "floors" : "floor";
|
||||||
|
}
|
||||||
|
|
||||||
|
//ceilings...
|
||||||
|
maxSelectedHeight = int.MinValue;
|
||||||
|
targetHeight = int.MaxValue;
|
||||||
|
|
||||||
|
//get highest ceiling height from selection
|
||||||
|
foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) {
|
||||||
|
if(group.Key.CeilHeight > maxSelectedHeight)
|
||||||
|
maxSelectedHeight = group.Key.CeilHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get next higher ceiling from surrounding unselected sectors
|
||||||
|
foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) {
|
||||||
|
foreach(Sidedef side in group.Key.Sidedefs) {
|
||||||
|
if(side.Other == null || ceilings.ContainsKey(side.Other.Sector) || floors.ContainsKey(side.Other.Sector))
|
||||||
|
continue;
|
||||||
|
if(side.Other.Sector.CeilHeight < targetHeight && side.Other.Sector.CeilHeight > maxSelectedHeight)
|
||||||
|
targetHeight = side.Other.Sector.CeilHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//change ceiling height
|
||||||
|
if(targetHeight != int.MaxValue) {
|
||||||
|
if(!undoGroupCreated) {
|
||||||
|
PreAction(UndoGroup.SectorHeightChange);
|
||||||
|
undoGroupCreated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) {
|
||||||
|
if(targetHeight != group.Key.CeilHeight)
|
||||||
|
group.Value.OnChangeTargetHeight(targetHeight - group.Key.CeilHeight);
|
||||||
|
}
|
||||||
|
} else if(ceilings.Count > 0) {
|
||||||
|
if(!string.IsNullOrEmpty(alignFailDescription))
|
||||||
|
alignFailDescription += " and ";
|
||||||
|
|
||||||
|
alignFailDescription += ceilings.Count > 1 ? "ceilings" : "ceiling";
|
||||||
|
}
|
||||||
|
|
||||||
|
//and things. Just align them to ceiling
|
||||||
|
if(General.Map.FormatInterface.HasThingHeight) {
|
||||||
|
foreach(BaseVisualThing vt in things) {
|
||||||
|
if(vt.Thing.Sector == null) continue;
|
||||||
|
ThingTypeInfo ti = General.Map.Data.GetThingInfo(vt.Thing.Type);
|
||||||
|
int zvalue = (int)(vt.Thing.Sector.FloorHeight + vt.Thing.Position.z);
|
||||||
|
|
||||||
|
if(zvalue != vt.Thing.Sector.CeilHeight - ti.Height) {
|
||||||
|
if(!undoGroupCreated) {
|
||||||
|
PreAction(UndoGroup.SectorHeightChange);
|
||||||
|
undoGroupCreated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vt.OnChangeTargetHeight((int)(vt.Thing.Sector.CeilHeight - ti.Height) - zvalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(alignFailDescription))
|
||||||
|
General.Interface.DisplayStatus(StatusType.Warning, "Unable to align selected " + alignFailDescription + "!");
|
||||||
|
|
||||||
|
PostAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
[BeginAction("lowersectortonearest")]
|
||||||
|
public void LowerSectorToNearest() {
|
||||||
|
Dictionary<Sector, VisualFloor> floors = new Dictionary<Sector, VisualFloor>();
|
||||||
|
Dictionary<Sector, VisualCeiling> ceilings = new Dictionary<Sector, VisualCeiling>();
|
||||||
|
List<BaseVisualThing> things = new List<BaseVisualThing>();
|
||||||
|
bool undoGroupCreated = false;
|
||||||
|
string alignFailDescription = string.Empty;
|
||||||
|
|
||||||
|
//get selection
|
||||||
|
if(selectedobjects.Count == 0) {
|
||||||
|
IVisualEventReceiver i = (target.picked as IVisualEventReceiver);
|
||||||
|
if(i is VisualFloor) {
|
||||||
|
VisualFloor vf = i as VisualFloor;
|
||||||
|
floors.Add(vf.Level.sector, vf);
|
||||||
|
} else if(i is VisualCeiling) {
|
||||||
|
VisualCeiling vc = i as VisualCeiling;
|
||||||
|
ceilings.Add(vc.Level.sector, vc);
|
||||||
|
} else if(i is BaseVisualThing) {
|
||||||
|
things.Add(i as BaseVisualThing);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
foreach(IVisualEventReceiver i in selectedobjects) {
|
||||||
|
if(i is VisualFloor) {
|
||||||
|
VisualFloor vf = i as VisualFloor;
|
||||||
|
floors.Add(vf.Level.sector, vf);
|
||||||
|
} else if(i is VisualCeiling) {
|
||||||
|
VisualCeiling vc = i as VisualCeiling;
|
||||||
|
ceilings.Add(vc.Level.sector, vc);
|
||||||
|
} else if(i is BaseVisualThing) {
|
||||||
|
things.Add(i as BaseVisualThing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//process floors...
|
||||||
|
int minSelectedHeight = int.MaxValue;
|
||||||
|
int targetHeight = int.MinValue;
|
||||||
|
|
||||||
|
//get minimum floor height from selection
|
||||||
|
foreach(KeyValuePair<Sector, VisualFloor> group in floors) {
|
||||||
|
if(group.Key.FloorHeight < minSelectedHeight)
|
||||||
|
minSelectedHeight = group.Key.FloorHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get next floor lower height from surrounding unselected sectors
|
||||||
|
foreach(KeyValuePair<Sector, VisualFloor> group in floors){
|
||||||
|
foreach(Sidedef side in group.Key.Sidedefs) {
|
||||||
|
if(side.Other == null || ceilings.ContainsKey(side.Other.Sector) || floors.ContainsKey(side.Other.Sector))
|
||||||
|
continue;
|
||||||
|
if(side.Other.Sector.FloorHeight > targetHeight && side.Other.Sector.FloorHeight < minSelectedHeight)
|
||||||
|
targetHeight = side.Other.Sector.FloorHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//change floor height
|
||||||
|
if(targetHeight != int.MinValue) {
|
||||||
|
PreAction(UndoGroup.SectorHeightChange);
|
||||||
|
undoGroupCreated = true;
|
||||||
|
|
||||||
|
foreach(KeyValuePair<Sector, VisualFloor> group in floors) {
|
||||||
|
if(targetHeight != group.Key.FloorHeight)
|
||||||
|
group.Value.OnChangeTargetHeight(targetHeight - group.Key.FloorHeight);
|
||||||
|
}
|
||||||
|
} else if(floors.Count > 0) {
|
||||||
|
alignFailDescription = floors.Count > 1 ? "floors" : "floor";
|
||||||
|
}
|
||||||
|
|
||||||
|
//ceilings...
|
||||||
|
minSelectedHeight = int.MaxValue;
|
||||||
|
int maxSelectedFloorHeight = int.MinValue;
|
||||||
|
targetHeight = int.MinValue;
|
||||||
|
|
||||||
|
//get minimum ceiling and maximum floor heights from selection
|
||||||
|
foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) {
|
||||||
|
if(group.Key.CeilHeight < minSelectedHeight)
|
||||||
|
minSelectedHeight = group.Key.CeilHeight;
|
||||||
|
|
||||||
|
if(group.Key.FloorHeight > maxSelectedFloorHeight)
|
||||||
|
maxSelectedFloorHeight = group.Key.FloorHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get next lower ceiling height from surrounding unselected sectors
|
||||||
|
foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) {
|
||||||
|
foreach(Sidedef side in group.Key.Sidedefs) {
|
||||||
|
if(side.Other == null || ceilings.ContainsKey(side.Other.Sector) || floors.ContainsKey(side.Other.Sector))
|
||||||
|
continue;
|
||||||
|
if(side.Other.Sector.CeilHeight > targetHeight && side.Other.Sector.CeilHeight < minSelectedHeight && side.Other.Sector.CeilHeight >= maxSelectedFloorHeight)
|
||||||
|
targetHeight = side.Other.Sector.CeilHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//change ceiling height
|
||||||
|
if(targetHeight != int.MinValue) {
|
||||||
|
if(!undoGroupCreated) {
|
||||||
|
PreAction(UndoGroup.SectorHeightChange);
|
||||||
|
undoGroupCreated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) {
|
||||||
|
if(targetHeight != group.Key.CeilHeight)
|
||||||
|
group.Value.OnChangeTargetHeight(targetHeight - group.Key.CeilHeight);
|
||||||
|
}
|
||||||
|
} else if(ceilings.Count > 0) {
|
||||||
|
if(!string.IsNullOrEmpty(alignFailDescription))
|
||||||
|
alignFailDescription += " and ";
|
||||||
|
|
||||||
|
alignFailDescription += ceilings.Count > 1 ? "ceilings" : "ceiling";
|
||||||
|
}
|
||||||
|
|
||||||
|
//and things. Just drop them to ground
|
||||||
|
if(General.Map.FormatInterface.HasThingHeight){
|
||||||
|
foreach(BaseVisualThing vt in things) {
|
||||||
|
if(vt.Thing.Sector == null) continue;
|
||||||
|
ThingTypeInfo ti = General.Map.Data.GetThingInfo(vt.Thing.Type);
|
||||||
|
|
||||||
|
if(vt.Thing.Position.z != 0){
|
||||||
|
if(!undoGroupCreated) {
|
||||||
|
PreAction(UndoGroup.SectorHeightChange);
|
||||||
|
undoGroupCreated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vt.OnChangeTargetHeight((int)-vt.Thing.Position.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(alignFailDescription))
|
||||||
|
General.Interface.DisplayStatus(StatusType.Warning, "Unable to align selected " + alignFailDescription + "!");
|
||||||
|
|
||||||
|
PostAction();
|
||||||
|
}
|
||||||
|
|
||||||
[BeginAction("showvisualthings")]
|
[BeginAction("showvisualthings")]
|
||||||
public void ShowVisualThings()
|
public void ShowVisualThings()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue