* A direct tag-to-tag relationship can now be established between two things, which allows event lines to be properly setup between them. This is intended for interpolation and patrol specials which are linked via a shared tag, instead of an argument. A POSITIVE value represents the parent thing, where a NEGATIVE value represents the child thing.

* Added interpolation and patrol point specials to the persistent event line processing
This commit is contained in:
Xabis 2017-02-14 12:33:50 -05:00 committed by spherallic
parent 21e2d93784
commit f8e048b1c1
5 changed files with 121 additions and 11 deletions

View file

@ -85,6 +85,7 @@ namespace CodeImp.DoomBuilder.Config
private string angletext; private string angletext;
private string flagsvaluetext; private string flagsvaluetext;
private string parametertext; private string parametertext;
private int thinglink;
//mxd. GLOOME rendering settings //mxd. GLOOME rendering settings
private Thing.SpriteRenderMode rendermode; private Thing.SpriteRenderMode rendermode;
@ -137,7 +138,8 @@ namespace CodeImp.DoomBuilder.Config
public string AngleText { get { return angletext; } } public string AngleText { get { return angletext; } }
public string FlagsValueText { get { return flagsvaluetext; } } public string FlagsValueText { get { return flagsvaluetext; } }
public string ParameterText { get { return parametertext; } } public string ParameterText { get { return parametertext; } }
#endregion public int ThingLink { get { return thinglink; } }
#endregion
#region ================== Constructor / Disposer #region ================== Constructor / Disposer
@ -180,9 +182,10 @@ namespace CodeImp.DoomBuilder.Config
this.angletext = "Angle"; this.angletext = "Angle";
this.flagsvaluetext = "Flags value"; this.flagsvaluetext = "Flags value";
this.parametertext = "Parameter"; this.parametertext = "Parameter";
this.thinglink = 0;
// We have no destructor
GC.SuppressFinalize(this); // We have no destructor
GC.SuppressFinalize(this);
} }
// Constructor // Constructor
@ -227,6 +230,7 @@ namespace CodeImp.DoomBuilder.Config
this.angletext = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".angletext", cat.AngleText); this.angletext = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".angletext", cat.AngleText);
this.flagsvaluetext = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".flagsvaluetext", cat.FlagsValueText); this.flagsvaluetext = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".flagsvaluetext", cat.FlagsValueText);
this.parametertext = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".parametertext", cat.ParameterText); this.parametertext = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".parametertext", cat.ParameterText);
this.thinglink = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".thinglink", 0);
// Read the args // Read the args
for (int i = 0; i < Linedef.NUM_ARGS; i++) for (int i = 0; i < Linedef.NUM_ARGS; i++)

View file

@ -12,7 +12,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
private class SpecialThings private class SpecialThings
{ {
public readonly Dictionary<int, List<Thing>> PatrolPoints; // PatrolPoint tag, list of PatrolPoints public readonly Dictionary<int, List<Thing>> PatrolPoints; // PatrolPoint tag, list of PatrolPoints
public readonly List<Thing> PatrolSpecials;
public readonly Dictionary<int, List<PathNode>> InterpolationPoints; // InterpolationPoint tag, list of InterpolationPoints public readonly Dictionary<int, List<PathNode>> InterpolationPoints; // InterpolationPoint tag, list of InterpolationPoints
public readonly List<Thing> InterpolationSpecials;
public readonly List<Thing> ThingsWithGoal; public readonly List<Thing> ThingsWithGoal;
public readonly List<Thing> Cameras; public readonly List<Thing> Cameras;
public readonly Dictionary<int, List<Thing>> ActorMovers; // ActorMover target tag, list of ActorMovers public readonly Dictionary<int, List<Thing>> ActorMovers; // ActorMover target tag, list of ActorMovers
@ -23,7 +25,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
public SpecialThings() public SpecialThings()
{ {
PatrolPoints = new Dictionary<int, List<Thing>>(); PatrolPoints = new Dictionary<int, List<Thing>>();
PatrolSpecials = new List<Thing>();
InterpolationPoints = new Dictionary<int, List<PathNode>>(); InterpolationPoints = new Dictionary<int, List<PathNode>>();
InterpolationSpecials = new List<Thing>();
ThingsWithGoal = new List<Thing>(); ThingsWithGoal = new List<Thing>();
Cameras = new List<Thing>(); Cameras = new List<Thing>();
ActorMovers = new Dictionary<int, List<Thing>>(); ActorMovers = new Dictionary<int, List<Thing>>();
@ -97,6 +101,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
} }
break; break;
case "patrolspecial":
result.PatrolSpecials.Add(t);
break;
case "$polyanchor": case "$polyanchor":
if(!result.PolyobjectAnchors.ContainsKey(t.AngleDoom)) result.PolyobjectAnchors[t.AngleDoom] = new List<Thing>(); if(!result.PolyobjectAnchors.ContainsKey(t.AngleDoom)) result.PolyobjectAnchors[t.AngleDoom] = new List<Thing>();
result.PolyobjectAnchors[t.AngleDoom].Add(t); result.PolyobjectAnchors[t.AngleDoom].Add(t);
@ -133,6 +141,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
result.InterpolationPoints[t.Tag].Add(new PathNode(t, blockmap, bsp, useblockmap)); result.InterpolationPoints[t.Tag].Add(new PathNode(t, blockmap, bsp, useblockmap));
break; break;
case "interpolationspecial":
result.InterpolationSpecials.Add(t);
break;
case "movingcamera": case "movingcamera":
if(t.Args[0] != 0 || t.Args[1] != 0) result.Cameras.Add(t); if(t.Args[0] != 0 || t.Args[1] != 0) result.Cameras.Add(t);
break; break;
@ -208,6 +220,23 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
} }
} }
// Process patrol specials
foreach (Thing t in result.PatrolSpecials)
{
if (!result.PatrolPoints.ContainsKey(t.Tag)) continue;
start = t.Position;
start.z += GetCorrectHeight(t, blockmap, true);
foreach (Thing tt in result.PatrolPoints[t.Tag])
{
end = tt.Position;
end.z += GetCorrectHeight(tt, blockmap, true);
lines.Add(new Line3D(start, end, General.Colors.Selection));
}
}
// Process cameras [CAN USE INTERPOLATION] // Process cameras [CAN USE INTERPOLATION]
foreach(Thing t in result.Cameras) foreach(Thing t in result.Cameras)
{ {
@ -321,6 +350,24 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
foreach(PathNode node in group.Value) node.PropagateCurvedFlag(); foreach(PathNode node in group.Value) node.PropagateCurvedFlag();
} }
// Process interpolation specials
foreach (Thing t in result.InterpolationSpecials)
{
int targettag = t.Tag;
if (targettag == 0 || !result.InterpolationPoints.ContainsKey(targettag)) continue; //no target / target doesn't exist
start = t.Position;
start.z += GetCorrectHeight(t, blockmap, true);
foreach (PathNode node in result.InterpolationPoints[targettag])
{
//Do not connect specials to the first or last node of a curved path, since those are used as spline control points only
if (node.IsCurved && (node.PreviousNodes.Count == 0 || node.NextNodes.Count == 0))
continue;
lines.Add(new Line3D(start, node.Position, General.Colors.Selection));
}
}
// 3. Make lines // 3. Make lines
HashSet<int> processedindices = new HashSet<int>(); HashSet<int> processedindices = new HashSet<int>();
foreach(KeyValuePair<int, List<PathNode>> group in result.InterpolationPoints) foreach(KeyValuePair<int, List<PathNode>> group in result.InterpolationPoints)

