From f986f5c98dbd6131482ac197d01dbd3d3e9db710 Mon Sep 17 00:00:00 2001 From: MaxED <j.maxed@gmail.com> Date: Mon, 3 Nov 2014 13:02:59 +0000 Subject: [PATCH] Fixed, game configurations: Boom game configurations used incorrect "thingflagscompare" block. Fixed, Thing edit form: implemented overcomplicated required flags check (which should work as expected this time. probably.). --- Build/Configurations/Includes/Boom_common.cfg | 2 +- Build/Configurations/Includes/Boom_misc.cfg | 43 +++-- Build/Configurations/Includes/Doom_misc.cfg | 2 + Build/Configurations/Includes/Hexen_misc.cfg | 12 +- Build/Configurations/Includes/UDMF_misc.cfg | 12 +- Source/Core/Config/GameConfiguration.cs | 28 +++ Source/Core/Config/ThingsFlagsCompare.cs | 167 ++++++++++++++++-- Source/Core/Windows/ThingEditForm.cs | 46 +---- Source/Core/Windows/ThingEditFormUDMF.cs | 48 ++--- 9 files changed, 246 insertions(+), 114 deletions(-) diff --git a/Build/Configurations/Includes/Boom_common.cfg b/Build/Configurations/Includes/Boom_common.cfg index 2f3151886..9a6dc4137 100644 --- a/Build/Configurations/Includes/Boom_common.cfg +++ b/Build/Configurations/Includes/Boom_common.cfg @@ -97,7 +97,7 @@ mapformat_doom // How to compare thing flags (for the stuck things error checker) thingflagscompare { - include("Doom_misc.cfg", "thingflagscompare"); + include("Boom_misc.cfg", "thingflagscompare"); } // Things flags masks diff --git a/Build/Configurations/Includes/Boom_misc.cfg b/Build/Configurations/Includes/Boom_misc.cfg index 2b4c30530..666f0863d 100644 --- a/Build/Configurations/Includes/Boom_misc.cfg +++ b/Build/Configurations/Includes/Boom_misc.cfg @@ -35,25 +35,30 @@ thingflagstranslation // How thing flags should be compared (for the stuck thing error check) thingflagscompare { - skills { - 1; - 2; - 4; - } - - gamemodes { - 16 { - invert = true; - } - - 32 { - invert = true; - } - - 64 { - invert = true; - } - } + skills { + 1; + 2; + 4; + } + + gamemodes { + 16 { + //invert = true; + ignoredgroup = "skills"; + ingnorethisgroupwhenunset = true; + } + + 32 { + invert = true; + requiredflag = "16"; + } + + 64 { + invert = true; + requiredflag = "16"; + requiredgroup = "skills"; + } + } } diff --git a/Build/Configurations/Includes/Doom_misc.cfg b/Build/Configurations/Includes/Doom_misc.cfg index e7444d4f1..9c94327f1 100644 --- a/Build/Configurations/Includes/Doom_misc.cfg +++ b/Build/Configurations/Includes/Doom_misc.cfg @@ -57,6 +57,8 @@ thingflagscompare gamemodes { 16 { comparemethod = "equal"; + ignoredgroup = "skills"; + ingnorethisgroupwhenunset = true; } } } diff --git a/Build/Configurations/Includes/Hexen_misc.cfg b/Build/Configurations/Includes/Hexen_misc.cfg index e6124b42b..e3292fc91 100644 --- a/Build/Configurations/Includes/Hexen_misc.cfg +++ b/Build/Configurations/Includes/Hexen_misc.cfg @@ -59,9 +59,15 @@ thingflagscompare } gamemodes { - 256; - 512; - 1024; + 256 { + requiredgroup = "skills"; + } + 512 { + requiredgroup = "skills"; + } + 1024 { + ignoredgroup = "skills"; + } } } diff --git a/Build/Configurations/Includes/UDMF_misc.cfg b/Build/Configurations/Includes/UDMF_misc.cfg index 8b20e8968..9bf0768db 100644 --- a/Build/Configurations/Includes/UDMF_misc.cfg +++ b/Build/Configurations/Includes/UDMF_misc.cfg @@ -48,9 +48,15 @@ thingflagscompare } gamemodes { - single; - dm; - coop; + single { + requiredgroup = "skills"; + } + coop { + requiredgroup = "skills"; + } + dm { + ignoredgroup = "skills"; + } } classes { diff --git a/Source/Core/Config/GameConfiguration.cs b/Source/Core/Config/GameConfiguration.cs index ce324935d..86bb77add 100644 --- a/Source/Core/Config/GameConfiguration.cs +++ b/Source/Core/Config/GameConfiguration.cs @@ -733,6 +733,34 @@ namespace CodeImp.DoomBuilder.Config } } + //mxd. Integrity check + foreach (KeyValuePair<string, Dictionary<string, ThingFlagsCompare>> group in thingflagscompare) + { + foreach (KeyValuePair<string, ThingFlagsCompare> flaggrp in group.Value) + { + // Required group is missing? + if (!string.IsNullOrEmpty(flaggrp.Value.RequiredGroup) && !thingflagscompare.ContainsKey(flaggrp.Value.RequiredGroup)) + { + General.ErrorLogger.Add(ErrorType.Warning, "thingflagscompare group '" + flaggrp.Value.RequiredGroup + "', required by flag '" + flaggrp.Key + "' does not exist!"); + flaggrp.Value.RequiredGroup = string.Empty; + } + + // Ignored group is missing? + if(!string.IsNullOrEmpty(flaggrp.Value.IgnoredGroup) && !thingflagscompare.ContainsKey(flaggrp.Value.IgnoredGroup)) + { + General.ErrorLogger.Add(ErrorType.Warning, "thingflagscompare group '" + flaggrp.Value.IgnoredGroup + "', ignored by flag '" + flaggrp.Key + "' does not exist!"); + flaggrp.Value.IgnoredGroup = string.Empty; + } + + // Required flag is missing? + if(!string.IsNullOrEmpty(flaggrp.Value.RequiredFlag) && !group.Value.ContainsKey(flaggrp.Value.RequiredFlag)) + { + General.ErrorLogger.Add(ErrorType.Warning, "thingflagscompare flag '" + flaggrp.Value.RequiredFlag + "', required by flag '" + flaggrp.Key + "' does not exist!"); + flaggrp.Value.RequiredFlag = string.Empty; + } + } + } + // Sort the translation flags, because they must be compared highest first! thingflagstranslation.Sort(); } diff --git a/Source/Core/Config/ThingsFlagsCompare.cs b/Source/Core/Config/ThingsFlagsCompare.cs index 417c50fba..fe71cb788 100644 --- a/Source/Core/Config/ThingsFlagsCompare.cs +++ b/Source/Core/Config/ThingsFlagsCompare.cs @@ -17,6 +17,8 @@ #region ================== Namespaces using System; +using System.Collections.Generic; +using System.Windows.Forms; using CodeImp.DoomBuilder.IO; using CodeImp.DoomBuilder.Map; @@ -39,6 +41,10 @@ namespace CodeImp.DoomBuilder.Config #region ================== Variables private readonly string flag; + private string requiredgroup; //mxd. This flag only works if at least one flag is set in the "requiredgroup" + private string ignoredgroup; //mxd. If this flag is set, flags from ignoredgroup can be... well... ignored! + private string requiredflag; //mxd. This flag only works if requiredflag is set. + private readonly bool ingnorethisgroupwhenunset; //mxd private readonly CompareMethod comparemethod; private readonly bool invert; private readonly string group; @@ -49,6 +55,9 @@ namespace CodeImp.DoomBuilder.Config public string Flag { get { return flag; } } public string Group { get { return group; } } + public string RequiredGroup { get { return requiredgroup; } internal set { requiredgroup = value; } } //mxd + public string IgnoredGroup { get { return ignoredgroup; } internal set { ignoredgroup = value; } } //mxd + public string RequiredFlag { get { return requiredflag; } internal set { requiredflag = value; } } //mxd #endregion @@ -77,6 +86,10 @@ namespace CodeImp.DoomBuilder.Config } invert = cfg.ReadSetting(cfgpath + ".invert", false); + requiredgroup = cfg.ReadSetting(cfgpath + ".requiredgroup", string.Empty); //mxd + ignoredgroup = cfg.ReadSetting(cfgpath + ".ignoredgroup", string.Empty); //mxd + requiredflag = cfg.ReadSetting(cfgpath + ".requiredflag", string.Empty); //mxd + ingnorethisgroupwhenunset = cfg.ReadSetting(cfgpath + ".ingnorethisgroupwhenunset", false); //mxd // We have no destructor GC.SuppressFinalize(this); @@ -97,25 +110,155 @@ namespace CodeImp.DoomBuilder.Config bool t2flag; // Check if the flags exist - if(!t1.Flags.ContainsKey(flag) || !t2.Flags.ContainsKey(flag)) { - //mxd. If a map is in UDMF format - check Fields - if(!General.Map.UDMF || !t1.Fields.ContainsKey(flag) || !t2.Fields.ContainsKey(flag)) - return 0; - - // tag flag inversion into account - t1flag = invert ? !(bool)t1.Fields[flag].Value : (bool)t1.Fields[flag].Value; - t2flag = invert ? !(bool)t2.Fields[flag].Value : (bool)t2.Fields[flag].Value; - } else { - // tag flag inversion into account - t1flag = invert ? !t1.Flags[flag] : t1.Flags[flag]; - t2flag = invert ? !t2.Flags[flag] : t2.Flags[flag]; + if (!t1.Flags.ContainsKey(flag) || !t2.Flags.ContainsKey(flag)) return 0; + + //mxd. We should ignore the flag if requiredgroup doesn't have any flags set + if(!string.IsNullOrEmpty(requiredgroup)) + { + bool t1hasrequiredflags = false; + bool t2hasrequiredflags = false; + foreach(string key in General.Map.Config.ThingFlagsCompare[requiredgroup].Keys) + { + if(t1.Flags.ContainsKey(key) && (General.Map.Config.ThingFlagsCompare[requiredgroup][key].invert ? !t1.Flags[key] : t1.Flags[key])) + t1hasrequiredflags = true; + if(t2.Flags.ContainsKey(key) && (General.Map.Config.ThingFlagsCompare[requiredgroup][key].invert ? !t2.Flags[key] : t2.Flags[key])) + t2hasrequiredflags = true; + } + + // Can't compare... + if (!t1hasrequiredflags || !t2hasrequiredflags) return 0; + } + + //mxd. We should ignore the flag if requiredflag is not set + if (string.IsNullOrEmpty(requiredflag)) + { + bool inverted = General.Map.Config.ThingFlagsCompare[group].ContainsKey(requiredflag) && General.Map.Config.ThingFlagsCompare[group][requiredflag].invert; + + bool t1hasrequiredflag = inverted ? !t1.Flags[requiredflag] : t1.Flags[requiredflag]; + bool t2hasrequiredflag = inverted ? !t2.Flags[requiredflag] : t2.Flags[requiredflag]; + + // Can't compare... + if(!t1hasrequiredflag || !t2hasrequiredflag) return 0; + } + + //mxd. We should also ignore the flag if it's in ingoredgroup + foreach(KeyValuePair<string, Dictionary<string, ThingFlagsCompare>> pair in General.Map.Config.ThingFlagsCompare) + { + foreach(KeyValuePair<string, ThingFlagsCompare> flaggrp in pair.Value) + { + if (!string.IsNullOrEmpty(flaggrp.Value.ignoredgroup) && group == flaggrp.Value.ignoredgroup) + { + bool t1ignoreflagset = flaggrp.Value.invert ? !t1.Flags[flaggrp.Key] : t1.Flags[flaggrp.Key]; + bool t2ignoreflagset = flaggrp.Value.invert ? !t2.Flags[flaggrp.Key] : t2.Flags[flaggrp.Key]; + + // Can't compare... + if(!t1ignoreflagset || !t2ignoreflagset) return 0; + } + } } + + // Take flag inversion into account + t1flag = invert ? !t1.Flags[flag] : t1.Flags[flag]; + t2flag = invert ? !t2.Flags[flag] : t2.Flags[flag]; if (comparemethod == CompareMethod.And && (t1flag && t2flag)) return 1; if (comparemethod == CompareMethod.Equal && (t1flag == t2flag)) return 1; return 0; } + //mxd + public static string CheckThingEditFormFlags(List<CheckBox> checkboxes) + { + Dictionary<string, bool> flags = new Dictionary<string, bool>(checkboxes.Count); + Dictionary<string, Dictionary<string, bool>> flagspergroup = new Dictionary<string, Dictionary<string, bool>>(General.Map.Config.ThingFlagsCompare.Count); + Dictionary<string, bool> requiredgroups = new Dictionary<string, bool>(); + Dictionary<string, bool> ignoredgroups = new Dictionary<string, bool>(); + + // Gather flags + foreach (CheckBox cb in checkboxes) + { + flags.Add(cb.Tag.ToString(), cb.CheckState == CheckState.Checked); + } + + // Gather flags per group + foreach (KeyValuePair<string, Dictionary<string, ThingFlagsCompare>> group in General.Map.Config.ThingFlagsCompare) + { + flagspergroup.Add(group.Key, new Dictionary<string, bool>()); + + foreach (KeyValuePair<string, ThingFlagsCompare> flaggrp in group.Value) + { + bool flagset = IsFlagSet(flags, flaggrp.Key, flaggrp.Value.invert) && (string.IsNullOrEmpty(flaggrp.Value.requiredflag) || IsFlagSet(flags, flaggrp.Value.requiredflag, group.Value[flaggrp.Value.requiredflag].invert)); + + if(flagset) + { + flagspergroup[group.Key].Add(flaggrp.Key, true); + + if(!string.IsNullOrEmpty(flaggrp.Value.requiredgroup) && !requiredgroups.ContainsKey(flaggrp.Value.requiredgroup)) + requiredgroups.Add(flaggrp.Value.requiredgroup, false); + } + else if(flaggrp.Value.ingnorethisgroupwhenunset) + { + ignoredgroups.Add(group.Key, false); + } + } + } + + // Check dependancies + foreach (KeyValuePair<string, Dictionary<string, bool>> group in flagspergroup) + { + foreach(KeyValuePair<string, bool> flaggrp in group.Value) + { + if(!flaggrp.Value) continue; + + string ignoredgrp = General.Map.Config.ThingFlagsCompare[group.Key][flaggrp.Key].ignoredgroup; + if (!string.IsNullOrEmpty(ignoredgrp) && !requiredgroups.ContainsKey(ignoredgrp)) + { + ignoredgroups.Add(ignoredgrp, false); + } + } + } + + // Get rid of ignoredgroups + foreach (KeyValuePair<string, bool> group in ignoredgroups) + { + flagspergroup.Remove(group.Key); + } + + // Return message + string result = string.Empty; + + foreach (KeyValuePair<string, Dictionary<string, bool>> group in flagspergroup) + { + if (group.Value.Count == 0) + { + switch(group.Key) + { + case "skills": + result += "Thing is not used in any skill level."; + break; + case "gamemodes": + result += "Thing is not used in any game mode."; + break; + case "classes": + result += "Thing is not used by any class."; + break; + default: + result += "At least one '" + group.Key + "' flag should be set."; + break; + } + } + } + + return result; + } + + //mxd + private static bool IsFlagSet(Dictionary<string, bool> flags, string flag, bool invert) + { + bool result = flags.ContainsKey(flag) && flags[flag]; + return (invert ? !result : result); + } + #endregion } } diff --git a/Source/Core/Windows/ThingEditForm.cs b/Source/Core/Windows/ThingEditForm.cs index f9765300c..e463eb239 100644 --- a/Source/Core/Windows/ThingEditForm.cs +++ b/Source/Core/Windows/ThingEditForm.cs @@ -633,47 +633,17 @@ namespace CodeImp.DoomBuilder.Windows { if(preventchanges) return; - foreach(KeyValuePair<string, Dictionary<string, ThingFlagsCompare>> group in General.Map.Config.ThingFlagsCompare) + string warn = ThingFlagsCompare.CheckThingEditFormFlags(flags.Checkboxes); + if(!string.IsNullOrEmpty(warn)) { - if(group.Value.Count < 2) continue; - bool haveflags = false; - - foreach(CheckBox cb in flags.Checkboxes) - { - if (group.Value.ContainsKey(cb.Tag.ToString()) && cb.CheckState != CheckState.Unchecked) - { - haveflags = true; - break; - } - } - - if (!haveflags) - { - switch(group.Key) - { - case "skills": - tooltip.SetToolTip(missingflags, "Thing is not used in any skill level."); - break; - - case "gamemodes": - tooltip.SetToolTip(missingflags, "Thing is not used in any game mode."); - break; - - case "classes": - tooltip.SetToolTip(missingflags, "Thing is not used by any class."); - break; - - default: - tooltip.SetToolTip(missingflags, "At least one '" + group.Key + "' flag should be set."); - break; - } - - missingflags.Visible = true; - settingsgroup.ForeColor = Color.DarkRed; - return; - } + //got missing flags + tooltip.SetToolTip(missingflags, warn); + missingflags.Visible = true; + settingsgroup.ForeColor = Color.DarkRed; + return; } + //everything is OK missingflags.Visible = false; settingsgroup.ForeColor = SystemColors.ControlText; } diff --git a/Source/Core/Windows/ThingEditFormUDMF.cs b/Source/Core/Windows/ThingEditFormUDMF.cs index 07bce8a8f..444038d1d 100644 --- a/Source/Core/Windows/ThingEditFormUDMF.cs +++ b/Source/Core/Windows/ThingEditFormUDMF.cs @@ -335,10 +335,11 @@ namespace CodeImp.DoomBuilder.Windows preventchanges = false; - //mxd. Trigger angle/pitch/roll update manually... + //mxd. Trigger updates manually... angle_WhenTextChanged(angle, EventArgs.Empty); pitch_WhenTextChanged(pitch, EventArgs.Empty); roll_WhenTextChanged(roll, EventArgs.Empty); + flags_OnValueChanged(flags, EventArgs.Empty); updateScriptControls(); //mxd @@ -862,46 +863,17 @@ namespace CodeImp.DoomBuilder.Windows { if(preventchanges) return; - foreach(KeyValuePair<string, Dictionary<string, ThingFlagsCompare>> group in General.Map.Config.ThingFlagsCompare) + string warn = ThingFlagsCompare.CheckThingEditFormFlags(flags.Checkboxes); + if(!string.IsNullOrEmpty(warn)) { - if(group.Value.Count < 2) continue; - bool haveflags = false; - - foreach(CheckBox cb in flags.Checkboxes) - { - if(group.Value.ContainsKey(cb.Tag.ToString()) && cb.CheckState != CheckState.Unchecked) { - haveflags = true; - break; - } - } - - if(!haveflags) - { - switch(group.Key) - { - case "skills": - tooltip.SetToolTip(missingflags, "Thing is not used in any skill level."); - break; - - case "gamemodes": - tooltip.SetToolTip(missingflags, "Thing is not used in any game mode."); - break; - - case "classes": - tooltip.SetToolTip(missingflags, "Thing is not used by any class."); - break; - - default: - tooltip.SetToolTip(missingflags, "At least one '" + group.Key + "' flag should be set."); - break; - } - - missingflags.Visible = true; - settingsgroup.ForeColor = Color.DarkRed; - return; - } + //got missing flags + tooltip.SetToolTip(missingflags, warn); + missingflags.Visible = true; + settingsgroup.ForeColor = Color.DarkRed; + return; } + //everything is OK missingflags.Visible = false; settingsgroup.ForeColor = SystemColors.ControlText; } -- GitLab