Changed, Select Similar Sectors action: when "Effect" option is enabled, all sectors with at least one matching generalized/predefined effect will be selected.

Added, Tag Explorer plugin: a separate category for each generalized/predefined effect is now created when "Sort by action special" sort mode is used.
Added, Edit Effect window: normal and generalized effects can now be set at the same time.
Fixed, Edit Action window: in some cases Generalized actions were incorrectly processed.
Fixed, Edit Effect window: in some cases Generalized effects were incorrectly processed.
Fixed, Select Similar window: Tab control was incorrectly anchored.
Fixed, Nodes Viewer mode, cosmetic: segs angles were calculated incorrectly when showing nodes in classic format.
Fixed: HiRes textures, which didn't override any texture or flat were not loaded.
Fixed, Tag Explorer plugin: linedef action categories were missing title when "Sort by action special" sort mode was used.
Cosmetic: renamed "Grid Setup" action to "Grid and Backdrop Setup".
This commit is contained in:
MaxED 2016-03-21 15:19:14 +00:00 committed by spherallic
parent 4e109000fa
commit a92610a2d8
14 changed files with 410 additions and 242 deletions

View file

@ -2,18 +2,6 @@
// Generalized sector types
gen_sectortypes
{
lighting
{
0 = "Normal";
1 = "Light Blinks (randomly)";
2 = "Light Blinks (0.5 sec)";
3 = "Light Blinks (1 sec)";
8 = "Light Glows (1+ sec)";
12 = "Light Blinks (0.5 sec sync)";
13 = "Light Blinks (1 sec sync)";
17 = "Light Flickers (randomly)";
}
damage
{
0 = "None";

View file

@ -1,17 +1,17 @@
0 = "None";
1 = "Light Blinks (randomly)";
2 = "Light Blinks (2 Hz)";
3 = "Light Blinks (1 Hz)";
4 = "Damage -10 or 20% health and Light Blinks (2 Hz)";
2 = "Light Blinks (0.5 sec.)";
3 = "Light Blinks (1 sec.)";
4 = "Damage -10 or 20% health and Light Blinks (0.5 sec.)";
5 = "Damage -5 or 10% health";
7 = "Damage -2 or 5% health";
8 = "Light Glows (1+ sec)";
8 = "Light Glows (1+ sec.)";
9 = "Secret";
10 = "Door Close Stay (after 30 sec)";
10 = "Door Close Stay (after 30 sec.)";
11 = "Damage -10 or 20% health and End level";
12 = "Light Blinks (1 Hz synchronized)";
13 = "Light Blinks (2 Hz synchronized)";
14 = "Door Open Close (opens after 5 min)";
12 = "Light Blinks (0.5 sec. synchronized)";
13 = "Light Blinks (1 sec. synchronized)";
14 = "Door Open Close (opens after 5 min.)";
16 = "Damage -10 or 20% health";
17 = "Light Flickers (randomly)";

View file

@ -2,111 +2,12 @@
// Generalized sector types
gen_sectortypes
{
effect
{
0 = "Normal";
1 = "Light Phased";
2 = "Light Sequence Start";
3 = "Light Sequence Special 1";
4 = "Light Sequence Special 2";
21 = "Light Phased";
22 = "Light Sequence Start";
23 = "Light Sequence Special 1";
24 = "Light Sequence Special 2";
26 = "Stairs Special 1";
27 = "Stairs Special 2";
65 = "Light Flicker";
66 = "Light Strobe Fast";
67 = "Light Strobe Slow";
68 = "Light Strobe Hurt";
69 = "Damage Hellslime";
71 = "Damage Nukage";
72 = "Light Glow";
74 = "Sector Door Close (30 sec)";
75 = "Damage End Level";
76 = "Light StrobeSlowSync";
77 = "Light StrobeFastSync";
78 = "Sector Door Raise (5 min)";
79 = "Low Friction";
80 = "Damage Super Hellslime";
81 = "Light Fire Flicker";
82 = "Damage -2 or -5% health (no protection)";
83 = "Damage -4 or -8% health (no protection)";
84 = "Scroll east + -2 or -5% health (no protection)";
87 = "Sector uses outside fog";
105 = "Delayed damage weak";
115 = "Instant death";
116 = "Delayed damage strong";
118 = "Carry player by tag";
196 = "Healing Sector";
197 = "Lightning Outdoor";
198 = "Lightning Indoor 2";
199 = "Lightning Indoor 1";
200 = "Sky 2 (MAPINFO)";
201 = "Scroll North (slow)";
202 = "Scroll North (medium)";
203 = "Scroll North (fast)";
204 = "Scroll East (slow)";
205 = "Scroll East (medium)";
206 = "Scroll East (fast)";
207 = "Scroll South (slow)";
208 = "Scroll South (medium)";
209 = "Scroll South (fast)";
210 = "Scroll West (slow)";
211 = "Scroll West (medium)";
212 = "Scroll West (fast)";
213 = "Scroll NorthWest (slow)";
214 = "Scroll NorthWest (medium)";
215 = "Scroll NorthWest (fast)";
216 = "Scroll NorthEast (slow)";
217 = "Scroll NorthEast (medium)";
218 = "Scroll NorthEast (fast)";
219 = "Scroll SouthEast (slow)";
220 = "Scroll SouthEast (medium)";
221 = "Scroll SouthEast (fast)";
222 = "Scroll SouthWest (slow)";
223 = "Scroll SouthWest (medium)";
224 = "Scroll SouthWest (fast)";
40 = "Wind East weak";
41 = "Wind East medium";
42 = "Wind East strong";
43 = "Wind North weak";
44 = "Wind North medium";
45 = "Wind North strong";
46 = "Wind South weak";
47 = "Wind South medium";
48 = "Wind South strong";
49 = "Wind West weak";
50 = "Wind West medium";
51 = "Wind West strong";
225 = "Carry East Slow";
226 = "Carry East Med.Slow";
227 = "Carry East Medium";
228 = "Carry East Med.Fast";
229 = "Carry East Fast";
230 = "Carry North Slow";
231 = "Carry North Med.Slow";
232 = "Carry North Medium";
233 = "Carry North Med.Fast";
234 = "Carry North Fast";
235 = "Carry South Slow";
236 = "Carry South Med.Slow";
237 = "Carry South Medium";
238 = "Carry South Med.Fast";
239 = "Carry South Fast";
240 = "Carry West Slow";
241 = "Carry West Med.Slow";
242 = "Carry West Medium";
243 = "Carry West Med.Fast";
244 = "Carry West Fast";
}
damage
{
0 = "None";
256 = "Damage 5 per second";
512 = "Damage 10 per second";
768 = "Damage 20 per second";
256 = "5 per second";
512 = "10 per second";
768 = "20 per second";
}
secret

View file

@ -23,7 +23,6 @@ using System.Globalization;
using CodeImp.DoomBuilder.IO;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.GZBuilder.Data;
using CodeImp.DoomBuilder.Data;
@ -734,7 +733,7 @@ namespace CodeImp.DoomBuilder.Config
IDictionary dic = cfg.ReadSetting("sectortypes", new Hashtable());
foreach(DictionaryEntry de in dic)
{
// Try paring the action number
// Try parsing the action number
int actionnumber;
if(int.TryParse(de.Key.ToString(),
NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite,
@ -790,10 +789,11 @@ namespace CodeImp.DoomBuilder.Config
foreach(DictionaryEntry de in dic)
{
// Check for valid structure
if(de.Value is IDictionary)
IDictionary value = de.Value as IDictionary;
if(value != null)
{
// Add option
geneffectoptions.Add(new GeneralizedOption("gen_sectortypes", "", de.Key.ToString(), (IDictionary)de.Value));
geneffectoptions.Add(new GeneralizedOption("gen_sectortypes", "", de.Key.ToString(), value));
}
else
{
@ -1046,7 +1046,8 @@ namespace CodeImp.DoomBuilder.Config
}
// This checks if an action is generalized or predefined
public static bool IsGeneralized(int action, List<GeneralizedCategory> categories)
public static bool IsGeneralized(int action) { return IsGeneralized(action, General.Map.Config.GenActionCategories); }
public static bool IsGeneralized(int action, IEnumerable<GeneralizedCategory> categories)
{
// Only actions above 0
if(action > 0)
@ -1082,41 +1083,88 @@ namespace CodeImp.DoomBuilder.Config
}
//mxd
public static bool IsGeneralizedSectorEffect(int effect, IEnumerable<GeneralizedOption> options)
public static bool IsGeneralizedSectorEffect(int effect, List<GeneralizedOption> options)
{
if(effect == 0) return false;
foreach(GeneralizedOption option in options)
int cureffect = effect;
for(int i = options.Count - 1; i > -1; i--)
{
foreach(GeneralizedBit bit in option.Bits)
for(int j = options[i].Bits.Count - 1; j > -1; j--)
{
if(bit.Index > 0 && (effect & bit.Index) == bit.Index) return true;
GeneralizedBit bit = options[i].Bits[j];
if(bit.Index > 0 && (cureffect & bit.Index) == bit.Index) return true;
cureffect -= bit.Index;
}
}
return false;
}
//mxd
public static HashSet<int> GetGeneralizedSectorEffectBits(int effect) { return GetGeneralizedSectorEffectBits(effect, General.Map.Config.GenEffectOptions); }
public static HashSet<int> GetGeneralizedSectorEffectBits(int effect, List<GeneralizedOption> options)
{
HashSet<int> result = new HashSet<int>();
if(effect > 0)
{
int cureffect = effect;
for(int i = options.Count - 1; i > -1; i--)
{
for(int j = options[i].Bits.Count - 1; j > -1; j--)
{
GeneralizedBit bit = options[i].Bits[j];
if(bit.Index > 0 && (cureffect & bit.Index) == bit.Index)
{
cureffect -= bit.Index;
result.Add(bit.Index);
}
}
}
if(cureffect > 0) result.Add(cureffect);
}
return result;
}
//mxd
public string GetGeneralizedSectorEffectName(int effect)
{
if(effect == 0) return "None";
string title = "Unknown";
string title = "Unknown generalized effect";
int matches = 0;
foreach(GeneralizedOption option in geneffectoptions)
int nongeneralizedeffect = effect;
// Check all options, in bigger to smaller order
for(int i = geneffectoptions.Count - 1; i > -1; i--)
{
foreach(GeneralizedBit bit in option.Bits)
for(int j = geneffectoptions[i].Bits.Count - 1; j > -1; j--)
{
if(bit.Index > 0 && (effect & bit.Index) == bit.Index)
GeneralizedBit bit = geneffectoptions[i].Bits[j];
if(bit.Index > 0 && (effect & bit.Index) == bit.Index)
{
title = option.Name + ": " + bit.Title;
title = geneffectoptions[i].Name + ": " + bit.Title;
nongeneralizedeffect -= bit.Index;
matches++;
break;
}
}
}
return (matches > 1 ? "Generalized (" + matches + " effects)" : title);
// Make generalized effect title
string gentitle = (matches > 1 ? "Generalized (" + matches + " effects)" : title);
// Generalized effect only
if(nongeneralizedeffect <= 0) return gentitle;
// Classic and generalized effects
if(General.Map.Config.SectorEffects.ContainsKey(nongeneralizedeffect))
return General.Map.Config.SectorEffects[nongeneralizedeffect].Title + " + " + gentitle;
if(matches > 0) return "Unknown effect + " + gentitle;
return "Unknown effect";
}
// This checks if a specific edit mode class is listed

View file

@ -55,13 +55,29 @@ namespace CodeImp.DoomBuilder.Config
foreach(DictionaryEntry de in opts)
{
// Is this an option and not just some value?
if(de.Value is IDictionary)
IDictionary value = de.Value as IDictionary;
if(value != null)
{
// Add the option
this.options.Add(new GeneralizedOption(structure, name, de.Key.ToString(), (IDictionary)de.Value));
this.options.Add(new GeneralizedOption(structure, name, de.Key.ToString(), value));
}
}
//mxd. Sort by bits step
if(this.options.Count > 1)
{
this.options.Sort(delegate(GeneralizedOption o1, GeneralizedOption o2)
{
if(o1.BitsStep > o2.BitsStep) return 1;
if(o1.BitsStep == o2.BitsStep)
{
if(o1 != o2) General.ErrorLogger.Add(ErrorType.Error, "\"" + o1.Name + "\" and \"" + o2.Name + "\" generalized categories have the same bit step (" + o1.BitsStep + ")!");
return 0;
}
return -1;
});
}
// We have no destructor
GC.SuppressFinalize(this);
}

View file

@ -39,6 +39,8 @@ namespace CodeImp.DoomBuilder.Config
// Properties
private string name;
private List<GeneralizedBit> bits;
private int bitstep; //mxd
public int BitsStep { get { return bitstep; } } // mxd. Each subsequent value is incremented by this number
#endregion
@ -82,6 +84,20 @@ namespace CodeImp.DoomBuilder.Config
// Sort the list
bits.Sort();
//mxd. Determine and check increment steps
if(bits.Count > 1)
{
// Use the second bit as the structure's step
bitstep = bits[1].Index;
// Check the rest of the values
for(int i = 1; i < bits.Count; i++)
{
if(bits[i].Index - bits[i - 1].Index != bitstep)
General.ErrorLogger.Add(ErrorType.Warning, "Structure \"" + fullpath + "." + name + "\" contains options with mixed increments (option \"" + bits[i].Title + "\" increment (" + (bits[i - 1].Index - bits[i].Index) + ") doesn't match the structure increment (" + bitstep + ")).");
}
}
// We have no destructor
GC.SuppressFinalize(this);

View file

@ -430,7 +430,7 @@ toggledynamicgrid
gridsetup
{
title = "Grid Setup";
title = "Grid and Backdrop Setup";
category = "classic";
description = "Shows the Custom Grid Setup dialog which allows you to set custom grid sizes and a background image.";
allowkeys = true;

View file

@ -81,7 +81,13 @@ namespace CodeImp.DoomBuilder.Windows
// Select category
foreach(GeneralizedCategory ac in category.Items)
if((action >= ac.Offset) && (action < (ac.Offset + ac.Length))) category.SelectedItem = ac;
{
if((action >= ac.Offset) && (action < (ac.Offset + ac.Length)))
{
category.SelectedItem = ac;
break; //mxd
}
}
// Anything selected?
if(category.SelectedIndex > -1)
@ -89,26 +95,27 @@ namespace CodeImp.DoomBuilder.Windows
// Go for all options in selected category
GeneralizedCategory sc = category.SelectedItem as GeneralizedCategory;
int actionbits = action - sc.Offset;
for(int i = 0; i < MAX_OPTIONS; i++)
// Go for all options, bigger steps first (mxd)
// INFO: both GeneralizedOptions and GeneralizedBits are incrimentally sorted
for(int i = MAX_OPTIONS - 1; i > -1; i--)
{
// Option used?
if(i < sc.Options.Count)
{
// Go for all bits
foreach(GeneralizedBit ab in sc.Options[i].Bits)
// Go for all bits, bigger bits first (mxd)
for(int b = sc.Options[i].Bits.Count - 1; b > -1; b--)
{
// Select this setting if matches
if((actionbits & ab.Index) == ab.Index)
GeneralizedBit bit = sc.Options[i].Bits[b];
if((actionbits & bit.Index) == bit.Index)
{
options[i].SelectedItem = ab;
if(ab.Index > 0) break; //mxd
options[i].SelectedItem = bit;
actionbits -= bit.Index; //mxd
if(bit.Index > 0) break; //mxd
}
}
}
else
{
break; //mxd
}
}
}
}

View file

@ -54,16 +54,12 @@ namespace CodeImp.DoomBuilder.Windows
Label[] optionlbls = { option0label, option1label, option2label, option3label,
option4label, option5label, option6label, option7label };
// Go for all predefined effects
bool selected = CreateEffects(effect); //mxd
allitems = new ListViewItem[effects.Items.Count]; //mxd
effects.Items.CopyTo(allitems, 0); //mxd
// Using generalized effects?
int nongeneralizedeffect = effect; //mxd
if(General.Map.Config.GeneralizedEffects)
{
// Go for all options
for(int i = 0; i < MAX_OPTIONS; i++)
// Go for all options, bigger steps first (mxd)
for(int i = MAX_OPTIONS - 1; i > -1; i--)
{
// Option used in selected category?
if(i < General.Map.Config.GenEffectOptions.Count)
@ -88,6 +84,7 @@ namespace CodeImp.DoomBuilder.Windows
if((effect & ab.Index) == ab.Index)
{
options[i].SelectedItem = ab;
nongeneralizedeffect -= ab.Index; //mxd
if(ab.Index > 0) break; //mxd
}
}
@ -100,15 +97,20 @@ namespace CodeImp.DoomBuilder.Windows
optionlbls[i].Visible = false;
}
}
// Open the generalized tab when given effect is generalized
if(!selected) tabs.SelectedTab = tabgeneralized;
}
else
{
// Remove generalized tab
tabs.TabPages.Remove(tabgeneralized);
}
//mxd. Go for all predefined effects
bool selected = CreateEffects(nongeneralizedeffect) && General.Map.Config.GeneralizedEffects; //mxd
allitems = new ListViewItem[effects.Items.Count]; //mxd
effects.Items.CopyTo(allitems, 0); //mxd
// Open the generalized tab when given effect is generalized
if(!selected && General.Map.Config.GeneralizedEffects) tabs.SelectedTab = tabgeneralized;
}
// This browses for an effect
@ -193,19 +195,16 @@ namespace CodeImp.DoomBuilder.Windows
{
// Presume no result
selectedeffect = 0;
// Predefined action?
if(tabs.SelectedTab == tabeffects)
//mxd. Add predefined effect?
if((effects.SelectedItems.Count > 0) && (effects.SelectedItems[0].Tag is SectorEffectInfo))
{
// Effect selected?
if((effects.SelectedItems.Count > 0) && (effects.SelectedItems[0].Tag is SectorEffectInfo))
{
// Our result
selectedeffect = ((SectorEffectInfo)effects.SelectedItems[0].Tag).Index;
}
// Our result
selectedeffect = ((SectorEffectInfo)effects.SelectedItems[0].Tag).Index;
}
// Generalized action
else
//mxd. Add generalized effects? (Don't add when "Any effect" is selected)
if(selectedeffect != -1 && General.Map.Config.GeneralizedEffects)
{
// Go for all options
for(int i = 0; i < MAX_OPTIONS; i++)

View file

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
@ -803,8 +804,21 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(flags.CeilingTexture && source.CeilTexture != target.CeilTexture) return false;
if(flags.Brightness && source.Brightness != target.Brightness) return false;
if(flags.Tag && !TagsMatch(source.Tags, target.Tags)) return false;
if(flags.Special && source.Effect != target.Effect) return false;
if(flags.Flags && !FlagsMatch(source.GetFlags(), target.GetFlags())) return false;
// Generalized effects require more tender loving care...
if(flags.Special && source.Effect != target.Effect)
{
if(!General.Map.Config.GeneralizedEffects || source.Effect == 0 || target.Effect == 0) return false;
// Get effect bits...
HashSet<int> sourcebits = GameConfiguration.GetGeneralizedSectorEffectBits(source.Effect);
HashSet<int> targetbits = GameConfiguration.GetGeneralizedSectorEffectBits(target.Effect);
// No bits match when at least one effect is not generalized, or when bits don't overlap
if(sourcebits.Count == 0 || targetbits.Count == 0 || !sourcebits.Overlaps(targetbits)) return false;
}
if(!General.Map.UDMF) return true;
// UI fields
@ -840,7 +854,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Built-in properties
if(linedefflags.Action && source.Action != target.Action) return false;
if(linedefflags.Activation && source.Activate != target.Activate) return false;
if(linedefflags.Tag && !TagsMatch(source.Tags, target.Tags)) return false; //mxd
if(linedefflags.Tag && !TagsMatch(source.Tags, target.Tags)) return false;
if(linedefflags.Arguments)
{
// Classic args

View file

@ -86,7 +86,8 @@
//
// tabControl
//
this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tabControl.Controls.Add(this.sectors);
this.tabControl.Controls.Add(this.linedefs);

View file

@ -151,10 +151,10 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
segs = new Seg[numsegs];
for(int i = 0; i < segs.Length; i++)
{
segs[i].startvertex = segsreader.ReadInt16();
segs[i].endvertex = segsreader.ReadInt16();
segs[i].angle = Angle2D.DoomToReal(segsreader.ReadInt16());
segs[i].lineindex = segsreader.ReadInt16();
segs[i].startvertex = segsreader.ReadUInt16();
segs[i].endvertex = segsreader.ReadUInt16();
segs[i].angle = Angle2D.DegToRad(General.ClampAngle(segsreader.ReadInt16() / 182 + 90)); //mxd 182 == 65536 / 360;
segs[i].lineindex = segsreader.ReadUInt16();
segs[i].leftside = segsreader.ReadInt16() != 0;
segs[i].offset = segsreader.ReadInt16();
}
@ -220,10 +220,10 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
//mxd. This loads all data from the ZNODES lump
private bool LoadZNodes()
{
List<string> supportedFormats = new List<string> { "XNOD", "XGLN", "XGL2", "XGL3" };
List<string> supportedformats = new List<string> { "XNOD", "XGLN", "XGL2", "XGL3" };
MemoryStream stream = General.Map.GetLumpData("ZNODES");
//boilerplate...
// Boilerplate...
if(stream.Length < 4)
{
MessageBox.Show("ZNODES lump is empty.", "Nodes Viewer mode", MessageBoxButtons.OK, MessageBoxIcon.Error);
@ -233,39 +233,39 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
using(BinaryReader reader = new BinaryReader(stream))
{
//read signature
// Read signature
nodesformat = new string(reader.ReadChars(4));
if(!supportedFormats.Contains(nodesformat))
if(!supportedformats.Contains(nodesformat))
{
MessageBox.Show("\"" + nodesformat + "\" node format is not supported.", "Nodes Viewer mode", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
uint vertsCount = reader.ReadUInt32();
uint newVertsCount = reader.ReadUInt32();
uint vertscount = reader.ReadUInt32();
uint newvertscount = reader.ReadUInt32();
//boilerplate...
if(vertsCount != General.Map.Map.Vertices.Count)
// Boilerplate...
if(vertscount != General.Map.Map.Vertices.Count)
{
MessageBox.Show("Error while reading ZNODES: vertices count in ZNODES lump (" + vertsCount + ") doesn't match with map's vertices count (" + General.Map.Map.Vertices.Count + ")!", "Nodes Viewer mode", MessageBoxButtons.OK, MessageBoxIcon.Error);
MessageBox.Show("Error while reading ZNODES: vertices count in ZNODES lump (" + vertscount + ") doesn't match with map's vertices count (" + General.Map.Map.Vertices.Count + ")!", "Nodes Viewer mode", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
//add map vertices
verts = new Vector2D[vertsCount + newVertsCount];
// Add map vertices
verts = new Vector2D[vertscount + newvertscount];
int counter = 0;
foreach(Vertex v in General.Map.Map.Vertices) verts[counter++] = v.Position;
//read extra vertices
for(int i = counter; i < counter + newVertsCount; i++)
// Read extra vertices
for(int i = counter; i < counter + newvertscount; i++)
{
verts[i].x = reader.ReadInt32() / 65536.0f;
verts[i].y = reader.ReadInt32() / 65536.0f;
}
//read subsectors
uint ssecCount = reader.ReadUInt32();
ssectors = new Subsector[ssecCount];
// Read subsectors
uint sseccount = reader.ReadUInt32();
ssectors = new Subsector[sseccount];
int firstseg = 0;
for(int i = 0; i < ssectors.Length; i++)
@ -275,9 +275,9 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
firstseg += ssectors[i].numsegs;
}
//read segments. offset and angle are unused anyway
uint segsCount = reader.ReadUInt32();
segs = new Seg[segsCount];
// Read segments. Offset and angle are unused anyway
uint segscount = reader.ReadUInt32();
segs = new Seg[segscount];
switch(nodesformat)
{
@ -314,20 +314,20 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
break;
}
//set second vertex, angle and reverse segs order
// Set second vertex, angle and reverse segs order
if(nodesformat == "XGLN" || nodesformat == "XGL2" || nodesformat == "XGL3")
{
int index = 0;
foreach(Subsector ss in ssectors)
{
//set the last vert
// Set the last vert
int lastseg = ss.firstseg + ss.numsegs - 1;
segs[lastseg].endvertex = segs[ss.firstseg].startvertex;
//set the rest
// Set the rest
for(int i = ss.firstseg + 1; i <= lastseg; i++) segs[i - 1].endvertex = segs[i].startvertex;
//set angle and subsector index
// Set angle and subsector index
for(int i = ss.firstseg; i <= lastseg; i++)
{
segs[i].angle = Vector2D.GetAngle(verts[segs[i].endvertex], verts[segs[i].startvertex]);
@ -338,17 +338,17 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
}
}
//read nodes
uint nodesCount = reader.ReadUInt32();
// Read nodes
uint nodescount = reader.ReadUInt32();
//boilerplate...
if(nodesCount < 1)
// Boilerplate...
if(nodescount < 1)
{
MessageBox.Show("The map has only one subsector.", "Why are you doing this, Stanley?..", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
nodes = new Node[nodesCount];
nodes = new Node[nodescount];
for(int i = 0; i < nodes.Length; i++)
{

View file

@ -39,11 +39,19 @@ namespace CodeImp.DoomBuilder.TagExplorer
public sealed partial class TagExplorer : UserControl
{
private struct SectorEffectData
{
public int Effect; //1024
public string CategoryName; // "Secret"
public string EffectName; // "Secret: Yes"
public bool IsGeneralized;
}
private const string DISPLAY_TAGS_AND_ACTIONS = "Tags and Action Specials";
private const string DISPLAY_TAGS = "Tags";
private const string DISPLAY_ACTIONS = "Action Specials";
private const string DISPLAY_POLYOBJECTS = "Polyobjects";
private readonly object[] DISPLAY_MODES = new object[] { DISPLAY_TAGS_AND_ACTIONS, DISPLAY_TAGS, DISPLAY_ACTIONS, DISPLAY_POLYOBJECTS };
private readonly object[] DISPLAY_MODES = { DISPLAY_TAGS_AND_ACTIONS, DISPLAY_TAGS, DISPLAY_ACTIONS, DISPLAY_POLYOBJECTS };
private string currentDisplayMode;
private string currentSortMode;
@ -356,10 +364,7 @@ namespace CodeImp.DoomBuilder.TagExplorer
}
}
//sort nodes
Sort(ref nodes, currentSortMode);
//add category
// Add category
if(nodes.Count > 0)
{
switch(currentSortMode)
@ -371,25 +376,89 @@ namespace CodeImp.DoomBuilder.TagExplorer
foreach(TreeNode node in nodes)
{
NodeInfo nodeInfo = node.Tag as NodeInfo;
NodeInfo info = node.Tag as NodeInfo;
if(nodeInfo.Action == 0)
if(info.Action == 0)
{
noAction.Nodes.Add(node);
continue;
}
SectorEffectInfo sei = General.Map.Config.GetSectorEffectInfo(nodeInfo.Action);
if(!categories.ContainsKey(sei.Index))
categories.Add(sei.Index, new TreeNode(sei.Index + " - " + sei.Title, 2, 2, new[] { node }));
List<SectorEffectData> effects = GetSectorEffects(info.Action);
if(effects.Count == 1 && !effects[0].IsGeneralized)
{
// The first node is already has all relevant data. Just add it
if(!categories.ContainsKey(effects[0].Effect))
{
TreeNode catnode = new TreeNode(effects[0].Effect + " - " + effects[0].CategoryName, 2, 2, new[] {node});
catnode.Tag = effects[0].Effect;
categories.Add(effects[0].Effect, catnode);
}
else
{
categories[effects[0].Effect].Nodes.Add(node);
}
}
else
categories[sei.Index].Nodes.Add(node);
}
TreeNode[] catNodes = new TreeNode[categories.Values.Count];
categories.Values.CopyTo(catNodes, 0);
{
// Add generalized effects
foreach(SectorEffectData data in effects)
{
// Create NodeInfo for each effect...
NodeInfo geninfo = new NodeInfo(info, data.Effect);
// Copy the initial node, otherwise it won't be added several times
string name = geninfo.GetName(ref comment, currentSortMode);
TreeNode nodecopy = new TreeNode(name, node.ImageIndex, node.SelectedImageIndex)
{
Tag = geninfo,
ToolTipText = node.ToolTipText
};
TreeNode category = new TreeNode(CAT_SECTORS, 2, 2, catNodes);
if(!categories.ContainsKey(data.Effect))
{
TreeNode catnode = new TreeNode(data.Effect + " - " + data.CategoryName, 2, 2, new[] {nodecopy});
catnode.Tag = data.Effect;
categories.Add(data.Effect, catnode);
}
else
{
categories[data.Effect].Nodes.Add(nodecopy);
}
}
}
}
// Because of generalized effects shenanigans, category and nodes resortings are required...
TreeNode[] catnodes = new TreeNode[categories.Values.Count];
categories.Values.CopyTo(catnodes, 0);
// Sort categories
Array.Sort(catnodes, delegate(TreeNode t1, TreeNode t2)
{
int effect1 = (int)t1.Tag;
int effect2 = (int)t2.Tag;
if(effect1 > effect2) return 1;
if(effect1 == effect2) return 0;
return -1;
});
// Sort nodes
foreach(TreeNode n in catnodes)
{
if(n.Nodes.Count > 0)
{
List<TreeNode> tosort = new List<TreeNode>(n.Nodes.Count);
foreach(TreeNode nn in n.Nodes) tosort.Add(nn);
Sort(ref tosort, currentSortMode);
n.Nodes.Clear();
n.Nodes.AddRange(tosort.ToArray());
}
}
TreeNode category = new TreeNode(CAT_SECTORS, 2, 2, catnodes);
if(noAction.Nodes.Count > 0) category.Nodes.Add(noAction);
treeView.Nodes.Add(category);
@ -401,6 +470,9 @@ namespace CodeImp.DoomBuilder.TagExplorer
Dictionary<int, TreeNode> categories = new Dictionary<int, TreeNode>();
TreeNode noTag = new TreeNode("No Tag", 2, 2);
// Sort nodes
Sort(ref nodes, currentSortMode);
foreach(TreeNode node in nodes)
{
NodeInfo nodeInfo = node.Tag as NodeInfo;
@ -435,6 +507,9 @@ namespace CodeImp.DoomBuilder.TagExplorer
break;
default:
// Sort nodes
Sort(ref nodes, currentSortMode);
treeView.Nodes.Add(new TreeNode(CAT_SECTORS, 2, 2, nodes.ToArray()));
break;
}
@ -513,7 +588,7 @@ namespace CodeImp.DoomBuilder.TagExplorer
LinedefActionInfo lai = General.Map.Config.GetLinedefActionInfo(nodeInfo.Action);
if(!categories.ContainsKey(lai.Index)) categories.Add(lai.Index, new TreeNode(lai.Index + " - " + lai.Name, 4, 4, new[] { node }));
if(!categories.ContainsKey(lai.Index)) categories.Add(lai.Index, new TreeNode(lai.Index + " - " + lai.Title, 4, 4, new[] { node }));
else categories[lai.Index].Nodes.Add(node);
}
TreeNode[] catNodes = new TreeNode[categories.Values.Count];
@ -709,6 +784,79 @@ namespace CodeImp.DoomBuilder.TagExplorer
return -1;
}
// This returns information on a sector effect
private static List<SectorEffectData> GetSectorEffects(int effect)
{
List<SectorEffectData> result = new List<SectorEffectData>(1);
// No effect?
if(effect == 0)
{
result.Add(new SectorEffectData { Effect = 0, CategoryName = "None", EffectName = "None" });
}
// Known effect?
else if(General.Map.Config.SectorEffects.ContainsKey(effect))
{
string title = General.Map.Config.SectorEffects[effect].Title;
result.Add(new SectorEffectData { Effect = effect, CategoryName = title, EffectName = title });
}
else
{
// Generalized effect(s)?
int initialeffect = effect;
// Check all effects, in bigger to smaller order
for(int i = General.Map.Config.GenEffectOptions.Count - 1; i > -1; i--)
{
for(int j = General.Map.Config.GenEffectOptions[i].Bits.Count - 1; j > -1; j--)
{
GeneralizedBit bit = General.Map.Config.GenEffectOptions[i].Bits[j];
if(bit.Index > 0 && (effect & bit.Index) == bit.Index)
{
initialeffect -= bit.Index;
result.Add(new SectorEffectData
{
Effect = bit.Index,
CategoryName = General.Map.Config.GenEffectOptions[i].Name,
EffectName = General.Map.Config.GenEffectOptions[i].Name + ": " + bit.Title,
IsGeneralized = true,
});
break;
}
}
}
// Add combined effect?
if(result.Count > 0 && initialeffect > 0)
{
string combinedeffect = General.Map.Config.GetGeneralizedSectorEffectName(effect);
result.Add(new SectorEffectData { Effect = effect, CategoryName = combinedeffect, EffectName = combinedeffect + ": " + effect, });
}
if(initialeffect > 0)
{
// Insert non-generalized effect as the first one
if(General.Map.Config.SectorEffects.ContainsKey(initialeffect))
{
string title = General.Map.Config.SectorEffects[initialeffect].Title;
result.Insert(0, new SectorEffectData { Effect = initialeffect, CategoryName = title, EffectName = title });
}
else
{
// Unknown effect...
result.Insert(0, new SectorEffectData { Effect = initialeffect, CategoryName = "Unknown", EffectName = "Unknown" });
}
}
else if(result.Count == 0)
{
// Unknown effect...
result.Add(new SectorEffectData { Effect = effect, CategoryName = "Unknown", EffectName = "Unknown" });
}
}
return result;
}
#endregion
#region ================== Events

View file

@ -1,4 +1,5 @@
using CodeImp.DoomBuilder.Config;
using System;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Types;
@ -12,13 +13,13 @@ namespace CodeImp.DoomBuilder.TagExplorer
private readonly int action;
private readonly int tag;
private readonly int polyobjnumber;
private readonly string defaultName;
private readonly string defaultname;
public int Index { get { return index; } }
public int Tag { get { return tag; } }
public int PolyobjectNumber { get { return polyobjnumber; } }
public int Action { get { return action; } }
public string DefaultName { get { return defaultName; } }
public string DefaultName { get { return defaultname; } }
public NodeInfoType Type { get { return type; } }
public string Comment { get { return GetComment(); } set { SetComment(value); } }
@ -31,10 +32,10 @@ namespace CodeImp.DoomBuilder.TagExplorer
tag = t.Tag;
polyobjnumber = ((t.SRB2Type > 9299 && t.SRB2Type < 9304) ? t.AngleDoom : int.MinValue);
ThingTypeInfo tti = General.Map.Data.GetThingInfoEx(t.SRB2Type);
defaultName = (tti != null ? tti.Title : "Thing");
defaultname = (tti != null ? tti.Title : "Thing");
}
public NodeInfo(Sector s, int tagindex)
public NodeInfo(Sector s, int tagindex)
{
type = NodeInfoType.SECTOR;
index = s.Index;
@ -42,13 +43,11 @@ namespace CodeImp.DoomBuilder.TagExplorer
tag = s.Tags[tagindex];
if(General.Map.Config.SectorEffects.ContainsKey(action))
{
defaultName = General.Map.Config.SectorEffects[action].Title;
}
defaultname = General.Map.Config.SectorEffects[action].Title;
else if(action > 0)
defaultname = General.Map.Config.GetGeneralizedSectorEffectName(action);
else
{
defaultName = "Sector";
}
defaultname = "Sector";
}
public NodeInfo(Linedef l, int tagindex)
@ -59,13 +58,44 @@ namespace CodeImp.DoomBuilder.TagExplorer
tag = l.Tags[tagindex];
polyobjnumber = ((l.Action > 0 && l.Action < 9) ? l.Args[0] : int.MinValue);
if(General.Map.Config.LinedefActions.ContainsKey(l.Action))
{
defaultName = General.Map.Config.LinedefActions[l.Action].Title;
}
if(General.Map.Config.LinedefActions.ContainsKey(action))
defaultname = General.Map.Config.LinedefActions[action].Title;
else if(action > 0 && GameConfiguration.IsGeneralized(action))
defaultname = "Generalized (" + General.Map.Config.GetGeneralizedActionCategory(action) + ")";
else
defaultname = "Linedef";
}
// Copy constructor
public NodeInfo(NodeInfo other, int neweffect)
{
this.type = other.type;
this.index = other.index;
this.action = neweffect;
this.tag = other.tag;
this.polyobjnumber = other.polyobjnumber;
switch(type)
{
defaultName = "Linedef";
case NodeInfoType.LINEDEF:
if(General.Map.Config.LinedefActions.ContainsKey(action))
defaultname = General.Map.Config.LinedefActions[action].Title;
else if(action > 0 && GameConfiguration.IsGeneralized(action))
defaultname = "Generalized (" + General.Map.Config.GetGeneralizedActionCategory(action) + ")";
else
defaultname = "Linedef";
break;
case NodeInfoType.SECTOR:
if(General.Map.Config.SectorEffects.ContainsKey(action))
defaultname = General.Map.Config.SectorEffects[action].Title;
else if(action > 0)
defaultname = General.Map.Config.GetGeneralizedSectorEffectName(action);
else
defaultname = "Sector";
break;
default: throw new NotImplementedException("Not implemented...");
}
}
@ -165,7 +195,7 @@ namespace CodeImp.DoomBuilder.TagExplorer
private string CombineName(string comment, string sortmode)
{
string name = (!string.IsNullOrEmpty(comment) ? comment : defaultName);
string name = (!string.IsNullOrEmpty(comment) ? comment : defaultname);
switch(sortmode)
{
@ -179,7 +209,7 @@ namespace CodeImp.DoomBuilder.TagExplorer
return (action > 0 ? "Action " + action + ": " : "") + name + ", Index " + index;
case SortMode.SORT_BY_POLYOBJ_NUMBER:
return "PO " + polyobjnumber + ": " + defaultName + ", Index " + index;
return "PO " + polyobjnumber + ": " + defaultname + ", Index " + index;
default:
return name;