public static IEnumerable <string> GetReferenceAliases(TES4Record qust)
        {
            IEnumerable <TES4SubrecordData> qstas = qust.GetSubrecords("QSTA");

            return(qstas.Select(qsta => qust.ExpandBytesIntoFormID(qsta)).Distinct().Select(formID => "Alias_" + formID.ToString("X8")));
        }
        public static string BuildString(TES4Record qust)
        {
            const string   indx = "INDX", qsta = "QSTA", ctda = "CTDA";
            var            subrecords     = qust.GetSubrecords(new string[] { indx, qsta, ctda });
            Nullable <int> targetIndex    = null;
            int            maxTargetIndex = 0;
            List <int>     stageIndexes   = new List <int>();
            Dictionary <int, List <Tuple <Func <int, bool>, bool> > > targetFuncs = new Dictionary <int, List <Tuple <Func <int, bool>, bool> > >();

            foreach (var subrecord in subrecords)
            {
                if (subrecord.Key == indx)
                {
                    int stageIndex = (int)subrecord.Value.FirstByte();
                    stageIndexes.Add(stageIndex);
                    targetIndex = null;
                }
                else if (subrecord.Key == qsta)
                {
                    targetIndex = targetIndex == null ? 0 : targetIndex.Value + 1;
                    if (targetIndex.Value > maxTargetIndex)
                    {
                        maxTargetIndex = targetIndex.Value;
                    }
                }
                else if (subrecord.Key == ctda)
                {
                    if (targetIndex == null)
                    {
                        continue;
                    }
                    int targetIndexInt = targetIndex.Value;
                    IReadOnlyList <byte> bytes = subrecord.Value.Bytes;
                    int  functionIndex = BitConverter.ToInt32(bytes.Skip(8).Take(4).ToArray(), 0);
                    bool getStage = functionIndex == 58, getStageDone = functionIndex == 59;
                    if (getStage)
                    {
                        bool anyRemainingNonZero = bytes.Skip(16).Where(b => b != (byte)0).Any();
                        if (anyRemainingNonZero)
                        {
                            throw new InvalidOperationException("anyRemainingNonZero");
                        }
                        int formID1 = BitConverter.ToInt32(bytes.Skip(12).Take(4).ToArray(), 0);
                        //int formID2 = BitConverter.ToInt32(bytes.Skip(16).Take(4).ToArray(), 0);
                        if (qust.FormID != formID1)
                        {
                            continue;
                        }
                        byte firstByte = bytes[0];
                        int  compareOperator = firstByte & 0b11110000;
                        int  flags = firstByte & 0b00001111;
                        bool equalTo = compareOperator == 0, notEqualTo = compareOperator == 0b00100000, lessThan = compareOperator == 0b10000000, greaterThan = compareOperator == 0b01000000, greaterThanOrEqualTo = compareOperator == 0b01100000, lessThanOrEqualTo = compareOperator == 0b10100000;
                        if (!(equalTo || notEqualTo || lessThan || greaterThan || greaterThanOrEqualTo || lessThanOrEqualTo))
                        {
                            throw new InvalidOperationException("Invalid compareOperator");
                        }
                        bool flagsNone = flags == 0, flagsOr = flags == 1;
                        if (!(flagsNone || flagsOr))
                        {
                            throw new InvalidOperationException("Invalid flags");
                        }
                        var currentList = targetFuncs.GetOrAdd(targetIndexInt, () => new List <Tuple <Func <int, bool>, bool> >(new List <Tuple <Func <int, bool>, bool> >()));
                        Func <int, bool> newFunc;
                        float            comparisonValue = BitConverter.ToSingle(bytes.Skip(4).Take(4).ToArray(), 0);//stage
                        if (equalTo)
                        {
                            newFunc = stageID => stageID == comparisonValue;
                        }
                        else if (notEqualTo)
                        {
                            newFunc = stageID => stageID != comparisonValue;
                        }
                        else if (lessThan)
                        {
                            newFunc = stageID => stageID < comparisonValue;
                        }
                        else if (lessThanOrEqualTo)
                        {
                            newFunc = stageID => stageID <= comparisonValue;
                        }
                        else if (greaterThan)
                        {
                            newFunc = stageID => stageID > comparisonValue;
                        }
                        else if (greaterThanOrEqualTo)
                        {
                            newFunc = stageID => stageID >= comparisonValue;
                        }
                        else
                        {
                            throw new InvalidOperationException();
                        }
                        currentList.Add(new Tuple <Func <int, bool>, bool>(newFunc, flagsOr));
                    }
                    else if (getStageDone)
                    {
                        bool anyRemainingNonZero = bytes.Skip(20).Where(b => b != (byte)0).Any();
                        if (anyRemainingNonZero)
                        {
                            throw new InvalidOperationException("anyRemainingNonZero");
                        }
                        int formID1 = BitConverter.ToInt32(bytes.Skip(12).Take(4).ToArray(), 0);
                        int formID2 = BitConverter.ToInt32(bytes.Skip(16).Take(4).ToArray(), 0);
                        if (qust.FormID != formID1)
                        {
                            continue;
                        }
                        byte firstByte       = bytes[0];
                        int  compareOperator = firstByte & 0b11110000;
                        int  flags           = firstByte & 0b00001111;
                        if (!(compareOperator == 0))
                        {
                            throw new InvalidOperationException("Invalid compareOperator");
                        }
                        if (!(flags == 0 /*none*/ || flags == 1 /*or*/))
                        {
                            throw new InvalidOperationException("Invalid flags");
                        }
                        float comparisonValue = BitConverter.ToSingle(bytes.Skip(4).Take(4).ToArray(), 0);//is "done"

                        /*if (comparisonValue == 1) { targetFuncs.GetOrAddNewIfNotContainsKey(targetIndexInt).Add(stageID => stageID > comparisonValue); }
                         * else if (comparisonValue == 0) { targetFuncs.GetOrAddNewIfNotContainsKey(targetIndexInt).Add(stageID => stageID <= comparisonValue); }*/
                    }
                }
            }
            var simplifiedTargetFuncs = targetFuncs.ToDictionary(kvp => kvp.Key, kvp =>
            {
                List <Tuple <Func <int, bool>, bool> > currentList = kvp.Value;
                List <Func <int, bool> > reducedList = new List <Func <int, bool> >();
                for (int j = 0; j < currentList.Count; j++)
                {
                    var currentTuple = currentList[j];
                    if (currentTuple.Item2 || j + 1 >= currentList.Count)
                    {
                        reducedList.Add(currentTuple.Item1);
                    }
                    else
                    {
                        var nextTuple            = currentList[j + 1];
                        Func <int, bool> newFunc = si => currentTuple.Item1(si) && nextTuple.Item1(si);
                        bool or        = nextTuple.Item2;
                        currentList[j] = Tuple.Create(newFunc, or);
                        currentList.RemoveAt(j + 1);
                        j--;
                    }
                }
                return(currentList.Select(x => x.Item1).ToArray());
            });
            Dictionary <int, Dictionary <int, bool> > stageDictionary = stageIndexes.ToDictionary(stageIndex => stageIndex, stageIndex =>
            {
                Dictionary <int, bool> innerDictionary = new Dictionary <int, bool>();
                for (int i = 0; i <= maxTargetIndex; i++)
                {
                    Func <int, bool>[] currentList;
                    bool result;
                    if (!simplifiedTargetFuncs.TryGetValue(i, out currentList))
                    {
                        result = true;
                    }
                    else
                    {
                        result = currentList.Any(x => x(stageIndex));
                    }
                    innerDictionary[i] = result;
                }
                return(innerDictionary);
            });
            StringBuilder contents   = new StringBuilder();
            bool          anyTargets = targetIndex != null;

            foreach (var stage in stageDictionary.OrderBy(s => s.Key))
            {
                var rowDictionary = stage.Value;
                contents.Append(stage.Key).Append(" - ");
                if (anyTargets)
                {
                    for (int i = 0; i <= maxTargetIndex; i++)
                    {
                        bool cell;
                        contents.Append(rowDictionary.TryGetValue(i, out cell) && cell ? "1" : "0").Append(" ");
                    }
                }
                contents.AppendLine();
            }
            return(contents.ToString());
        }