mirror of
https://git.do.srb2.org/STJr/ZoneBuilder.git
synced 2024-11-12 23:54:10 +00:00
154ceb0eb7
Changed, Map Analysis mode: some checks are now available only under certain conditions (for example, "Check polyobjects" is now available only when the map is in Hexen or UDMF map format). Updated documentation ("Game Configuration - Basic Settings" page).
178 lines
6.6 KiB
C#
178 lines
6.6 KiB
C#
#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 ================== Properties
|
|
|
|
// Only possible in Hexen/UDMF map formats
|
|
public override bool SkipCheck { get { return (!General.Map.UDMF && !General.Map.HEXEN); } }
|
|
|
|
#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.SRB2Type);
|
|
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
|
|
if(polyobjlines.ContainsKey(Polyobj_StartLine))
|
|
{
|
|
foreach(KeyValuePair<int, List<Linedef>> linesbytype in polyobjlines[Polyobj_StartLine])
|
|
{
|
|
// 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)
|
|
{
|
|
// The value of 0 can mean either "No mirror polyobj" or "Polyobj 0" here...
|
|
if(linedef.Args[1] > 0 && !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."));
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|