From d642d7c00a92b1d51da2f4885e27defcb6bc841a Mon Sep 17 00:00:00 2001 From: Xabis Date: Tue, 14 Feb 2017 12:33:50 -0500 Subject: [PATCH] * 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 --- Source/Core/Config/ThingTypeInfo.cs | 12 +++-- Source/Core/GZBuilder/Data/LinksCollector.cs | 47 +++++++++++++++++++ .../BuilderModes/ClassicModes/ThingsMode.cs | 22 ++++++++- .../BuilderModes/General/Association.cs | 25 ++++++++-- .../BuilderModes/General/BuilderPlug.cs | 26 +++++++++- 5 files changed, 121 insertions(+), 11 deletions(-) diff --git a/Source/Core/Config/ThingTypeInfo.cs b/Source/Core/Config/ThingTypeInfo.cs index fb65b74..d8c44eb 100644 --- a/Source/Core/Config/ThingTypeInfo.cs +++ b/Source/Core/Config/ThingTypeInfo.cs @@ -85,6 +85,7 @@ namespace CodeImp.DoomBuilder.Config private string angletext; private string flagsvaluetext; private string parametertext; + private int thinglink; //mxd. GLOOME rendering settings private Thing.SpriteRenderMode rendermode; @@ -137,7 +138,8 @@ namespace CodeImp.DoomBuilder.Config public string AngleText { get { return angletext; } } public string FlagsValueText { get { return flagsvaluetext; } } public string ParameterText { get { return parametertext; } } - #endregion + public int ThingLink { get { return thinglink; } } + #endregion #region ================== Constructor / Disposer @@ -180,9 +182,10 @@ namespace CodeImp.DoomBuilder.Config this.angletext = "Angle"; this.flagsvaluetext = "Flags value"; this.parametertext = "Parameter"; - - // We have no destructor - GC.SuppressFinalize(this); + this.thinglink = 0; + + // We have no destructor + GC.SuppressFinalize(this); } // Constructor @@ -227,6 +230,7 @@ namespace CodeImp.DoomBuilder.Config this.angletext = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".angletext", cat.AngleText); this.flagsvaluetext = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".flagsvaluetext", cat.FlagsValueText); this.parametertext = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".parametertext", cat.ParameterText); + this.thinglink = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".thinglink", 0); // Read the args for (int i = 0; i < Linedef.NUM_ARGS; i++) diff --git a/Source/Core/GZBuilder/Data/LinksCollector.cs b/Source/Core/GZBuilder/Data/LinksCollector.cs index 42e28d6..cfca1a3 100644 --- a/Source/Core/GZBuilder/Data/LinksCollector.cs +++ b/Source/Core/GZBuilder/Data/LinksCollector.cs @@ -12,7 +12,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data private class SpecialThings { public readonly Dictionary> PatrolPoints; // PatrolPoint tag, list of PatrolPoints + public readonly List PatrolSpecials; public readonly Dictionary> InterpolationPoints; // InterpolationPoint tag, list of InterpolationPoints + public readonly List InterpolationSpecials; public readonly List ThingsWithGoal; public readonly List Cameras; public readonly Dictionary> ActorMovers; // ActorMover target tag, list of ActorMovers @@ -23,7 +25,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data public SpecialThings() { PatrolPoints = new Dictionary>(); + PatrolSpecials = new List(); InterpolationPoints = new Dictionary>(); + InterpolationSpecials = new List(); ThingsWithGoal = new List(); Cameras = new List(); ActorMovers = new Dictionary>(); @@ -97,6 +101,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data } break; + case "patrolspecial": + result.PatrolSpecials.Add(t); + break; + case "$polyanchor": if(!result.PolyobjectAnchors.ContainsKey(t.AngleDoom)) result.PolyobjectAnchors[t.AngleDoom] = new List(); 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)); break; + case "interpolationspecial": + result.InterpolationSpecials.Add(t); + break; + case "movingcamera": if(t.Args[0] != 0 || t.Args[1] != 0) result.Cameras.Add(t); 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] foreach(Thing t in result.Cameras) { @@ -321,6 +350,24 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data 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 HashSet processedindices = new HashSet(); foreach(KeyValuePair> group in result.InterpolationPoints) diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs index 74caae7..2bb0b1d 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs @@ -57,6 +57,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Highlighted item private Thing highlighted; private readonly Association[] association = new Association[Thing.NUM_ARGS]; + private readonly Association directasso = new Association(); private readonly Association highlightasso = new Association(); // Interface @@ -90,6 +91,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { //mxd. Associations now requre initializing... for(int i = 0; i < association.Length; i++) association[i] = new Association(); + directasso = new Association(); } //mxd @@ -253,6 +255,7 @@ namespace CodeImp.DoomBuilder.BuilderModes renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, alpha); renderer.RenderNiGHTSPath(); 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) { @@ -353,8 +356,14 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd. Update label color? 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? - 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 { @@ -382,6 +391,11 @@ namespace CodeImp.DoomBuilder.BuilderModes LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action]; for(int i = 0; i < Thing.NUM_ARGS; i++) 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 else if(t.Action == 0) @@ -398,7 +412,11 @@ namespace CodeImp.DoomBuilder.BuilderModes // mxd. Clear associations? 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 highlighted = t; diff --git a/Source/Plugins/BuilderModes/General/Association.cs b/Source/Plugins/BuilderModes/General/Association.cs index 2eded8a..70a2423 100644 --- a/Source/Plugins/BuilderModes/General/Association.cs +++ b/Source/Plugins/BuilderModes/General/Association.cs @@ -29,10 +29,12 @@ namespace CodeImp.DoomBuilder.BuilderModes private HashSet tags; private Vector2D center; private UniversalType type; + private int directlinktype; public HashSet Tags { get { return tags; } } public Vector2D Center { get { return center; } } public UniversalType Type { get { return type; } } + public int DirectLinkType { get { return directlinktype; } } //mxd. This sets up the association public Association() @@ -74,34 +76,51 @@ namespace CodeImp.DoomBuilder.BuilderModes // This sets up the association 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 { tag }; //mxd this.type = (UniversalType)type; this.center = center; + this.directlinktype = directlinktype; } // This sets up the association 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 { tag }; //mxd this.type = type; this.center = center; + this.directlinktype = directlinktype; } //mxd. This also sets up the association public void Set(Vector2D center, IEnumerable tags, int type) { - this.tags = new HashSet(tags); //mxd - this.type = (UniversalType)type; - this.center = center; + this.Set(center, tags, (UniversalType)type, 0); } //mxd. This also sets up the association public void Set(Vector2D center, IEnumerable tags, UniversalType type) + { + this.Set(center, tags, type, 0); + } + + //mxd. This also sets up the association + public void Set(Vector2D center, IEnumerable tags, UniversalType type, int directlinktype) { this.tags = new HashSet(tags); //mxd this.type = type; this.center = center; + this.directlinktype = directlinktype; } // This compares an association diff --git a/Source/Plugins/BuilderModes/General/BuilderPlug.cs b/Source/Plugins/BuilderModes/General/BuilderPlug.cs index db5690d..2c15d96 100644 --- a/Source/Plugins/BuilderModes/General/BuilderPlug.cs +++ b/Source/Plugins/BuilderModes/General/BuilderPlug.cs @@ -746,6 +746,12 @@ namespace CodeImp.DoomBuilder.BuilderModes foreach(Thing t in General.Map.Map.Things) { 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); if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(asso.Center, t.Position)); //mxd } @@ -813,9 +819,17 @@ namespace CodeImp.DoomBuilder.BuilderModes // 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? 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]; 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]))) || @@ -826,12 +840,20 @@ namespace CodeImp.DoomBuilder.BuilderModes renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); 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? else if(t.Action == 0) { - ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); - if(ti != null) + //Draw the association, unless it 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 && Math.Abs(asso.DirectLinkType) != t.Type) { 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]))) ||