Newer
Older
#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* 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.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using CodeImp.DoomBuilder.BuilderModes.Interface;
using CodeImp.DoomBuilder.Windows;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.VisualModes;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Types;
using CodeImp.DoomBuilder.Data;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "GZDB Visual Mode",
SwitchAction = "gzdbvisualmode", // Action name used to switch to this mode
ButtonImage = "VisualModeGZ.png", // Image resource name for the button
ButtonOrder = 1, // Position of the button (lower is more to the left)
ButtonGroup = "001_visual",
UseByDefault = true)]
public class BaseVisualMode : VisualMode
{
#region ================== Constants
// Object picking
private const long PICK_INTERVAL = 80;
private const float PICK_RANGE = 0.98f;
// Gravity
private const float GRAVITY = -0.06f;
#endregion
#region ================== Variables
// Gravity
private Vector3D gravity;
private float cameraflooroffset = 41f; // same as in doom
private float cameraceilingoffset = 10f;
// Object picking
private VisualPickResult target;
private long lastpicktime;
private readonly Timer selectioninfoupdatetimer; //mxd
// This keeps extra element info
private Dictionary<Sector, SectorData> sectordata;
private Dictionary<Thing, ThingData> thingdata;
private Dictionary<Vertex, VertexData> vertexdata; //mxd
//private Dictionary<Thing, EffectDynamicLight> lightdata; //mxd
// This is true when a selection was made because the action is performed
// on an object that was not selected. In this case the previous selection
// is cleared and the targeted object is temporarely selected to perform
// the action on. After the action is completed, the object is deselected.
// We keep these to determine if we need to make a new undo level
private bool selectionchanged;
private int lastundogroup;
private VisualActionResult actionresult;
private bool undocreated;
// List of selected objects when an action is performed
private List<IVisualEventReceiver> selectedobjects;
//mxd. Used in Cut/PasteSelection actions
private readonly List<ThingCopyData> copybuffer;
private Type lasthighlighttype;
//mxd. Moved here from Tools
private struct SidedefAlignJob
{
public Sidedef sidedef;
public float offsetx;
public float scaleX; //mxd
MaxED
committed
public float scaleY; //mxd
private Sidedef controlside; //mxd
public Sidedef controlSide
{
get
{
return controlside;
}
set
{
controlside = value;
ceilingheight = (controlside.Index != sidedef.Index && controlside.Line.Args[1] == 0 ? controlside.Sector.FloorHeight : controlside.Sector.CeilHeight);
}
}
private int ceilingheight; //mxd
public int ceilingHeight { get { return ceilingheight; } } //mxd
// When this is true, the previous sidedef was on the left of
// this one and the texture X offset of this sidedef can be set
// directly. When this is false, the length of this sidedef
// must be subtracted from the X offset first.
public bool forward;
}
#endregion
#region ================== Properties
public override object HighlightedObject
{
get
{
// Geometry picked?
VisualGeometry vg = target.picked as VisualGeometry;
if(vg != null)
if(vg.Sidedef != null) return vg.Sidedef;
if(vg.Sector != null) return vg.Sector;
}
// Thing picked?
VisualThing vt = target.picked as VisualThing;
if(vt != null) return vt.Thing;
public object HighlightedTarget { get { return target.picked; } } //mxd
public bool UseSelectionFromClassicMode { get { return useSelectionFromClassicMode; } } //mxd
new public IRenderer3D Renderer { get { return renderer; } }
public bool IsSingleSelection { get { return singleselection; } }
public bool SelectionChanged { get { return selectionchanged; } set { selectionchanged |= value; } }
#endregion
#region ================== Constructor / Disposer
// Constructor
public BaseVisualMode()
{
// Initialize
this.gravity = new Vector3D(0.0f, 0.0f, 0.0f);
codeimp
committed
this.selectedobjects = new List<IVisualEventReceiver>();
this.copybuffer = new List<ThingCopyData>();
this.selectioninfoupdatetimer = new Timer();
selectioninfoupdatetimer.Interval = 100;
selectioninfoupdatetimer.Tick += SelectioninfoupdatetimerOnTick;
// We have no destructor
GC.SuppressFinalize(this);
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
selectioninfoupdatetimer.Dispose(); //mxd
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods
codeimp
committed
// This calculates brightness level
codeimp
committed
internal int CalculateBrightness(int level)
codeimp
committed
{
codeimp
committed
return renderer.CalculateBrightness(level);
codeimp
committed
}
MaxED
committed
//mxd. This calculates brightness level with doom-style shading
internal int CalculateBrightness(int level, Sidedef sd)
{
return renderer.CalculateBrightness(level, sd);
}
codeimp
committed
codeimp
committed
// This adds a selected object
internal void AddSelectedObject(IVisualEventReceiver obj)
{
selectedobjects.Add(obj);
selectionchanged = true;
selectioninfoupdatetimer.Start(); //mxd
codeimp
committed
}
// This removes a selected object
internal void RemoveSelectedObject(IVisualEventReceiver obj)
{
selectedobjects.Remove(obj);
selectionchanged = true;
selectioninfoupdatetimer.Start(); //mxd
codeimp
committed
}
// This is called before an action is performed
public void PreAction(int multiselectionundogroup)
actionresult = new VisualActionResult();
PickTargetUnlocked();
// If the action is not performed on a selected object, clear the
// current selection and make a temporary selection for the target.
codeimp
committed
if((target.picked != null) && !target.picked.Selected && (BuilderPlug.Me.VisualModeClearSelection || (selectedobjects.Count == 0)))
// Single object, no selection
singleselection = true;
ClearSelection();
undocreated = false;
singleselection = false;
// Check if we should make a new undo level
// We don't want to do this if this is the same action with the same
// selection and the action wants to group the undo levels
if((lastundogroup != multiselectionundogroup) || (lastundogroup == UndoGroup.None) ||
(multiselectionundogroup == UndoGroup.None) || selectionchanged)
{
// We want to create a new undo level, but not just yet
lastundogroup = multiselectionundogroup;
undocreated = false;
}
else
// We don't want to make a new undo level (changes will be combined)
undocreated = true;
}
codeimp
committed
// Called before an action is performed. This does not make an undo level
private void PreActionNoChange()
{
actionresult = new VisualActionResult();
singleselection = false;
undocreated = false;
// This is called after an action is performed
if(!string.IsNullOrEmpty(actionresult.displaystatus))
General.Interface.DisplayStatus(StatusType.Action, actionresult.displaystatus);
// Reset changed flags
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
foreach(VisualFloor vf in bvs.ExtraFloors) vf.Changed = false;
foreach(VisualCeiling vc in bvs.ExtraCeilings) vc.Changed = false;
foreach(VisualFloor vf in bvs.ExtraBackFloors) vf.Changed = false; //mxd
foreach(VisualCeiling vc in bvs.ExtraBackCeilings) vc.Changed = false; //mxd
bvs.Floor.Changed = false;
bvs.Ceiling.Changed = false;
}
if(singleselection) ClearSelection();
UpdateChangedObjects();
ShowTargetInfo();
}
// This sets the result for an action
public void SetActionResult(VisualActionResult result)
{
actionresult = result;
}
// This sets the result for an action
public void SetActionResult(string displaystatus)
{
actionresult = new VisualActionResult {displaystatus = displaystatus};
}
// This creates an undo, when only a single selection is made
// When a multi-selection is made, the undo is created by the PreAction function
public int CreateUndo(string description, int group, int grouptag)
if(!undocreated)
{
undocreated = true;
if(singleselection)
return General.Map.UndoRedo.CreateUndo(description, this, group, grouptag);
return General.Map.UndoRedo.CreateUndo(description, this, UndoGroup.None, 0);
}
// This creates an undo, when only a single selection is made
// When a multi-selection is made, the undo is created by the PreAction function
public int CreateUndo(string description)
return CreateUndo(description, UndoGroup.None, 0);
}
// This makes a list of the selected object
codeimp
committed
private void RebuildSelectedObjectsList()
{
// Make list of selected objects
selectedobjects = new List<IVisualEventReceiver>();
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
if(vs.Value != null)
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if((bvs.Floor != null) && bvs.Floor.Selected) selectedobjects.Add(bvs.Floor);
if((bvs.Ceiling != null) && bvs.Ceiling.Selected) selectedobjects.Add(bvs.Ceiling);
foreach(Sidedef sd in vs.Key.Sidedefs)
List<VisualGeometry> sidedefgeos = bvs.GetSidedefGeometry(sd);
foreach(VisualGeometry sdg in sidedefgeos)
{
if(sdg.Selected) selectedobjects.Add((IVisualEventReceiver)sdg);
}
}
}
}
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
{
if(vt.Value != null)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
if(bvt.Selected) selectedobjects.Add(bvt);
}
if(General.Map.UDMF && General.Settings.GZShowVisualVertices)
{
foreach(KeyValuePair<Vertex, VisualVertexPair> pair in vertices)
{
if(pair.Value.CeilingVertex.Selected)
selectedobjects.Add((BaseVisualVertex)pair.Value.CeilingVertex);
if(pair.Value.FloorVertex.Selected)
selectedobjects.Add((BaseVisualVertex)pair.Value.FloorVertex);
//mxd
UpdateSelectionInfo();
//mxd. Need this to apply changes to 3d-floor even if control sector doesn't exist as BaseVisualSector
internal BaseVisualSector CreateBaseVisualSector(Sector s)
{
BaseVisualSector vs = new BaseVisualSector(this, s);
return vs;
}
// This creates a visual sector
protected override VisualSector CreateVisualSector(Sector s)
{
BaseVisualSector vs = new BaseVisualSector(this, s);
allsectors.Add(s, vs); //mxd
return vs;
}
// This creates a visual thing
protected override VisualThing CreateVisualThing(Thing t)
{
BaseVisualThing vt = new BaseVisualThing(this, t);
return vt.Setup() ? vt : null;
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
// This locks the target so that it isn't changed until unlocked
public void LockTarget()
{
locktarget = true;
}
// This unlocks the target so that is changes to the aimed geometry again
public void UnlockTarget()
{
locktarget = false;
}
// This picks a new target, if not locked
private void PickTargetUnlocked()
{
if(!locktarget) PickTarget();
}
// This picks a new target
private void PickTarget()
{
// Find the object we are aiming at
Vector3D start = General.Map.VisualCamera.Position;
Vector3D delta = General.Map.VisualCamera.Target - General.Map.VisualCamera.Position;
delta = delta.GetFixedLength(General.Settings.ViewDistance * PICK_RANGE);
VisualPickResult newtarget = PickObject(start, start + delta);
// Should we update the info on panels?
bool updateinfo = (newtarget.picked != target.picked);
// Apply new target
target = newtarget;
// Show target info
if(updateinfo) ShowTargetInfo();
}
// This shows the picked target information
public void ShowTargetInfo()
{
// Any result?
if(target.picked != null)
{
// Geometry picked?
if(target.picked is VisualGeometry)
{
VisualGeometry pickedgeo = (VisualGeometry)target.picked;
// Sidedef?
if(pickedgeo is BaseVisualGeometrySidedef)
{
BaseVisualGeometrySidedef pickedsidedef = (BaseVisualGeometrySidedef)pickedgeo;
General.Interface.ShowLinedefInfo(pickedsidedef.GetControlLinedef(), pickedsidedef.Sidedef); //mxd
}
// Sector?
else if(pickedgeo is BaseVisualGeometrySector)
{
BaseVisualGeometrySector pickedsector = (BaseVisualGeometrySector)pickedgeo;
bool isceiling = (pickedsector is VisualCeiling); //mxd
General.Interface.ShowSectorInfo(pickedsector.Level.sector, isceiling, !isceiling);
General.Interface.HideInfo();
// Thing picked?
{
VisualThing pickedthing = (VisualThing)target.picked;
General.Interface.ShowThingInfo(pickedthing.Thing);
//mxd. Vertex picked?
else if(target.picked is VisualVertex)
VisualVertex pickedvert = (VisualVertex)target.picked;
}
}
else
{
General.Interface.HideInfo();
}
}
// This updates the VisualSectors and VisualThings that have their Changed property set
private void UpdateChangedObjects()
{
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
if(vs.Value != null)
{
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if(bvs.Changed) bvs.Rebuild();
}
}
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
{
if(vt.Value != null)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
if(bvt.Changed) bvt.Rebuild();
}
if(General.Map.UDMF)
{
foreach(KeyValuePair<Vertex, VisualVertexPair> pair in vertices)
pair.Value.Update();
}
//mxd. Update event lines (still better than updating them on every frame redraw)
renderer.SetEventLines(LinksCollector.GetThingLinks(General.Map.ThingsFilter.VisibleThings, blockmap));
MaxED
committed
protected override void MoveSelectedThings(Vector2D direction, bool absoluteposition)
MaxED
committed
List<VisualThing> visualthings = GetSelectedVisualThings(true);
if(visualthings.Count == 0) return;
PreAction(UndoGroup.ThingMove);
MaxED
committed
Vector3D[] coords = new Vector3D[visualthings.Count];
for(int i = 0; i < visualthings.Count; i++)
coords[i] = visualthings[i].Thing.Position;
//move things...
MaxED
committed
Vector3D[] translatedcoords = TranslateCoordinates(coords, direction, absoluteposition);
for(int i = 0; i < visualthings.Count; i++)
BaseVisualThing t = (BaseVisualThing)visualthings[i];
MaxED
committed
t.OnMove(translatedcoords[i]);
MaxED
committed
// Things may've changed sectors...
FillBlockMap();
PostAction();
}
MaxED
committed
private static Vector3D[] TranslateCoordinates(Vector3D[] coordinates, Vector2D direction, bool absolutePosition)
if(coordinates.Length == 0) return null;
direction.x = (float)Math.Round(direction.x);
direction.y = (float)Math.Round(direction.y);
Vector3D[] translatedCoords = new Vector3D[coordinates.Length];
//move things...
if(!absolutePosition) //...relatively (that's easy)
MaxED
committed
{
int camAngle = (int)Math.Round(Angle2D.RadToDeg(General.Map.VisualCamera.AngleXY));
int sector = General.ClampAngle(camAngle - 45) / 90;
direction = direction.GetRotated(sector * Angle2D.PIHALF);
for(int i = 0; i < coordinates.Length; i++)
translatedCoords[i] = coordinates[i] + new Vector3D(direction);
return translatedCoords;
}
//...to specified location preserving relative positioning (that's harder)
if(coordinates.Length == 1) //just move it there
MaxED
committed
{
translatedCoords[0] = new Vector3D(direction.x, direction.y, coordinates[0].z);
return translatedCoords;
}
//we need some reference
float minX = coordinates[0].x;
float maxX = minX;
float minY = coordinates[0].y;
float maxY = minY;
//get bounding coordinates for selected things
for(int i = 1; i < coordinates.Length; i++)
MaxED
committed
{
if(coordinates[i].x < minX)
minX = coordinates[i].x;
else if(coordinates[i].x > maxX)
maxX = coordinates[i].x;
if(coordinates[i].y < minY)
minY = coordinates[i].y;
else if(coordinates[i].y > maxY)
maxY = coordinates[i].y;
}
Vector2D selectionCenter = new Vector2D(minX + (maxX - minX) / 2, minY + (maxY - minY) / 2);
for(int i = 0; i < coordinates.Length; i++)
translatedCoords[i] = new Vector3D((float)Math.Round(direction.x - (selectionCenter.x - coordinates[i].x)), (float)Math.Round(direction.y - (selectionCenter.y - coordinates[i].y)), (float)Math.Round(coordinates[i].z));
return translatedCoords;
}
public override void UpdateSelectionInfo()
// Collect info
int numWalls = 0;
int numFloors = 0;
int numCeilings = 0;
int numThings = 0;
int numVerts = 0;
foreach(IVisualEventReceiver obj in selectedobjects)
{
if(!obj.IsSelected()) continue;
if(obj is BaseVisualThing) numThings++;
else if(obj is BaseVisualVertex) numVerts++;
else if(obj is VisualCeiling) numCeilings++;
else if(obj is VisualFloor) numFloors++;
else if(obj is VisualMiddleSingle || obj is VisualMiddleDouble || obj is VisualLower || obj is VisualUpper || obj is VisualMiddle3D || obj is VisualMiddleBack)
numWalls++;
}
List<string> results = new List<string>();
if(numWalls > 0) results.Add(numWalls + (numWalls > 1 ? " sidedefs" : " sidedef"));
if(numFloors > 0) results.Add(numFloors + (numFloors > 1 ? " floors" : " floor"));
if(numCeilings > 0) results.Add(numCeilings + (numCeilings > 1 ? " ceilings" : " ceiling"));
if(numThings > 0) results.Add(numThings + (numThings > 1 ? " things" : " thing"));
if(numVerts > 0) results.Add(numVerts + (numVerts > 1 ? " vertices" : " vertex"));
// Display results
string result = string.Empty;
if(results.Count > 0)
result = string.Join(", ", results.ToArray());
int pos = result.LastIndexOf(",", StringComparison.Ordinal);
if(pos != -1) result = result.Remove(pos, 1).Insert(pos, " and");
result += " selected.";
General.Interface.DisplayStatus(StatusType.Selection, result);
MaxED
committed
//mxd
MaxED
committed
internal void StartRealtimeInterfaceUpdate(SelectionType selectiontype)
{
switch(selectiontype)
MaxED
committed
{
case SelectionType.All:
case SelectionType.Linedefs:
case SelectionType.Sectors:
General.Interface.OnEditFormValuesChanged += Interface_OnSectorEditFormValuesChanged;
break;
case SelectionType.Things:
General.Interface.OnEditFormValuesChanged += Interface_OnThingEditFormValuesChanged;
break;
default:
General.Interface.OnEditFormValuesChanged += Interface_OnEditFormValuesChanged;
break;
MaxED
committed
}
}
//mxd
MaxED
committed
internal void StopRealtimeInterfaceUpdate(SelectionType selectiontype)
{
switch(selectiontype)
MaxED
committed
{
case SelectionType.All:
case SelectionType.Linedefs:
case SelectionType.Sectors:
General.Interface.OnEditFormValuesChanged -= Interface_OnSectorEditFormValuesChanged;
break;
case SelectionType.Things:
General.Interface.OnEditFormValuesChanged -= Interface_OnThingEditFormValuesChanged;
break;
default:
General.Interface.OnEditFormValuesChanged -= Interface_OnEditFormValuesChanged;
break;
MaxED
committed
}
}
#region ================== Extended Methods
// This requests a sector's extra data
internal SectorData GetSectorData(Sector s)
{
// Make fresh sector data when it doesn't exist yet
if(!sectordata.ContainsKey(s))
sectordata[s] = new SectorData(this, s);
return sectordata[s];
}
//mxd. This requests a sector's extra data or null if given sector doesn't have it
internal SectorData GetSectorDataEx(Sector s)
{
return (sectordata.ContainsKey(s) ? sectordata[s] : null);
}
// This requests a things's extra data
internal ThingData GetThingData(Thing t)
{
// Make fresh sector data when it doesn't exist yet
if(!thingdata.ContainsKey(t))
thingdata[t] = new ThingData(this, t);
return thingdata[t];
}
MaxED
committed
internal VertexData GetVertexData(Vertex v)
{
if(!vertexdata.ContainsKey(v))
vertexdata[v] = new VertexData(this, v);
return vertexdata[v];
}
MaxED
committed
internal BaseVisualVertex GetVisualVertex(Vertex v, bool floor)
{
if(!vertices.ContainsKey(v))
vertices.Add(v, new VisualVertexPair(new BaseVisualVertex(this, v, false), new BaseVisualVertex(this, v, true)));
return (floor ? (BaseVisualVertex)vertices[v].FloorVertex : (BaseVisualVertex)vertices[v].CeilingVertex);
}
MaxED
committed
internal void UpdateVertexHandle(Vertex v)
{
vertices.Add(v, new VisualVertexPair(new BaseVisualVertex(this, v, false), new BaseVisualVertex(this, v, true)));
MaxED
committed
vertices[v].Changed = true;
// This rebuilds the sector data
// This requires that the blockmap is up-to-date!
internal void RebuildElementData()
{
Sector[] sectorsWithEffects = null;
MaxED
committed
if(!General.Settings.GZDoomRenderingEffects)
MaxED
committed
{
//store all sectors with effects
MaxED
committed
if(sectordata != null && sectordata.Count > 0)
{
sectorsWithEffects = new Sector[sectordata.Count];
sectordata.Keys.CopyTo(sectorsWithEffects, 0);
MaxED
committed
if(vertices != null && vertices.Count > 0)
{
foreach(IVisualEventReceiver i in selectedobjects)
{
if(i is BaseVisualVertex) RemoveSelectedObject(i);
}
}
Dictionary<int, List<Sector>> sectortags = new Dictionary<int, List<Sector>>();
sectordata = new Dictionary<Sector, SectorData>(General.Map.Map.Sectors.Count);
thingdata = new Dictionary<Thing, ThingData>(General.Map.Map.Things.Count);
//mxd. rebuild all sectors with effects
MaxED
committed
if(sectorsWithEffects != null)
{
for(int i = 0; i < sectorsWithEffects.Length; i++)
{
// The visual sector associated is now outdated
MaxED
committed
if(VisualSectorExists(sectorsWithEffects[i]))
{
BaseVisualSector vs = (BaseVisualSector)GetVisualSector(sectorsWithEffects[i]);
vs.UpdateSectorGeometry(true);
}
}
}
MaxED
committed
if(General.Map.UDMF)
{
vertexdata = new Dictionary<Vertex, VertexData>(General.Map.Map.Vertices.Count); //mxd
vertices.Clear();
}
MaxED
committed
if(!General.Settings.GZDoomRenderingEffects) return; //mxd
// Find all sector who's tag is not 0 and hash them so that we can find them quicly
foreach(Sector s in General.Map.Map.Sectors)
{
if(tag == 0) continue;
if(!sectortags.ContainsKey(tag)) sectortags[tag] = new List<Sector>();
sectortags[tag].Add(s);
}
}
// Find sectors with 3 vertices, because they can be sloped
foreach(Sector s in General.Map.Map.Sectors)
{
// ========== Thing vertex slope, vertices with UDMF vertex offsets ==========
if(s.Sidedefs.Count == 3)
{
MaxED
committed
if(General.Map.UDMF) GetSectorData(s).AddEffectVertexOffset(); //mxd
List<Thing> slopeceilingthings = new List<Thing>(3);
List<Thing> slopefloorthings = new List<Thing>(3);
MaxED
committed
MaxED
committed
foreach(Sidedef sd in s.Sidedefs)
{
Vertex v = sd.IsFront ? sd.Line.End : sd.Line.Start;
// Check if a thing is at this vertex
VisualBlockEntry b = blockmap.GetBlock(blockmap.GetBlockCoordinates(v.Position));
MaxED
committed
foreach(Thing t in b.Things)
{
if((Vector2D)t.Position == v.Position)
{
switch(t.Type)
MaxED
committed
{
case 1504: slopefloorthings.Add(t); break;
case 1505: slopeceilingthings.Add(t); break;
}
MaxED
committed
if(slopefloorthings.Count > 0)
{
SectorData sd = GetSectorData(s);
sd.AddEffectThingVertexSlope(slopefloorthings, true);
}
// Slope any ceiling vertices?
MaxED
committed
if(slopeceilingthings.Count > 0)
{
SectorData sd = GetSectorData(s);
sd.AddEffectThingVertexSlope(slopeceilingthings, false);
}
}
}
// Find interesting linedefs (such as line slopes)
foreach(Linedef l in General.Map.Map.Linedefs)
{
MaxED
committed
switch(l.Action)
MaxED
committed
// ========== Plane Align (see http://zdoom.org/wiki/Plane_Align) ==========
case 181:
if(((l.Args[0] == 1) || (l.Args[1] == 1)) && (l.Front != null))
{
SectorData sd = GetSectorData(l.Front.Sector);
sd.AddEffectLineSlope(l);
}
if(((l.Args[0] == 2) || (l.Args[1] == 2)) && (l.Back != null))
{
SectorData sd = GetSectorData(l.Back.Sector);
sd.AddEffectLineSlope(l);
}
break;
MaxED
committed
// ========== Plane Copy (mxd) (see http://zdoom.org/wiki/Plane_Copy) ==========
case 118:
MaxED
committed
{
MaxED
committed
//check the flags...
bool floorCopyToBack = false;
bool floorCopyToFront = false;
bool ceilingCopyToBack = false;
bool ceilingCopyToFront = false;
if(l.Args[4] > 0 && l.Args[4] != 3 && l.Args[4] != 12)
{
floorCopyToBack = (l.Args[4] & 1) == 1;
floorCopyToFront = (l.Args[4] & 2) == 2;
ceilingCopyToBack = (l.Args[4] & 4) == 4;
ceilingCopyToFront = (l.Args[4] & 8) == 8;
}
MaxED
committed
// Copy slope to front sector
if(l.Front != null)
MaxED
committed
{
MaxED
committed
if( (l.Args[0] > 0 || l.Args[1] > 0) || (l.Back != null && (floorCopyToFront || ceilingCopyToFront)) )
{
SectorData sd = GetSectorData(l.Front.Sector);
sd.AddEffectPlaneClopySlope(l, true);
}
MaxED
committed
// Copy slope to back sector
if(l.Back != null)
MaxED
committed
{
MaxED
committed
if( (l.Args[2] > 0 || l.Args[3] > 0) || (l.Front != null && (floorCopyToBack || ceilingCopyToBack)) )
{
SectorData sd = GetSectorData(l.Back.Sector);
sd.AddEffectPlaneClopySlope(l, false);
}
MaxED
committed
break;
// ========== Sector 3D floor (see http://zdoom.org/wiki/Sector_Set3dFloor) ==========
case 160:
if(l.Front != null)
MaxED
committed
//mxd. Added hi-tag/line ID check
int sectortag = (General.Map.UDMF || (l.Args[1] & (int)Effect3DFloor.FloorTypes.HiTagIsLineID) != 0) ? l.Args[0] : l.Args[0] + (l.Args[4] << 8);
MaxED
committed
if(sectortags.ContainsKey(sectortag))
{
List<Sector> sectors = sectortags[sectortag];
foreach(Sector s in sectors)
{
SectorData sd = GetSectorData(s);
sd.AddEffect3DFloor(l);
}
}
MaxED
committed
break;
// ========== Transfer Brightness (see http://zdoom.org/wiki/ExtraFloor_LightOnly) =========
case 50:
if(l.Front != null && sectortags.ContainsKey(l.Args[0]))
MaxED
committed
List<Sector> sectors = sectortags[l.Args[0]];
foreach(Sector s in sectors)
{
SectorData sd = GetSectorData(s);
sd.AddEffectBrightnessLevel(l);
}
MaxED
committed
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
break;
// ========== mxd. Transfer Floor Brightness (see http://www.zdoom.org/w/index.php?title=Transfer_FloorLight) =========
case 210:
if(l.Front != null && sectortags.ContainsKey(l.Args[0]))
{
List<Sector> sectors = sectortags[l.Args[0]];
foreach(Sector s in sectors)
{
SectorData sd = GetSectorData(s);
sd.AddEffectTransferFloorBrightness(l);
}
}
break;
// ========== mxd. Transfer Ceiling Brightness (see http://www.zdoom.org/w/index.php?title=Transfer_CeilingLight) =========
case 211:
if(l.Front != null && sectortags.ContainsKey(l.Args[0]))
{
List<Sector> sectors = sectortags[l.Args[0]];
foreach(Sector s in sectors)
{
SectorData sd = GetSectorData(s);
sd.AddEffectTransferCeilingBrightness(l);
}
}
break;
}
}
// Find interesting things (such as sector slopes)
foreach(Thing t in General.Map.Map.Things)
{
MaxED
committed
switch(t.Type)
MaxED
committed
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// ========== Copy slope ==========
case 9511:
case 9510:
t.DetermineSector(blockmap);
if(t.Sector != null)
{
SectorData sd = GetSectorData(t.Sector);
sd.AddEffectCopySlope(t);
}
break;
// ========== Thing line slope ==========
case 9501:
case 9500:
t.DetermineSector(blockmap);
if(t.Sector != null)
{
SectorData sd = GetSectorData(t.Sector);
sd.AddEffectThingLineSlope(t);
}
break;
// ========== Thing slope ==========
case 9503:
case 9502:
t.DetermineSector(blockmap);
if(t.Sector != null)