// Returns true if ranges are covering value, false otherwise. internal bool IsCovering(Value value) { int from = 1, to = MAX_LEVEL; if (value is ValueAt) { ValueAt at = (ValueAt)value; if (at.LevelSpecified) { from = to = at.Level; } else if (at.QualitySpecified) { from = to = at.Quality; } // Else keep from = 1 and to = MAX_LEVEL. } else if (value is ValueForLevelRange) { ValueForLevelRange range = (ValueForLevelRange)value; from = range.From; if (range.ToSpecified) { to = range.To; } } else if (value is ValueForQualityRange) { ValueForQualityRange range = (ValueForQualityRange)value; from = range.From; if (range.ToSpecified) { to = range.To; } } else if (value is ValuePerLevel) { from = 2; } // Else keep from = 1 and to = MAX_LEVEL. // Traverse all ranges and move 'from' to end of range when 'from' is inside of that range. foreach (Range range in Ranges) { if (from >= range.From && from <= range.To) { from = range.To; } } // A <from, to> range is covered by our ranges when 'from' reached 'to'. return(from >= to); }
// Returns true if table defines all values as specified value. internal bool IsCovering(Value value) { int from = 1, to = MAX_LEVEL; if (value is ValueAt) { ValueAt at = (ValueAt)value; if (at.LevelSpecified) { from = to = at.Level; } else if (at.QualitySpecified) { from = to = at.Quality; } // Else keep from = 1 and to = MAX_LEVEL. } else if (value is ValueForLevelRange) { ValueForLevelRange range = (ValueForLevelRange)value; from = range.From; if (range.ToSpecified) { to = range.To; } } else if (value is ValueForQualityRange) { ValueForQualityRange range = (ValueForQualityRange)value; from = range.From; if (range.ToSpecified) { to = range.To; } } else if (value is ValuePerLevel) // ValuePerLevel doesn't define value for level 1. { from = 2; } // Else keep from = 1 and to = MAX_LEVEL. for (int level = from - 1; level < to; ++level) { if (Values[level] == null) { return(false); } } return(true); }
// Indexes attributes. internal void Index() { LevelIndex.Clear(); QualityIndex.Clear(); if (Attributes == null) { return; } foreach (GemAttribute attr in Attributes) { LookupTable levelTable = new LookupTable(); LookupTable qualityTable = new LookupTable(); LookupRanges levelRanges = new LookupRanges(); LookupRanges qualityRanges = new LookupRanges(); LookupGain levelGain = null; LookupGain qualityGain = null; LookupFixed fixedValue = null; foreach (Value value in attr.Values) { // Ignore values which doesn't have required cardinality of attribute. if (value.Cardinality != attr.Cardinality) { continue; } if (value is ValueAt) { ValueAt valueAt = (ValueAt)value; if (valueAt.LevelSpecified) { levelTable.Add(valueAt.Level, valueAt.ToValue()); } else if (valueAt.QualitySpecified) { qualityTable.Add(valueAt.Quality, valueAt.ToValue()); } else { fixedValue = new LookupFixed { Value = valueAt.ToValue() } }; } else if (value is ValueForLevelRange) { ValueForLevelRange range = (ValueForLevelRange)value; levelRanges.Add(range.From, range.To, range.ToValue()); } else if (value is ValueForQualityRange) { ValueForQualityRange range = (ValueForQualityRange)value; qualityRanges.Add(range.From, range.To, range.ToValue()); } else if (value is ValuePerLevel) { levelGain = new LookupGain { From = 2, Value = ((ValuePerLevel)value).ToValue() }; } else // value is ValuePerQuality { qualityGain = new LookupGain { Value = ((ValuePerQuality)value).ToValue() }; } } // Add level dependant attribute to index. // LookupFixed is added to LevelIndex only (due to quality-based attributes not being defined for non-quality gems). LookupBase.Method method = LookupBase.Method.None; if (!levelTable.IsEmpty()) { method |= LookupBase.Method.Table; } if (!levelRanges.IsEmpty()) { method |= LookupBase.Method.Range; } if (levelGain != null) { method |= LookupBase.Method.Gain; } if (fixedValue != null) { method |= LookupBase.Method.Fixed; } if (method != LookupBase.Method.None && method != LookupBase.Method.Table && method != LookupBase.Method.Range && method != LookupBase.Method.Gain && method != LookupBase.Method.Fixed) { LevelIndex.Add(attr.Name, new LookupMixed { Table = method.HasFlag(LookupBase.Method.Table) ? levelTable : null, Ranges = method.HasFlag(LookupBase.Method.Range) ? levelRanges : null, Gain = method.HasFlag(LookupBase.Method.Gain) ? levelGain : null, Fixed = method.HasFlag(LookupBase.Method.Fixed) ? fixedValue : null }); } else if (method.HasFlag(LookupBase.Method.Table)) { LevelIndex.Add(attr.Name, levelTable); } else if (method.HasFlag(LookupBase.Method.Range)) { LevelIndex.Add(attr.Name, levelRanges); } else if (method.HasFlag(LookupBase.Method.Gain)) { LevelIndex.Add(attr.Name, levelGain); } else if (method.HasFlag(LookupBase.Method.Fixed)) { LevelIndex.Add(attr.Name, fixedValue); } // Add quality dependant attribute to index. method = LookupBase.Method.None; if (!qualityTable.IsEmpty()) { method |= LookupBase.Method.Table; } if (!qualityRanges.IsEmpty()) { method |= LookupBase.Method.Range; } if (qualityGain != null) { method |= LookupBase.Method.Gain; } if (method != LookupBase.Method.None && method != LookupBase.Method.Table && method != LookupBase.Method.Range && method != LookupBase.Method.Gain) { QualityIndex.Add(attr.Name, new LookupMixed { Table = method.HasFlag(LookupBase.Method.Table) ? qualityTable : null, Ranges = method.HasFlag(LookupBase.Method.Range) ? qualityRanges : null, Gain = method.HasFlag(LookupBase.Method.Gain) ? qualityGain : null }); } else if (method.HasFlag(LookupBase.Method.Table)) { QualityIndex.Add(attr.Name, qualityTable); } else if (method.HasFlag(LookupBase.Method.Range)) { QualityIndex.Add(attr.Name, qualityRanges); } else if (method.HasFlag(LookupBase.Method.Gain)) { QualityIndex.Add(attr.Name, qualityGain); } } }
override public int Compare(Value x, Value y) { if (x is ValueAt) { ValueAt xAt = (ValueAt)x; if (y is ValueAt) { ValueAt yAt = (ValueAt)y; if (xAt.LevelSpecified) { return(yAt.LevelSpecified ? xAt.Level.CompareTo(yAt.Level) : -1); // x.Level specified < y.Quality specified/unspecified } else if (xAt.QualitySpecified) { return(yAt.QualitySpecified ? xAt.Quality.CompareTo(yAt.Quality) : (yAt.LevelSpecified ? 1 : -1)); // x.Quality specified > y.Level specified, x.Quality specified < y.Level unspecified } return(yAt.LevelSpecified || yAt.QualitySpecified ? 1 : 0); // x.Level & x.Quality unspecified > y.Level/Quality specified } else if (y is ValueForLevelRange) { ValueForLevelRange yRange = (ValueForLevelRange)y; if (xAt.LevelSpecified && yRange.ToSpecified && xAt.Level > yRange.To) // x.Level vs. y.To => x > y { return(1); } // Fall through (x < y) } else if (y is ValueForQualityRange) { ValueForQualityRange yRange = (ValueForQualityRange)y; if (xAt.QualitySpecified && yRange.ToSpecified && xAt.Quality > yRange.To) // x.Quality vs. y.To => x > y { return(1); } // Fall through (x < y) } return(-1); } else if (x is ValueForLevelRange) { ValueForLevelRange xRange = (ValueForLevelRange)x; if (y is ValueForLevelRange) { ValueForLevelRange yRange = (ValueForLevelRange)y; if (xRange.From == yRange.From) { if (xRange.ToSpecified) { return(yRange.ToSpecified ? xRange.To.CompareTo(yRange.To) : -1); // x.To specified < y.To unspecified } else { return(yRange.ToSpecified ? 1 : 0); // x.To unspecified > y.To specified } } return(xRange.From < yRange.From ? -1 : 1); } else if (y is ValueAt) { ValueAt yAt = (ValueAt)y; if (yAt.LevelSpecified && xRange.To < yAt.Level) // x.To vs. y.Level => x < y { return(-1); } // Fall through (x > y). } return(y is ValueAt ? 1 : -1); } else if (x is ValueForQualityRange) { ValueForQualityRange xRange = (ValueForQualityRange)x; if (y is ValueForQualityRange) { ValueForQualityRange yRange = (ValueForQualityRange)y; if (xRange.From == yRange.From) { if (xRange.ToSpecified) { return(yRange.ToSpecified ? xRange.To.CompareTo(yRange.To) : -1); // x.To specified < y.To unspecified } else { return(yRange.ToSpecified ? 1 : 0); // x.To unspecified > y.To specified } } return(xRange.From < yRange.From ? -1 : 1); } else if (y is ValueAt) { ValueAt yAt = (ValueAt)y; if (yAt.QualitySpecified && xRange.To < yAt.Quality) // x.To vs. y.Quality => x < y { return(-1); } // Fall through (x > y). } return(y is ValueAt || y is ValueForLevelRange ? 1 : -1); } else if (x is ValuePerLevel) { return(y is ValuePerLevel ? 0 : (y is ValuePerQuality ? -1 : 1)); } else if (x is ValuePerQuality) { return(y is ValuePerQuality ? 0 : 1); } return(0); }
// Merges value. public void Merge(Value value) { if (value is ValueAt) { ValueAt merge = (ValueAt)value; ValueAt with = (ValueAt)Values.Find(v => v is ValueAt && ((ValueAt)v).Level == merge.Level && ((ValueAt)v).Quality == merge.Quality); if (with == null) { if (merge.LevelSpecified) { // No need to add ValueAt, if there is ValueForLevelRange covering specified Level with same Text. ValueForLevelRange covers = (ValueForLevelRange)Values.Find(v => v is ValueForLevelRange && ((ValueForLevelRange)v).From <= merge.Level && ((ValueForLevelRange)v).To >= merge.Level && v.Text == merge.Text); if (covers == null) { Values.Add(merge); } } else if (merge.QualitySpecified) { // No need to add ValueAt, if there is ValueForQualityRange covering specified Quality with same Text. ValueForQualityRange covers = (ValueForQualityRange)Values.Find(v => v is ValueForQualityRange && ((ValueForQualityRange)v).From <= merge.Quality && ((ValueForQualityRange)v).To >= merge.Quality && v.Text == merge.Text); if (covers == null) { Values.Add(merge); } } else { // Value with no level nor quality specified replaces all values. Values.Clear(); Values.Add(merge); } } else { with.Text = merge.Text; } } else if (value is ValueForLevelRange) { ValueForLevelRange merge = (ValueForLevelRange)value; // Remove all ValueAt.LevelSpecified inside of range being merged and all ranges covered by it. Values.RemoveAll(v => v is ValueAt && ((ValueAt)v).LevelSpecified && ((ValueAt)v).Level >= merge.From && ((ValueAt)v).Level <= merge.To || v is ValueForLevelRange && ((ValueForLevelRange)v).From >= merge.From && ((ValueForLevelRange)v).To <= merge.To); // Split range covering merged one (<with.From <merge.From with.To> range.To>). ValueForLevelRange with = (ValueForLevelRange)Values.Find(v => v is ValueForLevelRange && ((ValueForLevelRange)v).From <merge.From && ((ValueForLevelRange)v).To> merge.To); if (with != null) { Values.Add(new ValueForLevelRange { From = merge.To + 1, To = with.To, Text = with.Text }); with.To = merge.From - 1; } else { // Shorten range intersecting merged one from left (<with.From <merge.From with.To> merge.To>). with = (ValueForLevelRange)Values.Find(v => v is ValueForLevelRange && ((ValueForLevelRange)v).From < merge.From && ((ValueForLevelRange)v).To >= merge.From); if (with != null) { with.To = merge.From - 1; // Replace single-level shortened range with ValueAt. if (with.From == with.To) { Values.Add(new ValueAt { Level = with.From, Text = with.Text }); Values.Remove(with); } } // Shorten range intersecting merged one from right (<merge.From <with.From merge.To> with.To>). with = (ValueForLevelRange)Values.Find(v => v is ValueForLevelRange && ((ValueForLevelRange)v).From <= merge.To && ((ValueForLevelRange)v).To > merge.To); if (with != null) { with.From = merge.To + 1; // Replace single-level shortened range with ValueAt. if (with.From == with.To) { Values.Add(new ValueAt { Level = with.From, Text = with.Text }); Values.Remove(with); } } } Values.Add(merge); } else if (value is ValueForQualityRange) { ValueForQualityRange merge = (ValueForQualityRange)value; // Remove all ValueAt.QualitySpecified inside of range being merged and all ranges covered by it. Values.RemoveAll(v => v is ValueAt && ((ValueAt)v).QualitySpecified && ((ValueAt)v).Quality >= merge.From && ((ValueAt)v).Quality <= merge.To || v is ValueForQualityRange && ((ValueForQualityRange)v).From >= merge.From && ((ValueForQualityRange)v).To <= merge.To); // Split range covering merged one (<with.From <merge.From with.To> range.To>). ValueForQualityRange with = (ValueForQualityRange)Values.Find(v => v is ValueForQualityRange && ((ValueForQualityRange)v).From <merge.From && ((ValueForQualityRange)v).To> merge.To); if (with != null) { Values.Add(new ValueForQualityRange { From = merge.To + 1, To = with.To, Text = with.Text }); with.To = merge.From - 1; } else { // Shorten range intersecting merged one from left (<with.From <merge.From with.To> merge.To>). with = (ValueForQualityRange)Values.Find(v => v is ValueForQualityRange && ((ValueForQualityRange)v).From < merge.From && ((ValueForQualityRange)v).To >= merge.From); if (with != null) { with.To = merge.From - 1; // Replace single-quality shortened range with ValueAt. if (with.From == with.To) { Values.Add(new ValueAt { Quality = with.From, Text = with.Text }); Values.Remove(with); } } // Shorten range intersecting merged one from right (<merge.From <with.From merge.To> with.To>). with = (ValueForQualityRange)Values.Find(v => v is ValueForQualityRange && ((ValueForQualityRange)v).From <= merge.To && ((ValueForQualityRange)v).To > merge.To); if (with != null) { with.From = merge.To + 1; // Replace single-quality shortened range with ValueAt. if (with.From == with.To) { Values.Add(new ValueAt { Quality = with.From, Text = with.Text }); Values.Remove(with); } } } Values.Add(merge); } else if (value is ValuePerLevel) { ValuePerLevel merge = (ValuePerLevel)value; ValuePerLevel with = (ValuePerLevel)Values.Find(v => v is ValuePerLevel); if (with == null) { // Value per level replaces any level specific values and ranges. Values.RemoveAll(v => (v is ValueAt && ((ValueAt)v).LevelSpecified) || v is ValueForLevelRange); Values.Add(merge); } else { with.Text = merge.Text; } } else if (value is ValuePerQuality) { ValuePerQuality merge = (ValuePerQuality)value; ValuePerQuality with = (ValuePerQuality)Values.Find(v => v is ValuePerQuality); if (with == null) { // Value per quality replaces any quality specific values and ranges. Values.RemoveAll(v => (v is ValueAt && ((ValueAt)v).QualitySpecified) || v is ValueForQualityRange); Values.Add(merge); } else { with.Text = merge.Text; } } }