2007-06-14 14:44:18 +00:00
2007-06-14 23:31:57 +00:00
#region = = = = = = = = = = = = = = = = = = Copyright ( c ) 2007 Pascal vd Heiden
2007-06-14 14:44:18 +00:00
/ *
* 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 .
*
* /
2007-06-14 23:31:57 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Namespaces
2007-06-14 12:37:46 +00:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Globalization ;
using System.Text ;
using CodeImp.DoomBuilder.Geometry ;
2007-10-21 18:06:10 +00:00
using CodeImp.DoomBuilder.Rendering ;
2007-10-21 22:41:46 +00:00
using CodeImp.DoomBuilder.Config ;
using System.Drawing ;
2008-12-06 13:20:47 +00:00
using CodeImp.DoomBuilder.IO ;
2009-01-03 20:54:12 +00:00
using CodeImp.DoomBuilder.VisualModes ;
2007-06-14 12:37:46 +00:00
2007-06-14 23:31:57 +00:00
#endregion
2007-06-14 12:37:46 +00:00
namespace CodeImp.DoomBuilder.Map
{
2008-10-16 08:45:23 +00:00
public sealed class Thing : SelectableElement
2007-06-14 12:37:46 +00:00
{
#region = = = = = = = = = = = = = = = = = = Constants
2007-12-26 00:31:32 +00:00
public const int NUM_ARGS = 5 ;
2007-06-24 18:56:43 +00:00
2007-06-14 12:37:46 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
// Map
2007-06-14 13:09:55 +00:00
private MapSet map ;
2007-06-14 12:37:46 +00:00
// Sector
private Sector sector = null ;
// List items
private LinkedListNode < Thing > mainlistitem ;
2009-03-30 07:45:39 +00:00
private LinkedListNode < Thing > selecteditem ;
2007-06-14 12:37:46 +00:00
// Properties
private int type ;
2007-06-24 18:56:43 +00:00
private Vector3D pos ;
2007-06-14 12:37:46 +00:00
private float angle ;
2008-05-31 19:31:45 +00:00
private Dictionary < string , bool > flags ;
2007-06-24 18:56:43 +00:00
private int tag ;
private int action ;
2008-05-29 21:09:43 +00:00
private int [ ] args ;
2007-10-20 01:04:47 +00:00
2007-10-21 18:06:10 +00:00
// Configuration
private float size ;
private PixelColor color ;
2008-11-17 16:14:45 +00:00
private bool fixedsize ;
2007-11-12 22:43:01 +00:00
private float iconoffset ; // Arrow or dot coordinate offset on the texture
2008-01-25 19:12:34 +00:00
2007-06-14 12:37:46 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
2007-07-07 09:40:34 +00:00
public MapSet Map { get { return map ; } }
2008-05-17 17:43:57 +00:00
public int Type { get { return type ; } set { type = value ; } }
2007-06-24 18:56:43 +00:00
public Vector3D Position { get { return pos ; } }
2007-10-14 15:44:55 +00:00
public float Angle { get { return angle ; } }
2008-05-17 17:43:57 +00:00
public int AngleDeg { get { return ( int ) Angle2D . RadToDeg ( angle ) ; } }
2008-05-31 19:31:45 +00:00
public Dictionary < string , bool > Flags { get { return flags ; } }
2008-05-17 17:43:57 +00:00
public int Action { get { return action ; } set { action = value ; } }
2008-05-29 21:09:43 +00:00
public int [ ] Args { get { return args ; } }
2007-10-21 22:41:46 +00:00
public float Size { get { return size ; } }
public float IconOffset { get { return iconoffset ; } }
public PixelColor Color { get { return color ; } }
2008-11-17 16:14:45 +00:00
public bool FixedSize { get { return fixedsize ; } }
2009-04-08 19:11:40 +00:00
public int Tag { get { return tag ; } set { tag = value ; if ( ( tag < 0 ) | | ( tag > General . Map . FormatInterface . HighestTag ) ) throw new ArgumentOutOfRangeException ( "Tag" , "Invalid tag number" ) ; } }
2007-10-24 17:25:03 +00:00
public Sector Sector { get { return sector ; } }
2007-06-14 12:37:46 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// Constructor
2008-05-10 16:09:45 +00:00
internal Thing ( MapSet map , LinkedListNode < Thing > listitem )
2007-06-14 12:37:46 +00:00
{
// Initialize
this . map = map ;
this . mainlistitem = listitem ;
2008-05-31 19:31:45 +00:00
this . flags = new Dictionary < string , bool > ( ) ;
2008-06-10 11:32:06 +00:00
this . args = new int [ NUM_ARGS ] ;
2007-06-14 12:37:46 +00:00
// We have no destructor
GC . SuppressFinalize ( this ) ;
}
2008-01-02 21:49:43 +00:00
// Disposer
2008-05-30 08:41:13 +00:00
public override void Dispose ( )
2007-06-14 12:37:46 +00:00
{
// Not already disposed?
if ( ! isdisposed )
{
// Already set isdisposed so that changes can be prohibited
isdisposed = true ;
// Remove from main list
mainlistitem . List . Remove ( mainlistitem ) ;
// Remove from sector
2008-12-10 22:58:58 +00:00
//if(sector != null) sector.DetachThing(sectorlistitem);
2007-06-14 12:37:46 +00:00
// Clean up
mainlistitem = null ;
map = null ;
sector = null ;
2008-05-30 08:41:13 +00:00
// Dispose base
base . Dispose ( ) ;
2007-06-14 12:37:46 +00:00
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Management
2008-12-06 13:20:47 +00:00
// Serialize / deserialize
internal void ReadWrite ( IReadWriteStream s )
{
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 ) ;
flags = new Dictionary < string , bool > ( c ) ;
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 type ) ;
s . rwVector3D ( ref pos ) ;
s . rwFloat ( ref angle ) ;
s . rwInt ( ref tag ) ;
s . rwInt ( ref action ) ;
for ( int i = 0 ; i < NUM_ARGS ; i + + ) s . rwInt ( ref args [ i ] ) ;
}
2007-06-24 18:56:43 +00:00
// This copies all properties to another thing
public void CopyPropertiesTo ( Thing t )
{
// Copy properties
t . type = type ;
t . angle = angle ;
t . pos = pos ;
2008-05-31 19:31:45 +00:00
t . flags = new Dictionary < string , bool > ( flags ) ;
2007-06-24 18:56:43 +00:00
t . tag = tag ;
t . action = action ;
2009-01-04 22:26:23 +00:00
t . args = ( int [ ] ) args . Clone ( ) ;
2007-11-12 22:43:01 +00:00
t . size = size ;
t . color = color ;
t . iconoffset = iconoffset ;
2008-11-17 16:14:45 +00:00
t . fixedsize = fixedsize ;
2008-10-16 08:45:23 +00:00
base . CopyPropertiesTo ( t ) ;
2007-06-24 18:56:43 +00:00
}
2009-03-10 17:22:22 +00:00
/// <summary>
/// Returns the index of the specified thing. This is a O(n) operation.
/// </summary>
public int GetIndex ( )
{
return map . GetIndexForThing ( this ) ;
}
2007-06-24 18:56:43 +00:00
2007-06-14 12:37:46 +00:00
// This determines which sector the thing is in and links it
public void DetermineSector ( )
{
Linedef nl ;
2007-10-24 17:25:03 +00:00
// Find the nearest linedef on the map
nl = map . NearestLinedef ( pos ) ;
if ( nl ! = null )
2007-06-14 12:37:46 +00:00
{
2007-10-24 17:25:03 +00:00
// Check what side of line we are at
if ( nl . SideOfLine ( pos ) < 0f )
{
// Front side
2009-01-03 20:54:12 +00:00
if ( nl . Front ! = null ) sector = nl . Front . Sector ; else sector = null ;
2007-10-24 17:25:03 +00:00
}
else
2007-06-14 12:37:46 +00:00
{
2007-10-24 17:25:03 +00:00
// Back side
2009-01-03 20:54:12 +00:00
if ( nl . Back ! = null ) sector = nl . Back . Sector ; else sector = null ;
2007-06-14 12:37:46 +00:00
}
}
2009-01-03 20:54:12 +00:00
else
2007-06-14 12:37:46 +00:00
{
sector = null ;
}
2009-01-03 20:54:12 +00:00
}
// This determines which sector the thing is in and links it
public void DetermineSector ( VisualBlockMap blockmap )
{
Linedef nl ;
// Find nearest sectors using the blockmap
List < Sector > possiblesectors = blockmap . GetBlock ( blockmap . GetBlockCoordinates ( pos ) ) . Sectors ;
2007-06-14 12:37:46 +00:00
2009-01-03 20:54:12 +00:00
// Check in which sector we are
sector = null ;
foreach ( Sector s in possiblesectors )
2007-06-14 12:37:46 +00:00
{
2009-01-03 20:54:12 +00:00
if ( s . Intersect ( pos ) )
{
sector = s ;
break ;
}
2007-06-14 12:37:46 +00:00
}
}
2008-12-31 14:08:40 +00:00
// This translates the flags into UDMF fields
internal void TranslateToUDMF ( )
{
// First make a single integer with all flags
int bits = 0 ;
int flagbit = 0 ;
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 ( ) ;
foreach ( FlagTranslation f in General . Map . Config . ThingFlagsTranslation )
{
// 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 + + )
2009-01-24 15:55:25 +00:00
flags [ f . Fields [ i ] ] = f . FieldValues [ i ] ;
2008-12-31 14:08:40 +00:00
}
else
{
// Add fields with inverted value
for ( int i = 0 ; i < f . Fields . Count ; i + + )
2009-01-24 15:55:25 +00:00
flags [ f . Fields [ i ] ] = ! f . FieldValues [ i ] ;
2008-12-31 14:08:40 +00:00
}
}
}
// This translates UDMF fields back into the normal flags
internal void TranslateFromUDMF ( )
{
// 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 . ThingFlags )
{
// Flag must be numeric
int flagbit = 0 ;
if ( int . TryParse ( f . Key , out flagbit ) )
{
foreach ( FlagTranslation ft in General . Map . Config . ThingFlagsTranslation )
{
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 ;
}
}
}
}
}
}
2009-03-30 07:45:39 +00:00
// Selected
protected override void DoSelect ( )
{
base . DoSelect ( ) ;
selecteditem = map . SelectedThings . AddLast ( this ) ;
}
// Deselect
protected override void DoUnselect ( )
{
base . DoUnselect ( ) ;
if ( selecteditem . List ! = null ) selecteditem . List . Remove ( selecteditem ) ;
selecteditem = null ;
}
2007-06-24 18:56:43 +00:00
2008-01-25 19:12:34 +00:00
#endregion
2007-06-24 18:56:43 +00:00
#region = = = = = = = = = = = = = = = = = = Changes
2007-06-14 12:37:46 +00:00
2008-06-01 20:25:46 +00:00
// This moves the thing
// NOTE: This does not update sector! (call DetermineSector)
public void Move ( Vector3D newpos )
{
// Change position
this . pos = newpos ;
2009-01-03 22:18:59 +00:00
General . Map . IsChanged = true ;
2008-06-01 20:25:46 +00:00
}
2008-04-07 14:33:41 +00:00
// This moves the thing
// NOTE: This does not update sector! (call DetermineSector)
public void Move ( Vector2D newpos )
{
// Change position
2008-12-06 13:20:47 +00:00
this . pos = new Vector3D ( newpos . x , newpos . y , pos . z ) ;
2009-01-03 22:18:59 +00:00
General . Map . IsChanged = true ;
2008-04-07 14:33:41 +00:00
}
2007-06-24 18:56:43 +00:00
// This moves the thing
// NOTE: This does not update sector! (call DetermineSector)
2008-06-01 20:25:46 +00:00
public void Move ( float x , float y , float zoffset )
2007-06-14 13:09:55 +00:00
{
2007-06-24 18:56:43 +00:00
// Change position
2007-10-24 17:25:03 +00:00
this . pos = new Vector3D ( x , y , zoffset ) ;
2009-01-03 22:18:59 +00:00
General . Map . IsChanged = true ;
2007-06-24 18:56:43 +00:00
}
// This rotates the thing
public void Rotate ( float newangle )
{
// Change angle
2007-10-24 17:25:03 +00:00
this . angle = newangle ;
2009-01-03 22:18:59 +00:00
General . Map . IsChanged = true ;
2007-06-24 18:56:43 +00:00
}
// This updates all properties
// NOTE: This does not update sector! (call DetermineSector)
2008-06-01 20:25:46 +00:00
public void Update ( int type , float x , float y , float zoffset , float angle ,
2008-05-31 19:31:45 +00:00
Dictionary < string , bool > flags , int tag , int action , int [ ] args )
2007-06-24 18:56:43 +00:00
{
// Apply changes
this . type = type ;
this . angle = angle ;
2008-05-31 19:31:45 +00:00
this . flags = new Dictionary < string , bool > ( flags ) ;
2007-06-24 18:56:43 +00:00
this . tag = tag ;
this . action = action ;
2008-05-29 21:09:43 +00:00
this . args = new int [ NUM_ARGS ] ;
2007-12-29 15:50:16 +00:00
args . CopyTo ( this . args , 0 ) ;
2007-10-24 17:25:03 +00:00
this . Move ( x , y , zoffset ) ;
2007-06-14 13:09:55 +00:00
}
2007-10-21 18:06:10 +00:00
// This updates the settings from configuration
public void UpdateConfiguration ( )
{
2007-10-21 22:41:46 +00:00
ThingTypeInfo ti ;
2007-10-21 18:06:10 +00:00
// Lookup settings
2009-01-21 16:18:30 +00:00
ti = General . Map . Data . GetThingInfo ( type ) ;
2007-10-21 22:41:46 +00:00
// Apply size
2009-02-16 10:06:58 +00:00
size = ti . Radius ;
2008-11-17 16:14:45 +00:00
fixedsize = ti . FixedSize ;
2007-10-21 22:41:46 +00:00
// Color valid?
if ( ( ti . Color > = 0 ) & & ( ti . Color < ColorCollection . NUM_THING_COLORS ) )
{
// Apply color
color = General . Colors . Colors [ ti . Color + ColorCollection . THING_COLORS_OFFSET ] ;
}
else
{
// Unknown thing color
color = General . Colors . Colors [ ColorCollection . THING_COLORS_OFFSET ] ;
}
// Apply icon offset (arrow or dot)
if ( ti . Arrow ) iconoffset = 0f ; else iconoffset = 0.25f ;
2007-10-21 18:06:10 +00:00
}
2007-06-14 12:37:46 +00:00
#endregion
2008-01-02 21:49:43 +00:00
#region = = = = = = = = = = = = = = = = = = Methods
2008-04-07 14:33:41 +00:00
// This snaps the vertex to the grid
public void SnapToGrid ( )
{
// Calculate nearest grid coordinates
this . Move ( General . Map . Grid . SnappedToGrid ( ( Vector2D ) pos ) ) ;
}
2008-06-01 20:25:46 +00:00
// This snaps the vertex to the map format accuracy
public void SnapToAccuracy ( )
{
// Round the coordinates
Vector3D newpos = new Vector3D ( ( float ) Math . Round ( pos . x , General . Map . FormatInterface . VertexDecimals ) ,
( float ) Math . Round ( pos . y , General . Map . FormatInterface . VertexDecimals ) ,
( float ) Math . Round ( pos . z , General . Map . FormatInterface . VertexDecimals ) ) ;
this . Move ( newpos ) ;
}
2008-01-02 21:49:43 +00:00
// This returns the distance from given coordinates
public float DistanceToSq ( Vector2D p )
{
2008-11-30 02:17:19 +00:00
return Vector2D . DistanceSq ( p , pos ) ;
2008-01-02 21:49:43 +00:00
}
// This returns the distance from given coordinates
public float DistanceTo ( Vector2D p )
{
2008-11-30 02:17:19 +00:00
return Vector2D . Distance ( p , pos ) ;
2008-01-02 21:49:43 +00:00
}
#endregion
2007-06-14 12:37:46 +00:00
}
}