public void UpdateAllContinues(string level, float tgt_x, float tgt_y, float tgt_z, GameContinue closest)
 {
     foreach (var lbl in labels)
     {
         GameContinue cont = (GameContinue)lbl.Tag;
         if (cont.Level != level)
         {
             lbl.Font = fontItalic;
         }
         else if (cont == closest)
         {
             lbl.Font = fontBold;
         }
         else
         {
             lbl.Font = fontRegular;
         }
         lbl.Text = $"{cont.Name}: {MathExt.Dist3D(tgt_x, tgt_y, tgt_z, cont.X, cont.Y, cont.Z)/4096}";
     }
 }
        public MainForm()
        {
            Emulator = new Emulators.PCSX2();
            InitializeComponent();
            MinimumSize     = Size;
            continueForm    = new ContinueForm(this);
            symbolTableForm = new SymbolTableForm();
            //continueForm.Show();
            PopulateGamesList();
            SetContinueLevels();

            memtimer = new Timer
            {
                Enabled  = false,
                Interval = 16
            };
            memtimer.Tick += (object sender, EventArgs e) =>
            {
                Emulator.UpdateProcess("pcsx2");
                if (Emulator.ProcessIsValid)
                {
                    try
                    {
                        Emulator.ReadFloat3(addrTargetPos, out float tgt_x, out float tgt_y, out float tgt_z);
                        lblPos.Text = $"X: {tgt_x/4096} ({tgt_x})\nY: {tgt_y/4096} ({tgt_y})\nZ: {tgt_z/4096} ({tgt_z})";

                        GameContinue close1 = null, close2 = null;
                        string       level = (string)dpdLevel.SelectedItem;
                        level = level.Substring(level.LastIndexOf('(') + 1, level.LastIndexOf(')') - (level.LastIndexOf('(') + 1));
                        foreach (var kvp in continues)
                        {
                            if (kvp.Key == level)
                            {
                                foreach (GameContinue cont in kvp.Value)
                                {
                                    float dist = MathExt.Dist3D(tgt_x, tgt_y, tgt_z, cont.X, cont.Y, cont.Z);
                                    if (close1 == null)
                                    {
                                        close1 = cont;
                                    }
                                    else if (dist < MathExt.Dist3D(tgt_x, tgt_y, tgt_z, close1.X, close1.Y, close1.Z))
                                    {
                                        close2 = close1;
                                        close1 = cont;
                                    }
                                    else if (close2 == null || dist < MathExt.Dist3D(tgt_x, tgt_y, tgt_z, close2.X, close2.Y, close2.Z))
                                    {
                                        close2 = cont;
                                    }
                                }
                                break;
                            }
                        }
                        if (close1 == null)
                        {
                            lblContinueName1.Text = "(no available checkpoint)";
                        }
                        else
                        {
                            lblContinueName1.Text = $"{close1.Name} ({MathExt.Dist3D(tgt_x, tgt_y, tgt_z, close1.X, close1.Y, close1.Z)/4096}m)";
                        }
                        if (close1 != null && close2 == null)
                        {
                            lblContinueName2.Text = "(idle deload has no effect)";
                        }
                        else if (close2 == null)
                        {
                            lblContinueName2.Text = "(no available checkpoint)";
                        }
                        else
                        {
                            lblContinueName2.Text = $"{close2.Name} ({MathExt.Dist3D(tgt_x, tgt_y, tgt_z, close2.X, close2.Y, close2.Z)/4096}m)";
                        }
                        if (close1 != null && close2 != null)
                        {
                            float mx = (close1.X + close2.X) / 2;
                            float my = (close1.Y + close2.Y) / 2;
                            float mz = (close1.Z + close2.Z) / 2;
                            float vx = close2.X - close1.X;
                            float vy = close2.Y - close1.Y;
                            float vz = close2.Z - close1.Z;
                            float bp = mx * vx + my * vy + mz * vz;
                            float d  = -(vx * tgt_x + vy * tgt_y + vz * tgt_z - bp) / (float)Math.Sqrt(vx * vx + vy * vy + vz * vz);
                            lblContinueMedianDist.Text = $"{d/4096}m ({d})";
                        }
                        else
                        {
                            lblContinueMedianDist.Text = "(no second checkpoint)";
                        }
                        if (continueForm.Visible)
                        {
                            continueForm.UpdateAllContinues(level, tgt_x, tgt_y, tgt_z, close1);
                        }
                        if (symbolTableForm.Visible)
                        {
                            Emulator.ReadMem(addrSymbolTable, 0x10000, out byte[] symboltable);
                            Emulator.ReadMem(addrSymbolTable + 65336, 0x10000, out byte[] symbolnameptrs);
                            symbolTableForm.UpdateSymbols(Emulator, addrSymbolTable);
                        }

                        lblError.Visible = false;
                        fraGame.Visible  = true;
                    }
                    catch (Win32Exception ex)
                    {
                        lblError.Text     = $"ERROR: {ex.Message}\n\nMake sure the settings are correct!";
                        lblError.Location = fraGame.Location;
                        lblError.Size     = fraGame.Size;
                        lblError.Visible  = true;
                        fraGame.Visible   = false;
                    }
                }
                else
                {
                    lblError.Text     = "Process could not be found, or is in an invalid state.\nGame may not be booted up, or emulator is unsupported.";
                    lblError.Location = fraGame.Location;
                    lblError.Size     = fraGame.Size;
                    lblError.Visible  = true;
                    fraGame.Visible   = false;
                }
            };

            dpdGame.SelectedIndex  = 1;
            dpdLevel.SelectedIndex = 0;
        }