View file

@ -57,6 +57,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Highlighted item // Highlighted item
private Thing highlighted; private Thing highlighted;
private readonly Association[] association = new Association[Thing.NUM_ARGS]; private readonly Association[] association = new Association[Thing.NUM_ARGS];
private readonly Association directasso = new Association();
private readonly Association highlightasso = new Association(); private readonly Association highlightasso = new Association();
// Interface // Interface
@ -90,6 +91,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{ {
//mxd. Associations now requre initializing... //mxd. Associations now requre initializing...
for(int i = 0; i < association.Length; i++) association[i] = new Association(); for(int i = 0; i < association.Length; i++) association[i] = new Association();
directasso = new Association();
} }
//mxd //mxd
@ -253,6 +255,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, alpha); renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, alpha);
renderer.RenderNiGHTSPath(); renderer.RenderNiGHTSPath();
for (int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.RenderAssociations(renderer, association[i], eventlines); for (int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.RenderAssociations(renderer, association[i], eventlines);
BuilderPlug.RenderAssociations(renderer, directasso, eventlines);
if((highlighted != null) && !highlighted.IsDisposed) if((highlighted != null) && !highlighted.IsDisposed)
{ {
@ -353,8 +356,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd. Update label color? //mxd. Update label color?
if(labels.ContainsKey(t)) labels[t].Color = General.Colors.Selection; if(labels.ContainsKey(t)) labels[t].Color = General.Colors.Selection;
//check if this thing directly links to another type of thing
ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type);
int linktype = 0;
if (ti != null)
linktype = ti.ThingLink;
// New association highlights something? // New association highlights something?
if(t.Tag != 0) highlightasso.Set(t.Position, t.Tag, UniversalType.ThingTag); if(t.Tag != 0) highlightasso.Set(t.Position, t.Tag, UniversalType.ThingTag, linktype);
} }
else else
{ {
@ -382,6 +391,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action]; LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action];
for(int i = 0; i < Thing.NUM_ARGS; i++) for(int i = 0; i < Thing.NUM_ARGS; i++)
association[i].Set(t.Position, t.Args[i], action.Args[i].Type); association[i].Set(t.Position, t.Args[i], action.Args[i].Type);
//Some things, such as Patrol and Interpolation specials, are associated via a shared tag rather than an argument
ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type);
if (ti != null && ti.ThingLink < 0)
directasso.Set(t.Position, t.Tag, (int)UniversalType.ThingTag);
} }
//mxd. Check if we can use thing arguments //mxd. Check if we can use thing arguments
else if(t.Action == 0) else if(t.Action == 0)
@ -398,7 +412,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
// mxd. Clear associations? // mxd. Clear associations?
if(clearassociations) if(clearassociations)
for(int i = 0; i < Thing.NUM_ARGS; i++) association[i].Set(new Vector2D(), 0, 0); {
for (int i = 0; i < Thing.NUM_ARGS; i++)
association[i].Set(new Vector2D(), 0, 0);
directasso.Set(new Vector2D(), 0, 0);
}
// Set new highlight and redraw display // Set new highlight and redraw display
highlighted = t; highlighted = t;

