/// <summary>
        /// Attempts to merge all of the 2da's in the passed array list into 1 merge
        /// 2da, by combining all of the non-empty rows in each 2da.  If 2 2da's have
        /// changes the same row then the merge will fail.
        /// </summary>
        /// <param name="baseline">The bioware baseline version of the 2da</param>
        /// <param name="list">The list of 2da's to merge</param>
        /// <returns>The merged 2da or null if the 2da's cannot be merged</returns>
        private _2DA Merge2das(_2DA baseline, ArrayList list)
        {
            // Create a flat list to have a strongly typed list of 2da's.
            _2DA[] merges = new _2DA[list.Count];
            list.CopyTo(merges);

            // Figure out the maximum number of rows we have to deal with
            int rows = baseline.Rows;
            foreach (_2DA merge in merges)
                rows = System.Math.Max(rows, merge.Rows);

            // Create the output 2da.
            _2DA output = new _2DA(baseline.Schema);
            output.Pad(rows);

            // Loop through all rows attempting to merge each row into the
            // output 2da.
            for (int i = 0; i < rows; i++)
            {
                StringCollection mergedRow = null;
                _2DA useForOutput = null;
                foreach (_2DA merge in merges)
                {
                    // Make an attempt to filter out junk rows with things
                    // such as "reserved", "deleted", etc in their labels.
                    // These often conflict but are really empty rows.
                    if (IsJunkRow(merge, i)) continue;

                    // If we have gone past the end of this 2da or the
                    // row is an empty row then ignore it.
                    if (i >= merge.Rows || merge.IsEmpty(i)) continue;

                    // If this is a row from the bioware version of the 2da
                    // and the data is the same as the bioware 2da then
                    // ignore this row in the 2da.
                    if (i < baseline.Rows &&
                        _2DA.CompareRow(baseline, i, merge, i, true)) continue;

                    // If we get here we have a non-empty row that differs from
                    // one of the bioware rows.  Only 1 2da file per row can
                    // get past this point for use to be able to do a successful
                    // merge, if 2 2da's get here then 2 have changed the same
                    // row and we cannot merge.

                    // If we don't have any proposed row data yet then
                    // save this 2da's row data.
                    if (null == useForOutput)
                    {
                        useForOutput = merge;
                        continue;
                    }

                    // If we get here we have 2 2da's that want to change the same row.
                    // Our only hope for a successful merge is that the data in the
                    // 2 2da's is identical.
                    if (_2DA.CompareRow(useForOutput, i, merge, i, true)) continue;

                    // We already have an output 2da, which means that 2 2da's have
                    // changed the same row, attempt to glue all of the merge changes
                    // together.  If we cannot generate a merged row then return null.
                    mergedRow = GenerateMergeRow(baseline, list, i);
                    if (null == mergedRow) return null;

                    // If we get here we have generated a merge row for all 2da's
                    // so we don't need to look at the data in this row any further
                    // break out of the loopo and use the mergedRow.
                    break;
                }

                // If we have merge 2da to copy from then copy the
                // cell data.  If we don't have a merge 2da but the row is
                // withing the baseline 2da then copy the baseline data.
                // Otherwise don't copy any data.
                if (null != mergedRow)
                    output.CopyRow(mergedRow, i);
                else if (null != useForOutput)
                    output.CopyRow(useForOutput, i, i);
                else if (i < baseline.Rows)
                    output.CopyRow(baseline, i, i);
            }

            return output;
        }
        /// <summary>
        /// Attempts to generate a merge row by taking all of the alterations made
        /// to the bioware row from the merge 2da's and incorporating them into 1
        /// row.  This will work unless 2 different 2da's change the same column
        /// in the row, which will make the merge fail.
        /// </summary>
        /// <param name="baseline">The bioware baseline 2da</param>
        /// <param name="list">The list of 2da's being merged</param>
        /// <param name="row">The row for which to generate a merge row</param>
        /// <returns>The merged row, or null if a merge row could not be
        /// generated.</returns>
        private StringCollection GenerateMergeRow(_2DA baseline, ArrayList list, int row)
        {
            try
            {
                // We cannot merge if the row is not in the baseline.
                if (row > baseline.Rows) return null;

                // Create a copy of the merge row in the baseline 2da.
                StringCollection resultRow = new StringCollection();
                StringCollection baselineRow = baseline.GetRowData(row);
                foreach (string s in baselineRow)
                    resultRow.Add(s);

                // Create a bool array to keep track of which columns
                // we modify.
                bool[] writtenTo = new bool[resultRow.Count];
                for (int i = 0; i < writtenTo.Length; i++)
                    writtenTo[i] = false;

                foreach (_2DA merge in list)
                {
                    // Get the row from the merge 2da.
                    StringCollection mergeRow = merge.GetRowData(row);

                    // If the collections do not have the same length then
                    // fail the merge, the added column may not be at the end.
                    if (mergeRow.Count != resultRow.Count) return null;

                    // Loop through all of the columns.
                    for (int i = 1; i < resultRow.Count; i++)
                    {
                        // Ignore empty data cells in the merge row.
                        if (_2DA.Empty == mergeRow[i]) continue;

                        // Compare the cell value against the baseline.  If it is the
                        // same then ignore it. (the result row starts out as the baseline
                        // so we do not need to set these values, and we need to ignore
                        // them to detect double writes to the same cell)
                        if (_2DA.CompareCell(baselineRow[i], mergeRow[i], true))
                            continue;

                        // Compare the cells from the result row and the merge row,
                        // if they are different then we need to copy the merge
                        // row's value into the result row.  However, if a previous
                        // merge 2da has modified this column then we have 2 different
                        // 2da's wanting non-bioware default values in the same
                        // column, if that happens there is no way to merge.
                        if (!_2DA.CompareCell(mergeRow[i], resultRow[i], true))
                        {
                            // If we've already changed the bioware default for this
                            // column we cannot merge return null.
                            if (writtenTo[i])
                                return null;
                            else
                            {
                                // Overwrite the bioware default for this column and
                                // save the fact that we have changed this column
                                resultRow[i] = mergeRow[i];
                                writtenTo[i] = true;
                            }
                        }
                    }
                }

                // If we get here we were able to take all of the various 2da
                // modifications to the bioware row and make 1 merge row with all
                // of the changes, return it.
                return resultRow;
            }
            catch (Exception)
            {
                return null;
            }
        }
        /// <summary>
        /// Returns true if the row is a junk row.
        /// </summary>
        /// <param name="file">The 2da to test</param>
        /// <param name="row">The row to test</param>
        /// <returns>True if the row is a junk row.</returns>
        private bool IsJunkRow(_2DA file, int row)
        {
            if (row >= file.Rows) return false;

            int index = file.GetIndex("LABEL");
            if (-1 == index) index = file.GetIndex("NAME");
            if (-1 == index) return false;

            // Check for common labels indicating that it is a junk row.
            string value = file[row, index].ToLower();
            if (-1 != value.IndexOf("deleted") ||
                -1 != value.IndexOf("reserved") ||
                -1 != value.IndexOf("user")) return true;

            return false;
        }
