2016-03-09 14:52:18 +00:00
#region = = = = = = = = = = = = = = = = = = Namespaces
using System ;
using System.Collections.Generic ;
using CodeImp.DoomBuilder.Config ;
using CodeImp.DoomBuilder.Map ;
using System.Threading ;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[ErrorChecker("Check Polyobjects", true, 100)]
public class CheckPolyobjects : ErrorChecker
{
#region = = = = = = = = = = = = = = = = = = Constants
private const int PROGRESS_STEP = 1000 ;
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Destructor
public CheckPolyobjects ( )
{
// Total progress is somewhat done when all linedefs and things are checked
SetTotalProgress ( ( General . Map . Map . Linedefs . Count + General . Map . Map . Things . Count ) / PROGRESS_STEP ) ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
// This runs the check
public override void Run ( )
{
int progress = 0 ;
int stepprogress = 0 ;
const string Polyobj_StartLine = "Polyobj_StartLine" ;
// <Polyobj_Action, <Polyobj_number, Lines using this number>>
Dictionary < string , Dictionary < int , List < Linedef > > > polyobjlines = new Dictionary < string , Dictionary < int , List < Linedef > > > ( ) ;
// All polyobject-related actions
HashSet < string > allactions = new HashSet < string > ( StringComparer . OrdinalIgnoreCase )
{
Polyobj_StartLine , "Polyobj_RotateLeft" ,
"Polyobj_RotateRight" , "Polyobj_Move" ,
"Polyobj_MoveTimes8" , "Polyobj_DoorSwing" ,
"Polyobj_DoorSlide" , "Polyobj_OR_MoveToSpot" ,
"Polyobj_MoveToSpot" , "Polyobj_Stop" ,
"Polyobj_MoveTo" , "Polyobj_OR_MoveTo" ,
"Polyobj_OR_RotateLeft" , "Polyobj_OR_RotateRight" ,
"Polyobj_OR_Move" , "Polyobj_OR_MoveTimes8"
} ;
Dictionary < int , List < Thing > > anchors = new Dictionary < int , List < Thing > > ( ) ;
Dictionary < int , List < Thing > > startspots = new Dictionary < int , List < Thing > > ( ) ;
// Collect Linedefs...
foreach ( Linedef l in General . Map . Map . Linedefs )
{
if ( l . Action > 0 & & General . Map . Config . LinedefActions . ContainsKey ( l . Action ) & & allactions . Contains ( General . Map . Config . LinedefActions [ l . Action ] . Id ) )
{
string id = General . Map . Config . LinedefActions [ l . Action ] . Id ;
if ( ! polyobjlines . ContainsKey ( id ) )
polyobjlines . Add ( id , new Dictionary < int , List < Linedef > > ( ) ) ;
// Polyobj number is always the first arg
if ( ! polyobjlines [ id ] . ContainsKey ( l . Args [ 0 ] ) )
polyobjlines [ id ] . Add ( l . Args [ 0 ] , new List < Linedef > ( ) ) ;
polyobjlines [ id ] [ l . Args [ 0 ] ] . Add ( l ) ;
}
UpdateProgress ( ref progress , ref stepprogress ) ;
}
// Collect Things...
foreach ( Thing t in General . Map . Map . Things )
{
ThingTypeInfo info = General . Map . Data . GetThingInfoEx ( t . Type ) ;
if ( info = = null ) continue ;
switch ( info . ClassName . ToLowerInvariant ( ) )
{
case "$polyanchor" :
if ( ! anchors . ContainsKey ( t . AngleDoom ) ) anchors . Add ( t . AngleDoom , new List < Thing > ( ) ) ;
anchors [ t . AngleDoom ] . Add ( t ) ;
break ;
case "$polyspawn" :
case "$polyspawncrush" :
case "$polyspawnhurt" :
if ( ! startspots . ContainsKey ( t . AngleDoom ) ) startspots . Add ( t . AngleDoom , new List < Thing > ( ) ) ;
startspots [ t . AngleDoom ] . Add ( t ) ;
break ;
}
UpdateProgress ( ref progress , ref stepprogress ) ;
}
// Check Linedefs. These can connect 1 - multiple (except Polyobj_StartLine)
// Polyobject number is always arg0.
foreach ( KeyValuePair < string , Dictionary < int , List < Linedef > > > group in polyobjlines )
{
foreach ( KeyValuePair < int , List < Linedef > > linesbytype in group . Value )
{
if ( ! startspots . ContainsKey ( linesbytype . Key ) )
SubmitResult ( new ResultInvalidPolyobjectLines ( linesbytype . Value , "\"" + group . Key + "\" action targets non-existing Polyobject Start Spot (" + linesbytype . Key + ")" ) ) ;
}
}
// Check Linedefs with Polyobj_StartLine action. These must connect 1 - 1.
// Polyobject number is arg0, Mirror polyobject number is arg1
2016-03-09 19:36:11 +00:00
if ( polyobjlines . ContainsKey ( Polyobj_StartLine ) )
2016-03-09 14:52:18 +00:00
{
2016-03-09 19:36:11 +00:00
foreach ( KeyValuePair < int , List < Linedef > > linesbytype in polyobjlines [ Polyobj_StartLine ] )
2016-03-09 14:52:18 +00:00
{
2016-03-09 19:36:11 +00:00
// Should be only one Polyobj_StartLine per Polyobject number
if ( linesbytype . Value . Count > 1 )
SubmitResult ( new ResultInvalidPolyobjectLines ( linesbytype . Value , "Several \"" + Polyobj_StartLine + "\" actions have the same Polyobject Number assigned (" + linesbytype . Key + "). They won't function correctly ingame." ) ) ;
// Check if Mirror Polyobject Number exists
foreach ( Linedef linedef in linesbytype . Value )
{
if ( ! startspots . ContainsKey ( linedef . Args [ 1 ] ) )
SubmitResult ( new ResultInvalidPolyobjectLines ( new List < Linedef > { linedef } , "\"" + Polyobj_StartLine + "\" action have non-existing Mirror Polyobject Number assigned (" + linedef . Args [ 1 ] + "). It won't function correctly ingame." ) ) ;
}
2016-03-09 14:52:18 +00:00
}
}
// Check Polyobject Anchors. These must connect 1 - 1.
foreach ( KeyValuePair < int , List < Thing > > group in anchors )
{
if ( ! startspots . ContainsKey ( group . Key ) )
SubmitResult ( new ResultInvalidPolyobjectThings ( group . Value , "Polyobject " + ( group . Value . Count > 1 ? "Anchors target" : "Anchor targets" ) + " non-existing Polyobject Start Spot (" + group . Key + ")" ) ) ;
if ( group . Value . Count > 1 )
SubmitResult ( new ResultInvalidPolyobjectThings ( group . Value , "Several Polyobject Anchors target the same Polyobject Start Spot (" + group . Key + "). They won't function correctly ingame." ) ) ;
}
// Check Polyobject Start Spots. These must connect 1 - 1.
foreach ( KeyValuePair < int , List < Thing > > group in startspots )
{
if ( ! anchors . ContainsKey ( group . Key ) )
SubmitResult ( new ResultInvalidPolyobjectThings ( group . Value , "Polyobject Start " + ( group . Value . Count > 1 ? "Spots are not targeted" : "Spot " + group . Key + " is not targeted" ) + " by any Polyobject Anchor" ) ) ;
if ( group . Value . Count > 1 )
SubmitResult ( new ResultInvalidPolyobjectThings ( group . Value , "Several Polyobject Start Spots have the same Polyobject number (" + group . Key + "). They won't function correctly ingame." ) ) ;
}
}
private void UpdateProgress ( ref int progress , ref int stepprogress )
{
// Handle thread interruption
try { Thread . Sleep ( 0 ) ; }
catch ( ThreadInterruptedException ) { return ; }
// We are making progress!
if ( ( + + progress / PROGRESS_STEP ) > stepprogress )
{
stepprogress = ( progress / PROGRESS_STEP ) ;
AddProgress ( 1 ) ;
}
}
#endregion
}
}