UDMF: most of the code now supports multiple sector/linedef tags ('moreids' UDMF property). The only things left out are Tag Explorer and Tag Range plugins.

This commit is contained in:
MaxED 2015-07-28 15:04:21 +00:00
parent b6be263ac1
commit b3ab923487
28 changed files with 327 additions and 175 deletions

View file

@ -181,7 +181,7 @@ namespace CodeImp.DoomBuilder.Controls
else if(isacsscript && General.Map.NumberedScripts.ContainsKey(l.Args[0]))
{
scriptitem = General.Map.NumberedScripts[l.Args[0]];
scriptname = scriptitem.Name;
scriptname = (scriptitem.HasCustomName ? scriptitem.Name : scriptitem.Index.ToString());
}
// Apply script args?

View file

@ -148,7 +148,7 @@ namespace CodeImp.DoomBuilder.Controls
else if(isacsscript && General.Map.NumberedScripts.ContainsKey(t.Args[0]))
{
scriptitem = General.Map.NumberedScripts[t.Args[0]];
scriptname = scriptitem.Name;
scriptname = (scriptitem.HasCustomName ? scriptitem.Name : scriptitem.Index.ToString());
}
// Apply script args?

View file

@ -277,6 +277,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
private void addtag_Click(object sender, EventArgs e)
{
// When an item has no tags, act like "New Tag" button
if(tags.Count == 1 && tags[0] == 0)
{
newtag_Click(sender, e);
return;
}
int nt = General.Map.Map.GetNewTag(tags);
tags.Add(nt);
rangemodes.Add(0);

View file

@ -10,12 +10,15 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
private readonly int index;
private readonly int cursorposition;
private readonly bool isinclude;
private readonly bool customname;
internal string Name { get { return name; } }
internal int Index { get { return index; } }
internal int CursorPosition { get { return cursorposition; } }
internal bool IsInclude { get { return isinclude; } }
internal bool HasCustomName { get { return customname; } }
// Constructor for misc usage
internal ScriptItem(string name, int cursorposition, bool isinclude)
{
this.name = name;
@ -23,17 +26,21 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
this.index = int.MinValue;
this.cursorposition = cursorposition;
this.isinclude = isinclude;
this.customname = true;
}
internal ScriptItem(int index, string name, List<string> argnames, int cursorposition, bool isinclude)
// Constructor for numbered script
internal ScriptItem(int index, string name, List<string> argnames, int cursorposition, bool isinclude, bool customname)
{
this.name = name;
this.argnames = argnames;
this.index = index;
this.cursorposition = cursorposition;
this.isinclude = isinclude;
this.customname = customname;
}
// Constructor for named script
internal ScriptItem(string name, List<string> argnames, int cursorposition, bool isinclude)
{
this.name = name;
@ -41,6 +48,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
this.index = int.MinValue;
this.cursorposition = cursorposition;
this.isinclude = isinclude;
this.customname = true;
}
internal static int SortByIndex(ScriptItem i1, ScriptItem i2)

View file

@ -116,13 +116,14 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
}
name = (name.Length > 0 ? name + " [" + n + "]" : "Script " + n);
bool customname = (name.Length > 0);
name = (customname ? name + " [" + n + "]" : "Script " + n);
List<string> argnames = new List<string>();
foreach(KeyValuePair<string, string> group in args) argnames.Add(group.Value);
// Add to collection
numberedscripts.Add(new ScriptItem(n, name, argnames, startpos, isinclude));
numberedscripts.Add(new ScriptItem(n, name, argnames, startpos, isinclude, customname));
}
}
}

View file