Example #4
0
 /// <summary>
 /// Copies a row from a source 2da to this 2da.
 /// </summary>
 /// <param name="source">The source 2da</param>
 /// <param name="sourceRow">The index of the row in the source 2da</param>
 /// <param name="row">The index of the row in this 2da</param>
 public void CopyRow(_2DA source, int sourceRow, int row)
 {
     // Get the row from the source 2da and let our overload do all of the
     // work.
     StringCollection sourceRowData = (StringCollection) source.rows[sourceRow];
     CopyRow(sourceRowData, row);
 }
Example #5
0
        /// <summary>
        /// Merges 2 2da objects, saving the results in a 2da file.  The method expects that
        /// the source 2da will have at least enough rows to be contiguous with the merge
        /// 2da (the source 2da should be padded by calling Pad() if necessary).  If the
        /// source and merge 2da's share some rows, the merge 2da rows will overwrite the
        /// source 2da rows.
        /// </summary>
        /// <param name="source">The source 2da</param>
        /// <param name="merge">The merge 2da</param>
        /// <param name="outFile">The name of the output 2da</param>
        public static void Merge2da(_2DA source, _2DA merge, string outFile)
        {
            using(StreamWriter writer = new StreamWriter(outFile, false))
            {
                // Write the 2da header.
                writer.WriteLine(headerString);
                writer.WriteLine();
                writer.WriteLine(source.Heading);

                // Make the column sizes in the source and 2da files to be the largest
                // of each file, to make the columns have the correct width.
                for (int i = 0; i < source.colSizes.Length; i++)
                {
                    source.colSizes[i] = System.Math.Max(source.colSizes[i], merge.colSizes[i]);
                    merge.colSizes[i] = source.colSizes[i];
                }

                // output all of the source strings before our merge.
                for (int i = 0; i < merge.Offset; i++)
                {
                    string s = source[i];
                    writer.WriteLine(s);
                }

                // Test all of the rows that the merge is about to overwrite to make sure they
                // are really empty.  If any are not then generate a warning message for those
                // rows.
                int end = System.Math.Min(source.rows.Count, merge.Offset + merge.rows.Count);
                for (int i = merge.Offset; i < end; i++)
                    if (!source.IsEmpty(i))
                    {
                        //CMain.Warning("Overwriting non-empty row {0} in {1}", i, source.FileName);
                    }

                // output all of the merge strings.
                for (int i = 0; i < merge.rows.Count; i++)
                {
                    string s = merge[i];
                    writer.WriteLine(s);
                }

                // output any remaining source strings, in case the merge is in the middle.
                for (int i = merge.Offset + merge.rows.Count; i < source.rows.Count; i++)
                {
                    string s = source[i];
                    writer.WriteLine(s);
                }

                writer.Flush();
                writer.Close();
            }
        }
