mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-23 04:12:12 +00:00
Added, Map Analysis mode: added "Check Polyobjects" checker.
Changed, Game configurations: "Polyobject Anchor" things should not trigger "Thing outside the map geometry" error in the Map Analysis mode. Updated ZDoom_DECORATE.cfg (A_SetScale).
This commit is contained in:
parent
53a2344838
commit
7446c576d6
7 changed files with 356 additions and 1 deletions
|
@ -1518,6 +1518,7 @@ other
|
|||
title = "Polyobject Anchor";
|
||||
sprite = "internal:anchor";
|
||||
fixedrotation = true;
|
||||
error = 0; // Can be outside of map geometry
|
||||
}
|
||||
3001
|
||||
{
|
||||
|
|
|
@ -1091,6 +1091,7 @@ zdoom
|
|||
sprite = "internal:anchor";
|
||||
class = "$PolyAnchor";
|
||||
fixedrotation = true;
|
||||
error = 0; // Can be outside of map geometry
|
||||
}
|
||||
|
||||
9301
|
||||
|
|
|
@ -238,7 +238,7 @@ keywords
|
|||
A_SetRipMin = "A_SetRipMin(int min)";
|
||||
A_SetRipMax = "A_SetRipMax(int max)";
|
||||
A_SetRoll = "A_SetRoll(float roll[, int flags = 0[, int pointer = AAPTR_DEFAULT]])";
|
||||
A_SetScale = "A_SetScale(float scaleX[, float scaleY = scaleX[, int pointer = AAPTR_DEFAULT]])";
|
||||
A_SetScale = "A_SetScale(float scaleX[, float scaleY = scaleX[, int pointer = AAPTR_DEFAULT[, bool usezero = false]]])";
|
||||
A_SetShadow = "A_SetShadow";
|
||||
A_SetShootable = "A_SetShootable";
|
||||
A_SetSolid = "A_SetSolid";
|
||||
|
|
|
@ -249,6 +249,7 @@
|
|||
<Compile Include="ErrorChecks\CheckMissingTextures.cs" />
|
||||
<Compile Include="ErrorChecks\CheckObsoleteThings.cs" />
|
||||
<Compile Include="ErrorChecks\CheckOverlappingVertices.cs" />
|
||||
<Compile Include="ErrorChecks\CheckPolyobjects.cs" />
|
||||
<Compile Include="ErrorChecks\CheckShortLinedefs.cs" />
|
||||
<Compile Include="ErrorChecks\CheckStrayVertices.cs" />
|
||||
<Compile Include="ErrorChecks\CheckTextureAlignment.cs" />
|
||||
|
@ -257,6 +258,8 @@
|
|||
<Compile Include="ErrorChecks\CheckUnknownThings.cs" />
|
||||
<Compile Include="ErrorChecks\CheckUnusedTextures.cs" />
|
||||
<Compile Include="ErrorChecks\CheckUnusedThings.cs" />
|
||||
<Compile Include="ErrorChecks\ResultInvalidPolyobjectLines.cs" />
|
||||
<Compile Include="ErrorChecks\ResultInvalidPolyobjectThings.cs" />
|
||||
<Compile Include="ErrorChecks\ResultMapTooBig.cs" />
|
||||
<Compile Include="ErrorChecks\ResultMissingFlat.cs" />
|
||||
<Compile Include="ErrorChecks\ResultNoErrors.cs" />
|
||||
|
|
167
Source/Plugins/BuilderModes/ErrorChecks/CheckPolyobjects.cs
Normal file
167
Source/Plugins/BuilderModes/ErrorChecks/CheckPolyobjects.cs
Normal file
|
@ -0,0 +1,167 @@
|
|||
#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
|
||||
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)
|
||||
{
|
||||
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."));
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
public class ResultInvalidPolyobjectLines : ErrorResult
|
||||
{
|
||||
#region ================== Variables
|
||||
|
||||
private readonly List<Linedef> lines;
|
||||
private readonly string linesinfo;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
public override int Buttons { get { return 0; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Destructor
|
||||
|
||||
public ResultInvalidPolyobjectLines(List<Linedef> lines, string details)
|
||||
{
|
||||
// Initialize
|
||||
this.lines = lines;
|
||||
this.hidden = true;
|
||||
foreach(Linedef l in lines)
|
||||
{
|
||||
this.viewobjects.Add(l);
|
||||
this.hidden &= l.IgnoredErrorChecks.Contains(this.GetType());
|
||||
}
|
||||
|
||||
if(lines.Count == 1)
|
||||
{
|
||||
linesinfo = "Incorrect Polyobject setup for linedef " + lines[0].Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
linesinfo = "Incorrect Polyobject setup for linedefs " + lines[0].Index;
|
||||
for(int i = 1; i < lines.Count - 1; i++) linesinfo += ", " + lines[i].Index;
|
||||
linesinfo += " and " + lines[lines.Count - 1].Index;
|
||||
}
|
||||
|
||||
this.description = linesinfo + ": " + details;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This sets if this result is displayed in ErrorCheckForm (mxd)
|
||||
internal override void Hide(bool hide)
|
||||
{
|
||||
hidden = hide;
|
||||
Type t = this.GetType();
|
||||
if(hide)
|
||||
{
|
||||
foreach(Linedef l in lines)
|
||||
l.IgnoredErrorChecks.Add(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(Linedef l in lines)
|
||||
if(l.IgnoredErrorChecks.Contains(t)) l.IgnoredErrorChecks.Remove(t);
|
||||
}
|
||||
}
|
||||
|
||||
// This must return the string that is displayed in the listbox
|
||||
public override string ToString()
|
||||
{
|
||||
return linesinfo;
|
||||
}
|
||||
|
||||
// Rendering
|
||||
public override void PlotSelection(IRenderer2D renderer)
|
||||
{
|
||||
foreach(Linedef l in lines)
|
||||
{
|
||||
renderer.PlotLinedef(l, General.Colors.Selection);
|
||||
renderer.PlotVertex(l.Start, ColorCollection.VERTICES);
|
||||
renderer.PlotVertex(l.End, ColorCollection.VERTICES);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
public class ResultInvalidPolyobjectThings : ErrorResult
|
||||
{
|
||||
#region ================== Variables
|
||||
|
||||
private readonly List<Thing> things;
|
||||
private readonly string thingsinfo;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
public override int Buttons { get { return 0; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Destructor
|
||||
|
||||
public ResultInvalidPolyobjectThings(List<Thing> things, string details)
|
||||
{
|
||||
// Initialize
|
||||
this.things = things;
|
||||
this.hidden = true;
|
||||
foreach(Thing t in things)
|
||||
{
|
||||
this.viewobjects.Add(t);
|
||||
this.hidden &= t.IgnoredErrorChecks.Contains(this.GetType());
|
||||
}
|
||||
|
||||
if(things.Count == 1)
|
||||
{
|
||||
thingsinfo = "Incorrect Polyobject setup for thing " + things[0].Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
thingsinfo = "Incorrect Polyobject setup for things " + things[0].Index;
|
||||
for(int i = 1; i < things.Count - 1; i++) thingsinfo += ", " + things[i].Index;
|
||||
thingsinfo += " and " + things[things.Count - 1].Index;
|
||||
}
|
||||
|
||||
this.description = thingsinfo + ": " + details;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This sets if this result is displayed in ErrorCheckForm (mxd)
|
||||
internal override void Hide(bool hide)
|
||||
{
|
||||
hidden = hide;
|
||||
Type t = this.GetType();
|
||||
if(hide)
|
||||
{
|
||||
foreach(Thing thing in things) thing.IgnoredErrorChecks.Add(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(Thing thing in things)
|
||||
if(thing.IgnoredErrorChecks.Contains(t)) thing.IgnoredErrorChecks.Remove(t);
|
||||
}
|
||||
}
|
||||
|
||||
// This must return the string that is displayed in the listbox
|
||||
public override string ToString()
|
||||
{
|
||||
return thingsinfo;
|
||||
}
|
||||
|
||||
// Rendering
|
||||
public override void RenderOverlaySelection(IRenderer2D renderer)
|
||||
{
|
||||
foreach(Thing thing in things)
|
||||
renderer.RenderThing(thing, General.Colors.Selection, Presentation.THINGS_ALPHA);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue