예제 #1
0
        private WiiUManager(IEnumerable<Title> databaseState)
        {
            _databaseState = new MapleList<Title>(databaseState);

            _bindingSource = new BindingSource {DataSource = _databaseState};

            InitializeForm();
        }
예제 #2
0
        public static void Load()
        {
            var dbFile = Path.GetFullPath(Path.Combine(Settings.ConfigDirectory, "database"));

            if (!File.Exists(dbFile) || new FileInfo(dbFile).Length <= 4000 || Settings.CacheDatabase)
            {
                File.WriteAllText(dbFile, JsonConvert.SerializeObject(_db = Create()));
            }
            else
            {
                var json = File.ReadAllText(dbFile);
                _db = JsonConvert.DeserializeObject <MapleList <Title> >(json);
            }

            LoadLibrary(Settings.LibraryDirectory);
        }
예제 #3
0
        public static async Task <MapleList <GraphicPack> > Init(bool force = false)
        {
            var databaseFile = Path.Combine(Settings.ConfigDirectory, "graphicPacks");

            GraphicPacks = new MapleList <GraphicPack>();

            if (!File.Exists(databaseFile) || Settings.CacheDatabase || force)
            {
                TextLog.MesgLog.WriteLog(@"Building graphic pack database...");

                var url  = "https://github.com/slashiee/cemu_graphic_packs/archive/master.zip";
                var data = await Web.DownloadDataAsync(url);

                File.WriteAllBytes(databaseFile, data);
            }

            try {
                if (File.Exists(databaseFile))
                {
                    TextLog.MesgLog.WriteLog(@"Loading graphic pack database...");
                    var data = File.ReadAllBytes(databaseFile);

                    using (var zipArchive = new ZipArchive(new MemoryStream(data))) {
                        zipArchive.Entries.Where(x => x.Name.Length == 0 && x.FullName.EndsWith("/"))
                        .ToList()
                        .ForEach(Process);
                    }

                    //GraphicPacks = JsonConvert.DeserializeObject<MapleList<GraphicPack>>(json);
                }
            }
            catch (Exception e) {
                if (RetryCount >= 3)
                {
                    TextLog.MesgLog.WriteLog(
                        $"GraphicPacks Init() failed too many times, cancelling...\n\n{e.Message}\n{e.StackTrace}");
                    return(GraphicPacks);
                }

                RetryCount++;
                File.Delete(databaseFile);
                await Init(true);
            }

            return(GraphicPacks);
        }
예제 #4
0
        public static void ConvertToMapleFootholds2(ref MapleList <FootholdLine> oldFootholds, ref MapleList <FootholdAnchor> oldAnchors)
        {
            //Part 1 - copying and filtering out unused anchors
            List <FootholdLine>   footholds = new List <FootholdLine>(oldFootholds.Count);
            List <FootholdAnchor> anchors   = new List <FootholdAnchor>(oldAnchors.Count);

            foreach (FootholdAnchor oldAnchor in oldAnchors)
            {
                if (oldAnchor.connectedLines.Count == 0)
                {
                    continue;
                }
                //if (oldAnchor.IsMoveHandled) throw new Exception();
                FootholdAnchor anchor = new FootholdAnchor(oldAnchor.Board, oldAnchor.X, oldAnchor.Y, oldAnchor.LayerNumber, oldAnchor.BeforeAdding);
                anchor.connectedLines = new List <MapleLine>(oldAnchor.connectedLines.Count);
                foreach (FootholdLine oldLine in oldAnchor.connectedLines)
                {
                    if (oldLine.cloneLine == null)
                    {
                        FootholdAnchor firstDot  = null;
                        FootholdAnchor secondDot = null;
                        if (oldLine.FirstDot.X > oldLine.SecondDot.X)
                        {
                            firstDot  = (FootholdAnchor)oldLine.SecondDot;
                            secondDot = (FootholdAnchor)oldLine.FirstDot;
                        }
                        else if (oldLine.FirstDot.X < oldLine.SecondDot.X)
                        {
                            firstDot  = (FootholdAnchor)oldLine.FirstDot;
                            secondDot = (FootholdAnchor)oldLine.SecondDot;
                        }
                        else
                        {
                            if (oldLine.FirstDot.Y > oldLine.SecondDot.Y)
                            {
                                firstDot  = (FootholdAnchor)oldLine.SecondDot;
                                secondDot = (FootholdAnchor)oldLine.FirstDot;
                            }
                            else
                            {
                                firstDot  = (FootholdAnchor)oldLine.FirstDot;
                                secondDot = (FootholdAnchor)oldLine.SecondDot;
                            }
                        }
                        if (anchor.X == firstDot.X && anchor.Y == firstDot.Y) //we are firstdot
                        {
                            firstDot  = anchor;
                            secondDot = null;
                        }
                        else //we are seconddot
                        {
                            firstDot  = null;
                            secondDot = anchor;
                        }
                        oldLine.cloneLine = FootholdLine.CreateCustomFootholdLine(oldLine.Board, firstDot, secondDot);
                        footholds.Add(oldLine.cloneLine);
                    }
                    else
                    {
                        if (oldLine.cloneLine.FirstDot == null)
                        {
                            oldLine.cloneLine.FirstDot = anchor;
                        }
                        else
                        {
                            oldLine.cloneLine.SecondDot = anchor;
                        }
                    }
                    anchor.connectedLines.Add(oldLine.cloneLine);
                }
                anchors.Add(anchor);
            }
            foreach (FootholdLine fhLine in oldFootholds)
            {
                fhLine.cloneLine = null;
            }

            //Part 2 - combining anchors that are on the exact same position
            anchors.Sort(new Comparison <FootholdAnchor>(FootholdAnchor.FHAnchorSorter));
            int            groupStart = 0; //inclusive
            int            groupEnd   = 0; //inclusive
            FootholdAnchor a;
            FootholdAnchor b;
            FootholdAnchor c;
            FootholdAnchor d;
            FootholdLine   line;

            for (int i = 0; i < anchors.Count - 1; i++)
            {
                a = anchors[i];
                b = anchors[i + 1];
                if (a.Y != b.Y && a.X != b.X && a.LayerNumber == b.LayerNumber)
                {
                    groupEnd = i;
                    if (groupEnd - groupStart == 1) //there are 2 objects in the group, since groupEnd and groupStart are inclusive
                    {
                        c = anchors[groupStart];
                        d = anchors[groupEnd];
                        if (c.connectedLines.Count == 1 && d.connectedLines.Count == 1)
                        {
                            d.removed = true;
                            line      = (FootholdLine)d.connectedLines[0];
                            if (line.FirstDot == d)
                            {
                                line.FirstDot = c;
                            }
                            else
                            {
                                line.SecondDot = c;
                            }
                            c.connectedLines.Add(line);
                        }
                    }
                    groupStart = groupEnd + 1;
                }
            }

            groupEnd = anchors.Count - 1;
            if (groupEnd - groupStart == 1) //there are 2 objects in the group, since groupEnd and groupStart are inclusive
            {
                c = anchors[groupStart];
                d = anchors[groupEnd];
                if (c.connectedLines.Count == 1 && d.connectedLines.Count == 1)
                {
                    d.removed = true;
                    line      = (FootholdLine)d.connectedLines[0];
                    if (line.FirstDot == d)
                    {
                        line.FirstDot = c;
                    }
                    else
                    {
                        line.SecondDot = c;
                    }
                    c.connectedLines.Add(line);
                }
            }

            //Part 3 - connecting footholds to anchors they pass through, selectively
            //this part is made purely to fix problems in the foothold structure caused
            //by the auto foothold connection feature for tiles
            for (int i = 0; i < footholds.Count; i++)
            {
                line = footholds[i];
                if (line.FirstDot.Y != line.SecondDot.Y)
                {
                    continue;
                }
                foreach (FootholdAnchor anchor in anchors)
                {
                    if (anchor.X == line.FirstDot.Y && ((IContainsLayerInfo)line.FirstDot).LayerNumber == anchor.LayerNumber)
                    {
                        if (anchor.connectedLines.Count == 1)
                        {
                            line = (FootholdLine)anchor.connectedLines[0];
                        }
                        else
                        {
                            line = (FootholdLine)(anchor.connectedLines[0].FirstDot.Y == anchor.connectedLines[0].SecondDot.Y ? anchor.connectedLines[0] : anchor.connectedLines[1]);
                        }
                        if (line.FirstDot.Y == line.SecondDot.Y) //blueCave2 tiles, first anchor of sloped tiles
                        {
                            //footholds.RemoveAt(i);
                            line.remove = true;
                            footholds.Add(new FootholdLine(line.Board, line.FirstDot, anchor));
                            footholds.Add(new FootholdLine(line.Board, anchor, line.SecondDot));
                            //i--;
                            break;
                            //anchor.keyAnchor = line.FirstDot.Y == line.SecondDot.Y && IsValidKeyAnchor(anchor);
                        }
                        else //junction anchor for sloped tiles
                        {
                            bool direction = line.FirstDot == anchor; //true = anchor is the left dot, so we need to delete the line going to the right
                            //footholds.RemoveAt(i);
                            line.remove = true;
                            if (direction)
                            {
                                footholds.Add(new FootholdLine(line.Board, line.FirstDot, anchor));
                            }
                            else
                            {
                                footholds.Add(new FootholdLine(line.Board, anchor, line.SecondDot));
                            }
                            break;
                        }
                    }
                }

                /*                     if (((line.FirstDot.X == line.SecondDot.X) && (anchor.X == line.FirstDot.X && anchor.Y > line.FirstDot.Y && anchor.Y < line.SecondDot.Y)
                || ((line.FirstDot.Y == line.SecondDot.Y) && (anchor.Y == line.FirstDot.Y && anchor.X > line.FirstDot.X && anchor.X < line.SecondDot.X)))
                || && ((IContainsLayerInfo)line.FirstDot).LayerNumber == anchor.LayerNumber)*/
            }

            FootholdLine lineA;
            FootholdLine lineB;

            //Part 4 - removing duplicate footholds (caused by step 3, case 1)
            footholds.Sort(new Comparison <FootholdLine>(FHSorter));
            for (int i = 0; i < footholds.Count - 1; i++)
            {
                lineA = footholds[i];
                lineB = footholds[i + 1];
                if (lineA.FirstDot.X == lineB.FirstDot.X && lineA.FirstDot.Y == lineB.FirstDot.Y &&
                    lineA.SecondDot.X == lineB.SecondDot.X && lineA.SecondDot.Y == lineB.SecondDot.Y)
                {
                    //footholds.RemoveAt(i);
                    lineA.remove = true;
                    i--;
                }
            }

            //Part 5 - executing foothold changes and updating anchors
            foreach (FootholdAnchor anchor in anchors)
            {
                for (int i = 0; i < anchor.connectedLines.Count; i++)
                {
                    if (((FootholdLine)anchor.connectedLines[i]).remove)
                    {
                        anchor.connectedLines.RemoveAt(i);
                    }
                }
            }
            List <FootholdLine> newFootholds = new List <FootholdLine>(footholds.Count);

            foreach (FootholdLine fh in footholds)
            {
                if (!fh.remove)
                {
                    newFootholds.Add(fh);
                }
            }
            footholds = newFootholds;


            //Part 6 - dealing with 3 way (or more) foothold junctions

            /*foreach (FootholdAnchor anchor in anchors)
             * {
             *  if (anchor.connectedLines.Count > 2)
             *  {
             *      if (anchor.keyAnchor)
             *      {
             *          int leftLineIndex = -1;
             *          int rightLineIndex = -1;
             *          int slopedLineIndex = -1;
             *          for(int i=0; i<anchor.connectedLines.Count; i++)
             *          {
             *              FootholdLine line = (FootholdLine)anchor.connectedLines[i];
             *              if (line.FirstDot.Y == line.SecondDot.Y)
             *              {
             *                  if (anchor == line.FirstDot) rightLineIndex = i;
             *                  else if (anchor == line.SecondDot) leftLineIndex = i;
             *                  else
             *                  {
             *                      MessageBox.Show("Error at foothold parsing"); //TODO
             *                  }
             *              }
             *              else if (line.FirstDot.X != line.SecondDot.X) slopedLineIndex = i;
             *          }
             *          if (leftLineIndex == -1 || rightLineIndex == -1 || slopedLineIndex == -1)
             *          {
             *              MessageBox.Show("Error at foothold parsing"); //TODO
             *          }
             *          FootholdLine slopedLine = (FootholdLine)anchor.connectedLines[slopedLineIndex];
             *          if (slopedLine.FirstDot.Y < slopedLine.SecondDot.Y)
             *          { //eliminate left
             *              EliminateFootholdTree(anchor, leftLineIndex, ref footholds);
             *          }
             *          else
             *          {
             *              //eliminate right
             *              EliminateFootholdTree(anchor, rightLineIndex, ref footholds);
             *          }
             *      }
             *      else
             *      {
             *          double lowestLength = double.MaxValue;
             *          int shortestLineIndex = -1;
             *          for (int i = 0; i < anchor.connectedLines.Count; i++)
             *          {
             *              double length = CalculateFootholdTreeLength(anchor, i);
             *              if (length < lowestLength)
             *              {
             *                  lowestLength = length;
             *                  shortestLineIndex = i;
             *              }
             *          }
             *          EliminateFootholdTree(anchor, shortestLineIndex, ref footholds);
             *      }
             *  }
             * }
             *
             * //Part 7 - executing foothold changes and updating anchors (again)
             * foreach (FootholdAnchor anchor in anchors)
             *  for (int i = 0; i < anchor.connectedLines.Count; i++)
             *      if (((FootholdLine)anchor.connectedLines[i]).remove)
             *          anchor.connectedLines.RemoveAt(i);*/

            oldAnchors.Clear();
            foreach (FootholdAnchor anchor in anchors) /*anchor.keyAnchor = false; */ oldAnchors {
예제 #5
0
        private async Task <MapleList <GraphicPack> > Create()
        {
            var graphicPacks = new MapleList <GraphicPack>();

            try
            {
                string dataString;
                if ((dataString = await Web.DownloadStringAsync("https://github.com/slashiee/cemu_graphic_packs/releases/latest")) == null)
                {
                    return(null);
                }

                var d    = dataString.Split('\n').ToList();
                var line = d.Find(x => x.Contains("graphicPacks_2"));
                line = line.Replace("\"", "");
                line = line.Replace("<a href=", "");
                line = line.Replace("rel=nofollow>", "");
                line = line.Trim();

                byte[] graphicPackBytes;
                if ((graphicPackBytes = await Web.DownloadDataAsync($"https://github.com{line}")) == null)
                {
                    return(null);
                }

                if (graphicPackBytes.Length <= 1)
                {
                    return(null);
                }

                using (var zipArchive = new ZipArchive(new MemoryStream(graphicPackBytes)))
                {
                    var list = zipArchive.Entries?.Where(x => x.FullName.Contains("rules.txt")).ToList();

                    if (list == null)
                    {
                        return(null);
                    }

                    foreach (var zipArchiveEntry in list)
                    {
                        var pack = Process(zipArchiveEntry);

                        if (pack != null && !graphicPacks.Contains(pack))
                        {
                            graphicPacks.Add(pack);
                        }
                    }
                }

                return(graphicPacks);
            }
            catch (Exception e)
            {
                if (RetryCount >= 3)
                {
                    TextLog.Write($"GraphicPacks Init() failed, cancelling...\n\n{e.Message}\n{e.StackTrace}");
                    return(null);
                }

                RetryCount++;
                return(await Create());
            }
        }
예제 #6
0
        private static MapleList <Title> Create()
        {
            var eShopTitlesStr    = Resources.eShopAndDiskTitles; //index 12
            var eShopTitleUpdates = Resources.eShopTitleUpdates;  //index 9

            _db = new MapleList <Title>();

            var titlekeys = WiiUTitleKeys();

            foreach (var wiiutitleKey in titlekeys)
            {
                var id     = wiiutitleKey["titleID"].Value <string>()?.ToUpper();
                var key    = wiiutitleKey["titleKey"].Value <string>()?.ToUpper();
                var name   = wiiutitleKey["name"].Value <string>();
                var region = wiiutitleKey["region"].Value <string>();

                if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(key))
                {
                    continue;
                }

                _db.Add(new Title {
                    ID = id, Key = key, Name = name, Region = region
                });
            }

            var lines = eShopTitlesStr.Replace("|", "").Split('\n').ToList();

            for (var i = 11; i < lines.Count; i++)
            {
                var id    = lines[i++].Replace("-", "").Trim().ToUpper();
                var title = _db.FirstOrDefault(x => x.ID == id) ?? new Title();

                title.ID          = id;
                title.Name        = lines[i++].Trim();
                title.ProductCode = lines[i++].Trim();
                title.CompanyCode = lines[i++].Trim();
                title.Notes       = lines[i++].Trim();
                title.Versions    = lines[i++].ToIntList(',');
                title.Region      = lines[i++].Trim();

                var num  = i++;
                var line = lines[num].ToLower().Trim();

                if (!line.Contains("yes") && !line.Contains("no"))
                {
                    continue;
                }

                title.AvailableOnCDN = lines[num].ToLower().Contains("yes");

                if (!_db.Contains(title))
                {
                    _db.Add(title);
                }
            }

            lines = eShopTitleUpdates.Replace("|", "").Split('\n').ToList();
            for (var i = 9; i < lines.Count; i++)
            {
                var line = lines[i].Trim();

                if (!line.Contains("-10"))
                {
                    continue;
                }

                var versionStr = lines[i + 3].Trim();
                var versions   = versionStr.ToIntList(',');

                var titleId = line.Replace("-", "").ToUpper();
                var title   = _db.ToList().Find(t => t.ID.Contains(titleId.Substring(8)));

                if (title != null)
                {
                    title.Versions = versions;
                }
            }

            foreach (var title in _db.Where(x => x.ContentType == "eShop/Application"))
            {
                var id = $"0005000C{title.Lower8Digits().ToUpper()}";

                JObject _title;
                if ((_title = WiiUTitleKey(titlekeys, id)) != null)
                {
                    title.HasDLC = _title.HasValues;
                }
            }

            return(_db);
        }
예제 #7
0
        public static void ConvertToMapleFootholds2(ref MapleList<FootholdLine> oldFootholds, ref MapleList<FootholdAnchor> oldAnchors)
        {
            //Part 1 - copying and filtering out unused anchors
            List<FootholdLine> footholds = new List<FootholdLine>(oldFootholds.Count);
            List<FootholdAnchor> anchors = new List<FootholdAnchor>(oldAnchors.Count);
            foreach (FootholdAnchor oldAnchor in oldAnchors)
            {
                if (oldAnchor.connectedLines.Count == 0) continue;
                //if (oldAnchor.IsMoveHandled) throw new Exception();
                FootholdAnchor anchor = new FootholdAnchor(oldAnchor.Board, oldAnchor.X, oldAnchor.Y, oldAnchor.LayerNumber, oldAnchor.BeforeAdding);
                anchor.connectedLines = new List<MapleLine>(oldAnchor.connectedLines.Count);
                foreach (FootholdLine oldLine in oldAnchor.connectedLines)
                {
                    if (oldLine.cloneLine == null)
                    {
                        FootholdAnchor firstDot = null;
                        FootholdAnchor secondDot = null;
                        if (oldLine.FirstDot.X > oldLine.SecondDot.X)
                        {
                            firstDot = (FootholdAnchor)oldLine.SecondDot;
                            secondDot = (FootholdAnchor)oldLine.FirstDot;
                        }
                        else if (oldLine.FirstDot.X < oldLine.SecondDot.X)
                        {
                            firstDot = (FootholdAnchor)oldLine.FirstDot;
                            secondDot = (FootholdAnchor)oldLine.SecondDot;
                        }
                        else
                        {
                            if (oldLine.FirstDot.Y > oldLine.SecondDot.Y)
                            {
                                firstDot = (FootholdAnchor)oldLine.SecondDot;
                                secondDot = (FootholdAnchor)oldLine.FirstDot;
                            }
                            else
                            {
                                firstDot = (FootholdAnchor)oldLine.FirstDot;
                                secondDot = (FootholdAnchor)oldLine.SecondDot;

                            }
                        }
                        if (anchor.X == firstDot.X && anchor.Y == firstDot.Y) //we are firstdot
                        {
                            firstDot = anchor;
                            secondDot = null;
                        }
                        else //we are seconddot
                        {
                            firstDot = null;
                            secondDot = anchor;
                        }
                        oldLine.cloneLine = FootholdLine.CreateCustomFootholdLine(oldLine.Board, firstDot, secondDot);
                        footholds.Add(oldLine.cloneLine);
                    }
                    else
                    {
                        if (oldLine.cloneLine.FirstDot == null) oldLine.cloneLine.FirstDot = anchor;
                        else oldLine.cloneLine.SecondDot = anchor;
                    }
                    anchor.connectedLines.Add(oldLine.cloneLine);
                }
                anchors.Add(anchor);
            }
            foreach (FootholdLine fhLine in oldFootholds)
                fhLine.cloneLine = null;

            //Part 2 - combining anchors that are on the exact same position
            anchors.Sort(new Comparison<FootholdAnchor>(FootholdAnchor.FHAnchorSorter));
            int groupStart = 0; //inclusive
            int groupEnd = 0; //inclusive
            FootholdAnchor a;
            FootholdAnchor b;
            FootholdAnchor c;
            FootholdAnchor d;
            FootholdLine line;
            for (int i = 0; i < anchors.Count - 1; i++)
            {
                a = anchors[i];
                b = anchors[i + 1];
                if (a.Y != b.Y && a.X != b.X && a.LayerNumber == b.LayerNumber)
                {
                    groupEnd = i;
                    if (groupEnd - groupStart == 1) //there are 2 objects in the group, since groupEnd and groupStart are inclusive
                    {
                        c = anchors[groupStart];
                        d = anchors[groupEnd];
                        if (c.connectedLines.Count == 1 && d.connectedLines.Count == 1)
                        {
                            d.removed = true;
                            line = (FootholdLine)d.connectedLines[0];
                            if (line.FirstDot == d)
                                line.FirstDot = c;
                            else
                                line.SecondDot = c;
                            c.connectedLines.Add(line);
                        }
                    }
                    groupStart = groupEnd + 1;
                }
            }

            groupEnd = anchors.Count - 1;
            if (groupEnd - groupStart == 1) //there are 2 objects in the group, since groupEnd and groupStart are inclusive
            {
                c = anchors[groupStart];
                d = anchors[groupEnd];
                if (c.connectedLines.Count == 1 && d.connectedLines.Count == 1)
                {
                    d.removed = true;
                    line = (FootholdLine)d.connectedLines[0];
                    if (line.FirstDot == d)
                        line.FirstDot = c;
                    else
                        line.SecondDot = c;
                    c.connectedLines.Add(line);
                }
            }

            //Part 3 - connecting footholds to anchors they pass through, selectively 
            //this part is made purely to fix problems in the foothold structure caused
            //by the auto foothold connection feature for tiles
            for (int i = 0; i < footholds.Count; i++)
            {
                line = footholds[i];
                if (line.FirstDot.Y != line.SecondDot.Y) continue;
                foreach (FootholdAnchor anchor in anchors)
                {
                    if (anchor.X == line.FirstDot.Y && ((IContainsLayerInfo)line.FirstDot).LayerNumber == anchor.LayerNumber)
                    {
                        if (anchor.connectedLines.Count == 1)
                            line = (FootholdLine)anchor.connectedLines[0];
                        else
                            line = (FootholdLine)(anchor.connectedLines[0].FirstDot.Y == anchor.connectedLines[0].SecondDot.Y ? anchor.connectedLines[0] : anchor.connectedLines[1]);
                        if (line.FirstDot.Y == line.SecondDot.Y) //blueCave2 tiles, first anchor of sloped tiles
                        {
                            //footholds.RemoveAt(i);
                            line.remove = true;
                            footholds.Add(new FootholdLine(line.Board, line.FirstDot, anchor));
                            footholds.Add(new FootholdLine(line.Board, anchor, line.SecondDot));
                            //i--;
                            break;
                            //anchor.keyAnchor = line.FirstDot.Y == line.SecondDot.Y && IsValidKeyAnchor(anchor);
                        }
                        else //junction anchor for sloped tiles
                        {
                            bool direction = line.FirstDot == anchor; //true = anchor is the left dot, so we need to delete the line going to the right
                            //footholds.RemoveAt(i);
                            line.remove = true;
                            if (direction)
                                footholds.Add(new FootholdLine(line.Board, line.FirstDot, anchor));
                            else
                                footholds.Add(new FootholdLine(line.Board, anchor, line.SecondDot));
                            break;
                        }
                    }
                }
                /*                     if (((line.FirstDot.X == line.SecondDot.X) && (anchor.X == line.FirstDot.X && anchor.Y > line.FirstDot.Y && anchor.Y < line.SecondDot.Y)
                 || ((line.FirstDot.Y == line.SecondDot.Y) && (anchor.Y == line.FirstDot.Y && anchor.X > line.FirstDot.X && anchor.X < line.SecondDot.X))) 
                 && ((IContainsLayerInfo)line.FirstDot).LayerNumber == anchor.LayerNumber)*/
            }

            FootholdLine lineA;
            FootholdLine lineB;
            //Part 4 - removing duplicate footholds (caused by step 3, case 1)
            footholds.Sort(new Comparison<FootholdLine>(FHSorter));
            for (int i = 0; i < footholds.Count - 1; i++)
            {
                lineA = footholds[i];
                lineB = footholds[i + 1];
                if (lineA.FirstDot.X == lineB.FirstDot.X && lineA.FirstDot.Y == lineB.FirstDot.Y &&
                    lineA.SecondDot.X == lineB.SecondDot.X && lineA.SecondDot.Y == lineB.SecondDot.Y)
                {
                    //footholds.RemoveAt(i);
                    lineA.remove = true;
                    i--;
                }
            }

            //Part 5 - executing foothold changes and updating anchors
            foreach (FootholdAnchor anchor in anchors)
                for (int i = 0; i < anchor.connectedLines.Count; i++)
                    if (((FootholdLine)anchor.connectedLines[i]).remove)
                        anchor.connectedLines.RemoveAt(i);
            List<FootholdLine> newFootholds = new List<FootholdLine>(footholds.Count);
            foreach (FootholdLine fh in footholds)
                if (!fh.remove)
                    newFootholds.Add(fh);
            footholds = newFootholds;


            //Part 6 - dealing with 3 way (or more) foothold junctions
            /*foreach (FootholdAnchor anchor in anchors)
            {
                if (anchor.connectedLines.Count > 2)
                {
                    if (anchor.keyAnchor)
                    {
                        int leftLineIndex = -1;
                        int rightLineIndex = -1;
                        int slopedLineIndex = -1;
                        for(int i=0; i<anchor.connectedLines.Count; i++)
                        {
                            FootholdLine line = (FootholdLine)anchor.connectedLines[i];
                            if (line.FirstDot.Y == line.SecondDot.Y)
                            {
                                if (anchor == line.FirstDot) rightLineIndex = i;
                                else if (anchor == line.SecondDot) leftLineIndex = i;
                                else
                                {
                                    MessageBox.Show("Error at foothold parsing"); //TODO
                                }
                            }
                            else if (line.FirstDot.X != line.SecondDot.X) slopedLineIndex = i;
                        }
                        if (leftLineIndex == -1 || rightLineIndex == -1 || slopedLineIndex == -1)
                        {
                            MessageBox.Show("Error at foothold parsing"); //TODO
                        }
                        FootholdLine slopedLine = (FootholdLine)anchor.connectedLines[slopedLineIndex];
                        if (slopedLine.FirstDot.Y < slopedLine.SecondDot.Y)
                        { //eliminate left
                            EliminateFootholdTree(anchor, leftLineIndex, ref footholds);
                        }
                        else
                        {
                            //eliminate right
                            EliminateFootholdTree(anchor, rightLineIndex, ref footholds);
                        }
                    }
                    else
                    {
                        double lowestLength = double.MaxValue;
                        int shortestLineIndex = -1;
                        for (int i = 0; i < anchor.connectedLines.Count; i++)
                        {
                            double length = CalculateFootholdTreeLength(anchor, i);
                            if (length < lowestLength)
                            {
                                lowestLength = length;
                                shortestLineIndex = i;
                            }
                        }
                        EliminateFootholdTree(anchor, shortestLineIndex, ref footholds);
                    }
                }
            }

            //Part 7 - executing foothold changes and updating anchors (again)
            foreach (FootholdAnchor anchor in anchors)
                for (int i = 0; i < anchor.connectedLines.Count; i++)
                    if (((FootholdLine)anchor.connectedLines[i]).remove)
                        anchor.connectedLines.RemoveAt(i);*/

            oldAnchors.Clear();
            foreach (FootholdAnchor anchor in anchors) { /*anchor.keyAnchor = false; */oldAnchors.Add(anchor); }
            oldFootholds.Clear();
            foreach (FootholdLine fh in footholds) { /*anchor.keyAnchor = false; */oldFootholds.Add(fh); }
        }