Example #6
0
        /// <summary>
        /// Factory method to create C2da objects from streams.
        /// </summary>
        /// <param name="stream">The stream to create the 2da object from</param>
        /// <returns>A 2da object for the stream.</returns>
        public static _2DA Load2da(Stream stream)
        {
            _2DA file = new _2DA();
            using (StreamReader reader = new StreamReader(stream, Encoding.ASCII))
            {
                file.Read(reader);
            }

            return file;
        }
Example #7
0
        /// <summary>
        /// Factory method to create C2da objects from 2da files.
        /// </summary>
        /// <param name="fileName">The name of the 2da file</param>
        /// <returns>A 2da object for the 2da file.</returns>
        public static _2DA Load2da(string fileName)
        {
            // Open the 2da file.
            _2DA file = new _2DA(fileName);
            using(StreamReader reader = new StreamReader(fileName))
            {
                file.Read(reader);
            }

            return file;
        }
Example #8
0
        /// <summary>
        /// Compares rows in 2 different 2da files to see if they are equal or not.
        /// </summary>
        /// <param name="twoDA1">The first 2da to test</param>
        /// <param name="row1">The row in the first 2da to compare</param>
        /// <param name="twoDA2">The second 2da to test</param>
        /// <param name="row">The row in the second 2da to compare</param>
        /// <param name="ignoreCase">True if the comparison should be case insensitive</param>
        /// <returns>True if the rows are equal false if they are not</returns>
        public static bool CompareRow(_2DA twoDA1, int row1, _2DA twoDA2, int row2,
			bool ignoreCase)
        {
            // Get the data for each of the rows.
            StringCollection row1Data = (StringCollection) twoDA1.rows[row1];
            StringCollection row2Data = (StringCollection) twoDA2.rows[row2];

            // If the rows have different amounts of cells then they are by
            // definition different.
            if (row1Data.Count != row2Data.Count) return false;

            // Loop through the rows doing a cell by cell compare, stopping
            // if we find any differences.  We start at column 1 to skip
            // the row numbrs which would of course be different.
            for (int i = 1; i < row1Data.Count; i++)
                if (!CompareCell(row1Data[i], row2Data[i], ignoreCase))
                    return false;

            // The rows are identical return true.
            return true;
        }