mirror of
https://git.do.srb2.org/STJr/ZoneBuilder.git
synced 2024-11-15 00:51:39 +00:00
316 lines
9.6 KiB
C#
316 lines
9.6 KiB
C#
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
/*
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
* This program is released under GNU General Public License
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#endregion
|
|
|
|
#region ================== Namespaces
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using CodeImp.DoomBuilder.IO;
|
|
using CodeImp.DoomBuilder.Map;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.Config
|
|
{
|
|
//mxd
|
|
public class ThingFlagsCompareGroup
|
|
{
|
|
public readonly string Name;
|
|
public readonly bool IsOptional; // When set to true, group flags won't be considered as required for a thing to show up ingame by CheckUnusedThings error check and ThingFlagsCompare.CheckThingEditFormFlags() method.
|
|
public readonly Dictionary<string, ThingFlagsCompare> Flags;
|
|
|
|
public ThingFlagsCompareGroup(Configuration cfg, string name)
|
|
{
|
|
Name = name;
|
|
Flags = new Dictionary<string, ThingFlagsCompare>();
|
|
IsOptional = cfg.ReadSetting("thingflagscompare." + name + ".optional", false);
|
|
|
|
IDictionary dic = cfg.ReadSetting("thingflagscompare." + name, new Hashtable());
|
|
foreach(DictionaryEntry de in dic)
|
|
{
|
|
if(de.Value != null && !(de.Value is IDictionary)) continue; // flag either has no value, or is defined as block
|
|
string flag = de.Key.ToString();
|
|
|
|
// Duplicate flags check
|
|
if(Flags.ContainsKey(flag))
|
|
General.ErrorLogger.Add(ErrorType.Warning, "ThingFlagsCompare flag \"" + flag + "\" is double defined in the \"" + name + "\" group");
|
|
|
|
Flags[flag] = new ThingFlagsCompare(cfg, name, flag);
|
|
}
|
|
}
|
|
|
|
// Compares flags group of the two things.
|
|
public ThingFlagsCompareResult Compare(Thing t1, Thing t2)
|
|
{
|
|
ThingFlagsCompareResult result = new ThingFlagsCompareResult();
|
|
foreach(ThingFlagsCompare tfc in Flags.Values)
|
|
{
|
|
// Current flag doesn't overlap when required flag does not overlap
|
|
if(!string.IsNullOrEmpty(tfc.RequiredFlag) && !GetFlag(tfc.RequiredFlag).Compare(t1, t2))
|
|
{
|
|
result.Result = -1;
|
|
continue;
|
|
}
|
|
|
|
// Compare current flag
|
|
bool flagoverlaps = tfc.Compare(t1, t2);
|
|
|
|
// Ignore this group when whole group doens't match or required flag is not set
|
|
if(!flagoverlaps && tfc.IgnoreGroupWhenUnset) return new ThingFlagsCompareResult { Result = 0 };
|
|
|
|
// If current flag overlaps, check IgnoredGroup and RequiredGroup settings
|
|
if(flagoverlaps)
|
|
{
|
|
result.Result = 1;
|
|
|
|
foreach(string s in tfc.IgnoredGroups)
|
|
{
|
|
if(!result.IgnoredGroups.Contains(s)) result.IgnoredGroups.Add(s);
|
|
}
|
|
|
|
if(tfc.RequiredGroups.Count > 0)
|
|
{
|
|
foreach(string s in tfc.RequiredGroups)
|
|
{
|
|
if(result.IgnoredGroups.Contains(s)) result.IgnoredGroups.Remove(s);
|
|
if(!result.RequiredGroups.Contains(s)) result.RequiredGroups.Add(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public ThingFlagsCompare GetFlag(string flag)
|
|
{
|
|
// Check our flags
|
|
if(Flags.ContainsKey(flag)) return Flags[flag];
|
|
|
|
// Check other groups
|
|
foreach(ThingFlagsCompareGroup group in General.Map.Config.ThingFlagsCompare.Values)
|
|
{
|
|
if(group != this && group.Flags.ContainsKey(flag)) return group.Flags[flag];
|
|
}
|
|
|
|
// Fial...
|
|
return null;
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
public class ThingFlagsCompareResult
|
|
{
|
|
public readonly HashSet<string> IgnoredGroups;
|
|
public readonly HashSet<string> RequiredGroups;
|
|
|
|
// -1 if group does not overlap
|
|
// 0 if group should be ignored
|
|
// 1 if group overlaps
|
|
public int Result;
|
|
|
|
public ThingFlagsCompareResult()
|
|
{
|
|
Result = -1;
|
|
IgnoredGroups = new HashSet<string>();
|
|
RequiredGroups = new HashSet<string>();
|
|
}
|
|
}
|
|
|
|
public class ThingFlagsCompare
|
|
{
|
|
private enum CompareMethod
|
|
{
|
|
Equal,
|
|
And
|
|
};
|
|
|
|
#region ================== Constants
|
|
|
|
#endregion
|
|
|
|
#region ================== Variables
|
|
|
|
private readonly string flag;
|
|
private readonly HashSet<string> requiredgroups; //mxd. This flag only works if at least one flag is set in the "requiredgroup"
|
|
private readonly HashSet<string> ignoredgroups; //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 char[] comma = new[] {','};
|
|
|
|
#endregion
|
|
|
|
#region ================== Properties
|
|
|
|
public string Flag { get { return flag; } }
|
|
public HashSet<string> RequiredGroups { get { return requiredgroups; } } //mxd
|
|
public HashSet<string> IgnoredGroups { get { return ignoredgroups; } } //mxd
|
|
public string RequiredFlag { get { return requiredflag; } internal set { requiredflag = value; } } //mxd
|
|
public bool IgnoreGroupWhenUnset { get { return ingnorethisgroupwhenunset; } } //mxd
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
// Constructor
|
|
public ThingFlagsCompare(Configuration cfg, string group, string flag)
|
|
{
|
|
string cfgpath = "thingflagscompare." + group + "." + flag;
|
|
this.flag = flag;
|
|
|
|
string cm = cfg.ReadSetting(cfgpath + ".comparemethod", "and");
|
|
switch(cm)
|
|
{
|
|
default:
|
|
General.ErrorLogger.Add(ErrorType.Warning, "Unrecognized value \"" + cm + "\" for comparemethod in " + cfgpath + " in game configuration " + cfg.ReadSetting("game", "<unnamed game>") + ". Defaulting to \"and\".");
|
|
goto case "and";
|
|
case "and":
|
|
comparemethod = CompareMethod.And;
|
|
break;
|
|
case "equal":
|
|
comparemethod = CompareMethod.Equal;
|
|
break;
|
|
}
|
|
|
|
invert = cfg.ReadSetting(cfgpath + ".invert", false);
|
|
|
|
//mxd
|
|
requiredgroups = new HashSet<string>();
|
|
string[] requiredgroupsarr = cfg.ReadSetting(cfgpath + ".requiredgroups", string.Empty).Split(comma, StringSplitOptions.RemoveEmptyEntries);
|
|
foreach(string s in requiredgroupsarr)
|
|
if(!requiredgroups.Contains(s)) requiredgroups.Add(s);
|
|
|
|
//mxd
|
|
ignoredgroups = new HashSet<string>();
|
|
string[] ignoredgroupsarr = cfg.ReadSetting(cfgpath + ".ignoredgroups", string.Empty).Split(comma, StringSplitOptions.RemoveEmptyEntries);
|
|
foreach(string s in ignoredgroupsarr)
|
|
if(!ignoredgroups.Contains(s)) ignoredgroups.Add(s);
|
|
|
|
requiredflag = cfg.ReadSetting(cfgpath + ".requiredflag", string.Empty); //mxd
|
|
ingnorethisgroupwhenunset = cfg.ReadSetting(cfgpath + ".ingnorethisgroupwhenunset", false); //mxd
|
|
|
|
// We have no destructor
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Methods
|
|
|
|
// Compares the flag of the two things.
|
|
public bool Compare(Thing t1, Thing t2)
|
|
{
|
|
//mxd. Get flags
|
|
bool t1flag = (invert ? !t1.IsFlagSet(flag) : t1.IsFlagSet(flag));
|
|
bool t2flag = (invert ? !t2.IsFlagSet(flag) : t2.IsFlagSet(flag));
|
|
|
|
//mxd. Ignore the flag when ingnorethisgroupwhenunset is set and both flags are unset
|
|
if(!t1flag && !t2flag && ingnorethisgroupwhenunset) return false;
|
|
|
|
//mxd. Compare them
|
|
switch(comparemethod)
|
|
{
|
|
case CompareMethod.And: return t1flag && t2flag;
|
|
case CompareMethod.Equal: return t1flag == t2flag;
|
|
default: throw new NotImplementedException("Unknown compare method!");
|
|
}
|
|
}
|
|
|
|
//mxd
|
|
public static List<string> CheckFlags(HashSet<string> flags)
|
|
{
|
|
Dictionary<string, HashSet<string>> flagspergroup = new Dictionary<string, HashSet<string>>(General.Map.Config.ThingFlagsCompare.Count);
|
|
HashSet<string> ignoredgroups = new HashSet<string>();
|
|
|
|
// Gather flags per group
|
|
foreach(KeyValuePair<string, ThingFlagsCompareGroup> group in General.Map.Config.ThingFlagsCompare)
|
|
{
|
|
flagspergroup.Add(group.Key, new HashSet<string>());
|
|
|
|
foreach(ThingFlagsCompare flag in group.Value.Flags.Values)
|
|
{
|
|
if(IsFlagSet(flags, flag.flag, flag.invert) &&
|
|
(string.IsNullOrEmpty(flag.requiredflag) || IsFlagSet(flags, flag.requiredflag, group.Value.GetFlag(flag.requiredflag).invert)))
|
|
{
|
|
flagspergroup[group.Key].Add(flag.Flag);
|
|
foreach(string s in flag.ignoredgroups)
|
|
if(!ignoredgroups.Contains(s)) ignoredgroups.Add(s);
|
|
}
|
|
else if(flag.ingnorethisgroupwhenunset)
|
|
{
|
|
flagspergroup.Remove(group.Key);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check required dependancies
|
|
foreach(KeyValuePair<string, HashSet<string>> group in flagspergroup)
|
|
{
|
|
foreach(string flag in group.Value)
|
|
{
|
|
foreach(string s in General.Map.Config.ThingFlagsCompare[group.Key].Flags[flag].requiredgroups)
|
|
{
|
|
if(ignoredgroups.Contains(s)) ignoredgroups.Remove(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get rid of ignoredgroups
|
|
foreach(string s in ignoredgroups) flagspergroup.Remove(s);
|
|
|
|
// Return message
|
|
List<string> result = new List<string>();
|
|
|
|
foreach(KeyValuePair<string, HashSet<string>> group in flagspergroup)
|
|
{
|
|
if(group.Value.Count == 0 && !General.Map.Config.ThingFlagsCompare[group.Key].IsOptional)
|
|
{
|
|
switch(group.Key)
|
|
{
|
|
case "skills":
|
|
result.Add("Thing is not used in any skill level.");
|
|
break;
|
|
case "gamemodes":
|
|
result.Add("Thing is not used in any game mode.");
|
|
break;
|
|
case "classes":
|
|
result.Add("Thing is not used by any class.");
|
|
break;
|
|
default:
|
|
result.Add("At least one \"" + group.Key + "\" flag should be set.");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//mxd
|
|
private static bool IsFlagSet(HashSet<string> flags, string flag, bool invert)
|
|
{
|
|
bool result = flags.Contains(flag);
|
|
return (invert ? !result : result);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
|