View file

@ -29,10 +29,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
private HashSet<int> tags; private HashSet<int> tags;
private Vector2D center; private Vector2D center;
private UniversalType type; private UniversalType type;
private int directlinktype;
public HashSet<int> Tags { get { return tags; } } public HashSet<int> Tags { get { return tags; } }
public Vector2D Center { get { return center; } } public Vector2D Center { get { return center; } }
public UniversalType Type { get { return type; } } public UniversalType Type { get { return type; } }
public int DirectLinkType { get { return directlinktype; } }
//mxd. This sets up the association //mxd. This sets up the association
public Association() public Association()
@ -74,34 +76,51 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This sets up the association // This sets up the association
public void Set(Vector2D center, int tag, int type) public void Set(Vector2D center, int tag, int type)
{
this.Set(center, tag, type, 0);
}
public void Set(Vector2D center, int tag, int type, int directlinktype)
{ {
this.tags = new HashSet<int> { tag }; //mxd this.tags = new HashSet<int> { tag }; //mxd
this.type = (UniversalType)type; this.type = (UniversalType)type;
this.center = center; this.center = center;
this.directlinktype = directlinktype;
} }
// This sets up the association // This sets up the association
public void Set(Vector2D center, int tag, UniversalType type) public void Set(Vector2D center, int tag, UniversalType type)
{
this.Set(center, tag, type, 0);
}
public void Set(Vector2D center, int tag, UniversalType type, int directlinktype)
{ {
this.tags = new HashSet<int> { tag }; //mxd this.tags = new HashSet<int> { tag }; //mxd
this.type = type; this.type = type;
this.center = center; this.center = center;
this.directlinktype = directlinktype;
} }
//mxd. This also sets up the association //mxd. This also sets up the association
public void Set(Vector2D center, IEnumerable<int> tags, int type) public void Set(Vector2D center, IEnumerable<int> tags, int type)
{ {
this.tags = new HashSet<int>(tags); //mxd this.Set(center, tags, (UniversalType)type, 0);
this.type = (UniversalType)type;
this.center = center;
} }
//mxd. This also sets up the association //mxd. This also sets up the association
public void Set(Vector2D center, IEnumerable<int> tags, UniversalType type) public void Set(Vector2D center, IEnumerable<int> tags, UniversalType type)
{
this.Set(center, tags, type, 0);
}
//mxd. This also sets up the association
public void Set(Vector2D center, IEnumerable<int> tags, UniversalType type, int directlinktype)
{ {
this.tags = new HashSet<int>(tags); //mxd this.tags = new HashSet<int>(tags); //mxd
this.type = type; this.type = type;
this.center = center; this.center = center;
this.directlinktype = directlinktype;
} }
// This compares an association // This compares an association

View file

@ -746,6 +746,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
foreach(Thing t in General.Map.Map.Things) foreach(Thing t in General.Map.Map.Things)
{ {
if(!asso.Tags.Contains(t.Tag)) continue; if(!asso.Tags.Contains(t.Tag)) continue;
//Do not draw the association if the user is hovering over a child link
ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type);
if (ti != null && ti.ThingLink < 0)
continue;
renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha);
if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(asso.Center, t.Position)); //mxd if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(asso.Center, t.Position)); //mxd
} }
@ -813,9 +819,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Things // Things
foreach(Thing t in General.Map.Map.Things) foreach(Thing t in General.Map.Map.Things)
{ {
// Get the thing type info
ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type);
// Known action on this thing? // Known action on this thing?
if((t.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(t.Action)) if((t.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(t.Action))
{ {
//Do not draw the association if this is a child link.
// This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead.
if(ti != null && asso.DirectLinkType < 0 && asso.DirectLinkType != -t.Type)
continue;
LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action]; LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action];
if( ((action.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[0]))) || if( ((action.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[0]))) ||
((action.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[1]))) || ((action.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[1]))) ||
@ -826,12 +840,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha);
if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center)); //mxd if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center)); //mxd
} }
//If there is a link setup on this thing, and it matches the association, then draw a direct link to any matching tag
if(ti != null && asso.DirectLinkType == t.Type && asso.Tags.Contains(t.Tag))
{
renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha);
if (General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center));
}
} }
//mxd. Thing action on this thing? //mxd. Thing action on this thing?
else if(t.Action == 0) else if(t.Action == 0)
{ {
ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); //Draw the association, unless it is a child link.
if(ti != null) // This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead.
if(ti != null && asso.DirectLinkType >= 0 && Math.Abs(asso.DirectLinkType) != t.Type)
{ {
if( ((ti.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[0]))) || if( ((ti.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[0]))) ||
((ti.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[1]))) || ((ti.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[1]))) ||