2009-04-19 18:07:22 +00:00
#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 CodeImp.DoomBuilder.Config ;
2014-03-19 13:03:47 +00:00
using CodeImp.DoomBuilder.Data ;
2009-04-19 18:07:22 +00:00
using CodeImp.DoomBuilder.Geometry ;
using System.Drawing ;
using CodeImp.DoomBuilder.IO ;
#endregion
namespace CodeImp.DoomBuilder.Map
{
2016-04-09 23:18:39 +00:00
public sealed class Linedef : SelectableElement , IMultiTaggedMapElement
2009-04-19 18:07:22 +00:00
{
#region = = = = = = = = = = = = = = = = = = Constants
2020-06-22 14:37:32 +00:00
public const double SIDE_POINT_DISTANCE = 0.01 ;
2009-04-19 18:07:22 +00:00
public const int NUM_ARGS = 5 ;
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
// Map
private MapSet map ;
// List items
private LinkedListNode < Linedef > startvertexlistitem ;
private LinkedListNode < Linedef > endvertexlistitem ;
private LinkedListNode < Linedef > selecteditem ;
// Vertices
private Vertex start ;
private Vertex end ;
// Sidedefs
private Sidedef front ;
private Sidedef back ;
// Cache
private bool updateneeded ;
2020-05-21 12:20:02 +00:00
private double lengthsq ;
private double lengthsqinv ;
private double length ;
private double lengthinv ;
private double angle ;
2009-04-19 18:07:22 +00:00
private RectangleF rect ;
2009-06-11 21:21:20 +00:00
private bool impassableflag ;
2009-04-19 18:07:22 +00:00
// Properties
private Dictionary < string , bool > flags ;
private int action ;
private int activate ;
2015-07-27 21:35:42 +00:00
private List < int > tags ; //mxd
2009-04-19 18:07:22 +00:00
private int [ ] args ;
2009-05-06 14:50:17 +00:00
private bool frontinterior ; // for drawing only
2013-03-18 13:52:27 +00:00
private int colorPresetIndex ; //mxd
2009-04-19 18:07:22 +00:00
// Clone
private int serializedindex ;
2019-12-20 04:12:39 +00:00
// Rendering
private int lastProcessed ;
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
public MapSet Map { get { return map ; } }
public Vertex Start { get { return start ; } }
public Vertex End { get { return end ; } }
public Sidedef Front { get { return front ; } }
public Sidedef Back { get { return back ; } }
public Line2D Line { get { return new Line2D ( start . Position , end . Position ) ; } }
2009-06-11 21:21:20 +00:00
internal Dictionary < string , bool > Flags { get { return flags ; } }
2013-03-18 13:52:27 +00:00
public int Action { get { return action ; } set { BeforePropsChange ( ) ; action = value ; UpdateColorPreset ( ) ; } }
public int Activate { get { return activate ; } set { BeforePropsChange ( ) ; activate = value ; UpdateColorPreset ( ) ; } }
2015-07-27 21:35:42 +00:00
public int Tag { get { return tags [ 0 ] ; } set { BeforePropsChange ( ) ; tags [ 0 ] = value ; if ( ( value < General . Map . FormatInterface . MinTag ) | | ( value > General . Map . FormatInterface . MaxTag ) ) throw new ArgumentOutOfRangeException ( "Tag" , "Invalid tag number" ) ; } } //mxd
2015-07-28 15:04:21 +00:00
public List < int > Tags { get { return tags ; } set { BeforePropsChange ( ) ; tags = value ; } } //mxd
2020-05-21 12:20:02 +00:00
public double LengthSq { get { return lengthsq ; } }
public double Length { get { return length ; } }
public double LengthInv { get { return lengthinv ; } }
public double Angle { get { return angle ; } }
2009-04-19 18:07:22 +00:00
public int AngleDeg { get { return ( int ) ( angle * Angle2D . PIDEG ) ; } }
public RectangleF Rect { get { return rect ; } }
public int [ ] Args { get { return args ; } }
internal int SerializedIndex { get { return serializedindex ; } set { serializedindex = value ; } }
2019-12-20 04:12:39 +00:00
internal int LastProcessed { get { return lastProcessed ; } set { lastProcessed = value ; } }
internal bool FrontInterior { get { return frontinterior ; } set { frontinterior = value ; } }
2009-06-11 21:21:20 +00:00
internal bool ImpassableFlag { get { return impassableflag ; } }
2013-05-27 12:20:15 +00:00
internal int ColorPresetIndex { get { return colorPresetIndex ; } } //mxd
2013-07-29 08:50:50 +00:00
internal bool ExtraFloorFlag ; //mxd
2009-06-11 21:21:20 +00:00
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// Constructor
2009-06-05 19:03:56 +00:00
internal Linedef ( MapSet map , int listindex , Vertex start , Vertex end )
2009-04-19 18:07:22 +00:00
{
// Initialize
Removed "Paste Properties Options" action.
Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action.
Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them.
Changed, Paste Properties Special window: only options relevant to current map format are now displayed.
Changed, Paste Properties Special window, UDMF: all UI-managed options are now available.
Fixed: MAPINFO parser was unable to process "include" directives.
Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection.
Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode.
Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time.
Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map.
Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled.
Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category.
Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll.
Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format.
Internal: merged methods from UDMFTools into UniFields, removed UDMFTools.
Updated Inno Setup script (added VC++ 2008 SP1 distributive).
Updated ZDoom_DECORATE.cfg (A_CheckBlock).
Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
this . elementtype = MapElementType . LINEDEF ; //mxd
2009-04-19 18:07:22 +00:00
this . map = map ;
2009-06-05 19:03:56 +00:00
this . listindex = listindex ;
2009-04-19 18:07:22 +00:00
this . updateneeded = true ;
this . args = new int [ NUM_ARGS ] ;
2015-07-27 21:35:42 +00:00
this . tags = new List < int > { 0 } ; //mxd
2014-02-26 14:11:06 +00:00
this . flags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-03-18 13:52:27 +00:00
this . colorPresetIndex = - 1 ; //mxd
2009-04-19 18:07:22 +00:00
// Attach to vertices
this . start = start ;
2009-06-11 21:21:20 +00:00
this . startvertexlistitem = start . AttachLinedefP ( this ) ;
2009-04-19 18:07:22 +00:00
this . end = end ;
2009-06-11 21:21:20 +00:00
this . endvertexlistitem = end . AttachLinedefP ( this ) ;
if ( map = = General . Map . Map )
General . Map . UndoRedo . RecAddLinedef ( this ) ;
2019-01-14 18:07:08 +00:00
2009-04-19 18:07:22 +00:00
// We have no destructor
GC . SuppressFinalize ( this ) ;
}
2009-06-11 21:21:20 +00:00
2009-04-19 18:07:22 +00:00
// Disposer
public override void Dispose ( )
{
// Not already disposed?
if ( ! isdisposed )
{
// Already set isdisposed so that changes can be prohibited
isdisposed = true ;
2009-06-11 21:21:20 +00:00
// Dispose sidedefs
if ( ( front ! = null ) & & map . AutoRemove ) front . Dispose ( ) ; else AttachFrontP ( null ) ;
if ( ( back ! = null ) & & map . AutoRemove ) back . Dispose ( ) ; else AttachBackP ( null ) ;
if ( map = = General . Map . Map )
General . Map . UndoRedo . RecRemLinedef ( this ) ;
2009-04-19 18:07:22 +00:00
// Remove from main list
2009-06-05 19:03:56 +00:00
map . RemoveLinedef ( listindex ) ;
2009-06-11 21:21:20 +00:00
2009-04-19 18:07:22 +00:00
// Detach from vertices
2009-06-11 21:21:20 +00:00
if ( startvertexlistitem ! = null ) start . DetachLinedefP ( startvertexlistitem ) ;
2009-04-19 18:07:22 +00:00
startvertexlistitem = null ;
2009-06-11 21:21:20 +00:00
start = null ;
if ( endvertexlistitem ! = null ) end . DetachLinedefP ( endvertexlistitem ) ;
2009-04-19 18:07:22 +00:00
endvertexlistitem = null ;
2009-06-11 21:21:20 +00:00
end = null ;
2009-04-19 18:07:22 +00:00
// Clean up
start = null ;
end = null ;
front = null ;
back = null ;
map = null ;
2015-09-16 20:22:20 +00:00
//mxd. Restore isdisposed so base classes can do their disposal job
isdisposed = false ;
2009-04-19 18:07:22 +00:00
// Clean up base
base . Dispose ( ) ;
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Management
2009-06-11 21:21:20 +00:00
// Call this before changing properties
protected override void BeforePropsChange ( )
{
if ( map = = General . Map . Map )
General . Map . UndoRedo . RecPrpLinedef ( this ) ;
}
// Serialize / deserialize (passive: doesn't record)
2013-03-18 13:52:27 +00:00
new internal void ReadWrite ( IReadWriteStream s )
2009-04-19 18:07:22 +00:00
{
2010-08-15 13:45:43 +00:00
if ( ! s . IsWriting )
{
BeforePropsChange ( ) ;
updateneeded = true ;
}
2009-06-11 21:21:20 +00:00
2009-04-19 18:07:22 +00:00
base . ReadWrite ( s ) ;
if ( s . IsWriting )
{
s . wInt ( flags . Count ) ;
foreach ( KeyValuePair < string , bool > f in flags )
{
s . wString ( f . Key ) ;
s . wBool ( f . Value ) ;
}
}
else
{
int c ; s . rInt ( out c ) ;
2014-02-26 14:11:06 +00:00
flags = new Dictionary < string , bool > ( c , StringComparer . Ordinal ) ;
2009-04-19 18:07:22 +00:00
for ( int i = 0 ; i < c ; i + + )
{
string t ; s . rString ( out t ) ;
bool b ; s . rBool ( out b ) ;
flags . Add ( t , b ) ;
}
}
s . rwInt ( ref action ) ;
s . rwInt ( ref activate ) ;
2015-07-27 21:35:42 +00:00
//mxd
if ( s . IsWriting )
{
s . wInt ( tags . Count ) ;
2015-12-28 15:01:53 +00:00
foreach ( int tag in tags ) s . wInt ( tag ) ;
2015-07-27 21:35:42 +00:00
}
else
{
int c ; s . rInt ( out c ) ;
tags = new List < int > ( c ) ;
for ( int i = 0 ; i < c ; i + + )
{
int t ; s . rInt ( out t ) ;
tags . Add ( t ) ;
}
}
2009-04-19 18:07:22 +00:00
for ( int i = 0 ; i < NUM_ARGS ; i + + ) s . rwInt ( ref args [ i ] ) ;
2013-03-18 13:52:27 +00:00
//mxd
2014-12-29 09:19:20 +00:00
if ( ! s . IsWriting ) UpdateColorPreset ( ) ;
2009-04-19 18:07:22 +00:00
}
// This sets new start vertex
public void SetStartVertex ( Vertex v )
{
2009-06-11 21:21:20 +00:00
if ( map = = General . Map . Map )
General . Map . UndoRedo . RecRefLinedefStart ( this ) ;
2009-04-19 18:07:22 +00:00
// Change start
2009-06-11 21:21:20 +00:00
if ( startvertexlistitem ! = null ) start . DetachLinedefP ( startvertexlistitem ) ;
2009-04-19 18:07:22 +00:00
startvertexlistitem = null ;
start = v ;
2009-06-11 21:21:20 +00:00
if ( start ! = null ) startvertexlistitem = start . AttachLinedefP ( this ) ;
2009-04-19 18:07:22 +00:00
this . updateneeded = true ;
}
// This sets new end vertex
public void SetEndVertex ( Vertex v )
{
2009-06-11 21:21:20 +00:00
if ( map = = General . Map . Map )
General . Map . UndoRedo . RecRefLinedefEnd ( this ) ;
2009-04-19 18:07:22 +00:00
// Change end
2009-06-11 21:21:20 +00:00
if ( endvertexlistitem ! = null ) end . DetachLinedefP ( endvertexlistitem ) ;
2009-04-19 18:07:22 +00:00
endvertexlistitem = null ;
end = v ;
2009-06-11 21:21:20 +00:00
if ( end ! = null ) endvertexlistitem = end . AttachLinedefP ( this ) ;
2009-04-19 18:07:22 +00:00
this . updateneeded = true ;
}
2009-06-07 10:26:06 +00:00
// This detaches a vertex
2009-06-11 21:21:20 +00:00
internal void DetachVertexP ( Vertex v )
2009-06-07 10:26:06 +00:00
{
if ( v = = start )
2009-06-11 21:21:20 +00:00
{
if ( startvertexlistitem ! = null ) start . DetachLinedefP ( startvertexlistitem ) ;
startvertexlistitem = null ;
start = null ;
}
2009-06-07 10:26:06 +00:00
else if ( v = = end )
2009-06-11 21:21:20 +00:00
{
if ( endvertexlistitem ! = null ) end . DetachLinedefP ( endvertexlistitem ) ;
endvertexlistitem = null ;
end = null ;
}
2009-06-07 10:26:06 +00:00
else
throw new Exception ( "Specified Vertex is not attached to this Linedef." ) ;
}
2009-04-19 18:07:22 +00:00
// This copies all properties to another line
2016-01-11 13:00:52 +00:00
public void CopyPropertiesTo ( Linedef l )
2009-04-19 18:07:22 +00:00
{
2009-06-11 21:21:20 +00:00
l . BeforePropsChange ( ) ;
2009-04-19 18:07:22 +00:00
// Copy properties
l . action = action ;
l . args = ( int [ ] ) args . Clone ( ) ;
l . flags = new Dictionary < string , bool > ( flags ) ;
2015-07-27 21:35:42 +00:00
l . tags = new List < int > ( tags ) ; //mxd
2009-04-19 18:07:22 +00:00
l . updateneeded = true ;
l . activate = activate ;
2009-06-11 21:21:20 +00:00
l . impassableflag = impassableflag ;
2013-03-18 13:52:27 +00:00
l . UpdateColorPreset ( ) ; //mxd
2009-04-19 18:07:22 +00:00
base . CopyPropertiesTo ( l ) ;
}
// This attaches a sidedef on the front
2009-06-11 21:21:20 +00:00
internal void AttachFront ( Sidedef s )
2009-04-19 18:07:22 +00:00
{
2009-06-11 21:21:20 +00:00
if ( map = = General . Map . Map )
General . Map . UndoRedo . RecRefLinedefFront ( this ) ;
// Attach and recalculate
AttachFrontP ( s ) ;
}
// Passive version, does not record the change
internal void AttachFrontP ( Sidedef s )
{
// Attach and recalculate
front = s ;
if ( front ! = null ) front . SetLinedefP ( this ) ;
updateneeded = true ;
2009-04-19 18:07:22 +00:00
}
// This attaches a sidedef on the back
2009-06-11 21:21:20 +00:00
internal void AttachBack ( Sidedef s )
2009-04-19 18:07:22 +00:00
{
2009-06-11 21:21:20 +00:00
if ( map = = General . Map . Map )
General . Map . UndoRedo . RecRefLinedefBack ( this ) ;
// Attach and recalculate
AttachBackP ( s ) ;
}
// Passive version, does not record the change
internal void AttachBackP ( Sidedef s )
{
// Attach and recalculate
back = s ;
if ( back ! = null ) back . SetLinedefP ( this ) ;
updateneeded = true ;
2009-04-19 18:07:22 +00:00
}
// This detaches a sidedef from the front
2009-06-11 21:21:20 +00:00
internal void DetachSidedefP ( Sidedef s )
2009-04-19 18:07:22 +00:00
{
// Sidedef is on the front?
if ( front = = s )
{
// Remove sidedef reference
2009-06-11 21:21:20 +00:00
if ( front ! = null ) front . SetLinedefP ( null ) ;
2009-04-19 18:07:22 +00:00
front = null ;
updateneeded = true ;
}
// Sidedef is on the back?
else if ( back = = s )
{
// Remove sidedef reference
2009-06-11 21:21:20 +00:00
if ( back ! = null ) back . SetLinedefP ( null ) ;
2009-04-19 18:07:22 +00:00
back = null ;
updateneeded = true ;
}
2009-06-11 21:21:20 +00:00
//else throw new Exception("Specified Sidedef is not attached to this Linedef.");
2009-04-19 18:07:22 +00:00
}
// This updates the line when changes have been made
public void UpdateCache ( )
{
// Update if needed
if ( updateneeded )
{
// Delta vector
Vector2D delta = end . Position - start . Position ;
// Recalculate values
lengthsq = delta . GetLengthSq ( ) ;
2020-05-22 19:39:18 +00:00
length = Math . Sqrt ( lengthsq ) ;
2020-06-22 14:37:32 +00:00
if ( length > 0.0 ) lengthinv = 1.0 / length ; else lengthinv = 1.0 / 0.0000000001 ;
if ( lengthsq > 0.0 ) lengthsqinv = 1.0 / lengthsq ; else lengthsqinv = 1.0 / 0.0000000001 ;
2009-04-19 18:07:22 +00:00
angle = delta . GetAngle ( ) ;
2020-05-21 12:20:02 +00:00
double l = Math . Min ( start . Position . x , end . Position . x ) ;
double t = Math . Min ( start . Position . y , end . Position . y ) ;
double r = Math . Max ( start . Position . x , end . Position . x ) ;
double b = Math . Max ( start . Position . y , end . Position . y ) ;
rect = new RectangleF ( ( float ) l , ( float ) t , ( float ) ( r - l ) , ( float ) ( b - t ) ) ;
2009-04-19 18:07:22 +00:00
2009-06-11 21:21:20 +00:00
// Cached flags
impassableflag = IsFlagSet ( General . Map . Config . ImpassableFlag ) ;
2013-03-18 13:52:27 +00:00
//mxd. Color preset
UpdateColorPreset ( ) ;
2009-06-11 21:21:20 +00:00
2009-04-19 18:07:22 +00:00
// Updated
updateneeded = false ;
}
}
// This flags the line needs an update because it moved
public void NeedUpdate ( )
{
// Update this line
updateneeded = true ;
// Update sectors as well
if ( front ! = null ) front . Sector . UpdateNeeded = true ;
if ( back ! = null ) back . Sector . UpdateNeeded = true ;
}
// This translates the flags and activations into UDMF fields
2014-12-29 09:19:20 +00:00
internal void TranslateToUDMF ( Type previousmapformatinterfacetype )
2009-04-19 18:07:22 +00:00
{
// First make a single integer with all bits from activation and flags
int bits = activate ;
2014-02-21 14:42:12 +00:00
int flagbit ;
2009-04-19 18:07:22 +00:00
foreach ( KeyValuePair < string , bool > f in flags )
if ( int . TryParse ( f . Key , out flagbit ) & & f . Value ) bits | = flagbit ;
// Now make the new flags
flags . Clear ( ) ;
2013-06-05 11:12:44 +00:00
2013-06-06 10:22:58 +00:00
//mxd. Add default activation flag if needed
if ( action ! = 0 & & activate = = 0 & & ! string . IsNullOrEmpty ( General . Map . Config . DefaultLinedefActivationFlag ) )
flags [ General . Map . Config . DefaultLinedefActivationFlag ] = true ;
2013-06-05 11:12:44 +00:00
2009-04-19 18:07:22 +00:00
foreach ( FlagTranslation f in General . Map . Config . LinedefFlagsTranslation )
{
// Flag found in bits?
if ( ( bits & f . Flag ) = = f . Flag )
{
// Add fields and remove bits
bits & = ~ f . Flag ;
for ( int i = 0 ; i < f . Fields . Count ; i + + )
flags [ f . Fields [ i ] ] = f . FieldValues [ i ] ;
}
else
{
// Add fields with inverted value
2014-12-03 23:15:26 +00:00
for ( int i = 0 ; i < f . Fields . Count ; i + + )
{
2013-06-05 11:12:44 +00:00
if ( ! flags . ContainsKey ( f . Fields [ i ] ) ) //mxd
flags [ f . Fields [ i ] ] = ! f . FieldValues [ i ] ;
}
2009-04-19 18:07:22 +00:00
}
}
2013-05-27 12:20:15 +00:00
2014-12-29 09:19:20 +00:00
//mxd. Hexen -> UDMF action translation. Hardcoded for now...
if ( previousmapformatinterfacetype = = typeof ( HexenMapSetIO ) )
{
2015-12-28 15:01:53 +00:00
switch ( Action )
2014-12-29 09:19:20 +00:00
{
case 121 : //Line_SetIdentification
//Convert arg0 to tag
2015-07-27 21:35:42 +00:00
tags [ 0 ] = args [ 0 ] + args [ 4 ] * 256 ;
2014-12-29 09:19:20 +00:00
//Convert arg1 to flags
ConvertArgToFlags ( 1 ) ;
//clear action and arguments
action = 0 ;
2015-12-28 15:01:53 +00:00
for ( int i = 0 ; i < args . Length ; i + + ) args [ i ] = 0 ;
2014-12-29 09:19:20 +00:00
break ;
case 208 : //TranslucentLine
//Convert arg0 to tag
2015-07-27 21:35:42 +00:00
tags [ 0 ] = args [ 0 ] ;
2014-12-29 09:19:20 +00:00
//Convert arg3 to flags
ConvertArgToFlags ( 3 ) ;
break ;
case 1 : ConvertArgToTag ( 3 , true ) ; break ; //Polyobj_StartLine
case 5 : ConvertArgToTag ( 4 , true ) ; break ; //Polyobj_ExplicitLine
case 181 : ConvertArgToTag ( 2 , true ) ; break ; //Plane_Align
case 215 : ConvertArgToTag ( 0 , true ) ; break ; //Teleport_Line
case 222 : ConvertArgToTag ( 0 , false ) ; break ; //Scroll_Texture_Model
case 160 : //Sector_3DFloor
// Convert to UDMF
2015-12-28 15:01:53 +00:00
if ( ( args [ 1 ] & 8 ) = = 8 ) // arg4 is LineID?
2014-12-29 09:19:20 +00:00
{
2015-07-27 21:35:42 +00:00
tags [ 0 ] = args [ 4 ] ;
2014-12-29 09:19:20 +00:00
args [ 1 ] & = ~ 8 ; // Unset flag
}
else // It's sector's HiTag then
{
args [ 0 ] + = args [ 4 ] * 256 ;
}
// Clear arg
args [ 4 ] = 0 ;
break ;
}
}
2013-05-27 12:20:15 +00:00
//mxd. Update cached flags
impassableflag = IsFlagSet ( General . Map . Config . ImpassableFlag ) ;
2014-12-29 09:19:20 +00:00
// Update color preset
UpdateColorPreset ( ) ;
2009-04-19 18:07:22 +00:00
}
// This translates UDMF fields back into the normal flags and activations
internal void TranslateFromUDMF ( )
{
2014-09-16 20:26:42 +00:00
//mxd. Clear UDMF-related properties
this . Fields . Clear ( ) ;
ExtraFloorFlag = false ;
2009-04-19 18:07:22 +00:00
// Make copy of the flags
Dictionary < string , bool > oldfields = new Dictionary < string , bool > ( flags ) ;
// Make the flags
flags . Clear ( ) ;
foreach ( KeyValuePair < string , string > f in General . Map . Config . LinedefFlags )
{
// Flag must be numeric
2014-02-21 14:42:12 +00:00
int flagbit ;
2009-04-19 18:07:22 +00:00
if ( int . TryParse ( f . Key , out flagbit ) )
{
foreach ( FlagTranslation ft in General . Map . Config . LinedefFlagsTranslation )
{
if ( ft . Flag = = flagbit )
{
// Only set this flag when the fields match
bool fieldsmatch = true ;
for ( int i = 0 ; i < ft . Fields . Count ; i + + )
{
if ( ! oldfields . ContainsKey ( ft . Fields [ i ] ) | | ( oldfields [ ft . Fields [ i ] ] ! = ft . FieldValues [ i ] ) )
{
fieldsmatch = false ;
break ;
}
}
// Field match? Then add the flag.
if ( fieldsmatch )
{
flags . Add ( f . Key , true ) ;
break ;
}
}
}
}
}
// Make the activation
foreach ( LinedefActivateInfo a in General . Map . Config . LinedefActivates )
{
bool foundactivation = false ;
foreach ( FlagTranslation ft in General . Map . Config . LinedefFlagsTranslation )
{
if ( ft . Flag = = a . Index )
{
// Only set this activation when the fields match
bool fieldsmatch = true ;
for ( int i = 0 ; i < ft . Fields . Count ; i + + )
{
if ( ! oldfields . ContainsKey ( ft . Fields [ i ] ) | | ( oldfields [ ft . Fields [ i ] ] ! = ft . FieldValues [ i ] ) )
{
fieldsmatch = false ;
break ;
}
}
// Field match? Then add the flag.
if ( fieldsmatch )
{
activate = a . Index ;
foundactivation = true ;
break ;
}
}
}
if ( foundactivation ) break ;
}
2013-05-27 12:20:15 +00:00
2014-12-29 09:19:20 +00:00
//mxd. UDMF -> Hexen action translation. Hardcoded for now...
2015-12-28 15:01:53 +00:00
if ( General . Map . FormatInterface is HexenMapSetIO )
2014-12-29 09:19:20 +00:00
{
2015-12-28 15:01:53 +00:00
switch ( action )
2014-12-29 09:19:20 +00:00
{
case 208 : //TranslucentLine
//Convert tag to arg0
2015-07-27 21:35:42 +00:00
if ( tags [ 0 ] < General . Map . FormatInterface . MinArgument | | tags [ 0 ] > General . Map . FormatInterface . MaxArgument )
2014-12-29 09:19:20 +00:00
{
2016-11-26 00:02:56 +00:00
string message = "Linedef " + Index + ": unable to convert Tag (" + tags [ 0 ] + ") to LineID because it's outside of supported argument range [" + General . Map . FormatInterface . MinArgument + ".." + General . Map . FormatInterface . MaxArgument + "]." ;
General . ErrorLogger . Add ( new MapElementErrorItem ( ErrorType . Warning , this , message ) ) ;
2014-12-29 09:19:20 +00:00
}
else
{
2015-07-27 21:35:42 +00:00
args [ 0 ] = tags [ 0 ] ;
2014-12-29 09:19:20 +00:00
}
//Convert flags to arg3
ConvertFlagsToArg ( oldfields , 3 ) ;
break ;
case 1 : ConvertTagToArg ( 3 ) ; break ; //Polyobj_StartLine
case 5 : ConvertTagToArg ( 4 ) ; break ; //Polyobj_ExplicitLine
case 181 : ConvertTagToArg ( 2 ) ; break ; //Plane_Align
case 215 : ConvertTagToArg ( 0 ) ; break ; //Teleport_Line
case 222 : ConvertTagToArg ( 0 ) ; break ; //Scroll_Texture_Model
case 160 : //Sector_3DFloor
2014-12-29 18:15:53 +00:00
if ( args [ 0 ] > General . Map . FormatInterface . MaxArgument ) // Split sector tag?
2014-12-29 09:19:20 +00:00
{
int hitag = args [ 0 ] / 256 ;
int lotag = args [ 0 ] - hitag ;
args [ 0 ] = lotag ;
args [ 4 ] = hitag ;
2015-07-27 21:35:42 +00:00
if ( tags [ 0 ] ! = 0 )
2014-12-29 09:19:20 +00:00
{
2016-11-26 00:02:56 +00:00
string message = "Linedef " + Index + ": unable to convert Tag (" + tags [ 0 ] + ") to LineID, because target sector tag (arg0) is greater than " + General . Map . FormatInterface . MaxArgument + "." ;
General . ErrorLogger . Add ( new MapElementErrorItem ( ErrorType . Warning , this , message ) ) ;
2014-12-29 09:19:20 +00:00
}
}
2014-12-29 18:15:53 +00:00
else if ( args [ 0 ] < General . Map . FormatInterface . MinArgument )
2014-12-29 09:19:20 +00:00
{
2016-11-26 00:02:56 +00:00
string message = "Linedef " + Index + ": unable to convert arg0 (" + args [ 0 ] + "), because it's outside of supported argument range [" + General . Map . FormatInterface . MinArgument + ".." + General . Map . FormatInterface . MaxArgument + "]." ;
General . ErrorLogger . Add ( new MapElementErrorItem ( ErrorType . Warning , this , message ) ) ;
2014-12-29 18:15:53 +00:00
}
2015-07-27 21:35:42 +00:00
else if ( tags [ 0 ] > General . Map . FormatInterface . MinArgument ) // Convert to LineID?
2014-12-29 18:15:53 +00:00
{
2015-07-27 21:35:42 +00:00
if ( tags [ 0 ] > General . Map . FormatInterface . MaxArgument )
2014-12-29 09:19:20 +00:00
{
2016-11-26 00:02:56 +00:00
string message = "Linedef " + Index + ": unable to convert Tag (" + tags [ 0 ] + ") to LineID, because linedef tag is greater than " + General . Map . FormatInterface . MaxArgument + "." ;
General . ErrorLogger . Add ( new MapElementErrorItem ( ErrorType . Warning , this , message ) ) ;
2014-12-29 09:19:20 +00:00
}
else
{
2015-07-27 21:35:42 +00:00
args [ 4 ] = tags [ 0 ] ;
2014-12-29 18:15:53 +00:00
args [ 1 ] | = 8 ; // Add "Use arg4 as LineID" flag
2014-12-29 09:19:20 +00:00
}
}
break ;
default : // Convert tag to Line_SetIdentification?
2015-07-27 21:35:42 +00:00
if ( tags [ 0 ] > General . Map . FormatInterface . MinArgument )
2014-12-29 09:19:20 +00:00
{
2015-12-28 15:01:53 +00:00
if ( action ! = 0 )
2014-12-29 09:19:20 +00:00
{
2016-11-26 00:02:56 +00:00
string message = "Linedef " + Index + ": unable to convert Tag (" + tags [ 0 ] + ") to LineID, because linedef already has an action." ;
General . ErrorLogger . Add ( new MapElementErrorItem ( ErrorType . Warning , this , message ) ) ;
2014-12-29 09:19:20 +00:00
}
else // Convert to Line_SetIdentification
{
2015-07-27 21:35:42 +00:00
int hiid = tags [ 0 ] / 256 ;
int loid = tags [ 0 ] - hiid ;
2014-12-29 09:19:20 +00:00
action = 121 ;
args [ 0 ] = loid ;
args [ 4 ] = hiid ;
ConvertFlagsToArg ( oldfields , 1 ) ;
}
2014-12-29 18:15:53 +00:00
}
2015-07-27 21:35:42 +00:00
else if ( tags [ 0 ] < General . Map . FormatInterface . MinArgument )
2014-12-29 18:15:53 +00:00
{
2016-11-26 00:02:56 +00:00
string message = "Linedef " + Index + ": unable to convert Tag (" + tags [ 0 ] + ") to LineID, because it's outside of supported argument range [" + General . Map . FormatInterface . MinArgument + ".." + General . Map . FormatInterface . MaxArgument + "]." ;
General . ErrorLogger . Add ( new MapElementErrorItem ( ErrorType . Warning , this , message ) ) ;
2014-12-29 09:19:20 +00:00
}
break ;
}
// Clear tag
2015-07-27 21:35:42 +00:00
tags [ 0 ] = 0 ;
2014-12-29 09:19:20 +00:00
}
2013-05-27 12:20:15 +00:00
//mxd. Update cached flags
impassableflag = IsFlagSet ( General . Map . Config . ImpassableFlag ) ;
2014-12-29 09:19:20 +00:00
// Update color preset
UpdateColorPreset ( ) ;
}
//mxd
private void ConvertArgToTag ( int argnum , bool cleararg )
{
// Convert arg to tag
2015-07-27 21:35:42 +00:00
tags [ 0 ] = args [ argnum ] ;
2014-12-29 09:19:20 +00:00
// Clear obsolete arg
if ( cleararg ) args [ argnum ] = 0 ;
}
//mxd
private void ConvertTagToArg ( int argnum )
{
2015-07-27 21:35:42 +00:00
if ( tags [ 0 ] < General . Map . FormatInterface . MinArgument | | tags [ 0 ] > General . Map . FormatInterface . MaxArgument )
2014-12-29 09:19:20 +00:00
{
2015-07-27 21:35:42 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + Index + ": unable to convert Tag (" + tags [ 0 ] + ") to LineID because it's outside of supported argument range [" + General . Map . FormatInterface . MinArgument + ".." + General . Map . FormatInterface . MaxArgument + "]." ) ;
2014-12-29 09:19:20 +00:00
}
else
{
2015-07-27 21:35:42 +00:00
args [ argnum ] = tags [ 0 ] ;
2014-12-29 09:19:20 +00:00
}
}
//mxd
private void ConvertArgToFlags ( int argnum )
{
if ( args [ argnum ] = = 0 ) return ;
// Convert to flags
if ( ( args [ argnum ] & 1 ) = = 1 ) flags [ "zoneboundary" ] = true ;
if ( ( args [ argnum ] & 2 ) = = 2 ) flags [ "jumpover" ] = true ;
if ( ( args [ argnum ] & 4 ) = = 4 ) flags [ "blockfloaters" ] = true ;
if ( ( args [ argnum ] & 8 ) = = 8 ) flags [ "clipmidtex" ] = true ;
if ( ( args [ argnum ] & 16 ) = = 16 ) flags [ "wrapmidtex" ] = true ;
if ( ( args [ argnum ] & 32 ) = = 32 ) flags [ "midtex3d" ] = true ;
if ( ( args [ argnum ] & 64 ) = = 64 ) flags [ "checkswitchrange" ] = true ;
if ( ( args [ argnum ] & 128 ) = = 128 ) flags [ "firstsideonly" ] = true ;
// Clear obsolete arg
args [ argnum ] = 0 ;
}
//mxd
private void ConvertFlagsToArg ( Dictionary < string , bool > oldflags , int argnum )
{
int bits = 0 ;
if ( oldflags . ContainsKey ( "zoneboundary" ) & & oldflags [ "zoneboundary" ] ) bits & = 1 ;
if ( oldflags . ContainsKey ( "jumpover" ) & & oldflags [ "jumpover" ] ) bits & = 2 ;
if ( oldflags . ContainsKey ( "blockfloaters" ) & & oldflags [ "blockfloaters" ] ) bits & = 4 ;
if ( oldflags . ContainsKey ( "clipmidtex" ) & & oldflags [ "clipmidtex" ] ) bits & = 8 ;
if ( oldflags . ContainsKey ( "wrapmidtex" ) & & oldflags [ "wrapmidtex" ] ) bits & = 16 ;
if ( oldflags . ContainsKey ( "midtex3d" ) & & oldflags [ "midtex3d" ] ) bits & = 32 ;
if ( oldflags . ContainsKey ( "checkswitchrange" ) & & oldflags [ "checkswitchrange" ] ) bits & = 64 ;
if ( oldflags . ContainsKey ( "firstsideonly" ) & & oldflags [ "firstsideonly" ] ) bits & = 128 ;
// Set arg
args [ argnum ] = bits ;
2009-04-19 18:07:22 +00:00
}
// Selected
protected override void DoSelect ( )
{
base . DoSelect ( ) ;
selecteditem = map . SelectedLinedefs . AddLast ( this ) ;
}
// Deselect
protected override void DoUnselect ( )
{
base . DoUnselect ( ) ;
if ( selecteditem . List ! = null ) selecteditem . List . Remove ( selecteditem ) ;
selecteditem = null ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
2021-08-25 18:31:28 +00:00
// Determine if this line and another line are associated by action and tag.
public bool IsAssociatedWith ( Linedef ld )
{
LinedefActionInfo actioninfo ;
return this ! = ld & &
Action > 0 & &
ld . Tag > 0 & &
tags . Contains ( ld . Tag ) & &
( actioninfo = General . Map . Config . GetLinedefActionInfo ( Action ) ) . LineToLineTag & &
( ! actioninfo . LineToLineSameAction | | Action = = ld . Action ) ;
}
2009-04-19 18:07:22 +00:00
// This checks and returns a flag without creating it
public bool IsFlagSet ( string flagname )
{
2014-12-29 09:19:20 +00:00
return flags . ContainsKey ( flagname ) & & flags [ flagname ] ;
2009-04-19 18:07:22 +00:00
}
2009-06-11 21:21:20 +00:00
// This sets a flag
public void SetFlag ( string flagname , bool value )
{
if ( ! flags . ContainsKey ( flagname ) | | ( IsFlagSet ( flagname ) ! = value ) )
{
BeforePropsChange ( ) ;
flags [ flagname ] = value ;
// Cached flags
if ( flagname = = General . Map . Config . ImpassableFlag ) impassableflag = value ;
2013-03-18 13:52:27 +00:00
//mxd
UpdateColorPreset ( ) ;
2009-06-11 21:21:20 +00:00
}
}
// This returns a copy of the flags dictionary
public Dictionary < string , bool > GetFlags ( )
{
return new Dictionary < string , bool > ( flags ) ;
}
2016-06-15 22:57:39 +00:00
//mxd. This returns enabled flags
public HashSet < string > GetEnabledFlags ( )
{
HashSet < string > result = new HashSet < string > ( ) ;
foreach ( KeyValuePair < string , bool > group in flags )
if ( group . Value ) result . Add ( group . Key ) ;
return result ;
}
2009-06-11 21:21:20 +00:00
// This clears all flags
public void ClearFlags ( )
{
2010-08-15 13:45:43 +00:00
BeforePropsChange ( ) ;
2009-06-11 21:21:20 +00:00
flags . Clear ( ) ;
impassableflag = false ;
2013-03-18 13:52:27 +00:00
//mxd
UpdateColorPreset ( ) ;
2009-06-11 21:21:20 +00:00
}
2009-04-19 18:07:22 +00:00
// This flips the linedef's vertex attachments
public void FlipVertices ( )
{
2009-06-28 14:47:21 +00:00
// make sure the start/end vertices are not automatically
// deleted if they do not belong to any other line
General . Map . Map . AutoRemove = false ;
2009-04-19 18:07:22 +00:00
// Flip vertices
2009-06-11 21:21:20 +00:00
Vertex oldstart = start ;
Vertex oldend = end ;
SetStartVertex ( oldend ) ;
SetEndVertex ( oldstart ) ;
2009-06-28 14:47:21 +00:00
General . Map . Map . AutoRemove = true ;
2009-06-11 21:21:20 +00:00
2009-05-06 14:50:17 +00:00
// For drawing, the interior now lies on the other side
frontinterior = ! frontinterior ;
2009-04-19 18:07:22 +00:00
// Update required (angle changed)
NeedUpdate ( ) ;
General . Map . IsChanged = true ;
}
// This flips the sidedefs
public void FlipSidedefs ( )
{
// Flip sidedefs
2009-06-11 21:21:20 +00:00
Sidedef oldfront = front ;
Sidedef oldback = back ;
AttachFront ( oldback ) ;
AttachBack ( oldfront ) ;
2009-04-19 18:07:22 +00:00
General . Map . IsChanged = true ;
}
// This returns a point for testing on one side
public Vector2D GetSidePoint ( bool front )
{
Vector2D n = new Vector2D ( ) ;
n . x = ( end . Position . x - start . Position . x ) * lengthinv * SIDE_POINT_DISTANCE ;
n . y = ( end . Position . y - start . Position . y ) * lengthinv * SIDE_POINT_DISTANCE ;
if ( front )
{
n . x = - n . x ;
n . y = - n . y ;
}
Vector2D p = new Vector2D ( ) ;
2020-06-22 14:37:32 +00:00
p . x = start . Position . x + ( end . Position . x - start . Position . x ) * 0.5 - n . y ;
p . y = start . Position . y + ( end . Position . y - start . Position . y ) * 0.5 + n . x ;
2009-04-19 18:07:22 +00:00
return p ;
}
// This returns a point in the middle of the line
public Vector2D GetCenterPoint ( )
{
2020-06-22 14:37:32 +00:00
return start . Position + ( end . Position - start . Position ) * 0.5 ;
2009-04-19 18:07:22 +00:00
}
// This applies single/double sided flags
public void ApplySidedFlags ( )
{
// Doublesided?
if ( ( front ! = null ) & & ( back ! = null ) )
{
// Apply or remove flags for doublesided line
2009-06-11 21:21:20 +00:00
SetFlag ( General . Map . Config . SingleSidedFlag , false ) ;
SetFlag ( General . Map . Config . DoubleSidedFlag , true ) ;
2009-04-19 18:07:22 +00:00
}
else
{
// Apply or remove flags for singlesided line
2009-06-11 21:21:20 +00:00
SetFlag ( General . Map . Config . SingleSidedFlag , true ) ;
SetFlag ( General . Map . Config . DoubleSidedFlag , false ) ;
2009-04-19 18:07:22 +00:00
}
General . Map . IsChanged = true ;
}
// This returns all points at which the line intersects with the grid
2019-01-14 18:07:08 +00:00
public List < Vector2D > GetGridIntersections ( )
{
2020-06-14 22:41:22 +00:00
return GetGridIntersections ( 0.0 ) ;
2019-01-14 18:07:08 +00:00
}
2020-06-14 22:41:22 +00:00
public List < Vector2D > GetGridIntersections ( double gridrotation , double gridoriginx = 0.0 , double gridoriginy = 0.0 )
2014-07-11 10:46:10 +00:00
{
2019-01-14 18:07:08 +00:00
return GetGridIntersections ( new Vector2D ( ) , gridrotation , gridoriginx , gridoriginy ) ;
2014-07-11 10:46:10 +00:00
}
// This returns all points at which the line intersects with the grid
2020-06-14 22:41:22 +00:00
public List < Vector2D > GetGridIntersections ( Vector2D gridoffset , double gridrotation = 0.0 , double gridoriginx = 0.0 , double gridoriginy = 0.0 )
2009-04-19 18:07:22 +00:00
{
List < Vector2D > coords = new List < Vector2D > ( ) ;
Vector2D v = new Vector2D ( ) ;
2020-05-21 12:20:02 +00:00
double minx , maxx , miny , maxy ;
2009-04-19 18:07:22 +00:00
bool reversex , reversey ;
2019-01-14 18:07:08 +00:00
Vector2D v1 = start . Position ;
Vector2D v2 = end . Position ;
bool transformed = Math . Abs ( gridrotation ) > 1e-4 | | Math . Abs ( gridoriginx ) > 1e-4 | | Math . Abs ( gridoriginy ) > 1e-4 ;
if ( transformed )
{
v1 = ( v1 - new Vector2D ( gridoriginx , gridoriginy ) ) . GetRotated ( - gridrotation ) ;
v2 = ( v2 - new Vector2D ( gridoriginx , gridoriginy ) ) . GetRotated ( - gridrotation ) ;
}
2009-04-19 18:07:22 +00:00
2019-01-14 18:07:08 +00:00
if ( v1 . x > v2 . x )
2009-04-19 18:07:22 +00:00
{
2019-01-14 18:07:08 +00:00
minx = v2 . x ;
maxx = v1 . x ;
2009-04-19 18:07:22 +00:00
reversex = true ;
}
else
{
2019-01-14 18:07:08 +00:00
minx = v1 . x ;
maxx = v2 . x ;
2009-04-19 18:07:22 +00:00
reversex = false ;
}
2019-01-14 18:07:08 +00:00
if ( v1 . y > v2 . y )
2009-04-19 18:07:22 +00:00
{
2019-01-14 18:07:08 +00:00
miny = v2 . y ;
maxy = v1 . y ;
2009-04-19 18:07:22 +00:00
reversey = true ;
}
else
{
2019-01-14 18:07:08 +00:00
miny = v1 . y ;
maxy = v2 . y ;
2009-04-19 18:07:22 +00:00
reversey = false ;
}
// Go for all vertical grid lines in between line start and end
2020-05-21 12:20:02 +00:00
double gx = General . Map . Grid . GetHigher ( minx ) + gridoffset . x ;
2009-04-19 18:07:22 +00:00
if ( gx < maxx )
{
2017-01-06 10:01:59 +00:00
for ( ; gx < maxx ; gx + = General . Map . Grid . GridSizeF )
2009-04-19 18:07:22 +00:00
{
// Add intersection point at this x coordinate
2020-05-21 12:20:02 +00:00
double u = ( gx - minx ) / ( maxx - minx ) ;
2020-06-14 22:41:22 +00:00
if ( reversex ) u = 1.0 - u ;
2009-04-19 18:07:22 +00:00
v . x = gx ;
2019-01-14 18:07:08 +00:00
v . y = v1 . y + ( v2 . y - v1 . y ) * u ;
2009-04-19 18:07:22 +00:00
coords . Add ( v ) ;
}
}
2020-05-21 12:20:02 +00:00
2009-04-19 18:07:22 +00:00
// Go for all horizontal grid lines in between line start and end
2020-05-21 12:20:02 +00:00
double gy = General . Map . Grid . GetHigher ( miny ) + gridoffset . y ;
2009-04-19 18:07:22 +00:00
if ( gy < maxy )
{
2017-01-06 10:01:59 +00:00
for ( ; gy < maxy ; gy + = General . Map . Grid . GridSizeF )
2009-04-19 18:07:22 +00:00
{
// Add intersection point at this y coordinate
2020-05-21 12:20:02 +00:00
double u = ( gy - miny ) / ( maxy - miny ) ;
2020-06-14 22:41:22 +00:00
if ( reversey ) u = 1.0 - u ;
2019-01-14 18:07:08 +00:00
v . x = v1 . x + ( v2 . x - v1 . x ) * u ;
2009-04-19 18:07:22 +00:00
v . y = gy ;
coords . Add ( v ) ;
}
}
2019-01-14 18:07:08 +00:00
if ( transformed )
{
for ( int i = 0 ; i < coords . Count ; i + + )
{
coords [ i ] = coords [ i ] . GetRotated ( gridrotation ) + new Vector2D ( gridoriginx , gridoriginy ) ;
}
}
2009-04-19 18:07:22 +00:00
// Profit
return coords ;
}
// This returns the closest coordinates ON the line
public Vector2D NearestOnLine ( Vector2D pos )
{
2020-05-21 12:20:02 +00:00
double u = Line2D . GetNearestOnLine ( start . Position , end . Position , pos ) ;
2020-06-22 14:37:32 +00:00
if ( u < 0.0 ) u = 0.0 ; else if ( u > 1.0 ) u = 1.0 ;
2009-04-19 18:07:22 +00:00
return Line2D . GetCoordinatesAt ( start . Position , end . Position , u ) ;
}
// This returns the shortest distance from given coordinates to line
2020-05-21 12:20:02 +00:00
public double SafeDistanceToSq ( Vector2D p , bool bounded )
2009-04-19 18:07:22 +00:00
{
Vector2D v1 = start . Position ;
Vector2D v2 = end . Position ;
// Calculate intersection offset
2020-05-21 12:20:02 +00:00
double u = ( ( p . x - v1 . x ) * ( v2 . x - v1 . x ) + ( p . y - v1 . y ) * ( v2 . y - v1 . y ) ) * lengthsqinv ;
2009-04-19 18:07:22 +00:00
2019-01-14 18:07:08 +00:00
// Limit intersection offset to the line
if ( bounded )
{
2019-10-31 20:16:59 +00:00
// We really don't want u to be 0 or 1, because that'd mean the distance will be measured
// from the vertices, which will result in linedefs being equally far away. We still need
// special handling for linedefs that are shorter than 1 mu (which is possible in UDMF)
// Detailed explanation here: https://github.com/jewalky/GZDoom-Builder-Bugfix/issues/307
2020-06-22 14:37:32 +00:00
if ( lengthinv > 1.0 )
2019-01-14 18:07:08 +00:00
{
2020-06-22 14:37:32 +00:00
u = Math . Max ( 0 , Math . Min ( 1.0 , u ) ) ;
2019-01-14 18:07:08 +00:00
}
2019-10-31 20:16:59 +00:00
else
2019-01-14 18:07:08 +00:00
{
2020-06-22 14:37:32 +00:00
u = Math . Max ( lengthinv , Math . Min ( 1.0 - lengthinv , u ) ) ;
2019-01-14 18:07:08 +00:00
}
}
/ *
// Calculate intersection point
Vector2D i = v1 + u * ( v2 - v1 ) ;
2009-04-19 18:07:22 +00:00
// Return distance between intersection and point
// which is the shortest distance to the line
float ldx = p . x - i . x ;
float ldy = p . y - i . y ;
2019-01-14 18:07:08 +00:00
* /
2017-02-08 12:18:01 +00:00
2019-01-14 18:07:08 +00:00
// ano - let's check to see if we can do the previous faster without using operator overloading and etc
// the answer: running it int.MaxValue / 64 times it tended to be around 100ms faster
2020-05-21 12:20:02 +00:00
double ldx = p . x - ( v1 . x + u * ( v2 . x - v1 . x ) ) ;
double ldy = p . y - ( v1 . y + u * ( v2 . y - v1 . y ) ) ;
2019-01-14 18:07:08 +00:00
return ldx * ldx + ldy * ldy ;
2009-04-19 18:07:22 +00:00
}
// This returns the shortest distance from given coordinates to line
2020-05-22 19:39:18 +00:00
public double SafeDistanceTo ( Vector2D p , bool bounded )
2009-04-19 18:07:22 +00:00
{
2020-05-22 19:39:18 +00:00
return Math . Sqrt ( SafeDistanceToSq ( p , bounded ) ) ;
2009-04-19 18:07:22 +00:00
}
// This returns the shortest distance from given coordinates to line
2020-05-21 12:20:02 +00:00
public double DistanceToSq ( Vector2D p , bool bounded )
2009-04-19 18:07:22 +00:00
{
Vector2D v1 = start . Position ;
Vector2D v2 = end . Position ;
2020-05-21 12:20:02 +00:00
2009-04-19 18:07:22 +00:00
// Calculate intersection offset
2020-05-21 12:20:02 +00:00
double u = ( ( p . x - v1 . x ) * ( v2 . x - v1 . x ) + ( p . y - v1 . y ) * ( v2 . y - v1 . y ) ) * lengthsqinv ;
2009-04-19 18:07:22 +00:00
// Limit intersection offset to the line
2020-06-22 14:37:32 +00:00
if ( bounded ) if ( u < 0.0 ) u = 0.0 ; else if ( u > 1.0 ) u = 1.0 ;
2009-04-19 18:07:22 +00:00
// Calculate intersection point
Vector2D i = v1 + u * ( v2 - v1 ) ;
// Return distance between intersection and point
// which is the shortest distance to the line
2020-05-21 12:20:02 +00:00
double ldx = p . x - i . x ;
double ldy = p . y - i . y ;
2009-04-19 18:07:22 +00:00
return ldx * ldx + ldy * ldy ;
}
// This returns the shortest distance from given coordinates to line
2020-05-22 19:39:18 +00:00
public double DistanceTo ( Vector2D p , bool bounded )
2009-04-19 18:07:22 +00:00
{
2020-05-22 19:39:18 +00:00
return Math . Sqrt ( DistanceToSq ( p , bounded ) ) ;
2009-04-19 18:07:22 +00:00
}
// This tests on which side of the line the given coordinates are
// returns < 0 for front (right) side, > 0 for back (left) side and 0 if on the line
2020-05-21 12:20:02 +00:00
public double SideOfLine ( Vector2D p )
2009-04-19 18:07:22 +00:00
{
Vector2D v1 = start . Position ;
Vector2D v2 = end . Position ;
// Calculate and return side information
return ( p . y - v1 . y ) * ( v2 . x - v1 . x ) - ( p . x - v1 . x ) * ( v2 . y - v1 . y ) ;
}
// This splits this line by vertex v
2010-08-15 19:43:00 +00:00
// Returns the new line resulting from the split, or null when it failed
2009-04-19 18:07:22 +00:00
public Linedef Split ( Vertex v )
{
Sidedef nsd ;
// Copy linedef and change vertices
2014-03-12 10:39:24 +00:00
Linedef nl = map . CreateLinedef ( v , end ) ;
2010-08-15 19:43:00 +00:00
if ( nl = = null ) return null ;
2009-04-19 18:07:22 +00:00
CopyPropertiesTo ( nl ) ;
SetEndVertex ( v ) ;
nl . Selected = this . Selected ;
nl . marked = this . marked ;
2013-07-29 08:50:50 +00:00
nl . ExtraFloorFlag = this . ExtraFloorFlag ; //mxd
2009-04-19 18:07:22 +00:00
// Copy front sidedef if exists
if ( front ! = null )
{
nsd = map . CreateSidedef ( nl , true , front . Sector ) ;
2010-08-15 19:43:00 +00:00
if ( nsd = = null ) return null ;
2009-04-19 18:07:22 +00:00
front . CopyPropertiesTo ( nsd ) ;
nsd . Marked = front . Marked ;
}
// Copy back sidedef if exists
if ( back ! = null )
{
nsd = map . CreateSidedef ( nl , false , back . Sector ) ;
2010-08-15 19:43:00 +00:00
if ( nsd = = null ) return null ;
2009-04-19 18:07:22 +00:00
back . CopyPropertiesTo ( nsd ) ;
nsd . Marked = back . Marked ;
2013-04-02 12:19:25 +00:00
}
2014-03-19 13:03:47 +00:00
//mxd
AdjustSplitCoordinates ( this , nl , General . Settings . SplitLineBehavior ) ;
2009-04-19 18:07:22 +00:00
// Return result
General . Map . IsChanged = true ;
return nl ;
}
// This joins the line with another line
// This line will be disposed
2010-08-15 19:43:00 +00:00
// Returns false when the operation could not be completed
public bool Join ( Linedef other )
2009-04-19 18:07:22 +00:00
{
// Check which lines were 2 sided
2016-05-18 20:31:40 +00:00
bool otherwas2s = ( ( other . Front ! = null ) & & ( other . Back ! = null ) ) ;
2016-05-29 00:38:55 +00:00
bool thiswas2s = ( ( this . Front ! = null ) & & ( this . Back ! = null ) ) ;
2009-04-19 18:07:22 +00:00
// Get sector references
2016-05-18 20:31:40 +00:00
Sector otherfs = ( other . front ! = null ? other . front . Sector : null ) ;
Sector otherbs = ( other . back ! = null ? other . back . Sector : null ) ;
Sector thisfs = ( this . front ! = null ? this . front . Sector : null ) ;
Sector thisbs = ( this . back ! = null ? this . back . Sector : null ) ;
2009-04-19 18:07:22 +00:00
// This line has no sidedefs?
2016-05-18 20:31:40 +00:00
if ( ( thisfs = = null ) & & ( thisbs = = null ) )
2009-04-19 18:07:22 +00:00
{
// We have no sidedefs, so we have no influence
// Nothing to change on the other line
}
// Other line has no sidedefs?
2016-05-18 20:31:40 +00:00
else if ( ( otherfs = = null ) & & ( otherbs = = null ) )
2009-04-19 18:07:22 +00:00
{
// The other has no sidedefs, so it has no influence
// Copy my sidedefs to the other
if ( this . Start = = other . Start )
{
2010-08-15 19:43:00 +00:00
if ( ! JoinChangeSidedefs ( other , true , front ) ) return false ;
if ( ! JoinChangeSidedefs ( other , false , back ) ) return false ;
2009-04-19 18:07:22 +00:00
}
else
{
2010-08-15 19:43:00 +00:00
if ( ! JoinChangeSidedefs ( other , false , front ) ) return false ;
if ( ! JoinChangeSidedefs ( other , true , back ) ) return false ;
2009-04-19 18:07:22 +00:00
}
// Copy my properties to the other
this . CopyPropertiesTo ( other ) ;
}
else
{
// Compare front sectors
2016-05-18 20:31:40 +00:00
if ( ( otherfs ! = null ) & & ( otherfs = = thisfs ) )
2009-04-19 18:07:22 +00:00
{
// Copy textures
if ( other . front ! = null ) other . front . AddTexturesTo ( this . back ) ;
if ( this . front ! = null ) this . front . AddTexturesTo ( other . back ) ;
2016-05-18 20:31:40 +00:00
// Change sidedefs?
2016-06-24 22:25:12 +00:00
if ( ! JoinChangeSidedefs ( other , true , back ) ) return false ;
2009-04-19 18:07:22 +00:00
}
// Compare back sectors
2016-05-18 20:31:40 +00:00
else if ( ( otherbs ! = null ) & & ( otherbs = = thisbs ) )
2009-04-19 18:07:22 +00:00
{
// Copy textures
if ( other . back ! = null ) other . back . AddTexturesTo ( this . front ) ;
if ( this . back ! = null ) this . back . AddTexturesTo ( other . front ) ;
2016-05-18 20:31:40 +00:00
// Change sidedefs?
2016-06-24 22:25:12 +00:00
if ( ! JoinChangeSidedefs ( other , false , front ) ) return false ;
2009-04-19 18:07:22 +00:00
}
// Compare front and back
2016-05-18 20:31:40 +00:00
else if ( ( otherfs ! = null ) & & ( otherfs = = thisbs ) )
2009-04-19 18:07:22 +00:00
{
// Copy textures
if ( other . front ! = null ) other . front . AddTexturesTo ( this . front ) ;
if ( this . back ! = null ) this . back . AddTexturesTo ( other . back ) ;
2016-05-18 20:31:40 +00:00
// Change sidedefs?
2016-06-24 22:25:12 +00:00
if ( ! JoinChangeSidedefs ( other , true , front ) ) return false ;
2009-04-19 18:07:22 +00:00
}
// Compare back and front
2016-05-18 20:31:40 +00:00
else if ( ( otherbs ! = null ) & & ( otherbs = = thisfs ) )
2009-04-19 18:07:22 +00:00
{
// Copy textures
if ( other . back ! = null ) other . back . AddTexturesTo ( this . back ) ;
if ( this . front ! = null ) this . front . AddTexturesTo ( other . front ) ;
2016-05-18 20:31:40 +00:00
// Change sidedefs?
2016-06-24 22:25:12 +00:00
if ( ! JoinChangeSidedefs ( other , false , back ) ) return false ;
2009-04-19 18:07:22 +00:00
}
else
{
// Other line single sided?
if ( other . back = = null )
{
// This line with its back to the other?
if ( this . start = = other . end )
{
// Copy textures
if ( this . back ! = null ) this . back . AddTexturesTo ( other . front ) ;
2016-05-18 20:31:40 +00:00
// Change sidedefs?
2016-06-24 22:25:12 +00:00
if ( ! JoinChangeSidedefs ( other , false , front ) ) return false ;
2009-04-19 18:07:22 +00:00
}
else
{
// Copy textures
if ( this . front ! = null ) this . front . AddTexturesTo ( other . front ) ;
2016-05-18 20:31:40 +00:00
// Change sidedefs?
2016-06-24 22:25:12 +00:00
if ( ! JoinChangeSidedefs ( other , false , back ) ) return false ;
2009-04-19 18:07:22 +00:00
}
}
// This line single sided?
2010-08-13 12:03:25 +00:00
else if ( this . back = = null )
2009-04-19 18:07:22 +00:00
{
// Other line with its back to this?
if ( other . start = = this . end )
{
2016-05-29 00:38:55 +00:00
if ( otherbs = = null )
2016-05-18 20:31:40 +00:00
{
// Copy textures
if ( other . back ! = null ) other . back . AddTexturesTo ( this . front ) ;
2009-04-19 18:07:22 +00:00
2016-05-18 20:31:40 +00:00
// Change sidedefs
if ( ! JoinChangeSidedefs ( other , false , front ) ) return false ;
}
2009-04-19 18:07:22 +00:00
}
else
{
2016-05-29 00:38:55 +00:00
if ( otherfs = = null )
2016-05-18 20:31:40 +00:00
{
// Copy textures
if ( other . front ! = null ) other . front . AddTexturesTo ( this . front ) ;
2009-04-19 18:07:22 +00:00
2016-05-18 20:31:40 +00:00
// Change sidedefs
if ( ! JoinChangeSidedefs ( other , true , front ) ) return false ;
}
2009-04-19 18:07:22 +00:00
}
}
else
{
// This line with its back to the other?
if ( this . start = = other . end )
{
2016-06-24 22:25:12 +00:00
// Copy textures
if ( other . back ! = null ) other . back . AddTexturesTo ( this . front ) ;
if ( this . back ! = null ) this . back . AddTexturesTo ( other . front ) ;
2009-04-19 18:07:22 +00:00
2016-06-24 22:25:12 +00:00
// Change sidedefs
if ( ! JoinChangeSidedefs ( other , false , front ) ) return false ;
2009-04-19 18:07:22 +00:00
}
2016-05-18 20:31:40 +00:00
// Both lines face the same way
2009-04-19 18:07:22 +00:00
else
{
2016-06-24 22:25:12 +00:00
// Copy textures
if ( other . back ! = null ) other . back . AddTexturesTo ( this . back ) ;
if ( this . front ! = null ) this . front . AddTexturesTo ( other . front ) ;
2009-04-19 18:07:22 +00:00
2016-06-24 22:25:12 +00:00
// Change sidedefs
if ( ! JoinChangeSidedefs ( other , false , back ) ) return false ;
2009-04-19 18:07:22 +00:00
}
}
}
// Apply single/double sided flags if the double-sided-ness changed
2016-05-18 20:31:40 +00:00
if ( ( ! otherwas2s & & ( other . Front ! = null & & other . Back ! = null ) ) | |
( otherwas2s & & ( other . Front = = null | | other . Back = = null ) ) )
2009-04-19 18:07:22 +00:00
other . ApplySidedFlags ( ) ;
// Remove unneeded textures
2016-05-29 00:38:55 +00:00
if ( other . front ! = null ) other . front . RemoveUnneededTextures ( ! ( otherwas2s & & thiswas2s ) ) ;
if ( other . back ! = null ) other . back . RemoveUnneededTextures ( ! ( otherwas2s & & thiswas2s ) ) ;
2009-04-19 18:07:22 +00:00
}
// If either of the two lines was selected, keep the other selected
if ( this . Selected ) other . Selected = true ;
if ( this . marked ) other . marked = true ;
// I got killed by the other.
this . Dispose ( ) ;
General . Map . IsChanged = true ;
2010-08-15 19:43:00 +00:00
return true ;
2009-04-19 18:07:22 +00:00
}
// This changes sidedefs (used for joining lines)
2010-08-13 12:03:25 +00:00
// target: The linedef on which to remove or create a new sidedef
// front: Side on which to remove or create the sidedef (true for front side)
// newside: The side from which to copy the properties to the new sidedef.
// If this is null, no sidedef will be created (only removed)
2010-08-15 19:43:00 +00:00
// Returns false when the operation could not be completed.
private bool JoinChangeSidedefs ( Linedef target , bool front , Sidedef newside )
2009-04-19 18:07:22 +00:00
{
// Change sidedefs
if ( front )
{
2010-08-13 12:03:25 +00:00
if ( target . front ! = null ) target . front . Dispose ( ) ;
2009-04-19 18:07:22 +00:00
}
else
{
2010-08-13 12:03:25 +00:00
if ( target . back ! = null ) target . back . Dispose ( ) ;
2009-04-19 18:07:22 +00:00
}
if ( newside ! = null )
{
2015-12-28 15:01:53 +00:00
Sidedef sd = map . CreateSidedef ( target , front , newside . Sector ) ;
2010-08-15 19:43:00 +00:00
if ( sd = = null ) return false ;
2009-04-19 18:07:22 +00:00
newside . CopyPropertiesTo ( sd ) ;
sd . Marked = newside . Marked ;
}
2010-08-15 19:43:00 +00:00
return true ;
2009-04-19 18:07:22 +00:00
}
2013-09-11 09:47:53 +00:00
//mxd
2014-12-03 23:15:26 +00:00
internal void UpdateColorPreset ( )
{
for ( int i = 0 ; i < General . Map . ConfigSettings . LinedefColorPresets . Length ; i + + )
{
if ( General . Map . ConfigSettings . LinedefColorPresets [ i ] . Matches ( this ) )
{
2013-09-11 09:47:53 +00:00
colorPresetIndex = i ;
return ;
}
}
colorPresetIndex = - 1 ;
}
2013-03-18 13:52:27 +00:00
2023-06-09 09:17:01 +00:00
/// <summary>
/// Changes the linedef's index to a new index.
/// </summary>
/// <param name="newindex">The new index to set</param>
public void ChangeIndex ( int newindex )
{
General . Map . UndoRedo . RecIndexLinedef ( Index , newindex ) ;
map ? . ChangeLindefIndex ( Index , newindex ) ;
}
2009-04-19 18:07:22 +00:00
// String representation
public override string ToString ( )
{
2016-05-18 20:31:40 +00:00
#if DEBUG
string starttext = ( start ! = null ? " (" + start : string . Empty ) ;
string endtext = ( end ! = null ? ", " + end + ")" : string . Empty ) ;
return "Linedef " + listindex + ( marked ? " (marked)" : "" ) + starttext + endtext ; //mxd
#else
2009-06-05 19:03:56 +00:00
return "Linedef " + listindex ;
2016-05-18 20:31:40 +00:00
#endif
2009-04-19 18:07:22 +00:00
}
#endregion
#region = = = = = = = = = = = = = = = = = = Changes
// This updates all properties
2015-07-27 21:35:42 +00:00
public void Update ( Dictionary < string , bool > flags , int activate , List < int > tags , int action , int [ ] args )
2009-04-19 18:07:22 +00:00
{
2009-06-11 21:21:20 +00:00
BeforePropsChange ( ) ;
2009-04-19 18:07:22 +00:00
// Apply changes
this . flags = new Dictionary < string , bool > ( flags ) ;
2015-07-27 21:35:42 +00:00
this . tags = new List < int > ( tags ) ; //mxd
2009-04-19 18:07:22 +00:00
this . activate = activate ;
this . action = action ;
this . args = new int [ NUM_ARGS ] ;
args . CopyTo ( this . args , 0 ) ;
this . updateneeded = true ;
}
2014-03-19 13:03:47 +00:00
// mxd. Moved here from BuilderModes.BuilderPlug
// This adjusts texture coordinates for splitted lines according to the user preferences
2014-12-03 23:15:26 +00:00
private static void AdjustSplitCoordinates ( Linedef oldline , Linedef newline , SplitLineBehavior splitlinebehavior )
{
switch ( splitlinebehavior )
{
2014-03-19 13:03:47 +00:00
case SplitLineBehavior . Interpolate :
//Make texture offset adjustments
2014-12-03 23:15:26 +00:00
if ( oldline . back ! = null )
{
if ( ( oldline . back . MiddleRequired ( ) & & oldline . back . LongMiddleTexture ! = MapSet . EmptyLongName ) | | oldline . back . HighRequired ( ) | | oldline . back . LowRequired ( ) )
{
2014-03-19 13:03:47 +00:00
int distance = ( int ) Vector2D . Distance ( newline . start . Position , newline . end . Position ) ;
2016-09-05 18:36:22 +00:00
if ( General . Map . UDMF & & General . Map . Config . UseLocalSidedefTextureOffsets )
2014-12-03 23:15:26 +00:00
{
2014-03-19 13:03:47 +00:00
if ( distance ! = 0 ) oldline . back . SetUdmfTextureOffsetX ( distance ) ;
2014-12-03 23:15:26 +00:00
}
else
{
2014-03-19 13:03:47 +00:00
oldline . back . OffsetX + = distance ;
}
}
}
2014-12-03 23:15:26 +00:00
if ( newline . front ! = null & & ( ( newline . front . MiddleRequired ( ) | | newline . front . LongMiddleTexture ! = MapSet . EmptyLongName ) | | newline . front . HighRequired ( ) | | newline . front . LowRequired ( ) ) )
{
2014-03-19 13:03:47 +00:00
int distance = ( int ) Vector2D . Distance ( oldline . start . Position , oldline . end . Position ) ;
2016-09-05 18:36:22 +00:00
if ( General . Map . UDMF & & General . Map . Config . UseLocalSidedefTextureOffsets )
2014-12-03 23:15:26 +00:00
{
2014-03-19 13:03:47 +00:00
if ( distance ! = 0 ) newline . front . SetUdmfTextureOffsetX ( distance ) ;
2014-12-03 23:15:26 +00:00
}
else
{
2014-03-19 13:03:47 +00:00
newline . front . OffsetX + = distance ;
}
}
//Clamp texture coordinates
2014-12-03 23:15:26 +00:00
if ( ( oldline . front ! = null ) & & ( newline . front ! = null ) )
{
2014-03-19 13:03:47 +00:00
//get texture
ImageData texture = null ;
2014-12-03 23:15:26 +00:00
if ( newline . front . MiddleRequired ( ) & & newline . front . LongMiddleTexture ! = MapSet . EmptyLongName & & General . Map . Data . GetTextureExists ( newline . front . LongMiddleTexture ) )
2014-03-19 13:03:47 +00:00
texture = General . Map . Data . GetTextureImage ( newline . front . MiddleTexture ) ;
2014-12-03 23:15:26 +00:00
else if ( newline . front . HighRequired ( ) & & newline . front . LongHighTexture ! = MapSet . EmptyLongName & & General . Map . Data . GetTextureExists ( newline . front . LongHighTexture ) )
2014-03-19 13:03:47 +00:00
texture = General . Map . Data . GetTextureImage ( newline . front . HighTexture ) ;
2014-12-03 23:15:26 +00:00
else if ( newline . front . LowRequired ( ) & & newline . front . LongLowTexture ! = MapSet . EmptyLongName & & General . Map . Data . GetTextureExists ( newline . front . LongLowTexture ) )
2014-03-19 13:03:47 +00:00
texture = General . Map . Data . GetTextureImage ( newline . front . LowTexture ) ;
//clamp offsetX
2016-09-02 19:18:37 +00:00
if ( texture ! = null & & texture . IsImageLoaded )
newline . front . OffsetX % = texture . Width ;
2014-03-19 13:03:47 +00:00
}
2014-12-03 23:15:26 +00:00
if ( ( oldline . back ! = null ) & & ( newline . back ! = null ) )
{
2014-03-19 13:03:47 +00:00
//get texture
ImageData texture = null ;
2014-12-03 23:15:26 +00:00
if ( newline . back . MiddleRequired ( ) & & newline . back . LongMiddleTexture ! = MapSet . EmptyLongName & & General . Map . Data . GetTextureExists ( newline . back . LongMiddleTexture ) )
2014-03-19 13:03:47 +00:00
texture = General . Map . Data . GetTextureImage ( newline . back . MiddleTexture ) ;
2014-12-03 23:15:26 +00:00
else if ( newline . back . HighRequired ( ) & & newline . back . LongHighTexture ! = MapSet . EmptyLongName & & General . Map . Data . GetTextureExists ( newline . back . LongHighTexture ) )
2014-03-19 13:03:47 +00:00
texture = General . Map . Data . GetTextureImage ( newline . back . HighTexture ) ;
2014-12-03 23:15:26 +00:00
else if ( newline . back . LowRequired ( ) & & newline . back . LongLowTexture ! = MapSet . EmptyLongName & & General . Map . Data . GetTextureExists ( newline . back . LongLowTexture ) )
2014-03-19 13:03:47 +00:00
texture = General . Map . Data . GetTextureImage ( newline . back . LowTexture ) ;
//clamp offsetX
2016-09-02 19:18:37 +00:00
if ( texture ! = null & & texture . IsImageLoaded )
newline . back . OffsetX % = texture . Width ;
2014-03-19 13:03:47 +00:00
}
break ;
case SplitLineBehavior . CopyXY :
2014-12-03 23:15:26 +00:00
if ( ( oldline . front ! = null ) & & ( newline . front ! = null ) )
{
2014-03-19 13:03:47 +00:00
newline . front . OffsetX = oldline . front . OffsetX ;
newline . front . OffsetY = oldline . front . OffsetY ;
//mxd. Copy UDMF offsets as well
2016-09-05 18:36:22 +00:00
if ( General . Map . UDMF & & General . Map . Config . UseLocalSidedefTextureOffsets )
2014-12-03 23:15:26 +00:00
{
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . front . Fields , "offsetx_top" , oldline . front . Fields . GetValue ( "offsetx_top" , 0.0 ) ) ;
UniFields . SetFloat ( newline . front . Fields , "offsetx_mid" , oldline . front . Fields . GetValue ( "offsetx_mid" , 0.0 ) ) ;
UniFields . SetFloat ( newline . front . Fields , "offsetx_bottom" , oldline . front . Fields . GetValue ( "offsetx_bottom" , 0.0 ) ) ;
2014-03-19 13:03:47 +00:00
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . front . Fields , "offsety_top" , oldline . front . Fields . GetValue ( "offsety_top" , 0.0 ) ) ;
UniFields . SetFloat ( newline . front . Fields , "offsety_mid" , oldline . front . Fields . GetValue ( "offsety_mid" , 0.0 ) ) ;
UniFields . SetFloat ( newline . front . Fields , "offsety_bottom" , oldline . front . Fields . GetValue ( "offsety_bottom" , 0.0 ) ) ;
2014-03-19 13:03:47 +00:00
}
}
2014-12-03 23:15:26 +00:00
if ( ( oldline . back ! = null ) & & ( newline . back ! = null ) )
{
2014-03-19 13:03:47 +00:00
newline . back . OffsetX = oldline . back . OffsetX ;
newline . back . OffsetY = oldline . back . OffsetY ;
//mxd. Copy UDMF offsets as well
2016-09-05 18:36:22 +00:00
if ( General . Map . UDMF & & General . Map . Config . UseLocalSidedefTextureOffsets )
2014-12-03 23:15:26 +00:00
{
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . back . Fields , "offsetx_top" , oldline . back . Fields . GetValue ( "offsetx_top" , 0.0 ) ) ;
UniFields . SetFloat ( newline . back . Fields , "offsetx_mid" , oldline . back . Fields . GetValue ( "offsetx_mid" , 0.0 ) ) ;
UniFields . SetFloat ( newline . back . Fields , "offsetx_bottom" , oldline . back . Fields . GetValue ( "offsetx_bottom" , 0.0 ) ) ;
2014-03-19 13:03:47 +00:00
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . back . Fields , "offsety_top" , oldline . back . Fields . GetValue ( "offsety_top" , 0.0 ) ) ;
UniFields . SetFloat ( newline . back . Fields , "offsety_mid" , oldline . back . Fields . GetValue ( "offsety_mid" , 0.0 ) ) ;
UniFields . SetFloat ( newline . back . Fields , "offsety_bottom" , oldline . back . Fields . GetValue ( "offsety_bottom" , 0.0 ) ) ;
2014-03-19 13:03:47 +00:00
}
}
break ;
case SplitLineBehavior . ResetXCopyY :
2014-12-03 23:15:26 +00:00
if ( ( oldline . front ! = null ) & & ( newline . front ! = null ) )
{
2014-03-19 13:03:47 +00:00
newline . front . OffsetX = 0 ;
newline . front . OffsetY = oldline . front . OffsetY ;
//mxd. Reset UDMF X offset as well
2016-09-05 18:36:22 +00:00
if ( General . Map . UDMF & & General . Map . Config . UseLocalSidedefTextureOffsets )
2014-12-03 23:15:26 +00:00
{
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . front . Fields , "offsetx_top" , 0.0 ) ;
UniFields . SetFloat ( newline . front . Fields , "offsetx_mid" , 0.0 ) ;
UniFields . SetFloat ( newline . front . Fields , "offsetx_bottom" , 0.0 ) ;
2014-03-19 13:03:47 +00:00
}
}
2014-12-03 23:15:26 +00:00
if ( ( oldline . back ! = null ) & & ( newline . back ! = null ) )
{
2014-03-19 13:03:47 +00:00
newline . back . OffsetX = 0 ;
newline . back . OffsetY = oldline . back . OffsetY ;
//mxd. Reset UDMF X offset and copy Y offset as well
2016-09-05 18:36:22 +00:00
if ( General . Map . UDMF & & General . Map . Config . UseLocalSidedefTextureOffsets )
2014-12-03 23:15:26 +00:00
{
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . back . Fields , "offsetx_top" , 0.0 ) ;
UniFields . SetFloat ( newline . back . Fields , "offsetx_mid" , 0.0 ) ;
UniFields . SetFloat ( newline . back . Fields , "offsetx_bottom" , 0.0 ) ;
2014-03-19 13:03:47 +00:00
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . back . Fields , "offsety_top" , oldline . back . Fields . GetValue ( "offsety_top" , 0.0 ) ) ;
UniFields . SetFloat ( newline . back . Fields , "offsety_mid" , oldline . back . Fields . GetValue ( "offsety_mid" , 0.0 ) ) ;
UniFields . SetFloat ( newline . back . Fields , "offsety_bottom" , oldline . back . Fields . GetValue ( "offsety_bottom" , 0.0 ) ) ;
2014-03-19 13:03:47 +00:00
}
}
break ;
case SplitLineBehavior . ResetXY :
2014-12-03 23:15:26 +00:00
if ( newline . front ! = null )
{
2014-03-19 13:03:47 +00:00
newline . front . OffsetX = 0 ;
newline . front . OffsetY = 0 ;
2016-09-05 18:36:22 +00:00
if ( General . Map . UDMF & & General . Map . Config . UseLocalSidedefTextureOffsets )
2014-12-03 23:15:26 +00:00
{
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . front . Fields , "offsetx_top" , 0.0 ) ;
UniFields . SetFloat ( newline . front . Fields , "offsetx_mid" , 0.0 ) ;
UniFields . SetFloat ( newline . front . Fields , "offsetx_bottom" , 0.0 ) ;
2014-03-19 13:03:47 +00:00
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . front . Fields , "offsety_top" , 0.0 ) ;
UniFields . SetFloat ( newline . front . Fields , "offsety_mid" , 0.0 ) ;
UniFields . SetFloat ( newline . front . Fields , "offsety_bottom" , 0.0 ) ;
2014-03-19 13:03:47 +00:00
}
}
2014-12-03 23:15:26 +00:00
if ( newline . back ! = null )
{
2014-03-19 13:03:47 +00:00
newline . back . OffsetX = 0 ;
newline . back . OffsetY = 0 ;
2016-09-05 18:36:22 +00:00
if ( General . Map . UDMF & & General . Map . Config . UseLocalSidedefTextureOffsets )
2014-12-03 23:15:26 +00:00
{
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . back . Fields , "offsetx_top" , 0.0 ) ;
UniFields . SetFloat ( newline . back . Fields , "offsetx_mid" , 0.0 ) ;
UniFields . SetFloat ( newline . back . Fields , "offsetx_bottom" , 0.0 ) ;
2014-03-19 13:03:47 +00:00
2020-05-22 19:39:18 +00:00
UniFields . SetFloat ( newline . back . Fields , "offsety_top" , 0.0 ) ;
UniFields . SetFloat ( newline . back . Fields , "offsety_mid" , 0.0 ) ;
UniFields . SetFloat ( newline . back . Fields , "offsety_bottom" , 0.0 ) ;
2014-03-19 13:03:47 +00:00
}
}
break ;
}
}
2009-04-19 18:07:22 +00:00
#endregion
}
}