@ -43,7 +43,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows
private void Setup()
{
//collect all tags
List<int> tags = new List<int>();
HashSet<int> tags = new HashSet<int>();
Dictionary<int, int> sectorsCountByTag = new Dictionary<int, int>();
Dictionary<int, int> linedefsCountByTag = new Dictionary<int, int>();
Dictionary<int, int> thingsCountByTag = new Dictionary<int, int>();
@ -52,12 +52,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag == 0) continue;
if(!tags.Contains(s.Tag)) tags.Add(s.Tag);
if(!sectorsCountByTag.ContainsKey(s.Tag))
sectorsCountByTag.Add(s.Tag, 1);
else
sectorsCountByTag[s.Tag] += 1;
tags.UnionWith(s.Tags);
foreach (int tag in s.Tags)
{
if(!sectorsCountByTag.ContainsKey(tag)) sectorsCountByTag.Add(tag, 0);
sectorsCountByTag[tag]++;
}
}
//...and linedefs...
@ -66,12 +66,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows
foreach(Linedef l in General.Map.Map.Linedefs)
{
if(l.Tag == 0) continue;
if(!tags.Contains(l.Tag)) tags.Add(l.Tag);
if(!linedefsCountByTag.ContainsKey(l.Tag))
linedefsCountByTag.Add(l.Tag, 1);
else
linedefsCountByTag[l.Tag] += 1;
tags.UnionWith(l.Tags);
foreach (int tag in l.Tags)
{
if(!linedefsCountByTag.ContainsKey(tag)) linedefsCountByTag.Add(tag, 0);
linedefsCountByTag[tag]++;
}
}
}
else
@ -87,10 +87,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows
if(t.Tag == 0) continue;
if(!tags.Contains(t.Tag)) tags.Add(t.Tag);
if(!thingsCountByTag.ContainsKey(t.Tag))
thingsCountByTag.Add(t.Tag, 1);
else
thingsCountByTag[t.Tag] += 1;
if(!thingsCountByTag.ContainsKey(t.Tag)) thingsCountByTag.Add(t.Tag, 0);
thingsCountByTag[t.Tag]++;
}
}
else
@ -130,7 +128,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows
List<Sector> list = new List<Sector>();
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag == tag)
if(s.Tags.Contains(tag))
{
list.Add(s);
if(list.Count == count) break;
@ -145,7 +143,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows
List<Linedef> list = new List<Linedef>();
foreach(Linedef l in General.Map.Map.Linedefs)
{
if(l.Tag == tag)
if(l.Tags.Contains(tag))
{
list.Add(l);
if(list.Count == count) break;

View file

@ -93,7 +93,7 @@ namespace CodeImp.DoomBuilder.Map
public int Activate { get { return activate; } set { BeforePropsChange(); activate = value; UpdateColorPreset(); } }
public int Tag { get { return tags[0]; } set { BeforePropsChange(); tags[0] = value; if((value < General.Map.FormatInterface.MinTag) || (value > General.Map.FormatInterface.MaxTag)) throw new ArgumentOutOfRangeException("Tag", "Invalid tag number"); } } //mxd
public List<int> Tags { get { return tags; } } //mxd
public List<int> Tags { get { return tags; } set { BeforePropsChange(); tags = value; } } //mxd
public float LengthSq { get { return lengthsq; } }
public float Length { get { return length; } }
public float LengthInv { get { return lengthinv; } }

View file

@ -22,6 +22,7 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using System.Drawing;
using System.IO;
using System.Linq;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.IO;
@ -2837,16 +2838,22 @@ namespace CodeImp.DoomBuilder.Map
case UniversalType.LinedefTag:
for(int i = 0; i < linedefs.Length; i++)
{
if(linedefs[i].Tag > 0 && !usedtags.ContainsKey(linedefs[i].Tag))
usedtags.Add(linedefs[i].Tag, false);
foreach (int tag in linedefs[i].Tags)
{
if(tag == 0) continue;
if(!usedtags.ContainsKey(tag)) usedtags.Add(tag, false);
}
}
break;
case UniversalType.SectorTag:
for(int i = 0; i < sectors.Length; i++)
{
if(sectors[i].Tag > 0 && !usedtags.ContainsKey(sectors[i].Tag))
usedtags.Add(sectors[i].Tag, false);
foreach(int tag in sectors[i].Tags)
{
if(tag == 0) continue;
if(!usedtags.ContainsKey(tag)) usedtags.Add(tag, false);
}
}
break;
}
@ -2929,30 +2936,44 @@ namespace CodeImp.DoomBuilder.Map
/// <summary>This calls a function for all tag fields in the marked or unmarked geometry. The obj parameter can be anything you wish to pass on to your TagHandler function.</summary>
public void ForAllTags<T>(TagHandler<T> handler, bool marked, T obj)
{
// Remove tags from sectors
// Call handler on sectors tags
foreach(Sector s in sectors)
{
if(s.Marked == marked)
{
int tag = s.Tag;
handler(s, false, UniversalType.SectorTag, ref tag, obj);
if(tag != s.Tag) s.Tag = tag;
//mxd. Multiple tags support...
bool changed = false;
for(int i = 0; i < s.Tags.Count; i++)
{
int tag = s.Tags[i];
handler(s, false, UniversalType.SectorTag, ref tag, obj);
if(tag != s.Tags[i])
{
s.Tags[i] = tag;
changed = true;
}
}
if(changed) s.Tags = s.Tags.Distinct().ToList();
}
// Remove tags from things
}
// Call handler on things tags
if(General.Map.FormatInterface.HasThingTag)
{
foreach(Thing t in things)
{
if(t.Marked == marked)
{
int tag = t.Tag;
handler(t, false, UniversalType.ThingTag, ref tag, obj);
if(tag != t.Tag) t.Tag = tag;
}
}
}
// Remove tags from thing actions
if(General.Map.FormatInterface.HasThingAction &&
General.Map.FormatInterface.HasActionArgs)
// Call handler on things action
if(General.Map.FormatInterface.HasThingAction && General.Map.FormatInterface.HasActionArgs)
{
foreach(Thing t in things)
{
@ -2960,29 +2981,44 @@ namespace CodeImp.DoomBuilder.Map
{
LinedefActionInfo info = General.Map.Config.GetLinedefActionInfo(t.Action);
for(int i = 0; i < Thing.NUM_ARGS; i++)
{
if(info.Args[i].Used && CheckIsTagType(info.Args[i].Type))
{
int tag = t.Args[i];
handler(t, true, (UniversalType)(info.Args[i].Type), ref tag, obj);
if(tag != t.Args[i]) t.Args[i] = tag;
}
}
}
}
}
// Remove tags from linedefs
// Call handler on linedefs tags
if(General.Map.FormatInterface.HasLinedefTag)
{
foreach(Linedef l in linedefs)
{
if(l.Marked == marked)
{
int tag = l.Tag;
handler(l, false, UniversalType.LinedefTag, ref tag, obj);
if(tag != l.Tag) l.Tag = tag;
//mxd. Multiple tags support...
bool changed = false;
for(int i = 0; i < l.Tags.Count; i++)
{
int tag = l.Tags[i];
handler(l, false, UniversalType.LinedefTag, ref tag, obj);
if(tag != l.Tags[i])
{
l.Tags[i] = tag;
changed = true;
}
}
if(changed) l.Tags = l.Tags.Distinct().ToList();
}
}
}
// Remove tags from linedef actions
// Call handler on linedefs action
if(General.Map.FormatInterface.HasActionArgs)
{
foreach(Linedef l in linedefs)
@ -2991,12 +3027,14 @@ namespace CodeImp.DoomBuilder.Map
{
LinedefActionInfo info = General.Map.Config.GetLinedefActionInfo(l.Action);
for(int i = 0; i < Linedef.NUM_ARGS; i++)
{
if(info.Args[i].Used && CheckIsTagType(info.Args[i].Type))
{
int tag = l.Args[i];
handler(l, true, (UniversalType)(info.Args[i].Type), ref tag, obj);
if(tag != l.Args[i]) l.Args[i] = tag;
}
}
}
}
}

View file

@ -107,7 +107,7 @@ namespace CodeImp.DoomBuilder.Map
internal Dictionary<string, bool> Flags { get { return flags; } } //mxd
public int Effect { get { return effect; } set { BeforePropsChange(); effect = value; } }
public int Tag { get { return tags[0]; } set { BeforePropsChange(); tags[0] = value; if((value < General.Map.FormatInterface.MinTag) || (value > General.Map.FormatInterface.MaxTag)) throw new ArgumentOutOfRangeException("Tag", "Invalid tag number"); } } //mxd
public List<int> Tags { get { return tags; } } //mxd
public List<int> Tags { get { return tags; } set { BeforePropsChange(); tags = value; } } //mxd
public int Brightness { get { return brightness; } set { BeforePropsChange(); brightness = value; updateneeded = true; } }
public bool UpdateNeeded { get { return updateneeded; } set { updateneeded |= value; triangulationneeded |= value; } }
public RectangleF BBox { get { return bbox; } }

View file

@ -346,8 +346,8 @@ namespace CodeImp.DoomBuilder.Map
// Check if the line or sectors have no action or tags because
// if they do, any texture on this side could be needed
if(force || ((linedef.Tag <= 0) && (linedef.Action == 0) && (sector.Tag <= 0) &&
((Other == null) || (Other.sector.Tag <= 0))))
if(force || ((linedef.Tag == 0) && (linedef.Action == 0) && (sector.Tag == 0) &&
((Other == null) || (Other.sector.Tag == 0))))
{
if(!HighRequired())
{

View file

@ -618,7 +618,7 @@ namespace CodeImp.DoomBuilder.Rendering
//mxd. This collects indices of linedefs, which are parts of sectors with 3d floors
public void UpdateExtraFloorFlag()
{
List<int> tagList = new List<int>();
HashSet<int> tags = new HashSet<int>();
//find lines with 3d floor action and collect sector tags
foreach(Linedef l in General.Map.Map.Linedefs)
@ -626,22 +626,19 @@ namespace CodeImp.DoomBuilder.Rendering
if(l.Action == 160)
{
int sectortag = (General.Map.UDMF || (l.Args[1] & 8) != 0) ? l.Args[0] : l.Args[0] + (l.Args[4] << 8);
if(sectortag != 0) tagList.Add(sectortag);
if(sectortag != 0 && !tags.Contains(sectortag)) tags.Add(sectortag);
}
}
tagList.Sort();
int[] tags = tagList.ToArray();
//find lines, which are related to sectors with 3d floors, and collect their valuable indices
foreach(Linedef l in General.Map.Map.Linedefs)
{
if(l.Front != null && l.Front.Sector != null && l.Front.Sector.Tag != 0 && Array.BinarySearch(tags, l.Front.Sector.Tag) > -1)
if(l.Front != null && l.Front.Sector != null && l.Front.Sector.Tag != 0 && tags.Overlaps(l.Front.Sector.Tags))
{
l.ExtraFloorFlag = true;
continue;
}
if(l.Back != null && l.Back.Sector != null && l.Back.Sector.Tag != 0 && Array.BinarySearch(tags, l.Back.Sector.Tag) > -1)
if(l.Back != null && l.Back.Sector != null && l.Back.Sector.Tag != 0 && tags.Overlaps(l.Back.Sector.Tags))
{
l.ExtraFloorFlag = true;
continue;

View file

@ -33,12 +33,14 @@ namespace CodeImp.DoomBuilder.Types
{
//collect tags
List<int> tags = new List<int>();
HashSet<int> tagshash = new HashSet<int>();
EnumList taglist = new EnumList();
foreach(Linedef t in General.Map.Map.Linedefs)
foreach(Linedef l in General.Map.Map.Linedefs)
{
if(t.Tag == 0 || tags.Contains(t.Tag)) continue;
tags.Add(t.Tag);
if(l.Tag == 0 || tagshash.IsSupersetOf(l.Tags)) continue;
tags.AddRange(l.Tags);
foreach(int i in l.Tags) tagshash.Add(i);
}
//now sort them in descending order

View file

@ -72,12 +72,14 @@ namespace CodeImp.DoomBuilder.Types
{
//collect tags
List<int> tags = new List<int>();
HashSet<int> tagshash = new HashSet<int>();
EnumList taglist = new EnumList();
foreach(Sector t in General.Map.Map.Sectors)
foreach(Sector s in General.Map.Map.Sectors)
{
if(t.Tag == 0 || tags.Contains(t.Tag)) continue;
tags.Add(t.Tag);
if(s.Tag == 0 || tagshash.IsSupersetOf(s.Tags)) continue;
tags.AddRange(s.Tags);
foreach (int i in s.Tags) tagshash.Add(i);
}
//now sort them in descending order

View file

@ -72,6 +72,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Constructor / Disposer
public LinedefsMode()
{
//mxd. Associations now requre initializing...
for(int i = 0; i < association.Length; i++) association[i].Set(new Vector2D(), 0, 0);
}
#endregion
#region ================== Methods
@ -87,22 +93,22 @@ namespace CodeImp.DoomBuilder.BuilderModes
// are or were drawn we need to redraw the entire display.
// Previous association highlights something?
if((highlighted != null) && (highlighted.Tag > 0)) completeredraw = true;
if((highlighted != null) && (highlighted.Tag != 0)) completeredraw = true;
// Set highlight association
if(l != null)
highlightasso.Set(new Vector2D((l.Start.Position + l.End.Position)/2), l.Tag, UniversalType.LinedefTag);
if(l != null && l.Tag != 0)
highlightasso.Set(new Vector2D((l.Start.Position + l.End.Position)/2), l.Tags, UniversalType.LinedefTag);
else
highlightasso.Set(new Vector2D(), 0, 0);
// New association highlights something?
if((l != null) && (l.Tag > 0)) completeredraw = true;
if((l != null) && (l.Tag != 0)) completeredraw = true;
// Use the line tag to highlight sectors (Doom style)
if(General.Map.Config.LineTagIndicatesSectors)
{
if(l != null)
association[0].Set(new Vector2D((l.Start.Position + l.End.Position)/2), l.Tag, UniversalType.SectorTag);
association[0].Set(new Vector2D((l.Start.Position + l.End.Position)/2), l.Tags, UniversalType.SectorTag);
else
association[0].Set(new Vector2D(), 0, 0);
}
@ -119,9 +125,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
for(int i = 0; i < Linedef.NUM_ARGS; i++)
{
// Previous association highlights something?
if((association[i].type == UniversalType.SectorTag) ||
(association[i].type == UniversalType.LinedefTag) ||
(association[i].type == UniversalType.ThingTag)) completeredraw = true;
if((association[i].Type == UniversalType.SectorTag) ||
(association[i].Type == UniversalType.LinedefTag) ||
(association[i].Type == UniversalType.ThingTag)) completeredraw = true;
// Make new association
if(action != null)
@ -130,9 +136,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
association[i].Set(new Vector2D(), 0, 0);
// New association highlights something?
if((association[i].type == UniversalType.SectorTag) ||
(association[i].type == UniversalType.LinedefTag) ||
(association[i].type == UniversalType.ThingTag)) completeredraw = true;
if((association[i].Type == UniversalType.SectorTag) ||
(association[i].Type == UniversalType.LinedefTag) ||
(association[i].Type == UniversalType.ThingTag)) completeredraw = true;
}
}

View file

@ -253,42 +253,54 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd
private string[] GetEffectText(Sector s)
{
string[] result = new []{string.Empty, string.Empty};
string tagstr = string.Empty;
string tagstrshort = string.Empty;
string effectstr = string.Empty;
string effectstrshort = string.Empty;
if(s.Effect != 0)
// Make effect text
if(s.Effect != 0)
{
if(effects.ContainsKey(s.Effect))
if(effects.ContainsKey(s.Effect))
effectstr = effects[s.Effect][0];
else
effectstr = s.Effect + " - " + General.Map.Config.GetGeneralizedSectorEffectName(s.Effect);
effectstrshort = "E" + s.Effect;
}
// Make tag text
if(s.Tag != 0)
{
if(s.Tags.Count > 1)
{
if(s.Tag != 0)
{
result[0] = "Tag " + s.Tag + ", " + effects[s.Effect][0];
result[1] = "T" + s.Tag + " " + "E" + s.Effect;
}
else
{
result[0] = effects[s.Effect][0];
result[1] = "E" + s.Effect;
}
}
else
{
string effect = s.Effect + " - " + General.Map.Config.GetGeneralizedSectorEffectName(s.Effect);
if(s.Tag != 0)
{
result[0] = "Tag " + s.Tag + ", Effect " + effect;
result[1] = "T" + s.Tag + " " + "E" + s.Effect;
}
else
{
result[0] = "Effect " + effect;
result[1] = "E" + s.Effect;
}
string[] stags = new string[s.Tags.Count];
for(int i = 0; i < s.Tags.Count; i++) stags[i] = s.Tags[i].ToString();
tagstr = "Tags " + string.Join(", ", stags);
tagstrshort = "T" + string.Join(",", stags);
}
}
else if(s.Tag != 0)
else
{
tagstr = "Tag " + s.Tag;
tagstrshort = "T" + s.Tag;
}
}
// Combine them
string[] result = new[] { string.Empty, string.Empty };
if(s.Effect != 0 && s.Tag != 0)
{
result[0] = "Tag " + s.Tag;
result[1] = "T" + s.Tag;
result[0] = tagstr + "; " + effectstr;
result[1] = tagstrshort + " " + effectstrshort;
}
else if(s.Effect != 0)
{
result[0] = effectstr;
result[1] = effectstrshort;
}
else if(s.Tag != 0)
{
result[0] = tagstr;
result[1] = tagstrshort;
}
return result;
@ -384,13 +396,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
// are or were drawn we need to redraw the entire display.
// Previous association highlights something?
bool completeredraw = (highlighted != null) && (highlighted.Tag > 0);
bool completeredraw = (highlighted != null) && (highlighted.Tag != 0);
// Set highlight association
if (s != null)
if (s != null && s.Tag != 0)
{
Vector2D center = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2));
highlightasso.Set(center, s.Tag, UniversalType.SectorTag);
highlightasso.Set(center, s.Tags, UniversalType.SectorTag);
}
else
{
@ -398,7 +410,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
// New association highlights something?
if((s != null) && (s.Tag > 0)) completeredraw = true;
if((s != null) && (s.Tag != 0)) completeredraw = true;
// Change label color
if((highlighted != null) && !highlighted.IsDisposed)

View file

@ -70,6 +70,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Constructor / Disposer
public ThingsMode()
{
//mxd. Associations now requre initializing...
for(int i = 0; i < association.Length; i++) association[i].Set(new Vector2D(), 0, 0);
}
#endregion
#region ================== Methods
@ -224,16 +230,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
// are or were drawn we need to redraw the entire display.
// Previous association highlights something?
if((highlighted != null) && (highlighted.Tag > 0)) completeredraw = true;
if((highlighted != null) && (highlighted.Tag != 0)) completeredraw = true;
// Set highlight association
if(t != null)
if(t != null && t.Tag != 0)
highlightasso.Set(t.Position, t.Tag, UniversalType.ThingTag);
else
highlightasso.Set(new Vector2D(), 0, 0);
// New association highlights something?
if((t != null) && (t.Tag > 0)) completeredraw = true;
if((t != null) && (t.Tag != 0)) completeredraw = true;
if(t != null)
{
@ -246,9 +252,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
for(int i = 0; i < Thing.NUM_ARGS; i++)
{
// Previous association highlights something?
if((association[i].type == UniversalType.SectorTag) ||
(association[i].type == UniversalType.LinedefTag) ||
(association[i].type == UniversalType.ThingTag)) completeredraw = true;
if((association[i].Type == UniversalType.SectorTag) ||
(association[i].Type == UniversalType.LinedefTag) ||
(association[i].Type == UniversalType.ThingTag)) completeredraw = true;
// Make new association
if(action != null)
@ -257,9 +263,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
association[i].Set(new Vector2D(), 0, 0);
// New association highlights something?
if((association[i].type == UniversalType.SectorTag) ||
(association[i].type == UniversalType.LinedefTag) ||
(association[i].type == UniversalType.ThingTag)) completeredraw = true;
if((association[i].Type == UniversalType.SectorTag) ||
(association[i].Type == UniversalType.LinedefTag) ||
(association[i].Type == UniversalType.ThingTag)) completeredraw = true;
}
// If we're changing associations, then we

View file

@ -17,6 +17,7 @@
#region ================== Namespaces
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Config;
@ -85,10 +86,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
foreach(Linedef l in list)
{
// Tag matches?
if(l.Tag == tag)
int index = l.Tags.IndexOf(tag);
if(index != -1)
{
// Replace
if(replace) l.Tag = replacetag;
if(replace)
{
l.Tags[index] = replacetag; //mxd
l.Tags = l.Tags.Distinct().ToList(); //mxd. We don't want duplicates
}
// Add to list
LinedefActionInfo info = General.Map.Config.GetLinedefActionInfo(l.Action);

View file

@ -17,6 +17,7 @@
#region ================== Namespaces
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Config;
@ -79,11 +80,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
foreach(Sector s in list)
{
// Tag matches?
if(s.Tag == tag)
int index = s.Tags.IndexOf(tag);
if(index != -1)
{
// Replace
if(replace) s.Tag = replacetag;
if(replace)
{
s.Tags[index] = replacetag; //mxd
s.Tags = s.Tags.Distinct().ToList(); //mxd. We don't want duplicates
}
// Add to list
SectorEffectInfo info = General.Map.Config.GetSectorEffectInfo(s.Effect);
if(!info.IsNull)
objs.Add(new FindReplaceObject(s, "Sector " + s.Index + " (" + info.Title + ")"));

View file

@ -16,6 +16,7 @@
#region ================== Namespaces
using System.Collections.Generic;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Types;
@ -25,15 +26,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
public struct Association
{
public int tag;
public UniversalType type;
public Vector2D Center { get { return center; } }
private HashSet<int> tags;
private Vector2D center;
private UniversalType type;
public HashSet<int> Tags { get { return tags; } }
public Vector2D Center { get { return center; } }
public UniversalType Type { get { return type; } }
// This sets up the association
public Association(Vector2D center, int tag, int type)
{
this.tag = tag;
this.tags = new HashSet<int>(); //mxd
tags.Add(tag); //mxd
this.type = (UniversalType)type;
this.center = center;
}
@ -41,7 +46,24 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This sets up the association
public Association(Vector2D center, int tag, UniversalType type)
{
this.tag = tag;
this.tags = new HashSet<int>(); //mxd
tags.Add(tag); //mxd
this.type = type;
this.center = center;
}
//mxd. This also sets up the association
public Association(Vector2D center, IEnumerable<int> tags, int type)
{
this.tags = new HashSet<int>(tags); //mxd
this.type = (UniversalType)type;
this.center = center;
}
//mxd. This also sets up the association
public Association(Vector2D center, IEnumerable<int> tags, UniversalType type)
{
this.tags = new HashSet<int>(tags); //mxd
this.type = type;
this.center = center;
}
@ -49,7 +71,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This sets up the association
public void Set(Vector2D center, int tag, int type)
{
this.tag = tag;
this.tags = new HashSet<int>(); //mxd
tags.Add(tag); //mxd
this.type = (UniversalType)type;
this.center = center;
}
@ -57,7 +80,24 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This sets up the association
public void Set(Vector2D center, int tag, UniversalType type)
{
this.tag = tag;
this.tags = new HashSet<int>(); //mxd
tags.Add(tag); //mxd
this.type = type;
this.center = center;
}
//mxd. This also sets up the association
public void Set(Vector2D center, IEnumerable<int> tags, int type)
{
this.tags = new HashSet<int>(tags); //mxd
this.type = (UniversalType)type;
this.center = center;
}
//mxd. This also sets up the association
public void Set(Vector2D center, IEnumerable<int> tags, UniversalType type)
{
this.tags = new HashSet<int>(tags); //mxd
this.type = type;
this.center = center;
}
@ -65,13 +105,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This compares an association
public static bool operator ==(Association a, Association b)
{
return (a.tag == b.tag) && (a.type == b.type);
return (a.type == b.type) && a.tags.SetEquals(b.tags);
}
// This compares an association
public static bool operator !=(Association a, Association b)
{
return (a.tag != b.tag) || (a.type != b.type);
return (a.type != b.type) || !a.tags.SetEquals(b.tags);
}
//mxd
@ -86,7 +126,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(!(obj is Association)) return false;
Association b = (Association)obj;
return (tag == b.tag) && (type == b.type);
return (type == b.type) && tags.SetEquals(b.tags);
}
}
}

View file

@ -525,15 +525,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
public static void PlotAssociations(IRenderer2D renderer, Association asso, List<Line3D> eventlines)
{
// Tag must be above zero
if(asso.tag < 1) return;
if(General.GetByIndex(asso.Tags, 0) < 1) return;
// Sectors?
switch(asso.type)
switch(asso.Type)
{
case UniversalType.SectorTag: {
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag != asso.tag) continue;
if(!asso.Tags.Overlaps(s.Tags))continue;
renderer.PlotSector(s, General.Colors.Indication);
if(!General.Settings.GZShowEventLines) continue;
@ -546,7 +546,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
case UniversalType.LinedefTag: {
foreach(Linedef l in General.Map.Map.Linedefs)
{
if(l.Tag != asso.tag) continue;
if(!asso.Tags.Overlaps(l.Tags)) continue;
renderer.PlotLinedef(l, General.Colors.Indication);
if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(asso.Center, l.GetCenterPoint())); //mxd
}
@ -559,25 +559,24 @@ namespace CodeImp.DoomBuilder.BuilderModes
public static void RenderAssociations(IRenderer2D renderer, Association asso, List<Line3D> eventlines)
{
// Tag must be above zero
if(asso.tag < 1) return;
if(General.GetByIndex(asso.Tags, 0) < 1) return;
// Things?
switch(asso.type)
switch(asso.Type)
{
case UniversalType.ThingTag: {
case UniversalType.ThingTag:
foreach(Thing t in General.Map.Map.Things)
{
if(t.Tag != asso.tag) continue;
if(!asso.Tags.Contains(t.Tag)) continue;
renderer.RenderThing(t, General.Colors.Indication, 1.0f);
if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(asso.Center, t.Position)); //mxd
}
break;
}
case UniversalType.SectorTag:
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag != asso.tag) continue;
if(!asso.Tags.Overlaps(s.Tags)) continue;
int highlightedColor = General.Colors.Highlight.WithAlpha(128).ToInt();
FlatVertex[] verts = new FlatVertex[s.FlatVertices.Length];
s.FlatVertices.CopyTo(verts, 0);
@ -592,16 +591,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
public static void PlotReverseAssociations(IRenderer2D renderer, Association asso, List<Line3D> eventlines)
{
// Tag must be above zero
if(asso.tag < 1) return;
if(General.GetByIndex(asso.Tags, 0) < 1) return;
// Doom style referencing to sectors?
if(General.Map.Config.LineTagIndicatesSectors && (asso.type == UniversalType.SectorTag))
if(General.Map.Config.LineTagIndicatesSectors && (asso.Type == UniversalType.SectorTag))
{
// Linedefs
foreach(Linedef l in General.Map.Map.Linedefs)
{
// Any action on this line?
if(l.Action <= 0 || l.Tag != asso.tag) continue;
if(l.Action <= 0 || !asso.Tags.Overlaps(l.Tags)) continue;
renderer.PlotLinedef(l, General.Colors.Indication);
if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(l.GetCenterPoint(), asso.Center)); //mxd
}
@ -614,11 +613,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
if((l.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(l.Action))
{
LinedefActionInfo action = General.Map.Config.LinedefActions[l.Action];
if( ((action.Args[0].Type == (int)asso.type) && (l.Args[0] == asso.tag)) ||
((action.Args[1].Type == (int)asso.type) && (l.Args[1] == asso.tag)) ||
((action.Args[2].Type == (int)asso.type) && (l.Args[2] == asso.tag)) ||
((action.Args[3].Type == (int)asso.type) && (l.Args[3] == asso.tag)) ||
((action.Args[4].Type == (int)asso.type) && (l.Args[4] == asso.tag)) )
if( ((action.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[0]))) ||
((action.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[1]))) ||
((action.Args[2].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[2]))) ||
((action.Args[3].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[3]))) ||
((action.Args[4].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[4]))))
{
renderer.PlotLinedef(l, General.Colors.Indication);
@ -632,7 +631,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public static void RenderReverseAssociations(IRenderer2D renderer, Association asso, List<Line3D> eventlines)
{
// Tag must be above zero
if(asso.tag < 1) return;
if(General.GetByIndex(asso.Tags, 0) < 1) return;
// Things
foreach(Thing t in General.Map.Map.Things)
@ -641,11 +640,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
if((t.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(t.Action))
{
LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action];
if( ((action.Args[0].Type == (int)asso.type) && (t.Args[0] == asso.tag)) ||
((action.Args[1].Type == (int)asso.type) && (t.Args[1] == asso.tag)) ||
((action.Args[2].Type == (int)asso.type) && (t.Args[2] == asso.tag)) ||
((action.Args[3].Type == (int)asso.type) && (t.Args[3] == asso.tag)) ||
((action.Args[4].Type == (int)asso.type) && (t.Args[4] == asso.tag)) )
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[2].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[2]))) ||
((action.Args[3].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[3]))) ||
((action.Args[4].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[4]))))
{
renderer.RenderThing(t, General.Colors.Indication, 1.0f);
if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center)); //mxd

View file

@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.GZBuilder.Tools;
@ -95,7 +96,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public bool CeilingSlope = true;
[FieldDescription("Floor Slope")]
public bool FloorSlope = true;
[FieldDescription("Tag")]
[FieldDescription("Tags")]
public bool Tag = true;
[FieldDescription("Effect")]
public bool Special = true;
@ -121,7 +122,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
private readonly float floorslopeoffset;
private readonly Vector3D ceilslope;
private readonly Vector3D floorslope;
private readonly int tag;
private readonly List<int> tags;
private readonly UniFields fields;
private readonly Dictionary<string, bool> flags; //mxd
@ -137,7 +138,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
floorslopeoffset = s.FloorSlopeOffset;
ceilslope = s.CeilSlope;
floorslope = s.FloorSlope;
tag = s.Tag;
tags = new List<int>(s.Tags); //mxd
fields = new UniFields(s.Fields);
flags = s.GetFlags(); //mxd
}
@ -149,7 +150,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(CopySettings.FloorTexture) s.SetFloorTexture(floortexture);
if(CopySettings.CeilingTexture) s.SetCeilTexture(ceilingtexture);
if(CopySettings.Brightness) s.Brightness = brightness;
if(CopySettings.Tag) s.Tag = tag;
if(CopySettings.Tag) s.Tags = new List<int>(tags); //mxd
if(CopySettings.Special) s.Effect = effect;
if (CopySettings.CeilingSlope)
{
@ -255,7 +256,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public bool Arguments = true;
[FieldDescription("Activation")]
public bool Activation = true;
[FieldDescription("Tag")]
[FieldDescription("Tags")]
public bool Tag = true;
[FieldDescription("Flags")]
public bool Flags = true;
@ -274,7 +275,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
private readonly Dictionary<string, bool> flags;
private readonly int action;
private readonly int activate;
private readonly int tag;
private readonly List<int> tags;
private readonly int[] args;
private readonly UniFields fields;
@ -286,7 +287,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
flags = l.GetFlags();
action = l.Action;
activate = l.Activate;
tag = l.Tag;
tags = new List<int>(l.Tags); //mxd
args = (int[])(l.Args.Clone());
fields = new UniFields(l.Fields);
}
@ -305,7 +306,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
l.SetFlag(f.Key, f.Value);
}
if(CopySettings.Activation) l.Activate = activate;
if(CopySettings.Tag) l.Tag = tag;
if(CopySettings.Tag) l.Tags = new List<int>(tags); //mxd
if(CopySettings.Action) l.Action = action;
if(CopySettings.Arguments)
{
@ -434,7 +435,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(flags.FloorTexture && source.FloorTexture != target.FloorTexture) return false;
if(flags.CeilingTexture && source.CeilTexture != target.CeilTexture) return false;
if(flags.Brightness && source.Brightness != target.Brightness) return false;
if(flags.Tag && source.Tag != target.Tag) return false;
if(flags.Tag && TagsMatch(source.Tags, target.Tags)) return false; //mxd
if(flags.Special && source.Effect != target.Effect) return false;
if(flags.Flags && !FlagsMatch(source.GetFlags(), target.GetFlags())) return false;
return !flags.Fields || UDMFTools.FieldsMatch(source.Fields, target.Fields);
@ -448,7 +449,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
if(linedefflags.Action && source.Action != target.Action) return false;
if(linedefflags.Activation && source.Activate != target.Activate) return false;
if(linedefflags.Tag && source.Tag != target.Tag) return false;
if(linedefflags.Tag && TagsMatch(source.Tags, target.Tags)) return false; //mxd
if(linedefflags.Arguments)
{
for(int i = 0; i < source.Args.Length; i++)
@ -514,5 +515,26 @@ namespace CodeImp.DoomBuilder.BuilderModes
if (!flags2.ContainsKey(group.Key) || flags2[group.Key] != flags1[group.Key]) return false;
return true;
}
//mxd
private static bool TagsMatch(List<int> tags1, List<int> tags2)
{
if(tags1.Count != tags2.Count) return false;
Dictionary<int, int> count = new Dictionary<int, int>();
foreach(int s in tags1)
{
if(count.ContainsKey(s)) count[s]++;
else count.Add(s, 1);
}
foreach(int s in tags2)
{
if(count.ContainsKey(s)) count[s]--;
else return false;
}
return count.Values.All(c => c == 0);
}
}
}

View file

@ -103,7 +103,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
findbutton.Text = (doreplace.Checked ? "Replace" : "Find");
replaceinput.Enabled = doreplace.Checked;
browsereplace.Enabled = doreplace.Checked;
browsereplace.Enabled = doreplace.Checked && newfinder != null && newfinder.Attributes.BrowseButton;
}
// Search type selected

View file

@ -231,10 +231,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
if(s.Line.Action == 160 && s.Line.Front != null)
{
int sectortag = s.Line.Args[0] + (s.Line.Args[4] << 8);
int sectortag = ((General.Map.UDMF || (s.Line.Args[1] & 8) != 0) ? s.Line.Args[0] : s.Line.Args[0] + (s.Line.Args[4] << 8));
foreach(Sector sector in General.Map.Map.Sectors)
{
if(sector.Tag == sectortag)
if(sector.Tags.Contains(sectortag))
{
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(sector);
vs.UpdateSectorGeometry(false);

View file

@ -465,12 +465,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
//check for 3d floors
if(Sidedef.Line.Action == 160)
{
int sectortag = Sidedef.Line.Args[0] + (Sidedef.Line.Args[4] << 8);
int sectortag = ((General.Map.UDMF || (Sidedef.Line.Args[1] & 8) != 0) ? Sidedef.Line.Args[0] : Sidedef.Line.Args[0] + (Sidedef.Line.Args[4] << 8));
if(sectortag == 0) return;
foreach(Sector sector in General.Map.Map.Sectors)
{
if(sector.Tag == sectortag)
if(sector.Tags.Contains(sectortag))
{
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(sector);
vs.UpdateSectorGeometry(true);

View file

@ -814,10 +814,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Find all sector who's tag is not 0 and hash them so that we can find them quicly
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag != 0)
foreach (int tag in s.Tags)
{
if(!sectortags.ContainsKey(s.Tag)) sectortags[s.Tag] = new List<Sector>();
sectortags[s.Tag].Add(s);
if(tag == 0) continue;
if(!sectortags.ContainsKey(tag)) sectortags[tag] = new List<Sector>();
sectortags[tag].Add(s);
}
}

View file

@ -33,7 +33,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
Sector sourcesector = null;
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag == thing.Args[0])
if(s.Tags.Contains(thing.Args[0]))
{
sourcesector = s;
break;

View file

@ -37,7 +37,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag == linedef.Args[floorArg])
if(s.Tags.Contains(linedef.Args[floorArg]))
{
sourcesector = s;
break;
@ -63,7 +63,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag == linedef.Args[ceilingArg])
if(s.Tags.Contains(linedef.Args[ceilingArg]))
{
sourcesector = s;
break;

View file

@ -37,7 +37,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
Linedef ld = null;
foreach(Linedef l in General.Map.Map.Linedefs)
{
if(l.Tag == t.Args[0])
if(l.Tags.Contains(t.Args[0]))
{
ld = l;
break;