mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-30 15:41:30 +00:00
0369c969d1
Draw Curve Mode: added settings panel. Sectors mode: added "Make Door" button to the toolbar. Swapped Side panel and Info panel z-order. Interface: split toolbar into 3 separate toolbars. All toolbar buttons are now viewable at 1024x768. Interface: grouped stuff in "Modes" menu a bit better. Interface: added "Draw [stuff]" buttons to modes toolbar. Interface: reorganized main menu. Hope it makes more sense now. API: added General.Interface.AddModesButton() and General.Interface.AddModesMenu(), which can be used to add buttons to specific group in "Modes" toolbar and menu items to specific group in "Modes" menu, so actions, which behave like an editing mode, but are not part of one can be added there.
271 lines
8.2 KiB
C#
271 lines
8.2 KiB
C#
|
|
#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.Map;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using CodeImp.DoomBuilder.Config;
|
|
using System.Threading;
|
|
using System.Drawing;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.BuilderModes
|
|
{
|
|
[ErrorChecker("Check stuck things", true, 1000)]
|
|
public class CheckStuckThings : ErrorChecker
|
|
{
|
|
#region ================== Constants
|
|
|
|
private const int PROGRESS_STEP = 10;
|
|
private const float ALLOWED_STUCK_DISTANCE = 6.0f;
|
|
|
|
enum StuckType
|
|
{
|
|
None = 0,
|
|
Line,
|
|
Thing
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor / Destructor
|
|
|
|
// Constructor
|
|
public CheckStuckThings()
|
|
{
|
|
// Total progress is done when all things are checked
|
|
SetTotalProgress(General.Map.Map.Things.Count / PROGRESS_STEP);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Methods
|
|
|
|
// This runs the check
|
|
public override void Run()
|
|
{
|
|
BlockMap<BlockEntry> blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap;
|
|
int progress = 0;
|
|
int stepprogress = 0;
|
|
float maxradius = 0;
|
|
|
|
foreach (ThingTypeInfo tti in General.Map.Data.ThingTypes)
|
|
{
|
|
if (tti.Radius > maxradius) maxradius = tti.Radius;
|
|
}
|
|
|
|
// Go for all the things
|
|
foreach(Thing t in General.Map.Map.Things)
|
|
{
|
|
ThingTypeInfo info = General.Map.Data.GetThingInfo(t.Type);
|
|
bool stuck = false;
|
|
StuckType stucktype = StuckType.None;
|
|
|
|
// Check this thing for getting stuck?
|
|
if( (info.ErrorCheck == ThingTypeInfo.THING_ERROR_INSIDE_STUCK) &&
|
|
(info.Blocking > ThingTypeInfo.THING_BLOCKING_NONE))
|
|
{
|
|
// Make square coordinates from thing
|
|
float blockingsize = t.Size - ALLOWED_STUCK_DISTANCE;
|
|
Vector2D lt = new Vector2D(t.Position.x - blockingsize, t.Position.y - blockingsize);
|
|
Vector2D rb = new Vector2D(t.Position.x + blockingsize, t.Position.y + blockingsize);
|
|
Vector2D bmlt = new Vector2D(t.Position.x - maxradius, t.Position.y - maxradius);
|
|
Vector2D bmrb = new Vector2D(t.Position.x + maxradius, t.Position.y + maxradius);
|
|
|
|
// Go for all the lines to see if this thing is stuck
|
|
List<BlockEntry> blocks = blockmap.GetSquareRange(new RectangleF(bmlt.x, bmlt.y, (bmrb.x - bmlt.x), (bmrb.y - bmlt.y)));
|
|
Dictionary<Linedef, Linedef> doneblocklines = new Dictionary<Linedef, Linedef>(blocks.Count * 3);
|
|
|
|
foreach(BlockEntry b in blocks)
|
|
{
|
|
foreach(Linedef l in b.Lines)
|
|
{
|
|
// Only test when sinlge-sided, two-sided + impassable and not already checked
|
|
if(((l.Back == null) || l.IsFlagSet(General.Map.Config.ImpassableFlag)) && !doneblocklines.ContainsKey(l))
|
|
{
|
|
// Test if line ends are inside the thing
|
|
if(PointInRect(lt, rb, l.Start.Position) ||
|
|
PointInRect(lt, rb, l.End.Position))
|
|
{
|
|
// Thing stuck in line!
|
|
stuck = true;
|
|
}
|
|
// Test if the line intersects the square
|
|
else if(Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, lt.y, rb.x, lt.y) ||
|
|
Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, lt.y, rb.x, rb.y) ||
|
|
Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, rb.y, lt.x, rb.y) ||
|
|
Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, rb.y, lt.x, lt.y))
|
|
{
|
|
// Thing stuck in line!
|
|
stuck = true;
|
|
stucktype = StuckType.Line;
|
|
}
|
|
|
|
// Checked
|
|
doneblocklines.Add(l, l);
|
|
}
|
|
}
|
|
|
|
// Check if thing is stuck in other things
|
|
if(info.Blocking != ThingTypeInfo.THING_BLOCKING_NONE) {
|
|
foreach (Thing ot in b.Things)
|
|
{
|
|
// Don't compare the thing with itself
|
|
if (t.Index == ot.Index) continue;
|
|
|
|
// Only check of items that can block
|
|
if (General.Map.Data.GetThingInfo(ot.Type).Blocking == ThingTypeInfo.THING_BLOCKING_NONE) continue;
|
|
|
|
// need to compare the flags
|
|
/* TODO: skill settings
|
|
Dictionary<string, bool> flags1 = t.GetFlags();
|
|
Dictionary<string, bool> flags2 = ot.GetFlags();
|
|
*/
|
|
|
|
if (FlagsOverlap(t, ot) && ThingsOverlap(t, ot))
|
|
{
|
|
stuck = true;
|
|
stucktype = StuckType.Thing;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Stuck?
|
|
if(stuck)
|
|
{
|
|
// Make result
|
|
switch (stucktype)
|
|
{
|
|
case StuckType.Line:
|
|
SubmitResult(new ResultStuckThingInLine(t));
|
|
break;
|
|
|
|
case StuckType.Thing:
|
|
SubmitResult(new ResultStuckThingInThing(t));
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check this thing for being outside the map?
|
|
if(info.ErrorCheck >= ThingTypeInfo.THING_ERROR_INSIDE)
|
|
{
|
|
// Get the nearest line to see if the thing is outside the map
|
|
bool outside;
|
|
Linedef l = General.Map.Map.NearestLinedef(t.Position);
|
|
if(l.SideOfLine(t.Position) <= 0)
|
|
{
|
|
outside = (l.Front == null);
|
|
}
|
|
else
|
|
{
|
|
outside = (l.Back == null);
|
|
}
|
|
|
|
// Outside the map?
|
|
if(outside)
|
|
{
|
|
// Make result
|
|
SubmitResult(new ResultThingOutside(t));
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Point in rect?
|
|
private bool PointInRect(Vector2D lt, Vector2D rb, Vector2D p)
|
|
{
|
|
return (p.x >= lt.x) && (p.x <= rb.x) && (p.y <= lt.y) && (p.y >= rb.y);
|
|
}
|
|
|
|
// Checks if two things overlap
|
|
private bool ThingsOverlap(Thing t1, Thing t2)
|
|
{
|
|
Vector3D p1 = t1.Position;
|
|
Vector3D p2 = t2.Position;
|
|
ThingTypeInfo t1info = General.Map.Data.GetThingInfo(t1.Type);
|
|
ThingTypeInfo t2info = General.Map.Data.GetThingInfo(t2.Type);
|
|
|
|
// simple bounding box collision detection
|
|
if ( p1.x + t1.Size - ALLOWED_STUCK_DISTANCE < p2.x - t2.Size + ALLOWED_STUCK_DISTANCE ||
|
|
p1.x - t1.Size + ALLOWED_STUCK_DISTANCE > p2.x + t2.Size - ALLOWED_STUCK_DISTANCE ||
|
|
p1.y - t1.Size + ALLOWED_STUCK_DISTANCE > p2.y + t2.Size - ALLOWED_STUCK_DISTANCE ||
|
|
p1.y + t1.Size - ALLOWED_STUCK_DISTANCE < p2.y - t2.Size + ALLOWED_STUCK_DISTANCE)
|
|
return false;
|
|
|
|
// if either thing blocks full height there's no need to check the z-axis
|
|
if (t1info.Blocking == ThingTypeInfo.THING_BLOCKING_FULL || t2info.Blocking == ThingTypeInfo.THING_BLOCKING_FULL)
|
|
return true;
|
|
|
|
// check z-axis
|
|
if (p1.z > p2.z + t2info.Height || p1.z + t1info.Height < p2.z)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Checks if the flags of two things overlap (i.e. if they show up at the same time)
|
|
private bool FlagsOverlap(Thing t1, Thing t2) {
|
|
var groups = new Dictionary<string, List<ThingFlagsCompare>>(StringComparer.Ordinal);
|
|
int overlappinggroups = 0;
|
|
|
|
// Create a summary which flags belong to which groups
|
|
foreach (ThingFlagsCompare tfc in General.Map.Config.ThingFlagsCompare) {
|
|
if (!groups.ContainsKey(tfc.Group))
|
|
groups[tfc.Group] = new List<ThingFlagsCompare>();
|
|
|
|
groups[tfc.Group].Add(tfc);
|
|
}
|
|
|
|
// Go through all flags in all groups and check if they overlap
|
|
foreach (string g in groups.Keys) {
|
|
foreach (ThingFlagsCompare tfc in groups[g]) {
|
|
if (tfc.Compare(t1, t2) > 0) {
|
|
overlappinggroups++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// All groups have to overlap for the things to show up
|
|
// at the same time
|
|
if (overlappinggroups == groups.Count)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|